关注了就能看到更多这么棒的文章哦~
Filesystem support for block sizes larger than the page size
February 20, 2025
This article was contributed by Pankaj Raghav
Gemini-1.5-flash translation
https://lwn.net/Articles/1009548/
内核所能支持的最大文件系统块大小一直受到 Linux 主机页大小的限制,即使文件系统本身可以处理更大的块大小。为 6.12 内核合并的 large-block-size (LBS) patches移除了 XFS 中的这一限制,从而将页大小与文件系统块大小解耦。XFS 是第一个获得此支持的文件系统,未来可能会有其他文件系统添加 LBS 支持。此外,LBS 补丁已被用于将 initial atomic-write support(初始原子写入支持)引入 XFS。
LBS 是一个含义过载的术语,因此有必要澄清它在内核上下文中的含义。在本文中,术语 LBS 指的是文件系统块大小大于系统页大小的情况。文件系统块是文件系统用于在磁盘上存储文件数据的最小单元。设置文件系统块大小只会影响数据路径中的 I/O 粒度,而不会对文件系统元数据产生任何影响。
Long history
LBS 最早的用例 来自 CD/DVD 领域,当时读取和写入必须以 32KB 或 64KB 的块执行。最初提议使用 LBS 支持来处理这些设备,并避免在设备驱动程序级别进行变通,但该方案从未被合并。除了这些历史需求之外,LBS 还支持测试大于主机页大小的文件系统块大小,从而允许开发人员在不支持 64KB 页面的 x86_64 系统上验证 64KB 块的 XFS 功能。鉴于采用更大页大小的架构日益增多,这一点尤其有价值。
LBS 的另一个新兴用例来自现代高容量固态存储设备 (SSD)。存储供应商正在 increasing their internal mapping unit(增加其内部映射单元),通常称为 Indirection Unit (IU),使其超过 4KB 以支持这些设备。如果 I/O 操作的大小与此更大的 IU 不匹配,则设备必须 perform read-modify-write operations(执行读-修改-写操作),从而增加写入放大因子。LBS 使文件系统能够将其块大小与设备的 IU 相匹配,从而避免这些代价高昂的操作。
虽然 LBS 听起来似乎与块层(block layer)有关,但内核中的块大小限制实际上 来自 page cache,而不是块层。获得文件系统 LBS 支持的主要要求是在页缓存中将文件系统块作为一个单元进行跟踪。由于块是数据的最小单元,因此页缓存不应在回写期间 partially evict(部分逐出)单个块。
过去曾多次 attempts(尝试)添加 LBS 支持。Dave Chinner 在 2018 年 最近一次努力通过在 iomap 中添加 IOMAP_F_ZERO_AROUND
标志来规避页缓存的限制。如果 I/O 操作的大小小于单个块,则此标志会用零填充 I/O 操作。这些补丁还移除了 writepage()
回调,以确保在回写期间写入整个大块。由于 folios(页)正逐渐受到关注,并且有可能直接在虚拟文件系统层解决部分逐出的问题,因此这项工作未被提交到主线 (mainline)。
Large folio support(大页支持)已添加到页缓存中,并在 5.18 版本中在 XFS 中启用。如果文件系统支持大页,则页缓存将根据 I/O 操作的大小,在读取和写入路径中有机会分配更大的页。文件系统在 inode 初始化期间调用 mapping_set_large_folios()
以启用大页功能。但是,如果系统内存不足,页缓存仍然可能会退回到分配 order-0 页(单个页),因此无法保证页的大小。
LBS 补丁由我和我的同事开发,它为文件系统添加了一种方式,可以将最小和最大页分配顺序告知页缓存,以匹配其块大小。页缓存将分配与文件系统设置的顺序约束匹配的大页,并确保不会发生块的部分逐出。mapping_set_folio_min_order()
和 mapping_set_folio_order_range()
API 已被添加,以控制页缓存中的分配顺序。顺序信息被编码在 address_space
struct 的 flags
成员中。
设置最小页顺序足以让文件系统添加 LBS 支持,因为它们只需要保证页缓存中分配的最小页。文件系统可以在 inode 初始化期间根据块大小设置最小页顺序。 mapping_set_large_folios()
的现有调用者不会注意到任何行为上的变化,因为该函数现在会将最小顺序设置为零,并将最大顺序设置为 MAX_PAGECACHE_ORDER
。
在内存压力下,内核会尝试将一个大页分解为单个页,这可能会违反页缓存中最小页顺序的承诺。主要的约束是,页缓存必须始终确保页缓存中的页永远不小于最小顺序。自 6.8 内核以来,内存管理子系统已支持将大页拆分为任何 lower-order folio(低阶页)。LBS 支持使用此功能来始终保持页缓存中的最小页顺序,即使由于内存压力或截断而拆分大页时也是如此。
Other filesystems?
读者可能想知道,既然页缓存基础设施已经就位,那么向其他文件系统添加 LBS 支持是否会很简单。不幸的是,答案是:视情况而定。即使页缓存中已经有了在任何文件系统中支持 LBS 的必要基础设施,但添加此支持的路径取决于文件系统的实现。XFS 已经为 LBS 支持准备了很长时间,这使得 LBS 补丁只需要在 XFS 中进行最少的更改。
文件系统需要支持大页才能支持 LBS。因此,目前任何在数据路径中使用 buffer heads(缓冲区头)的文件系统都无法支持 LBS。XFS 开发人员放弃了缓冲区头,并设计了 iomap 来解决缓冲区头的缺点。虽然目前正在进行支持缓冲区头中的大页的工作,但这可能需要一段时间才能添加。一旦将大页支持添加到文件系统,添加 LBS 支持就是要找到文件系统中任何对块大小做出假设的 corner cases(极端情况)。
LBS 已经在内核中找到了一个用例。页缓存中表示文件系统块的内存不会被拆分的保证已被用于 6.13 中的 atomic-write support in XFS(XFS 中的原子写入支持)。XFS 中的初始支持将仅允许原子地写入一个文件系统块。驱动器需要使用所需大小的原子写入作为其文件系统块大小进行格式化。
LBS 项目的下一个重点是 remove the logical-block-size restriction for block devices(删除块设备的逻辑块大小限制)。与文件系统块大小类似,逻辑块大小(logical block size),即存储设备可以寻址的最小大小,由于页缓存的限制,也被限制为主机页大小。当应用程序直接在设备上执行缓冲 I/O 操作时,块设备会将数据缓存在页缓存中,并且默认使用缓冲区头与页缓存进行交互。因此,需要在缓冲区头中支持大页才能消除块设备的这一限制。
在 LBS 的第一次尝试之后,过去 17 年中发生了许多核心变化,例如大页支持、XFS 使用 iomap 而不是缓冲区头、块层中的多页 bvec 支持等等。这使得添加 LBS 支持所需的更改相对较少。随着 6.12 完成这项工作,XFS 最终将支持它在 2001 年移植到 Linux 之前在 IRIX 中支持的所有功能。
[I would like to thank Luis Chamberlain and Daniel Gomez for their contributions to both this article and the LBS patches. Special thanks to Matthew Wilcox, Hannes Reinecke, Dave Chinner, Darrick Wong, and Zi Yan for their thorough reviews and valuable feedback that helped shape the LBS patch series.]
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
欢迎分享、转载及基于现有协议再创作~
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~