代码、内容参考来自于包括《操作系统真象还原》、《一个64位操作系统的设计与实现》以及《ORANGE’S:一个操作系统的实现》。
1.链式结构
硬盘是低速设备,其读写单位是扇区,为了避免频繁访问硬盘,操作系统不会有了一扇区数据就去读写一次磁盘,往往等数据积攒到足够大小时才一次性访问硬盘,这足够大小的数据就是块,硬盘读写单位是扇区,因此一个块是由多个扇区组成的,块大小是扇区大小的整数倍。
在Windows中,块被称为簇,比如在Windows中格式化分区时,若选择文件系统类型为FAT32,我们还可以选择多种不同大小的簇,有4KB,32KB等。以下为叙述方便,一律统称为块。
块是文件系统的读写单位,因此文件至少要占据一个块,当文件体积大于1个块时,文件肯定被拆分成多个块来存储。
拿FAT文件系统来说,FAT称为文件分配表,在此文件系统中存储的文件,其所有的块被用于链式结构来组织,在每个块的最后存储下一个块的地址,从而块与块之间串联到一起,这样一来,文件可以不连续存储,文件中的块可以分布在各个零散的空间中,有效地利用了存储空间,或者说是提升了磁盘的利用率,相当于节省了空间。
其结构如图所示:

通过链式结构来组织文件的弊端是当访问文件中的某个块时,必须要从头开始遍历块结点,效率不高。
2.索引结构
UINX操作系统使用索引结构inode,将文件以索引结构来组织,避免了访问某一数据块需要从头把其前所有数据块再遍历一次的缺点。 采用索引结构的文件系统,文件中的块依然可以分散到不连续的零散空间中,保留了磁盘高利用率的优点,更重要的是文件系统为每个文件的所有块建立了一个索引表,索引表就是块地址数组,每个数组元素就是块的地址,数组元素下标是文件块的索引,第n个数组元素指向文件中的第n个块,这样访问任意一个块的时候,只要从索引表中获得块地址就可以了,速度大大提升。
包含此索引表的索引结构称为inode,即index node,索引结点,用来索引、跟踪一个文件的所有块。 inode是文件索引结构组织形式的具体体现,必须为每个文件都单独配备一个这样的元信息数据结构,因此在UINX文件系统中,一个文件必须对应一个inode,磁盘中有多少文件就有多少inode。

UNIX将一部分块放在索引表中,如果文件很大,将其他块放在另一个索引表,具体做法是每个索引表中共15个索引项,暂时称此索引表为老索引表。老索引表中前12个索引项是文件的前12个块的地址,它们是文件的直接块,即可直接获得地址的块。若文件大于12个块,那就再建立个新的块索引表,新索引表称为一级间接块索引表,表中可容纳256个块的地址,各表项都是块的地址,这256个块地址需要通过一级间接块索引表才能获得,因此称为“间接块”,此表也要占用一个物理块来存储,该物理块的地址存储到老索引表的第 13 个索引项中。 有了一级间接块索引表,文件最大可达 12+256=268 个块。 要是文件超过268个块,可以再建立二级间接块索引表,此表中各表项存储的是一级间接块索引表,然后在老索引表中第14个索引项存储二级间接块索引表所在块的地址。还有三级。inode 中的前 12 个直接数据块指针和后 3 个间接块索引表用于指向文件的数据块实体。
inode逻辑结构如下:

