SGI XFS 文件系统

XFS 是一个高性能的日志文件系统,最初起源于 SGI IRIX 平台。它完全支持多线程,能够支持大文件和大型文件系统、扩展属性、可变的块大小,采用基于区段(extent)的设计,并大量使用 B 树(用于目录、区段、空闲空间)来提升性能和可扩展性。

更多详情请参考 https://xfs.wiki.kernel.org/ 上的文档。此实现与 IRIX 版本的 XFS 在磁盘格式上保持兼容。

挂载选项

挂载 XFS 文件系统时,接受以下选项。

allocsize=size

在进行延迟分配写出时,设置带缓冲的 I/O 文件末尾预分配大小(默认大小为 64KiB)。此选项的有效值从页大小(通常为 4KiB)到 1GiB(包含在内),按 2 的幂次递增。

默认行为是采用动态的文件末尾预分配大小,它使用一组启发式方法,根据文件当前的分配模式和访问模式来优化预分配大小。指定固定的 allocsize 值会关闭动态行为。

discard 或 nodiscard(默认)

启用/禁用下发命令,允许块设备回收文件系统释放的空间。这对于 SSD 设备、精简配置的 LUN 以及虚拟机镜像非常有用,但可能会对性能产生影响。

注意:目前建议使用 fstrim 应用程序来 discard 未使用的块,而不是使用 discard 挂载选项,因为该选项对性能的影响相当严重。

grpid/bsdgroups 或 nogrpid/sysvgroups(默认)

这些选项定义了新创建的文件将获得什么组 ID。当设置了 grpid 时,它将继承创建该文件的目录的组 ID;否则它将采用当前进程的 fsgid,除非该目录设置了 setgid 位,这种情况下它将从父目录获取 gid,并且如果它本身是一个目录,也会被设置 setgid 位。

filestreams

使数据分配器在整个文件系统范围内使用文件流(filestreams)分配模式,而不仅仅是在配置为使用它的目录上。

inode32 或 inode64(默认)

当指定了 inode32 时,表示 XFS 将 inode 的创建限制在不会导致 inode 号有效位数超过 32 位的区域。

当指定了 inode64 时,表示允许 XFS 在文件系统的任何位置创建 inode,包括那些会导致 inode 号占用超过 32 位有效位的区域。

提供 inode32 是为了与旧系统和应用程序保持向后兼容,因为 64 位 inode 号可能会给某些无法处理大 inode 号的应用程序带来问题。如果正在使用的应用程序无法处理大于 32 位的 inode 号,则应指定 inode32 选项。

largeio 或 nolargeio(默认)

如果指定了 nolargeio,则由 stat(2)st_blksize 中报告的最佳 I/O 将尽可能小,以允许用户应用程序避免低效的读/修改/写 I/O。这通常是机器的页大小,因为这是页缓存的粒度。

如果指定了 largeio,则使用指定了 swidth 创建的文件系统将在 st_blksize 中返回 swidth 值(以字节为单位)。如果文件系统未指定 swidth 但指定了 allocsize,则会返回 allocsize(以字节为单位)。否则,其行为与指定了 nolargeio 时相同。

logbufs=value

设置内存中日志缓冲区的数量。有效数字范围为 2 到 8(包含边界)。

默认值为 8 个缓冲区。

如果在小型系统上 8 个日志缓冲区的内存成本过高,可以将其减少,但这会对元数据密集型工作负载的性能造成一定损失。下面的 logbsize 选项控制每个缓冲区的大小,因此也与此情况相关。

lifetime(默认)或 nolifetime

启用基于用户提供的写入生命周期提示的数据放置。当统计上有利于降低垃圾回收成本时,这会开启相似生命周期数据的协同分配。

这些选项仅适用于分区实时(zoned rt)文件系统。

logbsize=value

设置每个内存日志缓冲区的大小。该大小可以以字节为单位指定,也可以使用带有“k”后缀的千字节指定。版本 1 和版本 2 日志的有效大小为 16384 (16k) 和 32768 (32k)。版本 2 日志的有效大小还包括 65536 (64k)、131072 (128k) 和 262144 (256k)。logbsize 必须是 mkfs(8) 时配置的日志条带单元的整数倍。

