7.1.3 Linux 的 EXT2 文件系统(inode)
在第五章当中我们介绍过 Linux 的文件除了原有的数据内容外,还含有非常多的权限与属性,这些权限与属性是为了保护每个使用者所拥有数据的隐密性。 而前一小节我们知道 filesystem 里面可能含有的 inode/block/superblock 等。为什么要谈这个呢?因为标准的 Linux 文件系统 Ext2 就是使用这种 inode 为基础的文件系统啦!
而如同前一小节所说的,inode 的内容在记录文件的权限与相关属性,至于 block 区块则是在记录文件的实际内容。 而且文件系统一开始就将 inode 与 block 规划好了,除非重新格式化(或者利用 resize2fs 等指令变更文件系统大小),否则 inode 与 block 固定后就不再变动。但是如果仔细考虑一下,如果我的文件系统高达数百GB时, 那么将所有的 inode 与 block 通通放置在一起将是很不智的决定,因为 inode 与 block 的数量太庞大,不容易管理。
为此之故,因此 Ext2 文件系统在格式化的时候基本上是区分为多个区块群组 (block group) 的,每个区块群组都有独立的 inode/block/superblock 系统。感觉上就好像我们在当兵时,一个营里面有分成数个连,每个连有自己的联络系统, 但最终都向营部回报连上最正确的信息一般!这样分成一群群的比较好管理啦!整个来说,Ext2 格式化后有点像下面这样:
图7.1.3、ext2文件系统示意图[1]
在整体的规划当中,文件系统最前面有一个开机扇区(boot sector),这个开机扇区可以安装开机管理程序, 这是个非常重要的设计,因为如此一来我们就能够将不同的开机管理程序安装到个别的文件系统最前端,而不用覆盖整颗磁盘唯一的 MBR, 这样也才能够制作出多重开机的环境啊!至于每一个区块群组(block group)的六个主要内容说明如后:
- data block (数据区块)
data block 是用来放置文件内容数据地方,在 Ext2 文件系统中所支持的 block 大小有 1K, 2K 及 4K 三种而已。在格式化时 block 的大小就固定了,且每个 block 都有编号,以方便 inode 的记录啦。 不过要注意的是,由于 block 大小的差异,会导致该文件系统能够支持的最大磁盘容量与最大单一文件大小并不相同。 因为 block 大小而产生的 Ext2 文件系统限制如下:[2]
Block 大小 | 1KB | 2KB | 4KB |
---|---|---|---|
最大单一文件限制 | 16GB | 256GB | 2TB |
最大文件系统总容量 | 2TB | 8TB | 16TB |
你需要注意的是,虽然 Ext2 已经能够支持大于 2GB 以上的单一文件大小,不过某些应用程序依然使用旧的限制, 也就是说,某些程序只能够捉到小于 2GB 以下的文件而已,这就跟文件系统无关了! 举例来说,鸟哥在环工方面的应用中有一套秀图软件称为PAVE[3], 这套软件就无法捉到鸟哥在数值模式仿真后产生的大于 2GB 以上的文件!所以后来只能找更新的软件来取代它了!
除此之外 Ext2 文件系统的 block 还有什么限制呢?有的!基本限制如下:
- 原则上,block 的大小与数量在格式化完就不能够再改变了(除非重新格式化);
- 每个 block 内最多只能够放置一个文件的数据;
- 承上,如果文件大于 block 的大小,则一个文件会占用多个 block 数量;
- 承上,若文件小于 block ,则该 block 的剩余容量就不能够再被使用了(磁盘空间会浪费)。
如上第四点所说,由于每个 block 仅能容纳一个文件的数据而已,因此如果你的文件都非常小,但是你的 block 在格式化时却选用最大的 4K 时,可能会产生一些容量的浪费喔!我们以下面的一个简单例题来算一下空间的浪费吧!
例题:假设你的Ext2文件系统使用 4K block ,而该文件系统中有 10000 个小文件,每个文件大小均为 50Bytes, 请问此时你的磁盘浪费多少容量?答:由于 Ext2 文件系统中一个 block 仅能容纳一个文件,因此每个 block 会浪费“ 4096 - 50 = 4046 (Byte)”, 系统中总共有一万个小文件,所有文件大小为:50 (Bytes) x 10000 = 488.3KBytes,但此时浪费的容量为:“ 4046 (Bytes) x 10000 = 38.6MBytes ”。想一想,不到 1MB 的总文件大小却浪费将近 40MB 的容量,且文件越多将造成越多的磁盘容量浪费。
什么情况会产生上述的状况呢?例如 BBS 网站的数据啦!如果 BBS 上面的数据使用的是纯文本来记载每篇留言, 而留言内容如果都写上“如题”时,想一想,是否就会产生很多小文件了呢?
好,既然大的 block 可能会产生较严重的磁盘容量浪费,那么我们是否就将 block 大小订为 1K 即可? 这也不妥,因为如果 block 较小的话,那么大型文件将会占用数量更多的 block ,而 inode 也要记录更多的 block 号码,此时将可能导致文件系统不良的读写性能。
所以我们可以说,在您进行文件系统的格式化之前,请先想好该文件系统预计使用的情况。 以鸟哥来说,我的数值模式仿真平台随便一个文件都好几百 MB,那么 block 容量当然选择较大的!至少文件系统就不必记录太多的 block 号码,读写起来也比较方便啊!
Tips事实上,现在的磁盘容量都太大了!所以,大概大家都只会选择 4K 的 block 大小吧!呵呵!
- inode table (inode 表格)
再来讨论一下 inode 这个玩意儿吧!如前所述 inode 的内容在记录文件的属性以及该文件实际数据是放置在哪几号 block 内! 基本上,inode 记录的文件数据至少有下面这些:[4]
- 该文件的存取模式(read/write/excute);
- 该文件的拥有者与群组(owner/group);
- 该文件的容量;
- 该文件创建或状态改变的时间(ctime);
- 最近一次的读取时间(atime);
- 最近修改的时间(mtime);
- 定义文件特性的旗标(flag),如 SetUID...;
- 该文件真正内容的指向 (pointer);
inode 的数量与大小也是在格式化时就已经固定了,除此之外 inode 还有些什么特色呢?
- 每个 inode 大小均固定为 128 Bytes (新的 ext4 与 xfs 可设置到 256 Bytes);
- 每个文件都仅会占用一个 inode 而已;
- 承上,因此文件系统能够创建的文件数量与 inode 的数量有关;
- 系统读取文件时需要先找到 inode,并分析 inode 所记录的权限与使用者是否符合,若符合才能够开始实际读取 block 的内容。
我们约略来分析一下 EXT2 的 inode / block 与文件大小的关系好了。inode 要记录的数据非常多,但偏偏又只有 128Bytes 而已, 而 inode 记录一个 block 号码要花掉 4Byte ,假设我一个文件有 400MB 且每个 block 为 4K 时, 那么至少也要十万笔 block 号码的记录呢!inode 哪有这么多可记录的信息?为此我们的系统很聪明的将 inode 记录 block 号码的区域定义为12个直接,一个间接, 一个双间接与一个三间接记录区。这是啥?我们将 inode 的结构画一下好了。
图7.1.4、inode 结构示意图
上图最左边为 inode 本身 (128 Bytes),里面有 12 个直接指向 block 号码的对照,这 12 笔记录就能够直接取得 block 号码啦! 至于所谓的间接就是再拿一个 block 来当作记录 block 号码的记录区,如果文件太大时, 就会使用间接的 block 来记录号码。如上图 7.1.4 当中间接只是拿一个 block 来记录额外的号码而已。 同理,如果文件持续长大,那么就会利用所谓的双间接,第一个 block 仅再指出下一个记录号码的 block 在哪里, 实际记录的在第二个 block 当中。依此类推,三间接就是利用第三层 block 来记录号码啦!
这样子 inode 能够指定多少个 block 呢?我们以较小的 1K block 来说明好了,可以指定的情况如下:
12 个直接指向: 12*1K=12K 由于是直接指向,所以总共可记录 12 笔记录,因此总额大小为如上所示;
间接: 256*1K=256K 每笔 block 号码的记录会花去 4Bytes,因此 1K 的大小能够记录 256 笔记录,因此一个间接可以记录的文件大小如上;
双间接: 256_256_1K=2562K 第一层 block 会指定 256 个第二层,每个第二层可以指定 256 个号码,因此总额大小如上;
三间接: 256_256_256*1K=2563K 第一层 block 会指定 256 个第二层,每个第二层可以指定 256 个第三层,每个第三层可以指定 256 个号码,因此总额大小如上;
总额:将直接、间接、双间接、三间接加总,得到 12 + 256 + 256_256 + 256_256*256 (K) = 16GB
此时我们知道当文件系统将 block 格式化为 1K 大小时,能够容纳的最大文件为 16GB,比较一下文件系统限制表的结果可发现是一致的!但这个方法不能用在 2K 及 4K block 大小的计算中, 因为大于 2K 的 block 将会受到 Ext2 文件系统本身的限制,所以计算的结果会不太符合之故。
Tips如果你的 Linux 依旧使用 Ext2/Ext3/Ext4 文件系统的话,例如鸟哥之前的 CentOS 6.x 系统,那么默认还是使用 Ext4 的文件系统喔! Ext4 文件系统的 inode 容量已经可以扩大到 256Bytes 了,更大的 inode 容量,可以纪录更多的文件系统信息,包括新的 ACL 以及 SELinux 类型等, 当然,可以纪录的单一文件大小达 16TB 且单一文件系统总容量可达 1EB 哩!
- Superblock (超级区块)
Superblock 是记录整个 filesystem 相关信息的地方, 没有 Superblock ,就没有这个 filesystem 了。他记录的信息主要有:
- block 与 inode 的总量;
- 未使用与已使用的 inode / block 数量;
- block 与 inode 的大小 (block 为 1, 2, 4K,inode 为 128Bytes 或 256Bytes);
- filesystem 的挂载时间、最近一次写入数据的时间、最近一次检验磁盘 (fsck) 的时间等文件系统的相关信息;
- 一个 valid bit 数值,若此文件系统已被挂载,则 valid bit 为 0 ,若未被挂载,则 valid bit 为 1 。
Superblock 是非常重要的,因为我们这个文件系统的基本信息都写在这里,因此,如果 superblock 死掉了, 你的文件系统可能就需要花费很多时间去挽救啦!一般来说, superblock 的大小为 1024Bytes。相关的 superblock 讯息我们等一下会以dumpe2fs指令来调用出来观察喔!
此外,每个 block group 都可能含有 superblock 喔!但是我们也说一个文件系统应该仅有一个 superblock 而已,那是怎么回事啊? 事实上除了第一个 block group 内会含有 superblock 之外,后续的 block group 不一定含有 superblock , 而若含有 superblock 则该 superblock 主要是做为第一个 block group 内 superblock 的备份咯,这样可以进行 superblock 的救援呢!
- Filesystem Description (文件系统描述说明)
这个区段可以描述每个 block group 的开始与结束的 block 号码,以及说明每个区段 (superblock, bitmap, inodemap, data block) 分别介于哪一个 block 号码之间。这部份也能够用dumpe2fs来观察的。
- block bitmap (区块对照表)
如果你想要新增文件时总会用到 block 吧!那你要使用哪个 block 来记录呢?当然是选择“空的 block ”来记录新文件的数据啰。 那你怎么知道哪个 block 是空的?这就得要通过 block bitmap 的辅助了。从 block bitmap 当中可以知道哪些 block 是空的,因此我们的系统就能够很快速的找到可使用的空间来处置文件啰。
同样的,如果你删除某些文件时,那么那些文件原本占用的 block 号码就得要释放出来, 此时在 block bitmap 当中相对应到该 block 号码的标志就得要修改成为“未使用中”啰!这就是 bitmap 的功能。
- inode bitmap (inode 对照表)
这个其实与 block bitmap 是类似的功能,只是 block bitmap 记录的是使用与未使用的 block 号码, 至于 inode bitmap 则是记录使用与未使用的 inode 号码啰!
- dumpe2fs: 查询 Ext 家族 superblock 信息的指令
了解了文件系统的概念之后,再来当然是观察这个文件系统啰!刚刚谈到的各部分数据都与 block 号码有关! 每个区段与 superblock 的信息都可以使用 dumpe2fs 这个指令来查询的!不过很可惜的是,我们的 CentOS 7 现在是以 xfs 为默认文件系统, 所以目前你的系统应该无法使用 dumpe2fs 去查询任何文件系统的。没关系,鸟哥先找自己的一部机器来跟大家介绍, 你可以在后续的格式化内容讲完之后,自己切出一个 ext4 的文件系统去查询看看即可。鸟哥这块文件系统是 1GB 的容量,使用默认方式来进行格式化的, 观察的内容如下:
[root@study ~]# dumpe2fs [-bh] 设备文件名
选项与参数:
-b :列出保留为坏轨的部分(一般用不到吧!?)
-h :仅列出 superblock 的数据,不会列出其他的区段内容!
范例:鸟哥的一块 1GB ext4 文件系统内容
[root@study ~]# blkid
&
lt;==这个指令可以叫出目前系统有被格式化的设备
/dev/vda1: LABEL="myboot" UUID="ce4dbf1b-2b3d-4973-8234-73768e8fd659" TYPE="xfs"
/dev/vda2: LABEL="myroot" UUID="21ad8b9a-aaad-443c-b732-4e2522e95e23" TYPE="xfs"
/dev/vda3: UUID="12y99K-bv2A-y7RY-jhEW-rIWf-PcH5-SaiApN" TYPE="LVM2_member"
/dev/vda5: UUID="e20d65d9-20d4-472f-9f91-cdcfb30219d6" TYPE="ext4"
&
lt;==看到 ext4 了!
[root@study ~]# dumpe2fs /dev/vda5
dumpe2fs 1.42.9 (28-Dec-2013)
Filesystem volume name:
&
lt;none
&
gt; # 文件系统的名称(不一定会有)
Last mounted on:
&
lt;not available
&
gt; # 上一次挂载的目录位置
Filesystem UUID: e20d65d9-20d4-472f-9f91-cdcfb30219d6
Filesystem magic number: 0xEF53 # 上方的 UUID 为 Linux 对设备的定义码
Filesystem revision #: 1 (dynamic) # 下方的 features 为文件系统的特征数据
Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit
flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl # 默认在挂载时会主动加上的挂载参数
Filesystem state: clean # 这块文件系统的状态为何,clean 是没问题
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 65536 # inode 的总数
Block count: 262144 # block 的总数
Reserved block count: 13107 # 保留的 block 总数
Free blocks: 249189 # 还有多少的 block 可用数量
Free inodes: 65525 # 还有多少的 inode 可用数量
First block: 0
Block size: 4096 # 单个 block 的容量大小
Fragment size: 4096
Group descriptor size: 64
....(中间省略)....
Inode size: 256 # inode 的容量大小!已经是 256 了喔!
....(中间省略)....
Journal inode: 8
Default directory hash: half_md4
Directory Hash Seed: 3c2568b4-1a7e-44cf-95a2-c8867fb19fbc
Journal backup: inode blocks
Journal features: (none)
Journal size: 32M # Journal 日志式数据的可供纪录总容量
Journal length: 8192
Journal sequence: 0x00000001
Journal start: 0
Group 0: (Blocks 0-32767) # 第一块 block group 位置
Checksum 0x13be, unused inodes 8181
Primary superblock at 0, Group descriptors at 1-1 # 主要 superblock 的所在喔!
Reserved GDT blocks at 2-128
Block bitmap at 129 (+129), Inode bitmap at 145 (+145)
Inode table at 161-672 (+161) # inode table 的所在喔!
28521 free blocks, 8181 free inodes, 2 directories, 8181 unused inodes
Free blocks: 142-144, 153-160, 4258-32767 # 下面两行说明剩余的容量有多少
Free inodes: 12-8192
Group 1: (Blocks 32768-65535) [INODE_UNINIT] # 后续为更多其他的 block group 喔!
....(下面省略)....
# 由于数据量非常的庞大,因此鸟哥将一些信息省略输出了!上表与你的屏幕会有点差异。
# 前半部在秀出 supberblock 的内容,包括标头名称(Label)以及inode/block的相关信息
# 后面则是每个 block group 的个别信息了!您可以看到各区段数据所在的号码!
# 也就是说,基本上所有的数据还是与 block 的号码有关就是了!很重要!
如上所示,利用 dumpe2fs 可以查询到非常多的信息,不过依内容主要可以区分为上半部是 superblock 内容, 下半部则是每个 block group 的信息了。从上面的表格中我们可以观察到鸟哥这个 /dev/vda5 规划的 block 为 4K, 第一个 block 号码为 0 号,且 block group 内的所有信息都以 block 的号码来表示的。 然后在 superblock 中还有谈到目前这个文件系统的可用 block 与 inode 数量喔!
至于 block group 的内容我们单纯看 Group0 信息好了。从上表中我们可以发现:
- Group0 所占用的 block 号码由 0 到 32767 号,superblock 则在第 0 号的 block 区块内!
- 文件系统描述说明在第 1 号 block 中;
- block bitmap 与 inode bitmap 则在 129 及 145 的 block 号码上。
- 至于 inode table 分布于 161-672 的 block 号码中!
- 由于 (1)一个 inode 占用 256 Bytes ,(2)总共有 672 - 161 + 1(161本身) = 512 个 block 花在 inode table 上, (3)每个 block 的大小为 4096 Bytes(4K)。由这些数据可以算出 inode 的数量共有 512 * 4096 / 256 = 8192 个 inode 啦!
- 这个 Group0 目前可用的 block 有 28521 个,可用的 inode 有 8181 个;
- 剩余的 inode 号码为 12 号到 8192 号。
如果你对文件系统的详细信息还有更多想要了解的话,那么请参考本章最后一小节的介绍喔! 否则文件系统看到这里对于基础认知您应该是已经相当足够啦!下面则是要探讨一下, 那么这个文件系统概念与实际的目录树应用有啥关连啊?