虚拟文件系统

前面几节讨论的都是”一个文件系统”。但真实的机器上同时存在好几种:硬盘上是 ext4,U 盘上是 FAT32,光盘上是 ISO9660,/proc 下面的东西根本不在任何磁盘上。

这些文件系统的内部实现毫无共同之处——FAT 靠文件分配表追链,ext4 靠 inode 与多级索引,procfs 干脆是内核临时生成的。然而用户程序对它们统统只用 open / read / write / close。

虚拟文件系统就是让这件事成立的那一层。

机制

虚拟文件系统要满足的三个要求

疑问点:虚拟文件系统的作用与实现方式

虚拟文件系统这一概念较为抽象,它具体解决什么问题、如何实现。

它解决的问题可以用一句话说清:让”调用方”和”实现方”彻底解耦。 教材把它拆成三条要求:

① 向上:向用户程序提供统一标准的系统调用接口,从而屏蔽下层各种文件系统实现上的差异。用户程序调用 read 时,不需要知道也无法知道这个文件到底在 ext4 上还是在 U 盘上。

② 向下:要求下层的文件系统必须实现某些规定的函数功能,如 open、read、write 等。一个新的文件系统想要接入,就必须提供 VFS 所要求的这组函数接口——这是接入的门槛,也是 VFS 能够统一分派的前提。

③ 中间:每打开一个文件,VFS 就在主存中新建一个 vnode,用统一的数据结构表示这个文件,无论该文件存储在哪个文件系统上。

三条合起来就是一个完整的分派机制:上面统一入口,下面统一约定,中间用一个统一的对象把两者接起来。

vnode 是怎么把两边接起来的

vnode 中除了保存文件的元数据,还保存一组”功能指针”,这些指针指向具体文件系统提供的那些函数。

于是 read 的执行路径变成:用户调用统一的 read → VFS 由 fd 找到对应的 vnode → 取出 vnode 中的读函数指针 → 跳转到 ext4 或 FAT 各自的实现。

同一条 read 调用,落到不同的文件系统就跳到不同的函数,而用户程序对此一无所知。这就是”统一接口、不同实现”在内核中的具体做法——与面向对象语言中接口与虚函数表的分派机制是同一套原理。

VFS 中的主要对象

对象表示什么
超级块对象一个已挂载的文件系统的整体信息
索引节点对象(vnode)一个文件本体的元数据
目录项对象路径中的一个组成部分(名字 → 索引节点的映射,用于缓存)
文件对象一次打开的状态

注意最后两个的分工,它与 4.1.3 的两级打开文件表完全对应:目录项对象属于”这个名字”,文件对象属于”这一次打开”。

边界

vnode 与 inode 的区别

这是本节最常考的一对,判据只有一句:inode 在外存,vnode 在主存。

inode 是具体文件系统落在磁盘上的结构,格式由该文件系统自己定义,ext4 的 inode 和别的文件系统的完全不同。

vnode 只存在于主存中,是 VFS 的统一抽象。文件被打开时,VFS 把 inode 中的信息复制到 vnode 中,并添加一些新的信息——最重要的就是那组指向具体文件系统函数的功能指针。

所以两者是”落盘格式”与”内存抽象”的关系:vnode 中有的功能指针,inode 里不会有(磁盘上存函数地址毫无意义);inode 中的磁盘地址信息,会被复制进 vnode。

VFS 不是一种文件系统

“虚拟文件系统”这个名字容易让人以为它是又一种像 ext4、FAT 那样的文件系统,这是最常见的误解。

VFS 不定义任何磁盘格式,不管理任何磁盘块,磁盘上不存在属于 VFS 的任何字节。 它是内核中的一个软件层,全部作用是接收请求并转发给真正的文件系统。

判据:凡是能被格式化到磁盘上的才是具体文件系统;VFS 只存在于内存中。

由此还能推出一条:磁盘布局中的超级块和 VFS 中的超级块对象不是同一个东西——前者是落在盘上的那几百个字节,后者是内核中表示”一个已挂载文件系统”的对象。两者可以对应理解,但不在同一层。

VFS 使”非磁盘对象”也能以文件面貌出现

这是 VFS 带来的一个重要能力,也是理解 UNIX”一切皆文件”的关键。

既然接入 VFS 的条件只是”提供那组函数”,那么这些函数背后是什么就完全自由了。 /proc 下的文件读起来像文件,实际上读函数是临时向内核查询数据并格式化成文本,磁盘上根本没有对应的块。

这与 4.1.1 中”特殊文件的读写落到设备驱动”是同一个机制在不同层次的体现:接口统一,实现自由。

VFS 与文件系统的四层结构

4.3.1 的四层描述的是一个文件系统内部的纵向分层;VFS 是横向的分派器,插在系统调用接口与各个具体文件系统之间。

它不是第五层。 准确的位置关系是:系统调用接口 → VFS → (ext4 的四层 / FAT 的四层 / procfs 的实现)。

对照速查

VFS 的三个要求方向
① 提供统一标准的系统调用接口向上(屏蔽差异)
② 要求下层实现规定的函数功能向下(接入门槛)
③ 每打开一个文件新建一个 vnode中间(统一表示)
inodevnode
在哪外存(磁盘)主存
属于谁具体文件系统VFS
格式各文件系统各不相同统一
有功能指针吗没有有(指向具体文件系统的函数)
何时产生文件创建时文件打开时(由 inode 复制并扩充)
VFS 四类对象表示
超级块对象一个已挂载的文件系统
索引节点对象(vnode)一个文件本体
目录项对象路径中的一个名字
文件对象一次打开

考点

  • VFS 的三个要求(向上统一接口、向下规定函数、中间建 vnode)
  • vnode 在主存,inode 在外存;vnode 由 inode 复制并增加功能指针
  • VFS 不是一种文件系统,磁盘上没有属于它的任何字节
  • 磁盘超级块 ≠ VFS 超级块对象
  • VFS 使 /proc 这类非磁盘对象也能以文件面貌出现
  • VFS 是横向分派器,不是四层结构的第五层

链接