Redian新闻
>
文件系统考古:如何支持多个文件系统

文件系统考古:如何支持多个文件系统

公众号新闻

Steve Kleiman 在 1986 年撰写了《Vnodes: An Architecture for Multiple File System Types in Sun UNIX[3]》一文。这篇论文幅较短,大部分内容是数据结构的列举,以及 C 语言结构之间相互指向的图表。

Steve Kleiman是分布式文件系统领域的专家,在 Sun Microsystem 工作了多年,曾参与开发 Sun Network File System(NFS)等项目,为分布式文件系统领域做出了重要贡献。

Kleiman 希望在 Unix 中能够拥有多个文件系统,并希望这些文件系统能够共享接口和内存。具体而言,他希望设计一个能够提供以下功能的架构:

一个可以支持多个实现的通用接口;支持 BSD FFS,以及两个远程文件系统 NFS 和 RFS,还有特定的非 Unix 文件系统,如 MS-DOS;接口定义的操作需要是原子性的。

并且,能够在不影响性能的情况下动态地处理内存和数据结构,支持重入(reentrant) 和多核,并且具有一定面向对象进行编程的特性。

重入(reentrant) 是指程序或子程序在尚未完成上一次调用之前,可以再次被调用且不会出错或发生冲突。

两个抽象概念

Steven 研究了文件系统的各种操作,决定将他们抽象为两个概念:

  • • vfs,虚拟文件系统,代表文件系统

  • • vnode,虚拟 inode,代表文件

vfs,虚拟文件系统,它提供统一的接口,使操作系统可以以一致的方式访问不同的文件系统,无论是本地文件系统还是网络文件系统。
vnode,虚拟 inode, 表示一个文件,每个文件都有一个相关联的索引节点,其中包含了文件的元数据(如文件权限、所有者、大小等)以及指向文件数据存储位置的指针。

采用了 C++风格(实际使用 C 语言),每一个类型会匹配一个虚函数表,通过虚函数表,系统在运行时根据对象的实际类型来调用适当的虚函数,实现动态绑定:

  • • 对于 vfs 类型,其虚函数表 struct vfsops,包含了一系列的函数指针,用来执行诸如 mount、unmount、sync 和 vget 等操作。在论文的后面,会解释这些函数的原型和功能;

  • • 对于 vnode 类型也是类似的,其虚函数表 struct vnodeops,包含 open、rdwr 和 close 等函数,还有create、unlink 和 rename 等函数。一些函数是针对特定的文件类型的,比如 readlink、mkdir、readdir 和 rmdir。

通过 vfs 对象来进行跟踪实际的挂载,其虚函数表 struct vfsops 指向适用于该特定子树的文件系统操作。

类似地,vnode 实例用来进行跟踪打开的文件。它包含 struct *vnodeops 指针,作为 vfs 的一部分,有指针 struct *vfs 指向文件系统实例。

vfs 和 vnode 这两个结构体都需要一些用于存储特定实现数据的字段(如“子类私有字段”)。他们都以 caddr_t ...data 指针结尾。这些私有数据并不是 vfs 和 vnode 的一部分,而是位于其他位置,并通过指针进行引用。

Vnodes 实操

在论文中,有一整页的内容专门用于展示各种相互指向的结构。乍一看可能会感到困惑,但一旦追踪下来,就会发现它非常直观和优雅。

Kleiman 详细解释了如何使用 lookuppn() 函数来解释事物的工作原理,该函数替代了传统 Unix 中的 namei() 函数。类似于 namei() ,这个函数接受一个路径,并返回表示该路径所代表的 vnode 的 struct vnode 指针。

路径遍历始于根 vnode 或当前进程的当前目录 vnode,具体取决于路径的第一个字符是否为 /。

然后,这个函数会依次取出路径的每一个子项,并调用当前 vnode 的 lookup 函数,它接受一个路径子项和一个假设是目录的当前 vnode,并返回代表那个子项的 vnode。

当一个目录是个挂载点,它的 vfsmountedhere 会被设置为一个指向 struct vfs 的指针。lookuppn 函数会跟随这个指针,并调用 vfs 的根函数,以获取该文件系统的根 vnode,替换当前正在处理的 vnode。

反过来也是可能的:当解析父目录(".. ")时,如果当前 vnode 的 "flags" 字段中设置了根标志,我们会跟随 vfsmountedhere 指针从当前 vnode 到 vfs。然后,我们可以使用该 vfs 中的 vnodecovered 字段来获取上层文件系统的 vnode。

无论如何,在成功完成后,会返回一个 struct vnode 指针,即所使用的路径。

新增的系统调用

为了使系统高效地运行,需要添加一些新的系统调用来完善接口。

在 Unix 的历史中,我们看到引入了 statsfs 和 fstatsfs ,通过这两个函数可以获得与用户空间中的文件系统进行交互的接口。getdirentries 函数可以让用户一次性获取多个目录条目(取决于提供的缓冲区大小),这大大加快了远程文件系统的目录读取速度。

在 Linux 系统中

通过查看 Linux 内核源代码,我们可以找到 Kleiman 设计的总体结构,尽管 Linux 内核的复杂性和丰富性掩盖了其中大部分内容。Linux 内核拥有丰富的文件系统类型,并且还添加了许多在 40 年前的 BSD 中不存在的功能。因此,我们可以找到更多的数据结构和系统调用,它们被用于实现命名空间、配额、属性、只读模式、目录名称缓存等功能。

文件

如果你仔细观察,原始的结构仍然可以找到:Linux 内存中的文件相关结构分为两部分,一个是已打开的文件,它是一个带有当前位置的 inode;另一个是 inode,它代表整个文件。

