ext4 通用信息¶
Ext4 是 ext3 文件系统的高级版本,它结合了可扩展性和可靠性增强功能,以支持大型文件系统(64 位),以适应不断增加的磁盘容量和最先进的功能要求。
邮件列表:linux-ext4@vger.kernel.org 网站:http://ext4.wiki.kernel.org
快速使用说明¶
注意:有关 ext4 入门的更多详细信息,请访问 ext4 wiki 站点,网址为:http://ext4.wiki.kernel.org/index.php/Ext4_Howto
e2fsprogs 的最新版本可以在以下位置找到
https://linuxkernel.org.cn/pub/linux/kernel/people/tytso/e2fsprogs/
或
http://sourceforge.net/project/showfiles.php?group_id=2406
或从以下位置获取最新的 git 存储库
使用 ext4 文件系统类型创建新的文件系统
# mke2fs -t ext4 /dev/hda1
或配置现有的 ext3 文件系统以支持扩展
# tune2fs -O extents /dev/hda1
如果使用 128 字节的 inode 创建了文件系统,则可以通过以下方式将其转换为使用 256 字节以提高效率
# tune2fs -I 256 /dev/hda1
挂载
# mount -t ext4 /dev/hda1 /wherever
在与其他文件系统进行性能比较时,始终尝试多种工作负载非常重要;工作负载参数的细微变化通常会完全改变哪个文件系统比其他文件系统表现良好的排名。在与 ext3 进行比较时,请注意 ext4 默认启用写屏障,而 ext3 默认不启用写屏障。因此,对于 ext3 和 ext4 文件系统,最好使用'-o barriers=[0|1]'挂载选项来明确指定是否启用屏障,以进行公平的比较。在调整 ext3 以获得最佳基准数字时,通常值得尝试更改数据日志模式;对于某些工作负载,'-o data=writeback' 可能更快。(但请注意,在 data=writeback 模式下挂载运行可能会在最近写入的文件中留下过时的暴露数据,以防出现不干净的关机,这在某些情况下可能是安全漏洞。)使用大型日志配置文件系统对于元数据密集型工作负载也很有帮助。
特性¶
当前可用¶
能够使用 > 16TB 的文件系统(e2fsprogs 支持尚未可用)
扩展格式减少了元数据开销(RAM,访问 IO,事务)
扩展格式在磁盘损坏(由于魔数)的情况下更强大,
树中的内部冗余
改进的文件分配(多块分配)
取消了 i_links_count[1] 施加的 32000 个子目录限制
mtime、atime、ctime、创建时间的纳秒时间戳
磁盘上的 inode 版本字段 (NFSv4, Lustre)
通过 uninit_bg 功能减少 e2fsck 时间
用于健壮性的日志校验和,性能
持久文件预分配(例如用于流媒体、数据库)
能够通过 flex_bg 功能将位图和 inode 表打包到更大的虚拟组中
大文件支持
使用 flex_bg 通过大型虚拟块组进行 inode 分配
延迟分配
大块(最大页面大小)支持
JBD2 和 ext4 中高效的新有序模式(避免使用缓冲区头来强制排序)
不区分大小写的文件名查找
基于文件的加密支持 (fscrypt)
基于文件的 verity 支持 (fsverity)
[1] 块大小为 1k 的文件系统可能会看到由目录哈希树的最大深度为 2 所施加的限制。
不区分大小写的文件名查找¶
不区分大小写的文件名查找功能在每个目录的基础上受支持,允许用户在同一文件系统中混合使用不区分大小写和区分大小写的目录。它通过翻转空目录的 +F inode 属性来启用。只有当我们知道如何以字节序列编码文本时,才定义不区分大小写的字符串匹配操作。因此,为了启用不区分大小写的目录,文件系统必须具有 casefold 功能,该功能存储所使用的文件系统范围的编码模型。默认情况下,采用的字符集是最新版本的 Unicode(在撰写本文时为 12.1.0),以 UTF-8 形式编码。比较算法通过将字符串归一化为 Unicode 定义的规范分解形式,然后进行逐字节比较来实现。
大小写感知在磁盘上保留名称,这意味着用户空间提供的文件名与实际写入磁盘的内容是逐字节匹配的。因此,内核使用的 Unicode 规范化格式是内部表示,不会暴露给用户空间或磁盘,但磁盘哈希除外,磁盘哈希用于具有 DX 功能的大型不区分大小写的目录。在 DX 目录中,必须使用文件名的 casefolded 版本来计算哈希,这意味着所使用的规范化格式实际上会影响目录条目的存储位置。
当我们从将文件名视为不透明的字节序列更改为将其视为编码的字符串时,我们需要解决当程序尝试使用无效名称创建文件时会发生什么。内核中的 Unicode 子系统将在这种情况下要执行的操作的决定权留给文件系统,文件系统通过启用/禁用严格模式来选择其首选行为。当 Ext4 遇到其中一个字符串且文件系统不需要严格模式时,它会退回到将整个字符串视为不透明的字节序列,这仍然允许用户在该文件上操作,但不区分大小写的查找将不起作用。
选项¶
挂载 ext4 文件系统时,接受以下选项:(*) == 默认
- ro
以只读方式挂载文件系统。请注意,即使以“只读”方式挂载,ext4 也会重播日志(因此会写入分区)。可以使用挂载选项“ro,noload”来防止写入文件系统。
- journal_checksum
启用日志事务的校验和。这将允许 e2fsck 和内核中的恢复代码检测内核中的损坏。这是一个兼容的更改,将被旧内核忽略。
- journal_async_commit
提交块可以写入磁盘,而无需等待描述符块。如果启用,旧内核无法挂载设备。这将启用内部的“journal_checksum”。
- journal_path=path, journal_dev=devnum
当外部日志设备的主/次设备号发生更改时,这些选项允许用户指定新的日志位置。日志设备可以通过其编码在 devnum 中的新主/次设备号或通过设备路径来识别。
- norecovery, noload
挂载时不加载日志。请注意,如果文件系统未干净地卸载,跳过日志重放会导致文件系统包含不一致性,从而导致各种问题。
- data=journal
所有数据在写入主文件系统之前都先提交到日志中。启用此模式将禁用延迟分配和 O_DIRECT 支持。
- data=ordered (*)
所有数据在将其元数据提交到日志之前都强制直接写入主文件系统。
- data=writeback
数据顺序未保留,数据可能在其元数据提交到日志之后写入主文件系统。
- commit=nrsec (*)
此设置将正在运行的事务的最大期限限制为 'nrsec' 秒。默认值为 5 秒。这意味着,如果断电,您最多会丢失最近 5 秒的元数据更改(但由于日志功能,您的文件系统不会损坏)。此默认值(或任何较低的值)会影响性能,但有利于数据安全。将其设置为 0 与将其保留为默认值(5 秒)的效果相同。将其设置为非常大的值将提高性能。请注意,由于延迟分配,即使是较旧的数据也可能在断电时丢失,因为这些数据的回写仅在 /proc/sys/vm/dirty_expire_centisecs 中设置的时间之后才开始。
- barrier=<0|1(*)>, barrier(*), nobarrier
这会启用/禁用在 jbd 代码中使用写屏障。 barrier=0 禁用,barrier=1 启用。这也需要一个可以支持屏障的 IO 堆栈,如果 jbd 在屏障写入时发生错误,它将再次禁用并发出警告。写屏障强制执行日志提交的正确的磁盘顺序,使易失性磁盘写缓存可以安全使用,但会牺牲一些性能。如果您的磁盘以某种方式由电池备份,则禁用屏障可能会安全地提高性能。“barrier” 和 “nobarrier” 挂载选项也可以用于启用或禁用屏障,以与其他 ext4 挂载选项保持一致。
- inode_readahead_blks=n
此调整参数控制 ext4 的 inode 表预读算法将预先读取到缓冲区缓存中的最大 inode 表块数。默认值为 32 个块。
- bsddf (*)
使 ‘df’ 的行为类似于 BSD。
- minixdf
使 ‘df’ 的行为类似于 Minix。
- debug
额外的调试信息将发送到 syslog。
- abort
模拟调用 ext4_abort() 进行调试的效果。这通常在重新挂载已经挂载的文件系统时使用。
- errors=remount-ro
在发生错误时,将文件系统重新挂载为只读。
- errors=continue
在文件系统发生错误时继续操作。
- errors=panic
如果发生错误,则使机器崩溃并停止。(这些挂载选项会覆盖在超级块中指定的错误行为,可以使用 tune2fs 进行配置)
- data_err=ignore(*)
如果 ordered 模式下的文件数据缓冲区中发生错误,则仅打印错误消息。
- data_err=abort
如果 ordered 模式下的文件数据缓冲区中发生错误,则中止日志。
- grpid | bsdgroups
新对象的组 ID 与其父对象的组 ID 相同。
- nogrpid (*) | sysvgroups
新对象的组 ID 与其创建者的组 ID 相同。
- resgid=n
可以使用保留块的组 ID。
- resuid=n
可以使用保留块的用户 ID。
- sb=
在此位置使用备用超级块。
- quota, noquota, grpquota, usrquota
这些选项会被文件系统忽略。它们仅供配额工具使用,以识别应启用配额的卷。有关更多详细信息,请参阅配额工具包中的文档 (http://sourceforge.net/projects/linuxquota)。
- jqfmt=<quota type>, usrjquota=<file>, grpjquota=<file>
这些选项告诉文件系统有关配额的详细信息,以便可以在日志重放期间正确更新配额信息。它们取代了上面的配额选项。有关更多详细信息,请参阅配额工具包中的文档 (http://sourceforge.net/projects/linuxquota)。
- stripe=n
mballoc 将尝试用于分配大小和对齐的文件系统块数。对于 RAID5/6 系统,这应该是数据磁盘的数量 * 文件系统块中的 RAID chunk 大小。
- delalloc (*)
将块分配延迟到 ext4 写出相关块之前。这使 ext4 可以更有效地做出更好的分配决策。
- nodelalloc
禁用延迟分配。当数据从用户空间复制到页面缓存时,通过 write(2) 系统调用或首次写入先前未分配的 mmap'ed 页面时,将分配块。
- max_batch_time=usec
ext4 应该等待其他文件系统操作与同步写操作批量处理的最长时间。由于同步写操作将强制执行提交,然后等待 I/O 完成,因此成本不高,并且可以大大提高吞吐量,我们等待一小段时间,看看是否有其他事务可以搭乘同步写操作的顺风车。使用的算法旨在通过测量完成提交事务所需的时间(平均而言)来自动调整磁盘的速度。将此时间称为“提交时间”。如果事务运行的时间小于提交时间,则 ext4 将尝试休眠提交时间,看看是否有其他操作将加入事务。提交时间受 max_batch_time 的限制,默认为 15000us (15ms)。可以通过将 max_batch_time 设置为 0 来完全关闭此优化。
- min_batch_time=usec
此参数将提交时间(如上所述)设置为至少 min_batch_time。它默认为零微秒。增加此参数可能会提高非常快的磁盘上多线程同步工作负载的吞吐量,但会增加延迟。
- journal_ioprio=prio
在提交操作期间,kjournald2 提交的 I/O 操作应使用的 I/O 优先级(从 0 到 7,其中 0 是最高优先级)。默认值为 3,比默认 I/O 优先级略高。
- auto_da_alloc(*), noauto_da_alloc
许多损坏的应用程序在通过诸如 fd = open(“foo.new”)/write(fd,..)/close(fd)/ rename(“foo.new”, “foo”) 之类的模式替换现有文件时,不使用 fsync(),或者更糟糕的是,fd = open(“foo”, O_TRUNC)/write(fd,..)/close(fd)。如果启用了 auto_da_alloc,ext4 将检测通过重命名和通过截断替换的模式,并强制分配任何延迟分配的块,以便在下一个日志提交中,在默认的 data=ordered 模式下,新文件的数据块在提交 rename() 操作之前被强制写入磁盘。这提供了与 ext3 大致相同的保证级别,并避免了当系统在延迟分配的块强制写入磁盘之前崩溃时可能发生的“零长度”问题。
- noinit_itable
不在后台初始化任何未初始化的 inode 表块。此功能可供安装 CD 使用,以便安装过程可以尽可能快地完成;然后,inode 表初始化过程将延迟到下次卸载文件系统时进行。
- init_itable=n
lazy itable init 代码将等待 n 倍的时间,这是它将上一个块组的 inode 表归零所花费的毫秒数。这可以最大限度地减少在初始化文件系统的 inode 表时对系统性能的影响。
- discard, nodiscard(*)
控制 ext4 在释放块时是否应向底层块设备发出 discard/TRIM 命令。这对 SSD 设备和稀疏/精简配置的 LUN 非常有用,但在完成足够的测试之前,默认情况下处于关闭状态。
- nouid32
禁用 32 位 UID 和 GID。这是为了与仅存储和期望 16 位值的旧内核进行互操作。
- block_validity(*), noblock_validity
这些选项启用或禁用内核中用于在内部数据结构中跟踪文件系统元数据块的工具。这允许多块分配器和其他例程注意到导致分配与文件系统元数据块重叠的块的错误或损坏的分配位图。
- dioread_lock, dioread_nolock
控制 ext4 是否应使用 DIO 读取锁定。如果指定了 dioread_nolock 选项,ext4 将在缓冲区写入之前分配未初始化的 extent,并在 IO 完成后将 extent 转换为已初始化。此方法允许 ext4 代码避免使用 inode 互斥锁,从而提高高速存储上的可伸缩性。但是,这不适用于数据日志记录,并且 dioread_nolock 选项将在内核警告的情况下被忽略。请注意,dioread_nolock 代码路径仅用于基于 extent 的文件。由于此选项包含的限制,它默认处于关闭状态(例如 dioread_lock)。
- max_dir_size_kb=n
这将限制目录的大小,以便任何尝试将其扩展到指定的千字节限制之外的操作都会导致 ENOSPC 错误。这在内存受限的环境中非常有用,在这些环境中,非常大的目录可能会导致严重的性能问题,甚至引发内存不足杀手。(例如,如果只有 512mb 的可用内存,一个 176mb 的目录可能会严重限制系统的运行效率。)
- i_version
启用 64 位 inode 版本支持。此选项默认处于关闭状态。
- dax
使用直接访问(无页面缓存)。请参阅 文件的直接访问。请注意,此选项与 data=journal 不兼容。
- inlinecrypt
如果可能,使用 blk-crypto 框架而不是文件系统层加密来加密/解密加密文件的内容。这允许使用内联加密硬件。磁盘上的格式不受影响。有关更多详细信息,请参阅 内联加密。
数据模式¶
有 3 种不同的数据模式
writeback 模式
在 data=writeback 模式下,ext4 根本不记录数据。此模式提供与 XFS、JFS 和 ReiserFS 在默认模式下的日志记录级别相似的日志记录级别 - 元数据日志记录。崩溃 + 恢复可能会导致在崩溃前不久写入的文件中出现不正确的数据。此模式通常会提供最佳的 ext4 性能。
ordered 模式
在 data=ordered 模式下,ext4 仅正式记录元数据,但它会在逻辑上将与数据更改相关的元数据信息与数据块分组到一个称为事务的单元中。当需要将新的元数据写入磁盘时,将首先写入相关的数据块。通常,此模式的性能略低于 writeback,但明显快于 journal 模式。
journal 模式
data=journal 模式提供完整的数据和元数据日志记录。所有新数据首先写入日志,然后再写入其最终位置。如果发生崩溃,可以重放日志,使数据和元数据都恢复到一致的状态。除了在需要同时从磁盘读取和写入数据的情况下,此模式是最慢的,此时它的性能优于所有其他模式。启用此模式将禁用延迟分配和 O_DIRECT 支持。
/proc 条目¶
有关已挂载的 ext4 文件系统的信息可以在 /proc/fs/ext4 中找到。每个已挂载的文件系统都会在 /proc/fs/ext4 中有一个目录,该目录基于其设备名称(例如,/proc/fs/ext4/hdc 或 /proc/fs/ext4/dm-0)。每个设备目录中的文件如下表所示。
/proc/fs/ext4/<devname> 中的文件
- mb_groups
多块分配器空闲块伙伴缓存的详细信息
/sys 条目¶
有关已挂载的 ext4 文件系统的信息可以在 /sys/fs/ext4 中找到。每个已挂载的文件系统都会在 /sys/fs/ext4 中有一个目录,该目录基于其设备名称(例如,/sys/fs/ext4/hdc 或 /sys/fs/ext4/dm-0)。每个设备目录中的文件如下表所示。
/sys/fs/ext4/<devname> 中的文件
(另请参阅 Documentation/ABI/testing/sysfs-fs-ext4)
- delayed_allocation_blocks
此文件是只读的,显示页面缓存中脏块的数量,这些块尚未在文件系统中分配位置。
- inode_goal
调整参数(如果非零)控制 inode 分配器使用的目标 inode,优先于所有其他分配启发法。这仅用于调试,在生产系统中应为 0。
- inode_readahead_blks
调整参数,控制 ext4 的 inode 表预读算法将预先读取到缓冲区缓存中的最大 inode 表块数。
- lifetime_write_kbytes
此文件是只读的,显示自创建以来已写入此文件系统的数据量(以千字节为单位)。
- max_writeback_mb_bump
回写代码在转到另一个 inode 之前尝试写入的最大兆字节数。
- mb_group_prealloc
如果 ext4 超级块中未设置条带大小,则多块分配器会将分配请求向上舍入为此调整参数的倍数
- mb_max_to_scan
多块分配器为找到最佳范围而搜索的最大范围数。
- mb_min_to_scan
多块分配器为找到最佳范围而搜索的最小范围数。
- mb_order2_req
调整参数,控制使用伙伴缓存的请求的最小大小(以 2 的幂为单位)。
- mb_stats
控制多块分配器是否应收集统计信息,这些统计信息在卸载期间显示。1 表示收集统计信息,0 表示不收集统计信息。
- mb_stream_req
块数少于此可调参数的文件将从特定于块组的预分配池中分配块,以便将小文件紧密地打包在一起。每个大文件都将从其自己唯一的预分配池中分配块。
- session_write_kbytes
此文件是只读的,显示自挂载以来已写入此文件系统的数据量(以千字节为单位)。
- reserved_clusters
这是一个 RW 文件,包含文件系统中保留的簇数,这些簇将在特定情况下使用,以避免代价高昂的零输出、意外的 ENOSPC 或可能的数据丢失。默认值为 2% 或 4096 个簇,以较小者为准,可以更改此值,但它永远不能超过文件系统中的簇数。如果在挂载文件时没有足够的空间用于保留空间,则文件挂载_不会_失败。
Ioctls¶
Ext4 实现了各种 ioctl,应用程序可以使用这些 ioctl 来访问 ext4 特有的功能。下表显示了这些 ioctl 的不完整列表。此列表包括真正的 ext4 特有的 ioctl (EXT4_IOC_*
) 以及最初可能是 ext4 特有的但现在也被某些其他文件系统支持的 ioctl (FS_IOC_*
)。
Ext4 ioctl 表
- FS_IOC_GETFLAGS
获取与 inode 关联的其他属性。ioctl 参数是一个整数位字段,位值在 ext4.h 中描述。
- FS_IOC_SETFLAGS
设置与 inode 关联的其他属性。ioctl 参数是一个整数位字段,位值在 ext4.h 中描述。
- EXT4_IOC_GETVERSION、EXT4_IOC_GETVERSION_OLD
获取为每个 inode 存储的 inode i_generation 编号。i_generation 编号通常仅在创建新 inode 时才会更改,它对于网络文件系统特别有用。此 ioctl 的“_OLD”版本是 FS_IOC_GETVERSION 的别名。
- EXT4_IOC_SETVERSION、EXT4_IOC_SETVERSION_OLD
设置存储的每个 inode 的 inode i_generation 编号。此 ioctl 的“_OLD”版本是 FS_IOC_SETVERSION 的别名。
- EXT4_IOC_GROUP_EXTEND
此 ioctl 的用途与调整大小挂载选项相同。它允许将文件系统调整为最后一个现有块组的末尾,进一步调整大小必须使用 resize2fs 完成,无论是联机还是脱机。该参数指向表示文件系统新块计数的无符号 logn 数字。
- EXT4_IOC_MOVE_EXT
将块范围从 orig_fd(此 ioctl 指向的)移动到 donor_fd(在传递给此 ioctl 的 move_extent 结构中指定的)。然后,在 orig_fd 和 donor_fd 之间交换 inode 元数据。这对于在线碎片整理尤其有用,因为分配器有机会更好地分配移动的块,理想情况下分配到一个连续的范围中。
- EXT4_IOC_GROUP_ADD
将新的组描述符添加到现有或新的组描述符块。新的组描述符由 ext4_new_group_input 结构描述,该结构作为参数传递给此 ioctl。这与 EXT4_IOC_GROUP_EXTEND 结合使用特别有用,后者允许将文件系统联机调整大小到最后一个现有块组的末尾。这两个 ioctl 组合使用在用户空间联机调整大小工具(例如 resize2fs)中。
- EXT4_IOC_MIGRATE
此 ioctl 对文件系统本身进行操作。它通过遍历原始 inode 的间接块映射并将连续的块范围转换为临时 inode 的 ext4 范围,从而将 ext3 间接块映射的 inode 转换为 ext4 范围映射的 inode。然后,交换 inode。当从 ext3 迁移到 ext4 文件系统时,此 ioctl 可能会有所帮助,但建议是创建新的 ext4 文件系统并从备份复制数据。请注意,文件系统必须支持范围才能使此 ioctl 工作。
- EXT4_IOC_ALLOC_DA_BLKS
强制将所有延迟分配的块分配给保留应用程序预期的 ext3 行为。请注意,这也会开始触发数据块的写入,但此行为将来可能会更改,因为它不是必需的,并且只是为了简单起见而这样做。
- EXT4_IOC_RESIZE_FS
将文件系统调整为新的大小。调整大小的文件系统的块数通过 64 位整数参数传入。内核分配位图和 inode 表,因此用户空间工具只传递新的块数。
- EXT4_IOC_SWAP_BOOT
使用 inode EXT4_BOOT_LOADER_INO (#5) 交换指定 inode 的 i_blocks 和关联属性(如 i_blocks、i_size、i_flags 等)。这通常用于将引导加载程序存储在文件系统的安全部分,普通用户不会意外更改它。先前引导加载程序的数据块将与给定的 inode 关联。
参考资料¶
- 内核源代码:<file:fs/ext4/>