版本 1 日志的默认值为 32768,而版本 2 日志的默认值为 MAX(32768, log_sunit)。

logdev=device 和 rtdev=device

使用外部日志(元数据日志)和/或实时设备。一个 XFS 文件系统最多包含三部分:数据段、日志段和实时段。实时段是可选的,日志段可以与数据段分开,也可以包含在数据段中。

max_atomic_write=value

设置原子写入的最大大小。该大小可以以字节为单位指定,也可以使用带“k”后缀的千字节、带“m”后缀的兆字节或带“g”后缀的吉字节指定。该大小不能大于最大写入大小、不能大于任何分配组的大小,也不能大于日志能够原子完成的重映射操作的大小。

默认值是将最大 I/O 完成大小设置为允许每个 CPU 一次处理一个。

max_open_zones=value

指定在分区实时设备上保持打开以供写入的最大区(zone)数量。较多的打开区有助于文件数据分离,但可能会影响 HDD 上的性能。

如果未指定 max_open_zones,则该值由分区实时设备的功能和大小决定。

noalign

数据分配将不会在条带单元边界处对齐。这仅与由 mkfs(8) 创建时带有非零数据对齐参数(sunitswidth)的文件系统相关。

norecovery

挂载文件系统时将不运行日志恢复。如果文件系统未被干净地卸载,以 norecovery 模式挂载时很可能会出现不一致。因此,某些文件或目录可能无法访问。以 norecovery 挂载的文件系统必须以只读方式挂载,否则挂载将会失败。

nouuid

不使用文件系统 uuid 检查重复挂载的文件系统。这对于挂载 LVM 快照卷非常有用,并且通常与 norecovery 结合使用以挂载只读快照。

noquota

强制关闭文件系统内的所有配额统计和强制执行。

uquota/usrquota/uqnoenforce/quota

启用用户磁盘配额统计,并(可选地)强制执行限制。更多详情请参考 xfs_quota(8)

gquota/grpquota/gqnoenforce

启用组磁盘配额统计,并(可选地)强制执行限制。更多详情请参考 xfs_quota(8)

pquota/prjquota/pqnoenforce

启用项目磁盘配额统计,并(可选地)强制执行限制。更多详情请参考 xfs_quota(8)

sunit=value 和 swidth=value

用于指定 RAID 设备或条带卷的条带单元和宽度。“value”必须以 512 字节块为单位指定。这些选项仅与使用非零数据对齐参数创建的文件系统相关。

指定的 sunitswidth 参数必须与现有的文件系统对齐特性兼容。通常这意味着对 sunit 唯一有效的更改是以 2 的幂次倍数进行增加。有效的 swidth 值是有效 sunit 值的任意整数倍。

通常,仅当底层 RAID 设备的几何结构被修改后(例如向 RAID5 LUN 添加新磁盘并进行重塑),才有必要使用这些挂载选项。

swalloc

当正在扩展当前文件末尾且文件大小大于条带宽度大小时,数据分配将被向上圆整到条带宽度边界。

wsync

指定后,所有文件系统命名空间操作都将同步执行。这确保了当命名空间操作(创建、取消链接等)完成时,对命名空间的更改已持久化到稳定存储上。这在高可用(HA)设置中非常有用,在这些设置中,故障转移绝不能导致客户端在故障转移事件期间或之后看到不一致的命名空间呈现。

errortag=tagname

指定后,将以默认频率启用名为“tagname”的错误注入标签。可以多次指定以启用多个错误标签。如果在重新挂载时指定此选项,且该错误标签之前被设置为任何其他值,则会将其重置为默认值。此选项仅在启用 CONFIG_XFS_DEBUG 时受支持,并且不会反映在 /proc/self/mounts 中。

V4 格式的弃用

V4 文件系统格式缺乏 V5 格式支持的某些功能,例如元数据校验和、增强的元数据验证以及存储 2038 年以后时间戳的能力。正因为如此,V4 格式已被弃用。所有用户都应通过备份文件、重新格式化以及从备份恢复来升级。