我们可以在此处找到文件对象[4],struct file 的实例。在文件的所有其他内容中,最值得注意的是一个字段 loff_t f_pos,它表示文件当前位置距离文件起始位置的偏移量(以字节为单位)。

文件的类[5]是通过一个虚函数表来定义。我们可以找到一个指针 struct file_operations *f_op 。它展示了文件可以执行的所有操作,其中最常见的是打开(open)、关闭(close)、定位(lseek)、读取(read)和写入(write)。

文件还包含指向 inode 的指针,即 struct inode *f_inode

索引节点

对于不需要偏移量的文件操作,它们是针对整个文件进行的,定义为 struct inode *

查看此处[6]的定义。我们可以看到这里还有其他的定义,40 年前的 BSD 中没有类似的定义,比如 ACL(访问控制列表)和属性(attributes)。

我们发现 inode 的类[7]通过虚函数表来定义,即 struct inode_operations *i_op。同样的,这其中很多函数涉及新特性,比如 ACL(访问控制列表)和扩展属性,但我们也会找到我们期望的功能,比如链接(link)、删除(unlink)、重命名(rename)等。

Inode 还包含一个指向文件系统的指针,即 struct super_block *i_sb

超级块

挂载点用 struct super_block 来表示,在此处查看其定义。同样地,它有 struct super_operations *s_op 定义的各个操作,在此处[8]查看其定义。

支持的文件系统不再有限,可以通过内核模块动态地添加新的文件系统,通过数据结构 struct file_system_type 来表示,它只有一个用于创建 superblock 的工厂函数 mount。

小结

Unix 发生了变化。它的运行时变得更加复杂,增加了许多新的功能,并增加了系统调用。系统变得更有结构。

但是,由 Steve Kleiman 和 Bill Joy(BSD 操作系统的共同创始人之一) 构思的原始设计和数据结构仍然存在,在当前的 Linux 系统中仍然可以找到,虽然已经过去了 40 年。

引用链接

[1] 50 years in filesystems: https://blog.koehntopp.info/2023/05/05/50-years-in-filesystems-1974.html
[2] KRISTIAN KÖHNTOPP: https://chaos.social/@isotopp
[3] Vnodes: An Architecture for Multiple File System Types in Sun UNIX: https://www.semanticscholar.org/paper/Vnodes%3A-An-Architecture-for-Multiple-File-System-in-Kleiman/e0d14c74f23ef9b21c2fc37b5197fbfe348a7fcf
[4] 文件对象: (https://github.com/torvalds/linux/blob/v6.3/include/linux/fs.h#L942C3-L981
[5] 文件的类: (https://github.com/torvalds/linux/blob/v6.3/include/linux/fs.h#L1754-L1798)
[6] 此处: https://github.com/torvalds/linux/blob/v6.3/include/linux/fs.h#L595-L705
[7] inode 的类: (https://github.com/torvalds/linux/blob/v6.3/include/linux/fs.h#L1800-L1840)
[8] 在此处: https://github.com/torvalds/linux/blob/v6.3/include/linux/fs.h#L1886-L1918


END



好用的开源IM应用




这里有最新开源资讯、软件更新、技术干货等内容

点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦


微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
俄德经典嘴仗:德国防长扬言核炸俄罗斯,绍伊古:下场问问你爷爷GDP垫底,这个沿海省份为何支棱不起来?“赴美生子和非法移民的孩子,将剥夺美籍!”川普放狠话,如果赢得2024年大选,第一天就签这个文件!上海在科技、产业领域将如何支持青年人才?官方这样解读→抖音新成立一个文娱部门,整合直播节目、音乐等多个业务|36氪独家支持多孩家庭购房,广州出手了!多地出台公积金支持政策黄春菊,朝气蓬勃继 exFAT 改进后,微软 CBL-Mariner 新增支持 XFS 根文件系统LPython:最新的高性能 Python 实现、速度极快且支持多后端Linus 亲自 review 代码,希望平息关于 Bcachefs 文件系统的 “内斗”全美多个支持控枪的大型组织首次联合起来共同支持拜登连任“旅游签证和非法移民的孩子,禁止获美籍!”川普放狠话,如果赢得2024年大选,第一天就会签这个文件人民币,美元双系统风险及解决的可能方案Linus亲自review代码,希望平息关于Bcachefs文件系统的 “内斗”希腊沃洛斯 (Volos),迷人夜幕从1300多辆减到333辆,保定公交车如何支撑市民出行?HadaFS:新型Burst Buffer文件系统“AI孙燕姿”爆火后,Meta发布通用语音生成AI:可合成6种语言,支持多种语音功能ChatGPT学会自己提问题了,还支持多文件上传如何在 Linux 中映射 SAN LUN、磁盘和文件系统 | Linux 中国如何高效实现文件传输:小文件用零拷贝、大文件用异步io+直接io如何高效实现文件传输:小文件采用零拷贝、大文件采用异步io+直接io【便民】候补车票订单如何支付?铁路会员积分可以给家人买票吗?来看这4个问答→如何管理有近 3 万个文件的超大型 Python 代码仓?美国买房贷款,有三个文件至关重要LPython:最新的高性能Python实现、速度极快且支持多后端国内第一款AI搜索来了!首发实测:0广告支持多轮追问,搜索结果自动总结成文千箴言万球炼(5) 嫉妒世间常态,磨砺锻炼能耐安装 Linux 的 6 种最佳文件系统一文读懂|Linux 虚拟文件系统(VFS)偶兴如何将千亿文件放进一个文件系统,EuroSys'23 CFS 论文背后的故事【讲座】新生家长必看:如何支持孩子克服焦虑抑郁、应对压力,守护好远航的心川普放狠话:旅游签证和非法移民的孩子,禁止获美籍!如果赢得2024年大选,第一天就会签这个文件!开放与集成:酷家乐云设计工具插件系统的秘密
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。