标签:
ext2文件系统
宗旨:技术的学习是有限的,分享的精神的无限的。
一、总体存储布局
一个磁盘可以划分成多个分区,每个分区必须先用格式化工具(例如某种mkfs命令)格 式化成某种格式的文件系统,然后才能存储文件,格式化的过程会在磁盘上写一些管理存储布局的 信息。
文件系统中存储的最小单位是块(Block),一个块究竟多大是在格式化时确定的,例如mke2fs的-b选项可以设定块大小为1024、 2048或4096字节。而上图中启动块(Boot Block) 的大小是确定的,就是1KB,启动块是由PC标准规定的,用来存储磁盘分区信息和启动信息,任何文件系统都不能使用启动块。启动块之后才是ext2文件系统的开始,ext2文件系统将整个分区划成若干个同样大小的块组(Block Group),每个块组都由以下部分组成。
1、 超级块(SuperBlock)
描述整个分区的文件系统信息,例如块大小、文件系统版本号、上次mount的时间等等。超级块在每个块组的开头都有一份拷贝。
2、 块组描述符表(GDT,GroupDescriptor Table)
由很多块组描述符组成,整个分区分成多少个块组就对应有多少个块组描述符。每个块组描述符(GroupDescriptor)存储一个块组的描述信息,例如在这个块组中从哪里开始是inode表,从哪里开始是数据块,空闲的inode和数据块还有多少个等等。和超级块类似,块组描述符表在每个块组的开头也都有一份拷贝,这些信息是非常重要的,一旦超级块意外损坏就会丢失整个分区的数据,一旦块组描述符意外损坏就会丢失整个块组的数据,因此它们都有多份拷贝。通常内核只用到第0个块组中的拷贝,当执行e2fsck检查文件系统一致性时,第0个块组中的超级块和块组描述符表就会拷贝到其它块组,这样当第0个块组的开头意外损坏时就可以用其它拷贝来恢复,从而减少损失。
3、块位图(BlockBitmap)
一个块组中的块是这样利用的:数据块存储所有文件的数据,比如某个分区的块大小 是1024字节,某个文件是2049字节,那么就需要三个数据块来存,即使第三个块只存了一个 字节也需要占用一个整块;超级块、块组描述符表、块位图、 inode位图、 inode表这几部分 存储该块组的描述信息。那么如何知道哪些块已经用来存储文件数据或其它描述信息,哪些块仍然空闲可用呢?块位图就是用来描述整个块组中哪些块已用哪些块空闲的,它本身占一个块,其中的每个bit代表本块组中的一个块,这个bit为1表示该块已用,这个bit为0表示该块 空闲可用。
为什么用df命令统计整个磁盘的已用空间非常快呢?因为只需要查看每个块组的块位图即可,而不需要搜遍整个分区。相反,用du命令查看一个较大目录的已用空间就非常慢,因为 不可避免地要搜遍整个目录的所有文件。
与此相联系的另一个问题是:在格式化一个分区时究竟会划出多少个块组呢?主要的限制在于块位图本身必须只占一个块。用mke2fs格式化时默认块大小是1024字节,可以用-b参数指定块大小,现在设块大小指定为b字节,那么一个块可以有8b个bit,这样大小的一个块位图就 可以表示8b个块的占用情况,因此一个块组最多可以有8b个块,如果整个分区有s个块,那么就可以有s/(8b)个块组。格式化时可以用-g参数指定一个块组有多少个块,但是通常不需要手 动指定, mke2fs工具会计算出最优的数值。
4、 inode位图(inodeBitmap)
和块位图类似,本身占一个块,其中每个bit表示一个inode是否空闲可用。
5、 inode表(inodeTable)
我们知道,一个文件除了数据需要存储之外,一些描述信息也需要存储,例如文件类型(常 规、目录、符号链接等),权限,文件大小,创建/修改/访问时间等,也就是ls -l命令看到 的那些信息,这些信息存在inode中而不是数据块中。每个文件都有一个inode,一个块组中的所有inode组成了inode表。
inode表占多少个块在格式化时就要决定并写入块组描述符中, mke2fs格式化工具的默认策略 是一个块组有多少个8KB就分配多少个inode。由于数据块占了整个块组的绝大部分,也可以 近似认为数据块有多少个8KB就分配多少个inode,换句话说,如果平均每个文件的大小 是8KB,当分区存满的时候inode表会得到比较充分的利用,数据块也不浪费。如果这个分区 存的都是很大的文件(比如电影),则数据块用完的时候inode会有一些浪费,如果这个分区 存的都是很小的文件(比如源代码),则有可能数据块还没用完inode就已经用完了,数据块 可能有很大的浪费。如果用户在格式化时能够对这个分区以后要存储的文件大小做一个预测,也可以用mke2fs的-i参数手动指定每多少个字节分配一个inode。
6、 数据块(DataBlock)
根据不同的文件类型有以下几种情况 对于常规文件,文件的数据存储在数据块中。 对于目录,该目录下的所有文件名和目录名存储在数据块中,注意文件名保存在它所在 目录的数据块中,除文件名之外, ls -l命令看到的其它信息都保存在该文件的inode中。注意这个概念:目录也是一种文件,是一种特殊类型的文件。对于符号链接,如果目标路径名较短则直接保存在inode中以便更快地查找,如果目标 路径名较长则分配一个数据块来保存。设备文件、 FIFO和socket等特殊文件没有数据块,设备文件的主设备号和次设备号保存 在inode中。
二、研究文件系统格式
首先创建一个1MB的文件并清零(用一个文件代替整个分区)
dd if=/dev/zero of=fs count=256 bs=4K
cp命令可以把一个文件拷贝成另一个文件,而dd命令可以把一个文件的一部分拷贝成另一个文件。这个命令的作用是把/dev/zero文件开头的1M(256×4K)字节拷贝成文件名为fs的文件。/dev/zero是一个特殊的设备文件,它没有磁盘数据块,对它进行读操作传给设 备号为1, 5的驱动程序。 /dev/zero这个文件可以看作是无穷大的,不管从哪里开始读,读出来的 都是字节0x00。因此这个命令拷贝了1M个0x00到fs文件。 if和of参数表示输入文件和输出文件,count和bs参数表示拷贝多少次,每次拷多少字节。
现在fs的大小仍然是1MB,但不再是全0了,其中已经有了块组和描述信息。用dumpe2fs工具可以 查看这个分区的超级块和块组描述符表中的信息:
根据上面讲过的知识简单计算一下,块大小是1024字节, 1MB的分区共有1024个块,第0个块是启 动块,启动块之后才算ext2文件系统的开始,因此Group 0占据第1个到第1023个块,共1023个 块。块位图占一个块,共有1024×8=8192个bit,足够表示这1023个块了,因此只要一个块组就够了。默认是每8KB分配一个inode,因此1MB的分区对应128个inode,这些数据都和dumpe2fs的输 出吻合。
用常规文件制作而成的文件系统也可以像磁盘分区一样mount到某个目录:
-o loop选项告诉mount这是一个常规文件而不是一个块设备文件。mount会把它的数据块中的数据 当作分区格式来解释。文件系统格式化之后在根目录下自动生成三个子目 录:., ..和lost+found。其它子目录下的.表示当前目录, ..表示上一级目录,而根目录 的.和..都表示根目录本身。 lost+found目录由e2fsck工具使用,如果在检查磁盘时发现错误,就把有错误的块挂在这个目录下,因为这些块不知道是谁的,找不到主,就放在这里“失物招领”了。
现在可以在/mnt目录下添加删除文件,这些操作会自动保存到文件fs中。然后把这个分区umount下 来,以确保所有的改动都保存到文件中了。sudo umount /mnt
现在我们用二进制查看工具查看这个文件系统的所有字节,并且同dumpe2fs工具的输出信息相比较,就可以很好地理解文件系统的存储布局了。
【截图中省略N行】
以*开头的行表示这一段数据全是零因此省略了。详细分析od输出的信息:
从000000开始的1KB是启动块,由于这不是一个真正的磁盘分区,启动块的内容全部为零。 从000400到0007ff的1KB是超级块,对照着dumpe2fs的输出信息,详细分析如下:
超级块中从0004d0到末尾的204个字节是填充字节,保留未用。注意, ext2文件系统 中各字段都是按小端存储的,如果把字节在文件中的位置看作地址,那么靠近文件开头的是低地 址,存低字节。
从000800开始是块组描述符表,这个文件系统较小,只有一个块组描述符,对照着dumpe2fs的输出 信息分析如下:
整个文件系统是1MB,每个块是1KB,应该有1024个块,除去启动块还有1023个块,分别编号 为1-1023,它们全都属于Group 0。其中, Block 1是超级块,接下来的块组描述符指出,块位图 是Block 6,因此中间的Block 2-5是块组描述符表,其中Block 3-5保留未用。块组描述符还指 出, inode位图是Block 7, inode表是从Block 8开始的,那么inode表到哪个块结束呢?由于超级块 中指出每个块组有128个inode,每个inode的大小是128字节,因此共占16个块, inode表的范围 是Block 8-23。
从Block 24开始就是数据块了。块组描述符中指出,空闲的数据块有986个,由于文件系统是新创 建的,空闲块是连续的Block 38-1023,用掉了前面的Block 24-37。从块位图中可以看出,前37位 (前4个字节加最后一个字节的低5位)都是1,就表示Block 1-37已用:
在块位图中, Block 38-1023对应的位都是0(一直到001870那一行最后一个字节的低7位),接下 来的位已经超出了文件系统的空间,不管是0还是1都没有意义。可见,块位图每个字节中的位应该 按从低位到高位的顺序来看。以后随着文件系统的使用和添加删除文件,块位图中的1就变得不连续了。
块组描述符指出,空闲的inode有117个,由于文件系统是新创建的,空闲的inode也是连续 的, inode编号从1到128,空闲的inode编号从12到128。从inode位图可以看出,前11位都是1,表 示前11个inode已用:
001c00这一行的128位就表示了所有inode,因此下面的行不管是0还是1都没有意义。已用 的11个inode中,前10个inode是被ext2文件系统保留的,其中第2个inode是根目录, 第11个inode是lost+found目录,块组描述符也指出该组有两个目录,就是根目录和lost+found。
探索文件系统还有一个很有用的工具debugfs,它提供一个命令行界面,可以对文件系统做各种操 作,例如查看信息、恢复数据、修正文件系统中的错误。下面用debugfs打开fs文件,然后在提示 符下输入help看看它都能做哪些事情:
把以上信息和od命令的输出对照起来分析:【根目录的inode】
上图中的st_mode以八进制表示,包含了文件类型和文件权限,最高位的4表示文件类型为目录(各 种文件类型的编码详见stat(2)),低位的755表示权限。 Size是1024,说明根目录现在只有一个数 据块。 Links为3表示根目录有三个硬链接,分别是根目录下的.和..,以及lost+found子目录下 的..。注意,虽然我们通常用/表示根目录,但是并没有名为/的硬链接,事实上, /是路径分隔 符,不能在文件名中出现。这里的Blockcount是以512字节为一个块来数的,并非格式化文件系统 时所指定的块大小,磁盘的最小读写单位称为扇区( Sector) ,通常是512字节,所 以Blockcount是磁盘的物理块数量,而非分区的逻辑块数量。根目录数据块的位置由上图中 的Blocks[0]指出,也就是第24个块,它在文件系统中的位置是24×0x400=0x6000,从od命令的输 出中找到006000地址【根目录数据块】
目录的数据块由许多不定长的记录组成,每条记录描述该目录下的一个文件,在上图中用框表示。 第一条记录描述inode号为2的文件,也就是根目录本身,该记录的总长度为12字节,其中文件名的 长度为1字节,文件类型为2(见下表,注意此处的文件类型编码和st_mode不一致),文件名是.。第二条记录也是描述inode号为2的文件(根目录),该记录总长度为12字节,其中文件名的长度 为2字节,文件类型为2,文件名字符串是..。第三条记录一直延续到该数据块的末尾,描 述inode号为11的文件( lost+found目录),该记录的总长度为1000字节(和前面两条记录加起来 是1024字节),文件类型为2,文件名字符串是lost+found,后面全是0字节。如果要在根目录下创 建新的文件,可以把第三条记录截短,在原来的0字节处创建新的记录。如果该目录下的文件名太 多,一个数据块不够用,则会分配新的数据块,块编号会填充到inode的Blocks[1]字段。
标签:
原文地址:http://blog.csdn.net/wqx521/article/details/50980244