在 inode 结构中,i结点编号是指此inode的序号,这通常是指它在inode数组中的下标,权限是指读、写、执行。属主是指文件的拥有者,时间是指创建时间、修改时间、访问时间等。文件大小是指文件的字节尺寸。 下面这些连续的各种块指针及索引表指针是文件所有块的索引,也就是指向文件的实体部分。
文件系统为实现文件管理方案,必然会创造出一些辅助管理的数据结构,只要用于管理、控制文件相关信息的数据结构都被称为FCB (File Contrl Block),即文件控制块, inode是FCB的一种。要想通过文件系统获得文件的实体,必须先要找到文件的inode。
Linux的文件系统借鉴了inode结构,同样是一个文件具有一个inode,有多少文件就有多少inode。但是硬盘空间是有限的,而且inode本身也要占用磁盘空间来存储,文件系统是针对各个分区来管理磁盘空间的,因此,各个分区的可用空间实际上被所有文件的inode结构和所有文件的数据块共享,inode结构是固定的,其大小自然也是固定的。
所有文件的inode结构使用的磁盘空间为x,所有文件的数据块使用的磁盘空间为y,那么x+y=分区容量。分区容量大小是固定的,x和y是变量,都是一方决定另一方占用的空间大小,这样在为分区规划文件系统的元信息时,必须要先将一方确定下来才行。这个先被确定下来的变量是x,x=文件数*inode大小,因此分区最大创建的文件数是有限制的,正如 Linux 中每分区的 inode 数量是固定的,inode的数量等于文件的数量,为方便管理,分区中所有文件的inode通过一个大表格来维护,此表格称为inode_table,在计算机中表格都可以用数组来表示,因此inode_table本质上就是inode数组,数组元素的下标便是文件 inode 的编号。
3.目录项与目录简介
inode 中却没有文件名
在Linux中,目录和文件都用inode来表示,因此目录也是文件,只是目录是包含文件的文件。为了表述清楚这两种文件,我们这里称目录为目录文件,一般意义上的文件称为普通文件。
同一种inode既用来表示普通文件,又用来表示目录文件,inode结构相同,因此区分该inode是普通文件,还是目录文件,唯一的地方只能是数据块本身的内容了,如果该inode表示的是普通文件,此inode指向的数据块中的内容是普通文件自己的数据。 如果该inode表示的是目录文件,此inode指向的数据块中的内容是该目录下的目录项。
目录项中至少要包括文件名、文件类型及文件对应的inode编号。
拿lib目录来说,其目录项如图所示。

通过文件名找文件实体数据块的流程是:
- 在目录中找到文件名所在的目录项。
- 从目录项中获取inode编号。
- 用inode编号作为inode数组的索引下标,找到inode。
- 从该inode中获取数据块的地址,读取数据块。
inode是文件的实质,但它并不能直接引用,必须通过文件名找到文件名所在的目录项,然后从该目录项中获得inode的编号,然后用此编号到inode数组中去找相关的inode,最终找到文件的数据块。

为了避免陷入循环,就有了根目录”/”。
4.超级块与文件系统布局
每个文件都有个inode,所有的inode都放在inode数组中,每个分区都有自己的根目录,其地址并不统一,也许分区a的根目录在本分区的第500扇区,分区b的根目录在本分区的第2012扇区,虽然固定,但不统一。我们需要在某个固定地方去获取文件系统元信息的配置,这个地方就是超级块,超级块是保存文件系统元信息的元信息。
inode 数组的地址及大小、inode位图地址及大小、根目录的地址和大小、空闲块位图的地址和大小,以上这几类信息要在超级块中保存。
因此一个简单的超级块结构如图所示。

超级块是文件系统元信息的配置文件,它是在为分区创建文件系统时创建的,所有有关文件系统元信息的配置都在超级块中,因此超级块的位置和大小不能再被配置了,必须是固定的,它被固定存储在各分区的第2个扇区,通常是占用一个扇区的大小,具体大小与实际文件系统类型为准。
文件系统布局结构大致如下:

操作系统引导块就是曾经介绍过的操作系统引导记录OBR所在的地址,即操作系统引导扇区,它位于各分区最开始的扇区,根据文件系统类型的不同,引导程序可能占用多个扇区,这多个扇区组成一个数据块,因此这里标出的是引导块,而不是引导扇区。在操作系统引导块后面的依次是超级块、空闲块的位图、inode位图、inode数组、根目录、空闲块区域。
根目录和空闲块区域是真正用于存储数据的区域,除了这两部分,其他几个部分占用的扇区数取决于分区的容量大小,或者是在创建文件系统的过程中手动设置。
5.参考
郑钢著操作系统真象还原
田宇著一个64位操作系统的设计与实现
丁渊著ORANGE’S:一个操作系统的实现