管理员和用户可以通过针对文件系统挂载点运行 xfs_info 并检查是否包含“crc=”的字符串来检测 V4 文件系统。如果未找到此类字符串,请将 xfsprogs 升级到最新版本并重试。

弃用将分两部分进行。现在可以通过 Kconfig 选项在内核编译时禁用对挂载 V4 文件系统的支持。这些选项在 2025 年 9 月被更改为默认值为 no。2030 年 9 月,支持将从代码库中完全移除。

注意:发行商可能会选择在上述日期之前取消对 V4 格式的支持。

已弃用的挂载选项

名称

移除时间表

挂载 V4 文件系统

2030 年 9 月

挂载 ascii-ci 文件系统

2030 年 9 月

已移除的挂载选项

名称

已移除

delaylog/nodelaylog

v4.0

ihashsize

v4.0

irixsgid

v4.0

osyncisdsync/osyncisosync

v4.0

barrier

v4.19

nobarrier

v4.19

ikeep/noikeep

v6.18

attr2/noattr2

v6.18

sysctl 参数

XFS 文件系统提供以下 sysctl 参数

fs.xfs.stats_clear (最小值: 0 默认值: 0 最大值: 1)

将其设置为 “1” 会清除 /proc/fs/xfs/stat 中累积的 XFS 统计信息。然后它会立即重置为 “0”。

fs.xfs.xfssyncd_centisecs (最小值: 100 默认值: 3000 最大值: 720000)

文件系统将元数据刷新到磁盘并运行内部缓存清理例程的时间间隔。

fs.xfs.filestream_centisecs (最小值: 1 默认值: 3000 最大值: 360000)

文件系统老化文件流缓存引用并将超时的 AG 返回给空闲流池的时间间隔。

fs.xfs.speculative_prealloc_lifetime

(单位:秒 最小值: 1 默认值: 300 最大值: 86400) 后台扫描具有未使用的推测性预分配的 inode 的时间间隔。该扫描会从干净的 inode 中移除未使用的预分配,并将未使用的空间释放回空闲池。

fs.xfs.error_level (最小值: 0 默认值: 3 最大值: 11)

用于在发生内部错误时报告错误的控制旋钮。例如,这将在文件系统关闭时生成详细的消息和回溯。当前的阈值是

XFS_ERRLEVEL_OFF: 0 XFS_ERRLEVEL_LOW: 1 XFS_ERRLEVEL_HIGH: 5

fs.xfs.panic_mask (最小值: 0 默认值: 0 最大值: 511)

导致某些错误条件调用 BUG()。该值是一个位掩码;将代表应导致 panic 的错误的标签进行按位或运算

XFS_NO_PTAG 0 XFS_PTAG_IFLUSH 0x00000001 XFS_PTAG_LOGRES 0x00000002 XFS_PTAG_AILDELETE 0x00000004 XFS_PTAG_ERROR_REPORT 0x00000008 XFS_PTAG_SHUTDOWN_CORRUPT 0x00000010 XFS_PTAG_SHUTDOWN_IOERROR 0x00000020 XFS_PTAG_SHUTDOWN_LOGERROR 0x00000040 XFS_PTAG_FSBLOCK_ZERO 0x00000080 XFS_PTAG_VERIFIER_ERROR 0x00000100

此选项仅用于调试目的。

fs.xfs.inherit_sync (最小值: 0 默认值: 1 最大值: 1)

将其设置为 “1” 将导致该目录中由 xfs_io(8) chattr 命令设置的 “sync” 标志被该目录中的文件继承。

fs.xfs.inherit_nodump (最小值: 0 默认值: 1 最大值: 1)

将其设置为 “1” 将导致该目录中由 xfs_io(8) chattr 命令设置的 “nodump” 标志被该目录中的文件继承。

fs.xfs.inherit_noatime (最小值: 0 默认值: 1 最大值: 1)

