3. 移植您的文件系统¶
3.1. 为什么要转换?¶
将文件系统转换为 iomap 有几个原因。
经典的 Linux I/O 路径效率不高。 Pagecache 操作一次锁定一个基本页面,然后调用文件系统以仅返回该页面的映射。 直接 I/O 操作一次构建一个文件块的 I/O 请求。 这对于像 ext2 这样的直接/间接映射的文件系统来说已经足够好,但对于像 XFS 这样的基于范围的文件系统来说效率非常低。
仅通过 iomap 支持大型页(folios);没有计划转换旧的 buffer_head 路径以使用它们。
只有通过 iomap 才支持直接访问类内存设备上的存储 (fsdax)。
降低了各个文件系统维护人员的维护开销。 iomap 本身处理常见的 pagecache 相关操作,例如分配、实例化、锁定和解锁页(folios)。 使用 iomap 的文件系统不需要实现 ->write_begin()、->write_end() 或 direct_IO address_space_operations。
3.2. 如何转换文件系统?¶
首先,从您的源代码中添加 #include <linux/iomap.h>
,并将 select FS_IOMAP
添加到您的文件系统的 Kconfig 选项中。 构建内核,使用 -g all
选项在文件系统支持的各种配置上运行 fstests,以构建哪些测试通过和哪些测试失败的基线。
推荐的方法是首先实现 ->iomap_begin
(如果需要,还有 ->iomap_end
),以允许 iomap 获取文件范围的只读映射。 在大多数情况下,这是对现有 get_block()
函数的相对简单的转换,用于只读映射。 FS_IOC_FIEMAP
是一个很好的首选目标,因为它很容易实现对其的支持,然后从用户空间确定范围映射迭代是否正确。 如果 FIEMAP 返回正确的信息,则这是一个很好的迹象,表明其他只读映射操作也会做正确的事情。
接下来,修改文件系统的 get_block(create = false)
实现,以使用新的 ->iomap_begin
实现来映射选定读取操作的文件空间。 在调试旋钮后面隐藏启用 iomap 映射功能的能力,以用于选定的调用路径。 有必要编写一些代码,以便从 iomap
结构中填充基于 bufferhead 的映射信息,但可以在不需要实现任何 iomap API 的情况下测试新功能。
一旦只读功能像这样工作,就逐个转换每个高级文件操作以使用 iomap 原生 API,而不是通过 get_block()
。 一次完成一个,回归应该是不言而喻的。 您确实有 fstests 的回归测试基线,对吧? 建议在处理 I/O 路径之前,转换交换文件激活、SEEK_DATA
和 SEEK_HOLE
。 此时的一个可能的复杂性将是由于 bufferheads 转换缓冲的读取 I/O 路径。 然而,缓冲的读取 I/O 路径还不需要转换,但直接 I/O 读取路径应该在此阶段进行转换。
此时,您应该检查您的 ->iomap_begin
函数。 如果它基于 flags
参数的分发在大量代码块之间切换,您应该考虑将其分解为每个操作的 iomap 操作,使用更小、更具内聚性的函数。 XFS 是一个很好的例子。
接下来要做的是在 ->iomap_begin
/->iomap_end
方法中实现 get_blocks(create == true)
功能。 强烈建议为写入操作创建单独的映射功能和 iomap 操作。 然后将直接 I/O 写入路径转换为 iomap,并开始在文件系统上认真地使用启用 DIO 的 fsx 运行。 这将清除新的写入映射实现引入的许多数据完整性边缘情况错误。
现在,转换任何剩余的文件操作以调用 iomap 函数。 这将使整个文件系统使用新的映射功能,并且在此步骤之后,它们应该在很大程度上被调试并且可以正常工作。
最有可能的是,此时,缓冲的读取和写入路径仍然需要转换。 映射功能都应该正常工作,因此所有需要做的就是重写所有与 bufferheads 交互的代码,以与 iomap 和页(folios)交互。 首先将常规文件 I/O(没有任何花哨的功能,如 fscrypt、fsverity、压缩或 data=journaling)转换为使用 iomap 会更容易。 一些花哨的功能(fscrypt 和压缩)尚未在 iomap 中实现。 对于将 pagecache 用于符号链接和目录的非日志文件系统,您也可以尝试将其处理转换为 iomap。
其余的留给读者作为练习,因为它对于每个文件系统都将是不同的。 如果您遇到问题,请通过电子邮件发送给 get_maintainers.pl
中的人员和列表寻求帮助。