关注了就能看到更多这么棒的文章哦~
The hard life of a virtual-filesystem developer
By Jonathan Corbet
February 1, 2024
Translated purely by Gemini
https://lwn.net/Articles/960088/
文件系统开发并不是一件容易的任务;性能要求通常很高,而且犯错的后果通常会导致数据丢失和用户愤怒。实现一个虚拟(或“伪”)文件系统—在内核中实现且缺乏正常的后备存储的文件系统—也可能具有挑战性,但原因各不相同。围绕事件文件系统的一系列对话让虚拟文件系统对于 Linux 这一难题成为了焦点。
长期存在的“tracefs”虚拟文件系统提供对 ftrace 追踪系统的访问;除此之外,它还实现了一个目录,其中包含系统已知每个跟踪点的控制文件组。在 6.6 内核上快速浏览显示,它包含 2,800 多个目录且目录中包含 16,000 多个文件。在 6.6 版本之前,内核必须为每个目录和文件维护目录输入项 (“dentry”) 和 inode 结构;所有这些结构都会占用相当多的内存。
有趣的是,多个跟踪层次结构实例可以被挂载,每个实例都会导致内核复制所有这些内存开销。即使只有单个跟踪层次结构,这些文件几乎不会在系统的生命周期中被访问,因此内存完全被浪费了。
Eventfs 在 6.6 中被合并,作为一种消除这种浪费的方法。它是表示实际跟踪点的 tracefs 部分的重新实现,但进行了优化,以便只有在实际访问文件时才分配 dentry 和 inode。大量内存被释放回系统供它更好地使用,而且欢呼声一片。
不过,如果在 eventfs 中没有冒出一系列 bug,其中一些具有安全影响,那么欢呼声会更加热烈。这个文件系统需要经过一系列修复补丁,而这个过程在撰写本文时仍进行当中。在我们整理这些内容时,追踪维护者 Steve Rostedt、Linus Torvalds 和其他人之间出现了一系列冗长的主题讨论。除此之外,还有很多关于虚拟文件大小的讨论的报告 、这些文件是否应该具有唯一 inode 号,以及许多关于如何与内核虚拟文件系统 (VFS) 层进行交互的详细信息的讨论。最终,Torvalds 最终创建了一个 patch 系列来解决 eventfs 中的许多问题。
对于那些想要比 LWN 惯常覆盖范围更为耸动的读者来说,现在可能是浏览在其他地方发布的文章的好时机。本文重点讨论讨论中提出的两点。
其中之一是缺乏面向准文件系统开发人员的文档。包括 VFS 维护者 Christian Brauner 在内的一些人不同意这种说法。实际上有相当数量的 VFS 文档,包括对 VFS 加锁规则的详细描述,而这正是内核中最为复杂的地方。但是,作为一个没有经验的内核开发人员,Rostedt 在进行这项工作的过程中绊倒了许多事情,事实表明许多事情仍然没有记录。对于希望实现虚拟文件系统的开发人员而言,这一点尤其正确,而实现虚拟文件系统往往是一次性项目,是重点放在内核其他部分的开发人员参与的。
例如,考虑被称为“kernfs”的子系统。它是一个旨在简化虚拟文件系统实现的框架;目前,它用来实现控制组和 resctrl 文件系统。它看起来正是虚拟文件系统开发人员所需要的,但存在一个小问题:它没有经过精心的记录。对于如何使用它,没有尝试做任何描述;结果,当 Rostedt 考虑它时,他得出结论:“”kernfs 看起来并不普通,并且我找不到有关如何使用它的任何文档”,因此就不再考虑它了。
也许,如果在开发 eventfs 时 kernfs 更易于访问,那么它就会被发现适合这项任务并且有助于防止困扰 eventfs 的冗长错误系列。也许如果提供缺少的文档,下一个虚拟文件系统项目可能会容易一些。
不过,正如 Torvalds 好好解释的那样,确实存在另一个问题:VFS 层面向“真实”文件系统的需求,这些文件系统负责将数据持久性存储在层次目录结构中。因此,它具有许多性能驱动的怪癖,这些怪癖不仅不利于虚拟文件系统,还会复杂化实现这些文件系统这项任务。不过,再深入一步,整个文件系统概念对于虚拟文件系统而言有点不合适:
并且意识到 [它们] 本身并不是被设计为文件系统——他们从字面上设计为截然不同的东西,而文件系统接口之后就只是一件次要的事情——它是一个进入奇怪的非文件系统世界的窗口,在这个窗口中,即使有时可以对它们进行某种复杂的转换,普通的文件系统操作也无法正常工作。
这样会导致即使是简单文件系统操作 (例如,在 /proc 文件上的 stat()) 在虚拟文件系统中也无法正常工作等病症。在普通文件系统中,文件本身的生命周期直接与文件系统操作相关联。相比之下,虚拟文件系统中表示的对象拥有它们自己的无关生命周期。Torvalds 说,两个独立世界的结合是 “”虚拟文件系统通常完全混乱的原因”。
那么,我们如何改进这种情况呢?一种方法是完全放弃虚拟文件系统的想法,称文件系统抽象根本不适合这种内核 ABI。有人认为,这是网络子系统(以及其他一些子系统)通过为复杂接口采用 netlink 而实现的。Netlink 对许多事情很有效,但它不是一个普遍流行的接口。当然,这种方法的一个较旧版本是简单地提供一组 ioctl() 调用。不过,使用 ioctl()
有些不受鼓励;它往往会产生差别极大的接口,这些接口在合并到内核之前很少接受检查。另一种方法是添加新的系统调用,就像 VFS 层本身在使用 listmount() 和 statmount() 系统调用 时所做的那样,而这些系统调用已合并用于 6.8 版本。
不过,最终,一个面向文件系统的接口是有价值的。它对用户很熟悉,可编写脚本,并且定义得很明确。如果一切都属于文件,那么可以引入针对文件编写且功能齐全的实用程序。这就是为什么多年来虚拟文件系统不断涌现的原因;这表明让开发人员更容易正确实现虚拟文件系统是有价值的。反过来,这也表明在 kernfs 等 API 上下功夫,并尤其对其进行文档化,对于减轻下一个接手虚拟文件系统项目的开发人员的工作难度大有帮助。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
欢迎分享、转载及基于现有协议再创作~
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~