ext2文件系统

来源:互联网 发布:淘宝店铺花呗怎么开通 编辑:程序博客网 时间:2024/06/06 02:55

经过前面两篇文章的讲解,我们对文件系统和磁盘管理有了大致的认识,那么现在我们应该找一个实例来深入认识这些方法,看看工业界是怎么把这些方法应用起来的(其实这些方法应该是首先被应用于工业界,然后再被操作系统总结出来的)。ext2文件系统,是Linux内核早期使用的文件系统,作为我们学习文件系统是很合适的。在学习ext2系统之前,我们不妨思考一下,如果给你一个光秃秃的磁盘,你需要创建一个文件系统,你要怎么做?文件的结构是怎么的?目录的结构是怎样的?怎么样来保证文件系统的可靠性?

ext2文件系统的磁盘组织

经过ext2格式化后的分区,其布局将呈现为下面这种形式:
这里写图片描述
ext2文件系统的盘块分成两大类,一类是存放文件内容数据的叫作数据盘块,另一类是保存元数据(管理数据)的叫作元数据盘块。但是它们的物理布局不是一刀切地简单分成两段,而是首先分成多个同尺寸块组(block group)的形式,在块组内再分成前后两部分——前面是元数据盘块后面是数据盘块。此外,一个硬盘的可引导分区的第一个
盘块是为引导系统而保留的,通常称为引导块(引导扇区),启动扇区并不是所有分区都需要的,非启动分区不需要这样的块。
每个块组包含以下元素:
超级块(super block):各个块组中的超级块都是相同的(互为备份),记录
文件系统全局性的管理信息和属性;
块组描述符(group descripter):每个块组中的块组描述符都是相同的(互为备份),记录各个块组的管理信息和相关属性;
其数据结构定义如下:
这里写图片描述
其中,当分配索引节点和数据盘块时,涉及到空闲盘块计数值bg_free_block_count、空闲索引节点计数值bg_free_inodes_count 和在用目录计数值bg_used_dirs_count 字段。数据盘块位图的块号在bg_block_bitmap 指出,索引节点位图盘块号bg_inode_bitmap指出,索引节点起点块号由bg_inode_table 指出。
下图是使用dump工具查看Linux的超级块和块组描述符片段:
这里写图片描述
一个数据盘块位图(data block bitmap):记录着本块组数据盘块(data blocks)的使用情况;
一个索引节点盘块位图(inode bitmap):记录着本块组索引节点表(inode table)的使用情况;
一个索引节点表(inode table):每个表项记录一个文件(普通文件或目录文件)的属性及数据块所在位置(含12 个直接索引项、1 个间接级索引、1 个二级间接索引
和1 个三级间接索引)。这里采用了外存组织方式的混合索引的组织方式。
这里写图片描述
其中i_block数组就是用来记录索引盘块号的包含直接索引到三级索引。
此外,在Unix系统万物皆文件的设计思想的影响下,目录也是通过索引结点来管理的,即一个索引结点可以指向一个文件,也可以指向一个目录,通过索引结点的i_mode字段来识别。
对于目录的结构体定义如下:
这里写图片描述
这里写图片描述
大量数据盘块(data blocks):记录着各种文件数据,使用情况由前面的数据盘块
位图记录,因此一个块组的数据盘块数量不得超过数据盘块位图的记录能力。

文件数据的定位

通过上面对ext2文件系统的整体布局的解读,我们已经认识到了ext2将磁盘分成一块一块,每一块称为块组,在每一个块组里面又分为元数据区和数据区。那么对于一个给定的文件名,是如何定位文件内容是存放在哪一个盘块呢?
下面就以temp.txt文件为例,讲解如何读取temp.txt的内容:
首先创建temp.txt文件,并在里面写上一些内容,然后使用ls命令查看其对应的索引结点和文件长度:
这里写图片描述
由上图我们知道索引结点为12,长度为40;
然后,我们使用公式,从索引结点号计算出文件所在的盘块号,这里就体现了文件系统的核心层-管理对象及其属性的软件集合。