将其设置为 “1” 将导致该目录中由 xfs_io(8) chattr 命令设置的 “noatime” 标志被该目录中的文件继承。

fs.xfs.inherit_nosymlinks (最小值: 0 默认值: 1 最大值: 1)

将其设置为 “1” 将导致该目录中由 xfs_io(8) chattr 命令设置的 “nosymlinks” 标志被该目录中的文件继承。

fs.xfs.inherit_nodefrag (最小值: 0 默认值: 1 最大值: 1)

将其设置为 “1” 将导致该目录中由 xfs_io(8) chattr 命令设置的 “nodefrag” 标志被该目录中的文件继承。

fs.xfs.rotorstep (最小值: 1 默认值: 1 最大值: 256)

在 “inode32” 分配模式下,此选项决定分配器在移动到下一个分配组之前,尝试在同一个分配组中分配多少个文件。其目的是控制分配器为新文件分配区段时在分配组之间移动的速率。

已弃用的 sysctl 参数

当前没有。

已移除的 sysctl 参数

名称

已移除

fs.xfs.xfsbufd_centisec

v4.0

fs.xfs.age_buffer_centisecs

v4.0

fs.xfs.irix_symlink_mode

v6.18

fs.xfs.irix_sgid_inherit

v6.18

fs.xfs.speculative_cow_prealloc_lifetime

v6.18

错误处理

XFS 可以根据在其运行过程中发现的错误类型采取不同的行为。该实现为错误处理程序引入了以下概念

- 失败速度(failure speed)

定义在文件系统操作期间发现特定错误时,XFS 应以多快的速度将错误向上冒泡。它可以立即传播、在达到指定的重试次数后传播、在设定的时间段后传播,或者干脆永远重试。

- 错误类别(error classes)

指定错误配置将应用于的子系统,例如元数据 IO 或内存分配。不同的子系统将具有不同的错误处理程序,并且可以为其配置行为。

- 错误处理程序(error handlers)

定义特定错误的行为。

文件系统在发生错误时的行为可以通过 sysfs 文件进行设置。每个错误处理程序独立工作——特定类别的错误处理程序满足的第一个条件将导致错误被传播,而不是被重置和重试。

当错误传播时文件系统采取的动作取决于上下文——在不可恢复错误的情况下,它可能会导致关机,它可能会被报告回用户空间,或者它甚至可能被忽略,因为对于该错误我们无能为力,也没有人可以向其报告(例如在卸载期间)。

对于每个挂载的文件系统,配置文件按以下层次结构组织

/sys/fs/xfs/<dev>/error/<class>/<error>/

其中:
<dev>

已挂载文件系统的短设备名。这与 XFS 内核错误消息中显示的设备名相同,即 “XFS(<dev>): ...”

<class>

错误配置所属的子系统。从 4.9 版本开始,定义的类别有

  • “metadata”:应用于元数据缓冲区写 IO

<error>

各个错误处理程序配置。

每个文件系统在其顶级目录中都定义了“全局”错误配置选项

/sys/fs/xfs/<dev>/error/

fail_at_unmount (最小值: 0 默认值: 1 最大值: 1)

定义卸载时的文件系统错误行为。

如果设置为 1,XFS 将在卸载期间覆盖所有其他错误配置,并将其替换为“立即失败”特性。即:不进行重试,没有重试超时。当存在持久性错误时,这总是允许卸载成功。

如果设置为 0,配置的重试行为将继续,直到所有重试和/或超时耗尽。当存在持久性错误时,这会延迟卸载完成,并且在“永远重试”处理程序配置的情况下,可能会阻止文件系统完全卸载。

注意:无法保证在卸载正在进行时可以设置 fail_at_unmount。sysfs 条目可能会在“永远重试”错误处理程序配置导致卸载挂起之前被正在卸载的文件系统移除,因此必须在卸载开始之前对文件系统进行适当配置,以防止卸载挂起。

每个文件系统都有特定的错误类别处理程序,用于定义特定错误的错误传播行为。还定义了一个“默认”错误处理程序,用于定义所有未定义特定处理程序的错误的行为。如果为单个错误配置了多个重试约束,则第一个到期的重试配置将导致错误被传播。处理程序配置位于目录中

