对文件系统而言,文件仅是一系列可读写的数据块。文件系统并不需要了解数据块应该放到物理介质上什么位置。这些都是设备驱动的任务。无论何时,只要文件系统需要从包含它的块设备中读取信息或数据,它就将请求底层的设备驱动读取一个基本块大小整数倍的数据块。EXT2文件系统将它所使用的逻辑分区划分成数据块组。每个数据块组都将那些对文件系统完整性最重要的信息复制出来,同时将实际文件盒目录看做信息与数据块。
罗即文件系统管理的是一个逻辑空间,这个逻辑空间就像一个大的数组,数组的每个元素就是文件系统操作的基本单位——逻辑块。逻辑块是从0开始编号的,而且,逻辑块是连续的,逻辑块相对的是物理块。通常,EXT2的物理块占一个或几个连续的扇区。
一般而言,只有块组0的超级块才读入内存,其他块组的超级块仅仅作为备份。在系统运行期间,要将超级块复制到内存系统缓冲区。
块位图和节点位图
在EXT2文件系统中,采用位图描述数据块和索引节点的使用情况,每个块组中占用两个块,即一个用来描述该数据块的使用情况,另一个描述该组索引节点的使用情况。这两个块分别称为数据位图块和索引节点位图块。数据位图块中的每一位表示该块组中的每一个块的使用情况,如果为0,则表示相应数据块空闲,如果是1,则表示已分配。
索引节点表
每个块组中的索引节点都存储在各自的索引节点表中,并且按索引节点号依次存储。索引节点表通常占好几个数据块,索引节点表所占的块使用时也想普通的数据块一样被调入块高速缓存。
EXT2整个磁盘的逻辑结构如图所示:
EXT2文件系统的几个数据结构
1 EXT2超级块
超级块中包含了描述文件系统基本尺寸和形态的信息。文件系统管理器利用他们来使用和维护文件系统。EXT2超级块是用来描述EXT2文件系统整体信息的数据结构,是EXT2的核心所在。超级块经函数ext2_fill_supter读入后,又在内存中建立一个映像super_block.u.ext2_sb_info结构。
结构ext2_super_block列出如下:
逻辑块是从0开始编号的,对块大小为1KB的文件系统,s_first_data_block为1,对其他文件系统,则为0.
2 EXT2超级块信息结构
EXT2超级块被读入内存后,主要用于填写VFS的超级块。此外,它还要填写另外一个结构ext2_super_info。结构ext2_super_info描述了EXT2文件系统特定的信息。之所以要用到这个结构,是因为VFS的超级块必须兼容各种文件系统的不同的超级块结构,因此每个文件系统超级块特定的特性必须用另一个结构保存于内存中,以加快对文件的操作。EXT2超级块与VFS超级块的关系如图所示:
结构ext2_super_info列出如下:
3 超级块的操作函数结构
超级块的操作函数结构如下所示:
4 EXT2的索引节点inode
在EXT2文件系统中每个文件与目录由惟一的inode来描述。每个数据块组的EXT2 inode被保存在inode表中,同时还有一个位图被系统用来跟踪已分配和未分配的inode。
EXT2文件系统使用索引节点来记录文件信息。每个普通文件盒目录都有惟一的索引节点与之对应,索引节点中含有文件或目录的重要信息。当你要访问一个文件或目录时,通过文件或目录名首先找到与之对应的索引节点,然后通过索引节点得到文件或目录的信息及磁盘上的具体的存储位置。
EXT2在硬盘上的索引节点的数据结构如下:
EXT2通过索引节点中的数据块指针数组进行逻辑块到物理块的映射。在EXT2索引节点中,数据块中数组共有15项,前12个为直接指针,后三个分别为“一次间接指针”、“二次间接指针”、“三次间接指针”,EXT2默认的物理块大小为1KB,块地址占4个字节,所以每个物理块可以存储256个地址。这样,文件大小最大可达12KB+256KB+64MB+16GB。但实际上,Linux是32位系统,故文件大小最大只能为4GB,及整个文件系统都被一个文件所占用。索引节点的物理块指针数组如图所示:
系统是以逻辑块号为索引查找物理块的。例如,要找到第100个逻辑块对应的物理块,因为256+12>100>12,所以要用到一次间接块,在一次间接块中查找第88项,此项内容就是对应的物理块的地址。
节点在磁盘上是经过编号的。其中,有一些节点有特殊用途,用户不能使用。这些特殊节点定义为:
5 EXT2文件系统的节点信息结构
与EXT2超级块类似,当磁盘上的索引节点调入内存后,除了要填写VFS的索引节点外,系统还要根据它填写另一个数据结构ext2_inode_info,其作用也是为了存储特定文件系统自己的特性。
结构ext2_inode_info分析如下:
VFS索引节点中没有物理块指针数组的域,这个EXT2特有的信息在调入内存后,就必须保持在ext2_inode_info这个结构中。
6 节点操作函数结构
7 文件操作函数结构
8 EXT2文件系统的组描述符
在块组中紧跟着超级块后面的块是组描述符,在start_sect+block_size*2位置上。乘以2的原因是block_size是KByte为单位,我们用扇区访问。组描述符表每一项为组描述符,是一个叫ext2_group_desc的数据结构,供32字节。它用来描述某个块组的整体信息。
找到了组描述符,可得到很多信息,如该组块组位图的位置,该组块inode位图位置,该组块inode表的位置等。
组描述符的定义如下:
EXT2 文件系统建立过程
在 函数init_ext2_fs注册了EXT2文件系统,函数分析如下:
文件系统实例ext2_fs_type列出如下:
函数ext2_get_sb打开块设备,得到超级块,将这个超级块加到全局super_blocks链表中,并挂接文件系统。函数ext2_get_sb列出如下:
函数ext2_fill_super从硬盘中读出超级块数据并填充超级块结构。
超级块操作函数集实例ext2_sops列出如下:
文件的读写
文件的读写操作都调用到具体文件系统的读写操作函数结构,这里即调用到EXT2文件系统的ext2_file_operations结构,得到具体的操作函数。
下图为read系统调用的操作函数层次图,可见EXT2文件系统的读操作最终调用ext2_readpage函数完成,对于文件读操作过程中的文件对内存的映射过程。
结构ext2_file_operations是EXT2文件系统对于文件的操作函数集,列出如下:
ext2_aops结构是EXT2 文件系统中具体操作实现函数集,它被ext2_file_operations结构的函数所调用。列出如下:
ext2_aops结构中的这些函数列出如下:
这些函数除了调用的ext2_get_block函数是EXT2文件系统特有的外,其他都是fs/buffer.c中的函数。
ext2_get_block()将对文件系统的逻辑块号转换为块设备的逻辑块号。这种转化关系是由ext2_inode结构中i_block[]数组描述的i_block[]的前12项为直接索引表,第13项为间接索引块指针,第14项为二重索引块指针,第15项为三重索引块指针。当文件长度不超过12个块时,可通过直接块索引表直接定位目标块;当文件长度超过12块,并且剩余的部分不超过间接块索引数量时,就在间接块索引块中定位目标块,依次类推。
函数ext2_get_block功能是从逻辑块序号得到对应物理块。若对应物理块被删除,则重新分配,并得到它间接块路径。
函数ext2_get_block具体分析如下:
系统是以逻辑块号为索引查找物理块的。例如,要找到第100个逻辑块对应的物理块,因为256+12>100>12,所以要用到一次间接块,在一次间接块中查找第88项,此项内容就是对应的物理块的地址。
函数ext2_get_branch从物理块中读取数据到chain的buffer中,函数的参数说明如下:
- inode 操作的节点
- depth 间接块的深度
- offset 间接物理块的指针数组
- chain 存储读取物理块的数据
- 存储错误标志
函数ext2_get_branch的功能是填充Indirect结构的数组,如果运行正常,则返回NULL。函数分析如下:
函数ext2_alloc_branch分配并建立一个块链表,其中参数inode表示需分配块的节点,参数num表示间接块的深度,参数offsets是一个数组,即offsets[num],参数branch是存储链表的地方。函数分析如下:
文件扩展时的数据块分配策略
文件系统普遍存在的一个问题是碎片化,即一个文件所包含的数据块遍布整个文件系统,这使得对文件数据块的顺序访问越来越慢。EXT2文件系统试图通过分配一个和当前文件数据块在物理位置上邻接,或者至少位于同一个数据块组中的新块来解决这个问题。
EXT2的目录项及文件的定位
在EXT2中,目录是一种特殊的文件,它是由ext2_dir_entry结构组成的列表。为了减少磁盘空间的浪费,这个结构是可变长的。但是,它还有一定的长度方面的限制:一是文件名最长只能为255个字符;二是尽管文件名长度可以不限,但系统自动将之变成4的整数倍,不足的地方用0填充。
链接文件
EXT2把文件名和文件信息分开存储,其中文件信息用索引节点来描述,目录项是用来联系文件名和索引节点的。目录项中,每一对文件名和索引节点号的一个一一对应称为一个链接,这就是说,同一个索引节点表可以对应多个不同的文件名。这种链接称为硬链接。可以用ln命令为一个已存在的文件建立一个新的硬链接:
ln /home/cyf/file1 /home/cyf/file2
建立了一个文件file2,链接到file1上。file2和file1有相同的索引节点号,也就是和file1共享同一个索引节点。在建立了一个新的硬链接后,这个索引节点中的i_links_count值将加1,i_links_count的值反映了链接到这个索引节点上的文件数。
使用硬链接的好处在于:
1)由于删除文件时,实际上先对i_links_count做减1,如果i_links_count不为0,则结束,即仅仅删除了一个硬链接,实际文件的数据并没有删除。只有在i_links_count为0时,真正将文件从磁盘上删除。这样,你可以对重要的文件作多个链接,防止文件被删除。
2)允许用户在不进入某个目录的情况下对该目录下面的文件进行处理。
符号链接与硬链接最大的不同就在于它并不与索引节点建立链接,也就是说,当为一个文件建立一个符号链接时,索引节点的链接计数并不变化。当你删除一个文件时,它的符号链接文件也就失去了作用,而当你删除一个文件的符号链接文件,对该文件本身并无影响。