inode_location_in_byte = inode_talbe_location + inode_offset*inode_size = inode_talbe_location + ((inode_number-1) % inodes_per_group) * inode_size

其中inode_table_location表示索引结点描述符起始位置,在块组描述符的bg_group_description字段得到。而inodes_per_group和inode_size则是前面超级块信息的数值。inode_number是索引块号。
经过上述公式的转换,我们得到该索引结点在磁盘中的位置为0x41D80:
这里写图片描述
其中第五个字节就是文件长度,为0x28000000,按小端读取,即是40,跟ls命令一致。我们知道ext2文件系统是采用多级索引混合的外存组织方式,而存放多级索引信息的是i_block数组,根据上面结构体的定义,i_block数组在结构体偏移40个字节,所以i_block[]首地址在0x41d80+0x28=0x41da8:该地址的直接索引值为0x601,所以文件temp.txt前面1KB所在的盘块起始地址为0x601*0x400=0x180400(因为该文件长度为40,一个盘块足以存取文件内容,所以i_block数组后面的值都为0):
这里写图片描述
发现内容跟temp.txt文件内容一致,为Hello world! abcdefghijklmnopqrstuvwxyz的ASCII码表示。

目录项的解读

为了解读目录项,首先创建目录项directory,该目录包含三个文件:
这里写图片描述
根据上图得到其索引结点号为121921,根据公式得到索引结点地址:0x1e000c00:
这里写图片描述
第四个字节表示目录文件大小为0x400(小端读取),即1024,i_block数组在后40个字节处,其中i_block[0]=0x078101=121921,跟ls命令一致。
再使用dd命令读取目录文件的内容:
这里写图片描述
对目录项的解读:
1) 首4 字节的数据是目录文件第一个目录项的inode 号 0x1dc41=121921,该目录是目录自身(也就是常说的“.”目录)。这个目录项指向的文件的inode 号为77217,即是directory 自身。这跟前面的ls –i 命令所查看到的inode 一致。
2) 接着的2 字节的数据是rec_len 属性 0xC=12,说明第一个目录项的大小为12 字节,这个属性是正确分割目录文件内容的重要信息,否则无法定位下一条目录项(目录项大小是不固定的)。
3) 接下来的1 字节数据是name_len,这里是为了正确读取name[]所需要的信息,0x1=1。
4) 再接下来的1 字节数据是file_type,0x2 代表这个目录项指向的文件是目录文件5) 再接下来,该目录的所有数据都是名字字符串name[],然后前面知道了name_len 为1,所以我们只看name[]的第一个字节是数据,0x2e 这里就要用ASCII 解读,0x2e=“.”。
继续分析可以知道,第二个项是“..”目录(即父目录/mnt/bean)索引节点号是0x02=2、
目录项长度0x0c=12 字节、文件名字符串长0x02=2 字节;第三个项是“file1”文件,其索
引节点号是0x01dc42=121922、目录项长度0x10=16 字节、文件名字符串长0x05=5 字节;
第四个项是“file2”文件,其索引节点号是0x01dc44=121924、目录项长度0x10=16 字节、
文件名字符串长0x05=5 字节;第五个项是“file3”文件,其索引节点号是0x01dc43=121923、
目录项长度0x03c8=968 字节、文件名字符串长0x05=5 字节。

总结

通过对上面ext2系统的讲解,相信同学们也明白了文件系统的系统架构和工作流程。ext2文件系统主要包含超级块、块组描述符、索引结点、目录项等结构体,明白了结构体的功能以后,需要知道如何通过索引结点号计算出索引结点在磁盘中的位置,然后就是对索引结点的解析,因为索引结点可能对应文件或者目录,这需要不同的解析,最后才能通过i_block数组里面的数据计算出文件内容的盘块地址,最终得到文件内容。明白了上述步骤,也算是掌握了ext2文件系统了吧。我觉得可以对比操作系统通用的文件管理和磁盘管理方法,看看ext2到底使用了哪种方法来加深印象,这样自己就更加理解文件系统了。