/sys/fs/xfs/<dev>/error/<class>/<error>/

max_retries (最小值: -1 默认值: 视情况而定 最大值: INTMAX)

定义在文件系统传播错误之前,对特定错误允许的最大重试次数。给定错误上下文(例如特定的元数据缓冲区)的重试次数在每次操作成功完成时都会重置。

将该值设置为 “-1” 将导致 XFS 针对此特定错误永远重试。

将该值设置为 “0” 将导致 XFS 在报告特定错误时立即失败。

将该值设置为 “N”(其中 0 < N < 最大值)将使 XFS 在传播错误之前重试该操作 “N” 次。

retry_timeout_seconds (最小值: -1 默认值: 视情况而定 最大值: 1 天)

定义发现特定错误时,允许文件系统重试其操作的时间量(以秒为单位)。

将该值设置为 “-1” 将允许 XFS 针对此特定错误永远重试。

将该值设置为 “0” 将导致 XFS 在报告特定错误时立即失败。

将该值设置为 “N”(其中 0 < N < 最大值)将允许 XFS 在传播错误之前最多重试该操作 “N” 秒。

注意:特定错误处理程序的默认行为取决于类别和错误上下文。例如,“metadata/ENODEV”的默认值是 “0” 而不是 “-1”,因此该错误处理程序默认采用“立即失败”的行为。这样做是因为无论重试多少次元数据 IO,ENODEV 都是一个致命的、不可恢复的错误。

工作队列并发(Workqueue Concurrency)

XFS 使用内核工作队列来并行化元数据更新进程。这使其能够充分利用能够同时处理多个 IO 操作的存储硬件。此接口暴露了 XFS 的内部实现细节,因此它明确不属于内核可能向用户空间提供的任何用户空间 API/ABI 保证的一部分。这些是 XFS 用于并发的通用工作队列实现的未文档化特性,这里提供它们纯粹是为了诊断和调优目的,并且未来随时可能更改。

文件系统工作队列的控制旋钮按当前任务和数据设备的短名称进行组织。它们都可以在以下路径中找到

/sys/bus/workqueue/devices/${task}!${device}

任务(Task)

描述

xfs_iwalk-$pid

对整个文件系统的 inode 扫描。目前仅限于挂载时的 quotacheck。

xfs-gc

对超出 EOF 推测性分配或用于暂存写时复制操作的磁盘空间进行后台垃圾回收。

例如,/dev/nvme0n1 的 quotacheck 工作队列的控制旋钮可以在 /sys/bus/workqueue/devices/xfs_iwalk-1111!nvme0n1/ 中找到。

XFS 工作队列中有趣的控制旋钮如下

控制旋钮(Knob)

描述

max_active

可以启动来运行工作的后台线程的最大数量。

cpumask

允许线程在其上运行的 CPU。

nice

调度线程的相对优先级。这些是可以应用于用户空间进程的相同的 nice 级别。

分区文件系统(Zoned Filesystems)

对于分区文件系统,以下属性暴露在

/sys/fs/xfs/<dev>/zoned/

max_open_zones (最小值: 1 默认值: 视情况而定 最大值: UINTMAX)

此只读属性公开了可用于数据放置的最大打开区数量。该值在挂载时确定,并受底层分区设备的能力、文件系统大小以及 max_open_zones 挂载选项的限制。

nr_open_zones (最小值: 0 默认值: 视情况而定 最大值: UINTMAX)

此只读属性公开了文件系统当前使用的打开区数量。

zonegc_low_space (最小值: 0 默认值: 0 最大值: 100)

定义一个百分比,表示垃圾回收(GC)应保持多少未使用的空间可用于写入。较高的值将回收更多由未使用块占用的空间,从而针对写入突发创建更大的缓冲区,但代价是增加写入放大。无论此值如何,垃圾回收始终旨在释放最少数量的块,以便出于数据放置的目的保持 max_open_zones 处于打开状态。