第二扩展文件系统¶
ext2 最初于 1993 年 1 月发布。由 R'emy Card、Theodore Ts’o 和 Stephen Tweedie 编写,是对扩展文件系统的重大重写。它目前仍然是(2001 年 4 月)Linux 中使用的主要文件系统。 也有可用于 NetBSD、FreeBSD、GNU HURD、Windows 95/98/NT、OS/2 和 RISC OS 的实现。
选项¶
大多数默认值由文件系统超级块确定,可以使用 tune2fs(8) 设置。内核确定的默认值用 (*) 表示。
bsddf |
(*) |
使 |
minixdf |
使 |
|
check=none, nocheck |
(*) |
挂载时不对位图进行额外的检查(已删除 check=normal 和 check=strict 选项) |
dax |
使用直接访问(无页面缓存)。请参阅 文件直接访问。 |
|
debug |
额外的调试信息被发送到内核 syslog。对开发人员很有用。 |
|
errors=continue |
在文件系统错误时继续。 |
|
errors=remount-ro |
在发生错误时将文件系统重新挂载为只读。 |
|
errors=panic |
如果发生错误,则使机器崩溃并停止。 |
|
grpid, bsdgroups |
使对象的组 ID 与其父对象相同。 |
|
nogrpid, sysvgroups |
新对象的组 ID 为其创建者的组 ID。 |
|
nouid32 |
使用 16 位 UID 和 GID。 |
|
oldalloc |
启用旧的块分配器。Orlov 的性能应该更好,如果对您来说情况相反,我们希望得到一些反馈。 |
|
orlov |
(*) |
使用 Orlov 块分配器。(请参阅 http://lwn.net/Articles/14633/ 和 http://lwn.net/Articles/14446/。) |
resuid=n |
可以使用保留块的用户 ID。 |
|
resgid=n |
可以使用保留块的组 ID。 |
|
sb=n |
在此位置使用备用超级块。 |
|
user_xattr |
启用 “user.” POSIX 扩展属性(需要 CONFIG_EXT2_FS_XATTR)。 |
|
nouser_xattr |
不支持 “user.” 扩展属性。 |
|
acl |
启用 POSIX 访问控制列表支持(需要 CONFIG_EXT2_FS_POSIX_ACL)。 |
|
noacl |
不支持 POSIX ACL。 |
|
quota, usrquota |
启用用户磁盘配额支持(需要 CONFIG_QUOTA)。 |
|
grpquota |
启用组磁盘配额支持(需要 CONFIG_QUOTA)。 |
noquota 选项被 ext2 悄悄忽略。
规范¶
ext2 与传统的 Unix 文件系统共享许多属性。 它具有块、索引节点和目录的概念。它在规范中为访问控制列表 (ACL)、片段、取消删除和压缩保留了空间,尽管这些尚未实现(有些作为单独的补丁提供)。还有一个版本控制机制,允许以最大程度的兼容方式添加新功能(例如日志)。
块¶
设备或文件中的空间被分成块。这些块的大小是固定的,为 1024、2048 或 4096 字节(Alpha 系统上为 8192 字节),这是在创建文件系统时决定的。较小的块意味着每个文件浪费的空间更少,但需要稍多的记账开销,并且还会对文件和文件系统的大小施加其他限制。
块组¶
块被聚集到块组中,以减少碎片并最大程度地减少读取大量连续数据时的磁头寻道。有关每个块组的信息保存在紧接在超级块之后的块中的描述符表中。每个组的开头附近的两个块保留用于块使用位图和索引节点使用位图,这些位图显示正在使用哪些块和索引节点。由于每个位图都限制为一个块,这意味着块组的最大大小为块大小的 8 倍。
每个块组中位图之后的块被指定为该块组的索引节点表,其余块是数据块。块分配算法尝试在与包含它们inode的同一块组中分配数据块。
超级块¶
超级块包含有关文件系统配置的所有信息。超级块的主副本存储在设备开头偏移 1024 字节的位置,这对于挂载文件系统至关重要。由于它非常重要,因此超级块的备份副本存储在整个文件系统的块组中。ext2 的第一个版本(修订版 0)在每个块组的开头存储一个副本,以及组描述符块的备份。由于这可能会占用大型文件系统的大量空间,因此后来的修订版可以选择通过仅将备份放置在特定组中来减少备份副本的数量(这是稀疏超级块功能)。选择的组是 0、1 和 3、5 和 7 的幂。
超级块中的信息包含以下字段:例如文件系统中索引节点和块的总数以及有多少是空闲的,每个块组中有多少索引节点和块,文件系统何时挂载(以及是否已干净卸载),何时被修改,它是什么版本的文件系统(请参见下面的修订部分)以及哪个操作系统创建了它。
如果文件系统是修订版 1 或更高版本,则还有其他字段,例如卷名、唯一标识号、索引节点大小以及用于存储配置信息的可选文件系统功能的空间。
超级块(以及所有其他 ext2 结构)中的所有字段都以小端格式存储在磁盘上,因此文件系统可以在机器之间移植,而无需知道它是在哪台机器上创建的。
索引节点¶
索引节点(索引节点)是 ext2 文件系统中的一个基本概念。 文件系统中的每个对象都由一个索引节点表示。索引节点结构包含指向包含对象中保存的数据的文件系统块的指针,以及有关对象的所有元数据,但其名称除外。有关对象的元数据包括权限、所有者、组、标志、大小、使用的块数、访问时间、更改时间、修改时间、删除时间、链接数、片段、版本(对于 NFS)以及扩展属性 (EA) 和/或访问控制列表 (ACL)。
索引节点结构中存在一些保留字段,当前未使用,还有几个字段被重载。 如果索引节点是目录,则保留一个字段用于目录 ACL,或者如果索引节点是常规文件,则保留该字段用于文件大小的顶部 32 位(允许文件大小大于 2GB)。转换器字段在 Linux 下未使用,但 HURD 使用它来引用将用于解释此对象的程序的索引节点。大多数剩余的保留字段都已被 Linux 和 HURD 用于更大的所有者和组字段。HURD 还具有更大的模式字段,因此它使用另一个剩余的字段来存储额外的更多位。
索引节点中存在指向包含文件数据的第一个 12 个块的指针。 有一个指向间接块的指针(其中包含指向下一组块的指针),一个指向双间接块的指针(其中包含指向间接块的指针)以及一个指向三间接块的指针(其中包含指向双间接块的指针)。
标志字段包含一些 ext2 特有的标志,这些标志不受标准 chmod 标志的支持。 这些标志可以使用 lsattr 列出,并使用 chattr 命令更改,并允许在每个文件的基础上进行特定的文件系统行为。存在用于安全删除、不可删除、压缩、同步更新、不可变性、仅追加、可转储、no-atime、索引目录和数据日志的标志。并非所有这些都受支持。
目录¶
目录是一个文件系统对象,它像文件一样具有索引节点。它是一个特殊格式的文件,其中包含将每个名称与一个索引节点号关联的记录。文件系统的后续版本还对对象的类型(文件、目录、符号链接、设备、fifo、套接字)进行编码,以避免需要检查索引节点本身以获取此信息(Glibc 2.2 中尚不支持利用此功能)。
索引节点分配代码尝试分配与首次创建它们的目录位于同一块组中的索引节点。
当前 ext2 的实现使用单链表来存储目录中的文件名; 正在进行的增强功能使用文件名的哈希,以允许查找而无需扫描整个目录。
当前实现永远不会删除已分配的用于保存更多文件的空目录块。
特殊文件¶
符号链接也是具有索引节点的文件系统对象。 它们值得特别提及,因为如果符号链接少于 60 个字节,则其数据将存储在索引节点本身中。 它使用通常用于存储指向数据块的指针的字段。这是一个值得的优化,因为我们避免为符号链接分配完整的块,并且大多数符号链接都少于 60 个字符长。
字符和块特殊设备永远不会分配给数据块。相反,它们的设备编号存储在索引节点中,再次重用通常用于指向数据块的字段。
保留空间¶
在 ext2 中,有一种机制可以为特定用户(通常是超级用户)保留一定数量的块。 这旨在允许系统即使在非特权用户填满所有可用的空间时也继续运行(这独立于文件系统配额)。 它还可以防止文件系统完全填满,这有助于对抗碎片。
文件系统检查¶
在启动时,大多数系统会在其文件系统上运行一致性检查 (e2fsck)。 ext2 文件系统的超级块包含多个字段,这些字段指示 fsck 是否应实际运行(因为在启动时检查文件系统如果很大则可能需要很长时间)。如果文件系统未干净卸载、超出最大挂载计数或超出检查之间的最大时间,fsck 将运行。
功能兼容性¶
ext2 中使用的兼容性特性机制非常复杂。它允许安全地向文件系统添加特性,而不会不必要地牺牲与旧版本文件系统代码的兼容性。最初的修订版 0 (EXT2_GOOD_OLD_REV) 的 ext2 不支持特性兼容性机制,该机制是在修订版 1 中引入的。有三个 32 位字段,一个用于兼容特性 (COMPAT),一个用于只读兼容 (RO_COMPAT) 特性,另一个用于不兼容 (INCOMPAT) 特性。
这些特性标志对内核有特定的含义,如下所示:
COMPAT 标志表示文件系统中存在某个特性,但磁盘上的格式与旧的磁盘格式 100% 兼容,因此,一个对该特性一无所知的内核也可以读取/写入文件系统,而不会有任何损坏文件系统(甚至使其不一致)的风险。这本质上只是一个标志,表示“此文件系统具有内核或 e2fsck 可能需要注意的(隐藏)特性”(稍后会详细介绍 e2fsck 和特性标志)。ext3 的 HAS_JOURNAL 特性是一个 COMPAT 标志,因为 ext3 日志只是一个包含数据块的常规文件,因此如果内核不了解 ext3 日志,则无需对其进行特殊注意。
RO_COMPAT 标志表示磁盘上的格式在读取方面与旧的磁盘格式 100% 兼容(即,该特性不会更改可见的磁盘格式)。但是,旧内核写入此类文件系统会/可能损坏文件系统,因此会阻止这种情况发生。最常见的此类特性 SPARSE_SUPER 是一个 RO_COMPAT 特性,因为稀疏组允许文件数据块位于以前存储超级块/组描述符备份的位置,而 ext2_free_blocks() 拒绝释放这些块,这会导致位图不一致。如果旧内核尝试释放跨越组边界的一系列块,也会收到错误,但这在 SPARSE_SUPER 文件系统中是合法的布局。
INCOMPAT 标志表示磁盘上的格式已发生某种变化,使得旧内核无法读取该格式,或者如果旧内核尝试挂载该格式,则会导致问题。FILETYPE 是一个 INCOMPAT 标志,因为旧内核会认为文件名长度超过 256 个字符,这会导致目录列表损坏。COMPRESSION 标志是一个明显的不兼容标志 - 如果内核不了解压缩,您只会从 read() 收到垃圾,而不是自动解压您的数据。需要 ext3 的 RECOVER 标志来防止不了解 ext3 日志的内核在不重放日志的情况下挂载文件系统。
对于 e2fsck,它对这些标志的处理需要比内核更严格。如果它不了解任何 COMPAT、RO_COMPAT 或 INCOMPAT 标志,它将拒绝检查文件系统,因为它无法验证给定特性是否有效。允许 e2fsck 在具有未知特性的文件系统上成功运行,会给用户带来虚假的安全感。拒绝检查具有未知特性的文件系统,可以很好地激励用户更新到最新的 e2fsck。这也意味着任何向 ext2 添加特性标志的人员还需要更新 e2fsck 以验证这些特性。
元数据¶
经常有人声称,ext2 实现的异步元数据写入速度快于 ffs 同步元数据方案,但可靠性较低。这两种方法都可以通过各自的 fsck 程序来解决。
如果您特别偏执,可以通过 3 种方法在 ext2 上进行同步元数据写入:
如果拥有程序源代码,则按文件进行:使用 O_SYNC 标志打开 open()
如果您没有源代码,则按文件进行:对文件使用 “chattr +S”
按文件系统:向挂载添加 “sync” 选项(或在 /etc/fstab 中添加)
第一个和最后一个不是 ext2 特有的,但确实强制元数据同步写入。另请参见下面的“日志”。
限制¶
ext2 的磁盘布局施加了各种限制。其他限制由当前内核代码的实现施加。许多限制是在首次创建文件系统时确定的,并且取决于选择的块大小。inode 与数据块的比率在文件系统创建时是固定的,因此增加 inode 数量的唯一方法是增加文件系统的大小。目前没有可以更改 inode 与块的比率的工具。
通过稍微更改磁盘格式并使用兼容性标志来表示格式更改(以牺牲一些兼容性为代价),可以克服这些限制中的大多数。
文件系统块大小 |
1kB |
2kB |
4kB |
8kB |
---|---|---|---|---|
文件大小限制 |
16GB |
256GB |
2048GB |
2048GB |
文件系统大小限制 |
2047GB |
8192GB |
16384GB |
32768GB |
对于单个块设备,2.4 内核的限制为 2048GB,因此目前无法创建大于此限制的文件系统。内核的页面大小也对块大小有上限,因此只有 Alpha 系统(以及其他支持更大页面的架构)才允许使用 8kB 块。
单个目录中最多允许有 32000 个子目录。
使用当前的线性链接列表目录实现,单个目录中大约有 10-15k 个文件的“软”上限。此限制源于在此类大型目录中创建和删除(以及查找)文件时出现的性能问题。使用哈希目录索引(正在开发中)允许单个目录中存在 100k-1M+ 个文件,而不会出现性能问题(尽管此时 RAM 大小会成为一个问题)。
单个目录中文件数量的(无意义的)绝对上限(由文件大小决定,实际限制显然要小得多)超过 130 万亿个文件。它本可以更高,但没有足够的 4 个字符的名称来组成唯一的目录条目,因此它们必须是 8 个字符的文件名,即使这样,我们也很快就要用完唯一的文件名了。
日志¶
Stephen Tweedie 开发了 ext2 代码的日志扩展。它避免了元数据损坏的风险,并且无需在崩溃后等待 e2fsck 完成,而无需更改磁盘上的 ext2 布局。简而言之,日志是一个常规文件,用于存储在写入文件系统之前已修改的整个元数据(和可选的数据)块。这意味着可以在现有 ext2 文件系统中添加日志,而无需进行数据转换。
当对文件系统进行更改时(例如,重命名文件),这些更改将存储在日志中的一个事务中,并且在崩溃时可以是完整的,也可以是不完整的。如果事务在崩溃时是完整的(或在系统未崩溃的正常情况下),则该事务中的任何块都保证代表有效的文件系统状态,并被复制到文件系统中。如果事务在崩溃时是不完整的,则无法保证该事务中块的一致性,因此会丢弃这些块(这意味着它们代表的任何文件系统更改也会丢失)。如果您想了解有关 ext4 和日志的更多信息,请查看 Documentation/filesystems/ext4/。
参考资料¶
内核源代码 |
|
e2fsprogs (e2fsck) |
|
设计与实现 |
|
日志 (ext3) |
|
文件系统调整大小 |
|
压缩[1] |
以下操作系统的实现:
Windows 95/98/NT/2000 |
|
Windows 95 [1] |
|
DOS 客户端[1] |
|
OS/2 [2] |
|
RISC OS 客户端 |