在先前关于Linux文件系统的文章中,我写了一份说明书去介绍Linux文件系统,里面有一些高级的概念,比如说,一切都是文件。我很想去深入地讨论更多EXT文件系统的特性的信息。所以,首先让我们来回答这个问题:什么是文件系统?一个文件系统应该遵循以下特点:
1.数据存储:文件系统主要的功能是结构化存储和取回数据。
2.命名空间:提供一套命名和组织的方法,就是命名和结构化数据的规则。
3.安全模型:一种访问控制的策略。
4.API:系统操控文件系统对象的函数,就像操作文件夹和文件一样。
5.实现:一个实现以上功能的软件。
这篇文章集中与上面清单的第一项,还有探究元数据结构---在EXT文件系统中提供数据存储的逻辑框架。
EXT文件系统历史
虽然是为Linux编写的,但EXT文件系统起源于Minix操作系统,而Minix文件系统早在1987年首次发布,比Linux还早五年就已经发布了。如果我们查看EXT文件系统家族从其Minix根开始的历史和技术演变,就会更容易理解EXT4文件系统。
Minix
当编写原始Linux内核,Linus Torvalds需要一个文件系统,但是不想开发它。因此他简单的使用了Minix文件系统,这是 Andrew S. Tanenbaum开发的,而且是Tanenbaum 的Minix操作系统的一部分。Minix是类Unix操作系统,为教育使用而开发。它的代码开放使用,而且合理的授权给Torvalds,允许他将它用于Linux的初代版本。
Minix结构如下,其中大部分位于文件系统生成的分区中:
-
引导扇区(boot sector)安装于硬盘的第一个扇区。引导块(boot block)包含一个非常小的引导记录和一个分区表。
-
每一个分区中的第一个块是超级块(superblock),它包含了定义其他文件系统结构的元数据,并将它们定位在分配给分区的物理磁盘上。
-
节点位图块(inode bitmap block),它确定了哪个节点在使用以及哪个节点是空闲的。
-
节点(inodes),它们在磁盘上有它们自己的空间。每个节点包含了一个文件的信息,包括数据块的位置,即文件所属的区域。
-
区域位图(zone bitmap)跟踪记录数据区域的使用和释放。
-
数据区域(data zone),数据实际上存储的位置。
对于位图的两个类型来说,一个bit代表了一个特有的数据区域或者一个特有的节点。如果这个bit是0,这个区域或者节点是空闲的而且可供使用,但是如果这个bit是1,这个数据区域或者节点是在使用中的。
节点是什么?它是索引节点(index-node)的缩写,一个节点是在磁盘上的一个256字节的块,而且它存储文件相关的数据。这些数据包括文件的大小;文件的用户和所属组的用户ID;文件模式(即访问权限);以及三个时间戳具体说明了时间,包括:文件最后访问时间,最后修改时间,以及节点中的数据最后修改时间。
节点也包含了:指向硬盘上文件数据所在的位置。在Minix和EXT1-3文件系统中,它是一个数据区域和块的列表。Minix文件系统节点支持9个数据块,7个直接指针和2个间接指针。如果你想了解的更多,这有一个很好的PDF详细描述了Minix文件系统结构,以及在Wikipedia上对节点指针结构的快速概述。
EXT
最初的EXT文件系统(Extended)由Rémy Card编写,并于1992年与Linux一起发布,以规避Minix文件系统的一些大小限制。其中主要的结构变化是基于Unix文件系统(UFS)的文件系统元数据,该结构也被称为伯克利快速文件系统(FFS)。我发现很少有关于此EXT文件系统的可考究的发布信息,显然是因为它存在重大问题,并很快被EXT2文件系统所取代。
EXT2
EXT2文件系统非常成功。它在Linux发行版中被使用了很多年,并且它是我在1997年左右开始使用Red Hat Linux 5.0时遇到的第一个文件系统。EXT2文件系统与EXT文件系统具有基本相同的元数据结构,但EXT2更具前瞻性,因为在元数据结构之间保留大量磁盘空间以供未来使用。
像Minix一样,EXT2在其安装的硬盘的第一个扇区中有一个引导扇区,其中包括一个非常小的引导记录和一个分区表。在引导扇区后面有一些预留空间,它跨越引导记录和硬盘上通常位于下一个柱面边界上的第一个分区之间的空间。 GRUB2(可能还有GRUB1)使用这个空间作为其启动代码的一部分。
每个EXT2分区中的空间被划分为多个柱面组,可以更加精细地管理数据空间。 根据我的经验,组大小通常约为8MB。下面的图1显示了柱面组的基本结构。柱面中的数据分配单元是块,其大小通常为4K。
图1:EXT文件系统中柱面组的结构
柱面组中的第一个块是一个超级块,它包含定义其他文件系统结构并将其定位在物理磁盘上的元数据。 分区中的一些附加组将具有备份超级块,但不是全部。 损坏的超级块可以使用dd等磁盘实用程序将备份超级块的内容复制到主超级块。 它并不经常发生,但是多年前曾经有一个受损的超级块,我可以使用其中一个备份超级块来恢复其内容。 幸运的是,我已经预见到并使用dumpe2fs命令转储我系统上分区的描述符信息。
下面是dumpe2fs命令的部分输出。它显示了超级块中包含的元数据,以及关于文件系统中前两个柱面组的数据。
# dumpe2fs /dev/sda1
Filesystem volume name: boot
Last mounted on: /boot
Filesystem UUID: 79fc5ed8-5bbc-4dfe-8359-b7b36be6eed3
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent 64bit flex_bg sparse_super large_file huge_file dir nlink extra_isize
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 122160
Block count: 488192
Reserved block count: 24409
Free blocks: 376512
Free inodes: 121690
First block: 0
Block size: 4096
Fragment size: 4096
Group descriptor size: 64
Reserved GDT blocks: 238
Blocks per group: 32768
Fragments per group: 32768
Inodes per group: 8144
Inode blocks per group: 509
Flex block group size: 16
Filesystem created: Tue Feb 7 09:33:34 2017
Last mount time: Sat Apr 29 21:42:01 2017
Last write time: Sat Apr 29 21:42:01 2017
Mount count: 25
Maximum mount count: -1
Last checked: Tue Feb 7 09:33:34 2017
Check interval: 0 (<none>)
Lifetime writes: 594 MB
Reserved blocks uid: 0 (user root)
Reserved blocks gid: 0 (group root)
First inode: 11
Inode size: 256
Required extra isize: 32
Desired extra isize: 32
Journal inode: 8
Default directory hash: half_md4
Directory Hash Seed: c780bac9-d4bf-4f35-b695-0fe35e8d2d60
Journal backup: inode blocks
Journal features: journal_64bit
Journal size: 32M
Journal length: 8192
Journal sequence: 0x00000213
Journal start: 0
Group 0: (Blocks 0-32767)
Primary superblock at 0, Group descriptors at 1-1
Reserved GDT blocks at 2-239
Block bitmap at 240 (+240)
Inode bitmap at 255 (+255)
Inode