📄 026_pre_fs_c.html
字号:
<html lang="zh-CN" xmlns:gdoc=""> <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <style type="text/css">/* default css */table { font-size: 1em; line-height: inherit;}div, address, ol, ul, li, option, select { margin-top: 0px; margin-bottom: 0px;}p { margin: 0px;}body { margin: 0px; padding: 0px; font-family: Verdana, sans-serif; font-size: 10pt; background-color: #ffffff;}h6 { font-size: 10pt }h5 { font-size: 11pt }h4 { font-size: 12pt }h3 { font-size: 13pt }h2 { font-size: 14pt }h1 { font-size: 16pt }blockquote {padding: 10px; border: 1px #DDD dashed }a img {border: 0}div.google_header, div.google_footer { position: relative; margin-top: 1em; margin-bottom: 1em;}/* end default css */ /* default print css */ @media print { body { padding: 0; margin: 0; } div.google_header, div.google_footer { display: block; min-height: 0; border: none; } div.google_header { flow: static(header); } /* used to insert page numbers */ div.google_header::before, div.google_footer::before { position: absolute; top: 0; } div.google_footer { flow: static(footer); } /* always consider this element at the start of the doc */ div#google_footer { flow: static(footer, start); } span.google_pagenumber { content: counter(page); } span.google_pagecount { content: counter(pages); } } @page { @top { content: flow(header); } @bottom { content: flow(footer); } } /* end default print css */ /* custom css *//* end custom css */ /* ui edited css */ body { font-family: Verdana; font-size: 10.0pt; line-height: normal; background-color: #ffffff; } .documentBG { background-color: #ffffff; } /* end ui edited css */</style> </head> <body revision="dcbsxfpf_11hd7t62:5"> <table align=center cellpadding=0 cellspacing=0 height=5716 width=802>
<tbody>
<tr>
<td height=5716 valign=top width=802>
<pre>2006-12-21 <br> </pre>
<pre> 阅读fs之前普通文件系统包含大量与disk互动的部分.为了更好的理解这些操作.先将IDE<br>驱动的相关部分研究一下. 解决一直有点模糊的问题.</pre>
<pre> <b>大容量磁盘相关问题</b>
最初的问题来自于BIOS的设计人员和ATA接口的设计人员没有达成一致的意见,BIOS和ATA
为CHS分配的总的字节数,以及cylinder, head, and sector各占用多少bit,都不相同。更严
重的问题是好像谁也没有预见到磁盘的容量增长的如此迅速!
</pre>
<pre> 先来看看各种借口的容量限制: <br>BIOS int 13接口:<br> Cylinder head sector limitation time reach limitation<br>bits 10 8 6 total 24bits 8.4GB <br>ATA 接口: cylinder head sector<br>bits 16 4 8 total 28bits 137.4GB Sept 2001 160 GB Maxtor Diamondmax<br></pre>
<pre>扩展 int 13 接口:(97年之后的bios基本都支持)<br>bits 8bytes*8 64bit LBA number 9.4 trillion gigabytes !!!!<br>ATA-6 接口:<br>bits 6bytes*8 48bit LBA number less tan Extended int13,but Large enough!!!</pre>
<pre> 可以看到,BIOS被设计成最大可寻址8GB, ATA-1-5也只能寻址到137GB。这是设计上的硬伤。<br>这两个限制也由此而来。<br><br>在达到8GB之前值得注意的限制是528MB限制:<br>bios 13 和 ATA-5的联合,old bios 直接使用用户传入的CHS给ATA, BIOS mode->Normal<br> Cylinder head sector limitation time<br> 10 4 6 2^20 = 528MB being a problem around 1993 <br> </pre>
<pre> 为了解决这个问题,BIOS引入了Extended CHS,即ECHS,有些bios中叫large mode. <br>以一个2.95GiB的硬盘为例, 硬件报告的CHS是 6136/16/63<br> Cylinders Heads Sectors Capacity <br>IDE/ATA Limits 65,536 16 256 128 GiB<br>Hard Disk Logical Geometry 6,136 16 63 2.95 GiB<br>BIOS Translation Factor divide by 8 multiply by 8<br>BIOS Translated Geometry 767 128 63 2.95 GiB<br>BIOS Int 13h Limits 1024 256 63 7.88GiB<br> </pre>
<pre> 突破8G的限制只用使用extended int13+ LBA mode(ATA). 如果在使用LBA模式的情况<br>下还有int 13的程序,则BIOS将CHS直接转换成LBA地址,这个叫assisted LBA. <br> 无论如何,只要使用BIOS无论是ECHS转换还是assisted LBA, 都无法突破8.5 GBlimit.<br>并且还有一个问题值得一提: 最大head 数不是256,而是255,因为dos和window95 不能处理<br>head为256的情况.所以总的限制比8.5GB要稍微少一些. <br> </pre>
<pre> ATA规定,大于8.4 GB 的硬盘应该报告CHS为16383/16/63,这意味着`geometry'过时了,<br>硬盘的总大小不能通过geometry来计算了,只能从IDENTIFY command返回的LBA capacity域<br>来获知. 大于137.4 GB的硬盘应该报告LBA capacity是0xfffffff = 268435455 sectors <br>(137G),正确的disksize在新的48 bit的域中.<br> </pre>
<pre> 下面列出linux对大容量磁盘的支持情况:<br> >8.4 GB kernel should be 2.0.34 or later.<br> >33.8 GB kernel should be 2.0.39/2.2.14/2.3.21 or later.<br> > 137 GB kernel should be 2.4.19/2.5.3 or later. <br> </pre>
<pre> 检查一个版本的linux是否支持大容量硬盘,可以看函数<font color=#0000ff>do_rw_disk</font> (ide-disk.c).</pre>
<pre>refrence:<br>1. Large Disk Drives >8.4Gb (in addtion, a IBM doc attached)<br>http://www-oss.fnal.gov/projects/fermilinux/common/faq/old/0009.html</pre>
<pre>2. PC guid of hard disk<br> http://www.pcguide.com/ref/hdd/index.htm<br> </pre>
<pre> <br> <b>block size的种种问题</b></pre>
<pre> 分析mm的时候说过do_generic_file_read的几个问题,关键的一点是理解最基本的观点。<br>首先是磁盘上的文件尽量缓存在内存,这样才能更快的读写。缓存在内存中,最基本的单<br>位就是内存页面了,在i386上,常见的大小是4k。<br> 通过缓存读取文件的时候,首先是把用户指定的以字节为单位的offset,size转换成<br>以4k为单位的内存页,这样可以直接拷贝数据给用户。如果文件不在缓存中,就要从磁盘<br>读取,比如通过block_read_full_page从磁盘读取一个page大小的数据。<br> <br> 文件存储于一个具体的文件系统,而这个文件系统有自己的分配单位,那就是block,<br>比如对于ext2,block就是具体的ext2可以分配的最小单位,常见的ext2的block size是<br>1k,可以为2k,4k,但是不能大于4k(refer. ext2_read_super)。<br> 作为存储在这个ext2上的文件,属于它的所有block纪录在磁文件的inode中,纪录的<br>是每一个block的block number。ext2上bocknumber 从1开始(block0#是boot),最大看磁<br>盘容量了,呵呵。这样一来,就把每个文件,以block size为单位分成了从0开始的block。<br>每个文件都是这样一个线型空间,通过inode的一个数组映射到ext2文件系统上从1开始的<br>block空间去。<br> <br> 过了这样一个步骤,就要和磁盘打交道。通常这个接口是bread(block#, size).<br>struct buffer_head * bread(kdev_t dev, int block, int size)<br>{<br> struct buffer_head * bh;</pre>
<pre> bh = getblk(dev, block, size); /*bh包含了block#和block的size信息*/<br> if (buffer_uptodate(bh))<br> return bh;<br> ll_rw_block(READ, 1, &bh); /* 传递给硬盘驱动*/<br> wait_on_buffer(bh);<br> if (buffer_uptodate(bh))<br> return bh;<br> brelse(bh);<br> return NULL;<br>}<br> 这个函数的意思是按照块大小是size读取块号为block的块. 换一种角度,bread按照文件系<br>统理解磁盘的方式提供一个访问磁盘的接口,块大小由size指定,读取那个块由block指定.至<br>于磁盘怎么划分扇区,就不用操心了.<br></pre>
<pre> <b><font size=3>IDE Driver overview</font></b></pre>
<pre> 我们从bread入手,看看磁盘驱动如何读取磁盘扇区。上边说了bread,这里从ll_rw_block<br>开始。过程虽然从代码里看很复杂,但是主线并不复杂: 给buffer设置一个回叫函数,等磁盘<br>完成读取后通过这个回叫函数设置bh的uptodate位,同时,如果有任务等待这个bh读取完成则唤醒<br>等待的任务. <br> 提交给磁盘的时候,磁盘将这个操作安排到一个队列,然后对所有请求进行调度,以提高磁盘io<br>速度,然后根据调度的结果执行读取任务.<br><font color=#0000ff>ll_rw_block</font>(int rw, int nr, struct buffer_head * bhs[])<br>{<br> unsigned int major;<br> int correct_size;<br> int i;<br> /*先进行一系列的检查*/<br> </pre>
<pre> 1. /* Determine correct block size for this device. */<br> 2. /* Verify requested block sizes. */<br> 3. 如果是写操作,看看设备是否容许写<br> <br> /*接着是为bh设置b_end_io:end_buffer_io_sync,通过这个函数通知等待的进程*/<br> for (i = 0; i < nr; i++) {<br> struct buffer_head *bh;<br> bh = bhs[i];</pre>
<pre> /* Only one thread can actually submit the I/O. */<br> if (test_and_set_bit(BH_Lock, &bh->b_state))<br> continue;</pre>
<pre> /* We have the buffer lock */<br> bh->b_end_io = end_buffer_io_sync;<br> </pre>
<pre> ......... //考虑一些可能存在竞争的情况<br> </pre>
<pre> submit_bh(rw, bh); /*提交申请给磁盘驱动程序*/<br> }<br> return;<br> .... //clean<br>}<br> </pre>
<pre> 然后是通过submit_bh给磁盘驱动提交申请:<br>void <font color=#0000ff>submit_bh</font>(int rw, struct buffer_head * bh)<br>{<br> if (!test_bit(BH_Lock, &bh->b_state))<br> BUG();</pre>
<pre> set_bit(BH_Req, &bh->b_state);</pre>
<pre> /*<br> * First step, 'identity mapping' - RAID or LVM might<br> * further remap this.<br> * 这里把文件系统定义的block#(size)转化为扇区号<br> */<br> bh->b_rdev = bh->b_dev;<br> bh->b_rsector = bh->b_blocknr * (bh->b_size>>9);</pre>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -