第二扩展文件系统

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

(*)

使 df 的行为类似于 BSD。

minixdf

使 df 的行为类似于 Minix。

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)。

ext2 静默忽略 noquota 选项。

规范

ext2 与传统的 Unix 文件系统共享许多属性。它具有块、inode 和目录的概念。它在规范中为访问控制列表 (ACL)、片段、取消删除和压缩留有空间,尽管这些尚未实现(有些可作为单独的补丁提供)。还有一个版本控制机制,允许以最大程度的兼容方式添加新功能(例如日志)。

设备或文件中的空间被分成块。这些是固定大小的,为 1024、2048 或 4096 字节(Alpha 系统上为 8192 字节),这是在创建文件系统时决定的。较小的块意味着每个文件的浪费空间更少,但需要稍微更多的会计开销,并且还对文件和文件系统的大小施加了其他限制。

块组

块被聚集到块组中,以减少碎片并最大限度地减少读取大量连续数据时的磁头寻道量。有关每个块组的信息保存在紧跟在超级块之后的块中的描述符表中。每个组开始附近的两个块保留用于块使用位图和 inode 使用位图,它们显示哪些块和 inode 正在使用中。由于每个位图都限制为单个块,这意味着块组的最大大小是块大小的 8 倍。

每个块组中位图后面的块被指定为该块组的 inode 表,其余的是数据块。块分配算法尝试在与包含数据块的 inode 相同的块组中分配数据块。

超级块

超级块包含有关文件系统配置的所有信息。超级块的主要副本存储在距设备开头 1024 字节的偏移量处,这对于挂载文件系统至关重要。由于它非常重要,超级块的备份副本存储在整个文件系统的块组中。ext2 的第一个版本(修订版 0)在每个块组的开头存储一个副本,以及组描述符块的备份。因为这会占用大型文件系统的相当大的空间,所以稍后的修订版可以选择通过仅将备份放在特定组中来减少备份副本的数量(这是稀疏超级块功能)。选择的组是 0、1 以及 3、5 和 7 的幂。

超级块中的信息包含诸如文件系统中 inode 和块的总数以及有多少是空闲的、每个块组中有多少 inode 和块、文件系统的挂载时间(以及是否干净地卸载了)、修改时间、文件系统的版本(请参阅下面的修订部分)以及哪个操作系统创建了它。

如果文件系统是修订版 1 或更高版本,则会有额外的字段,例如卷名、唯一标识号、inode 大小以及用于存储配置信息的可选文件系统功能的空间。

超级块中的所有字段(以及所有其他 ext2 结构中)都以小端格式存储在磁盘上,因此文件系统可以在机器之间移植,而无需知道它是在哪台机器上创建的。

Inodes

inode(索引节点)是 ext2 文件系统中的一个基本概念。文件系统中的每个对象都由一个 inode 表示。inode 结构包含指向包含对象中保存的数据的文件系统块的指针,以及除其名称之外的有关对象的所有元数据。有关对象的元数据包括权限、所有者、组、标志、大小、使用的块数、访问时间、更改时间、修改时间、删除时间、链接数、片段、版本(对于 NFS)以及扩展属性 (EA) 和/或访问控制列表 (ACL)。

inode 结构中有一些保留字段当前未使用,还有几个字段已重载。如果 inode 是目录,则保留一个字段用于目录 ACL;如果 inode 是常规文件,则保留一个字段用于文件大小的前 32 位(允许文件大小大于 2GB)。翻译器字段在 Linux 下未使用,但 HURD 使用它来引用将用于解释此对象的程序的 inode。大多数剩余的保留字段已被 Linux 和 HURD 用于更大的所有者和组字段。HURD 也有一个更大的模式字段,因此它使用另一个剩余字段来存储额外的更多位。

有指向包含文件数据的前 12 个块的指针在 inode 中。有一个指向间接块的指针(其中包含指向下一组块的指针),一个指向双重间接块的指针(其中包含指向间接块的指针)和一个指向三重间接块的指针(其中包含指向双重间接块的指针)。

