1. 虚拟文件系统(VFS)
1. 为什么需要 VFS
计算机中可能同时存在多种文件系统(如磁盘的 UFS、移动硬盘的 NTFS、U 盘的 FAT 等),各文件系统的函数接口名称、参数格式可能各不相同。若没有统一的抽象层,用户程序就必须根据文件所属的文件系统类型来编写不同的调用代码,极为不便。
为此操作系统引入了虚拟文件系统(Virtual File System,VFS),在具体文件系统之上提供一个统一的抽象接口层。
1.2 VFS 的三个核心特性
1. 向上提供统一标准接口
无论文件实际存储在哪种文件系统中,用户进程只需按 VFS 规定的标准(如 Linux 遵循 POSIX 标准)调用 open、read、write 等接口,不必关心底层细节。
2. 向下要求实现规定的函数接口
任何想被该操作系统支持的文件系统,必须按 VFS 的规定实现特定的函数接口(如 open、read、write 等)。若无法实现,则该文件系统不被此操作系统支持。
3. 每个被打开的文件在内存中对应一个 v-node
不同文件系统的目录项格式差异很大(如 UFS 的目录项只含文件名和 inode 编号,而 FAT 的 FCB 直接包含所有文件信息),VFS 无法用同一种数据结构直接表示。为此,每当打开一个文件时,VFS 会在内存中为其创建一个 v-node(虚拟节点),将文件的各种信息统一复制进去,从而用同一种结构表示来自任意文件系统的文件。
1.3 v-node 的结构与作用
v-node 只存在于内存中,包含两类关键信息:
| 字段 | 说明 |
|---|---|
| 文件元数据 | 文件大小、权限、时间戳等(来源于底层 FCB/inode) |
| 函数功能指针 | 指向该文件所属文件系统的函数列表(open/read/write 的具体实现地址) |
通过函数功能指针,VFS 在对文件执行任何操作时,都可以找到对应文件系统的具体实现函数并调用,从而实现"统一接口 → 分发到具体文件系统"的调用链。
1.4 v-node vs inode
| v-node | inode(索引节点) | |
|---|---|---|
| 存在位置 | 仅存在于内存 | 外存中持久存储,访问时调入内存 |
| 作用范围 | 适用于任何文件系统(UFS/FAT/NTFS 等) | 属于 UFS 等特定文件系统 |
| 生命周期 | 文件打开时创建,关闭后销毁 | 文件存在则持久存在 |
| 内容 | 文件元数据 + 函数功能指针 | 文件物理地址、权限、大小等元数据 |
打开 UFS 中的文件时:先从外存读入 inode → 将 inode 中的信息复制到 v-node → 后续操作通过 v-node 进行。
2. 文件系统的挂载
文件系统挂载(又称安装/装载)是指将一个新的文件系统接入操作系统,使其可以被正常访问。日常操作(如插入 U 盘)就会触发文件系统挂载。
2.1 挂载的三个步骤
1. 在 VFS 挂载表中注册
VFS 在内存中维护一张挂载表,记录每个已挂载文件系统的格式、容量等基本信息。新挂载的文件系统需要在挂载表中新增一个表项,让 VFS 能够"发现"它。
2. 向 VFS 提供函数地址列表
由于各文件系统的 open/read/write 实现各不相同,新文件系统需要向 VFS 提供自己的函数地址列表(即 v-node 中函数功能指针所指向的内容),VFS 才能正确调用该文件系统提供的功能。
3. 挂载到指定挂载点
将新文件系统挂载到现有目录树中的某个位置(挂载点):
| 操作系统 | 挂载点位置 | 示例 |
|---|---|---|
| Windows | 与 C/D/E 盘并列的盘符 | 插入 U 盘后出现 G: 盘 |
| macOS/Linux | 根目录下某个子目录 | 挂载到 /Volumes/ 或 /mnt/ 下 |
只有确定了挂载点,用户才能通过路径访问新文件系统中的文件。