📖 推荐阅读:《Yocto项目实战教程:高效定制嵌入式Linux系统》
🎥 更多学习视频请关注 B 站:嵌入式Jerry
📁 理解 Linux 虚拟文件系统 VFS:一次读写的背后发生了什么?
🧠 开篇 5 个问题,你能答对几个?
- 用户空间调用
open()
,内核是怎么知道你打开的是 ext4 还是 FAT32? - Linux 文件系统支持那么多种格式,却用一样的命令,这是如何做到的?
inode
、dentry
、file
这些结构具体代表什么?它们如何协作?/proc
、/sys
下的节点是怎么创建的?属于什么文件系统?- 内核中哪些源文件、结构体、函数真正实现了 VFS 的逻辑?
一、什么是 VFS?不是伪文件系统!
✅ 正确认识术语
术语 | 专业定义 | 易混对象 | 正确认识 |
---|---|---|---|
VFS(Virtual File System) | Linux 内核中的虚拟文件系统抽象层,负责统一接口、调度底层文件系统 | /proc 、/sys 等伪文件系统 | ❗VFS 是架构,不是文件系统 |
伪文件系统(pseudo file system) | 没有真实存储设备的文件系统,常用于导出内核信息 | procfs、sysfs、debugfs | 是 VFS 的“用户”,不是 VFS 本身 |
🧾 VFS 是 Linux 的文件系统核心架构;伪文件系统是 VFS 框架下的一种具体实现类型。
二、VFS 的作用与架构图解
📌 核心作用:
- 统一处理
open() / read() / write()
系统调用 - 为 ext4、xfs、nfs、procfs 等各种文件系统提供共通接口
- 支持路径解析、挂载、inode 管理、缓存调度等核心逻辑
🎯 架构图(VFS 是桥梁):
用户空间应用层
┌────────────────────┐
│ open(), read(), write() │
└────────────────────┘
↓
┌────────────────────┐
│ VFS(Virtual File System) │ ← 抽象架构层
└────────────────────┘
↙︎ ↓ ↘︎
ext4驱动 NFS驱动 procfs驱动
↓ ↓ ↓
块设备 网络传输 内核信息导出
三、VFS 的核心数据结构与作用
结构体 | 文件位置 | 说明 |
---|---|---|
struct file | include/linux/fs.h | 表示一个打开的文件(对应用户态 fd ) |
struct inode | include/linux/fs.h | 表示文件/目录元数据(大小、权限、类型) |
struct dentry | include/linux/dcache.h | 路径中的一个目录项节点,支持层级查找 |
struct super_block | include/linux/fs.h | 表示一个挂载的文件系统的全局信息 |
struct file_operations | include/linux/fs.h | 提供文件操作函数表(read/write/ioctl 等) |
struct inode_operations | include/linux/fs.h | 提供 inode 操作函数表(lookup/create 等) |
四、一次 open() 的调用过程在内核中如何流转?
以用户调用 open("/mnt/data/test.txt")
为例:
用户空间
↓
sys_openat() → do_sys_open() 【fs/open.c】
↓
do_filp_open() 【fs/namei.c】
↓
path_openat() → vfs_open() 【fs/namei.c】
↓
路径查找(namei → dentry/inode) 【fs/namei.c / fs/dcache.c】
↓
实际文件系统的 open() 被调用 【ext4/file.c 等】
↓
构造 file 结构,返回 fd 【fs/file_table.c】
✅ 所有通用逻辑由 VFS 实现,调用最终由注册的
file_operations
决定使用哪个底层文件系统。
五、VFS 相关源码结构划分(非常重要)
📁 核心目录 /fs
:虚拟文件系统 + 各种具体文件系统
文件/目录 | 说明 |
---|---|
fs/open.c | 实现 open/close/creat 等系统调用 |
fs/namei.c | 路径查找 namei 系统,处理 dentry + inode |
fs/file_table.c | 管理 file 结构的分配与释放 |
fs/inode.c | 管理 inode 分配、缓存和引用计数 |
fs/dcache.c | 管理 dentry 缓存(dcache)加速路径查找 |
fs/super.c | super_block 管理与挂载流程 |
fs/filesystems.c | 所有 file_system_type 注册入口 |
fs/ext4/ 、fs/fat/ 等 | 各种具体文件系统的实现 |
🎯 小结:核心 VFS 实现在
/fs/*.c
,而具体文件系统实现是/fs/xxx/
子目录。
六、VFS 如何管理多个文件系统类型?
每个文件系统都注册一个结构体:
// 位置:fs/ext4/super.c
static struct file_system_type ext4_fs_type = {
.name = "ext4",
.mount = ext4_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
注册接口:
register_filesystem(&ext4_fs_type); // 注册到全局文件系统表
然后在挂载时,VFS 根据类型调用 mount()
函数创建 super_block
,连接 dentry 树,建立根目录。
七、VFS 与驱动开发的连接点(以 debugfs 为例)
驱动开发中,我们经常通过以下接口向用户导出调试信息:
接口函数 | 所属文件系统 | 所在路径 | 用途 |
---|---|---|---|
proc_create() | procfs | fs/proc | /proc/my_driver |
debugfs_create_file() | debugfs | fs/debugfs | /sys/kernel/debug/... |
device_create_file() | sysfs | fs/sysfs | /sys/class/... |
这些伪文件系统本质上也是接入 VFS,通过实现标准接口挂接文件节点,最终由用户通过 cat
、echo
等命令交互。
八、常见误区澄清
❌ 错误说法 | ✅ 正确理解 |
---|---|
/proc 是虚拟文件系统 VFS | ❌ /proc 是伪文件系统,VFS 是其上层架构 |
VFS 就是 Linux 的 ext4 系统 | ❌ ext4 是具体实现,VFS 是抽象中间层 |
file 就是打开的文件 | ❌ 是内核的结构体,用户看到的是 fd |
驱动中的 proc_create() 和 VFS 无关 | ❌ 是通过 procfs 挂接到 VFS 架构的 |
🔚 回答开篇五个问题
问题 | 解答 |
---|---|
1️⃣ open() 怎么知道是 ext4 还是 FAT? | 通过挂载点的 file_system_type ,由 VFS 查表调度到对应驱动 |
2️⃣ 为什么用一样的命令? | VFS 统一了 open/read/write 接口,屏蔽底层差异 |
3️⃣ inode、dentry、file 是什么? | 分别表示文件元信息、路径节点、打开文件实例,是 VFS 的核心结构体 |
4️⃣ /proc 、/sys 是怎么来的? | 它们属于伪文件系统,通过 procfs 、sysfs 接入 VFS |
5️⃣ 内核中哪些源码负责这些操作? | /fs/open.c 、/fs/namei.c 、/fs/dcache.c 、/fs/file_table.c 等实现核心调用流程 |
📘 推荐阅读路径
阶段 | 文件 | 说明 |
---|---|---|
① 入门路径解析 | fs/namei.c | 关注 do_filp_open() 、path_openat() |
② 文件打开流程 | fs/open.c | 看 sys_openat() 系统调用入口 |
③ 缓存机制 | fs/dcache.c 、fs/inode.c | 理解目录项与 inode 缓存逻辑 |
④ 文件系统挂载 | fs/super.c | 理解 mount() 、get_sb_nodev() 等流程 |
⑤ file/inode 生命周期 | fs/file_table.c | 掌握分配与引用计数机制 |
📖 推荐阅读:《Yocto项目实战教程:高效定制嵌入式Linux系统》
🎥 更多学习视频请关注 B 站:嵌入式Jerry