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

  • 使用 ext4 文件系统类型创建一个新的文件系统

    # mke2fs -t ext4 /dev/hda1

    或者配置现有的 ext3 文件系统以支持 extent

    # tune2fs -O extents /dev/hda1

    如果文件系统是使用 128 字节的 inode 创建的,则可以通过以下方式将其转换为使用 256 字节以获得更高的效率

    # tune2fs -I 256 /dev/hda1

  • 挂载

    # mount -t ext4 /dev/hda1 /wherever

  • 当与其他文件系统比较性能时,始终尝试多种工作负载非常重要;通常,工作负载参数的细微变化会完全改变文件系统相比其他文件系统的排名。 当与 ext3 进行比较时,请注意 ext4 默认启用写入屏障,而 ext3 默认不启用写入屏障。 因此,通过 `-o barriers=[0|1]` 挂载选项为 ext3 和 ext4 文件系统显式指定是否启用屏障以进行公平比较非常有用。 在调整 ext3 以获得最佳基准测试结果时,通常值得尝试更改数据日志模式; `-o data=writeback` 对于某些工作负载可能会更快。(但请注意,以 data=writeback 挂载运行时,在发生不干净的关机时,可能会在最近写入的文件中留下过时的数据,这在某些情况下可能是安全风险。)使用大型日志配置文件系统也有助于元数据密集型工作负载。

特点

当前可用

  • 能够使用 > 16TB 的文件系统(e2fsprogs 支持尚未可用)

  • extent 格式减少了元数据开销(RAM、IO 用于访问、事务)

  • extent 格式在磁盘损坏的情况下更健壮,因为使用了 magic,

  • 树中的内部冗余

  • 改进的文件分配(多块分配)

  • 取消 i_links_count 施加的 32000 个子目录限制[1]

  • mtime、atime、ctime、创建时间的 nsec 时间戳

  • 磁盘上的 inode 版本字段(NFSv4、Lustre)

  • 通过 uninit_bg 功能减少 e2fsck 时间

  • 用于稳健性和性能的日志校验和

  • 持久文件预分配(例如,用于流媒体、数据库)

  • 能够通过 flex_bg 功能将位图和 inode 表打包到更大的虚拟组中

  • 大文件支持

  • 使用 flex_bg 通过大型虚拟块组进行 inode 分配

  • 延迟分配

  • 大块(高达页面大小)支持

  • JBD2 和 ext4 中高效的新 ordered 模式(避免使用缓冲区头来强制排序)

  • 不区分大小写的文件名查找

  • 基于文件的加密支持 (fscrypt)

  • 基于文件的完整性支持 (fsverity)

[1] 块大小为 1k 的文件系统可能会受到目录哈希树的最大深度为 2 的限制。

不区分大小写的文件名查找

不区分大小写的文件名查找功能在每个目录的基础上都支持,允许用户在同一文件系统中混合使用不区分大小写和区分大小写的目录。 它通过翻转空目录的 +F inode 属性来启用。 不区分大小写的字符串匹配操作仅在我们知道文本如何在字节序列中编码时才定义。 因此,为了启用不区分大小写的目录,文件系统必须具有 casefold 功能,该功能存储使用的文件系统范围的编码模型。 默认情况下,采用的字符集是最新版本的 Unicode(在撰写本文时为 12.1.0),以 UTF-8 形式编码。 比较算法通过将字符串规范化为 Unicode 定义的规范分解形式来实现,然后进行字节与字节的比较。

大小写感知在磁盘上保留名称,这意味着 userspace 提供的文件名与实际写入磁盘的内容逐字节匹配。 因此,内核使用的 Unicode 规范化格式是内部表示,不会暴露给用户空间或磁盘,但具有 DX 功能的大型不区分大小写的目录上使用的磁盘哈希除外。 在 DX 目录上,必须使用文件名的大小写折叠版本计算哈希值,这意味着使用的规范化格式实际上会影响目录条目的存储位置。

当我们从将文件名视为不透明的字节序列更改为将其视为编码的字符串时,我们需要解决程序尝试使用无效名称创建文件时会发生什么情况。 内核中的 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(*)

如果文件数据缓冲区中发生错误,则只打印错误消息。

data_err=abort

如果文件数据缓冲区中发生错误,则中止日志。

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 块大小。

delalloc (*)

将块分配推迟到 ext4 写入有问题的块之前。 这允许 ext4 更有效地做出更好的分配决策。

nodelalloc

禁用延迟分配。 当数据从用户空间复制到页面缓存时(通过 write(2) 系统调用),或者当第一次写入先前未分配的 mmap 页面时,会分配块。

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”) 或更糟糕的模式(fd = open(“foo”, O_TRUNC)/write(fd,..)/close(fd))替换现有文件时不使用 fsync()。 如果启用了 auto_da_alloc,ext4 将检测到通过重命名和通过截断模式进行的替换,并强制分配任何延迟分配的块,以便在下一个日志提交时,在默认 data=ordered 模式下,新文件的数据块将被强制在 rename() 操作提交之前写入磁盘。 这提供了与 ext3 大致相同的保证级别,并避免了在系统崩溃之前延迟分配的块被强制写入磁盘时可能发生的“零长度”问题。

noinit_itable

不要在后台初始化任何未初始化的 inode 表块。 安装 CD 可以使用此功能,以便安装过程可以尽快完成; 然后,inode 表初始化过程将被推迟到下次卸载文件系统时。

init_itable=n

延迟 itable 初始化代码将等待 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> 中的文件

(另请参见 ABI 文件测试/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

多块分配器将搜索以找到最佳 extent 的最大 extent 数。

mb_min_to_scan

多块分配器将搜索以找到最佳 extent 的最小 extent 数。

mb_order2_req

调整参数,用于控制使用伙伴缓存的请求的最小大小(作为 2 的幂)。

mb_stats

控制多块分配器是否应收集统计信息,这些统计信息在卸载期间显示。 1 表示收集统计信息,0 表示不收集统计信息。

mb_stream_req

块数少于此可调参数的文件将从特定于块组的预分配池中分配其块,以便将小文件紧密地打包在一起。 每个大文件将从其自己唯一的预分配池中分配其块。

session_write_kbytes

此文件是只读的,显示了自挂载此文件系统以来已写入该文件系统的数据千字节数。

reserved_clusters

这是一个 RW 文件,包含文件系统中保留的集群数,这些集群将在特定情况下使用,以避免代价高昂的清零、意外的 ENOSPC 或可能的数据丢失。 默认值为 2% 或 4096 个集群,以较小者为准,并且可以更改,但是它永远不会超过文件系统中的集群数。 如果在挂载文件时没有足够的空间用于保留空间,则挂载将_不会_失败。

Ioctls

Ext4 实现了各种 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进行,可以是在线或离线。 参数指向表示文件系统新块计数的无符号长整型数。

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 的 i_blocks 和关联属性(例如 i_blocks、i_size、i_flags 等)与 inode EXT4_BOOT_LOADER_INO (#5) 交换。 这通常用于将引导加载程序存储在文件系统的安全部分中,普通用户不会意外更改它。 先前引导加载程序的数据块将与给定的 inode 关联。

参考

内核源代码: <file:fs/ext4/>

<file:fs/jbd2/>

程序: http://e2fsprogs.sourceforge.net/

有用的链接: https://fedoraproject.org/wiki/ext3-devel

http://www.bullopensource.org/ext4/ http://ext4.wiki.kernel.org/index.php/Main_Page https://fedoraproject.org/wiki/Features/Ext4