标志字段包含一些 ext2 特定的标志,这些标志无法通过标准 chmod 标志进行处理。可以使用 lsattr 列出这些标志,并使用 chattr 命令更改,并允许在每个文件的基础上进行特定的文件系统行为。有用于安全删除、不可删除、压缩、同步更新、不变性、仅附加、可转储、no-atime、索引目录和数据日志的标志。并非所有这些都已支持。

目录

目录是一个文件系统对象,并且具有像文件一样的 inode。它是一个特殊格式的文件,包含将每个名称与 inode 编号关联的记录。文件系统的更高版本还对对象类型(文件、目录、符号链接、设备、fifo、套接字)进行编码,以避免需要检查 inode 本身以获取此信息(Glibc 2.2 中尚不存在利用此功能的支持)。

inode 分配代码尝试分配与首次创建的目录位于同一块组中的 inode。

ext2 的当前实现使用单链表来存储目录中的文件名;一个待处理的增强功能使用文件名的哈希来允许查找,而无需扫描整个目录。

当前实现从不删除分配用于保存更多文件的空目录块。

特殊文件

符号链接也是具有 inode 的文件系统对象。它们值得特别提及,因为如果符号链接小于 60 字节,则它们的数据存储在 inode 本身中。它使用通常用于存储指向数据块的指针的字段。这是一个值得的优化,因为我们避免为符号链接分配一个完整的块,并且大多数符号链接小于 60 个字符。

字符和块特殊设备永远不会分配给它们数据块。相反,它们的设备编号存储在 inode 中,再次重用将用于指向数据块的字段。

保留空间

在 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 标志是一个明显的 INCOMPAT 标志 - 如果内核不了解压缩,您只会从 read() 收到垃圾,而不是自动解压缩您的数据。需要 ext3 RECOVER 标志来防止不了解 ext3 日志的内核在不重放日志的情况下挂载文件系统。

对于 e2fsck,它需要比内核更严格地处理这些标志。如果它不了解任何 COMPAT、RO_COMPAT 或 INCOMPAT 标志,它将拒绝检查文件系统,因为它无法验证给定功能是否有效。允许 e2fsck 在具有未知功能的文件系统上成功运行是用户的错误安全感。拒绝检查具有未知功能的文件系统可以很好地激励用户更新到最新的 e2fsck。这也意味着任何将功能标志添加到 ext2 的人都需要更新 e2fsck 以验证这些功能。

元数据

经常有人声称 ext2 异步元数据的写入实现比 ffs 同步元数据方案更快,但可靠性较差。两种方法都可以通过各自的 fsck 程序同样解决。

如果您非常偏执,则有 3 种方法可以在 ext2 上同步元数据写入

  • 如果每个文件都有程序源代码:使用 O_SYNC 标志来 open()

  • 如果每个文件没有源代码:在文件上使用“chattr +S”

  • 每个文件系统:将“sync”选项添加到 mount(或在 /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/。

参考

内核源代码

file:/usr/src/linux/fs/ext2/

e2fsprogs (e2fsck)

http://e2fsprogs.sourceforge.net/

设计与实现

http://e2fsprogs.sourceforge.net/ext2intro.html

日志 (ext3)

ftp://ftp.uk.linux.org/pub/linux/sct/fs/jfs/

文件系统调整大小

http://ext2resize.sourceforge.net/

压缩 [1]

http://e2compr.sourceforge.net/

适用于以下平台的实现

Windows 95/98/NT/2000

http://www.chrysocome.net/explore2fs

Windows 95 [1]

http://www.yipton.net/content.html#FSDEXT2

DOS 客户端 [1]

ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/

OS/2 [2]

ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/

RISC OS 客户端

http://www.esw-heim.tu-clausthal.de/~marco/smorbrod/IscaFS/