为什么 Linux 能挂载任何文件系统?秘密藏在四个数据结构里
image.png"一切皆文件"——学 Linux 的人都听过这句话。
但你有没有想过:为什么 ext4、NTFS、网络硬盘、甚至 /proc 这种根本不在磁盘上的"假"文件系统,都能挂到同一棵目录树里,用起来还感觉不出区别?
答案就俩字:加一层。Linux 圈有句调侃——"没有什么是加一层解决不了的"。这一层,叫 VFS(虚拟文件系统)。
今天一篇讲透它,重点是撑起"一切皆文件"的四个核心数据结构。搞懂它们,你对 Linux 文件系统的理解会上一个台阶——这也是内核岗面试的高频考点。
哆哆jarvis,前芯片原厂驱动工程师,专写嵌入式 / Linux 底层的硬核干货,也分享副业做亚马逊踩坑到盈利的真实经历,关注不迷路。
一、VFS 到底是什么
VFS 是一个内核软件层,夹在"系统调用"和"具体文件系统"中间,干两件事:
- 处理所有跟文件相关的系统调用(
open / read / write…);
不管底下是 ext4、NTFS 还是 NFS,VFS 都用同一套接口对接——所以用户根本感觉不到差别。
二、精髓:用 C 写出来的"面向对象"
VFS 凭什么能用"一套接口"对接所有文件系统?靠多态。
它定义了几组操作接口——super_operations、inode_operations、file_operations——每个具体文件系统各自实现这套接口、填进自己的函数指针表。VFS 上层只调统一接口,运行时通过函数指针分发到具体实现。
这不就是虚函数表吗?对,这就是 C 语言版的面向对象。所以"挂载一个新文件系统",本质就是把它那套 ops 实现注册进来。
💡 这套"接口 + 函数指针表"的套路,在 Linux 驱动里到处都是(file_operations、各种 xxx_ops)。看懂 VFS,等于看懂半个内核的设计哲学。
三、四大核心对象
VFS 把所有文件系统抽象成 4 种数据结构。记住每个"描述什么 + 关键点"就够了:
① 超级块 super_block —— 一个"已挂载的文件系统" 存整个文件系统的信息(块大小、根目录、类型…)。关键是 s_op(操作表,多态入口)和 s_root(挂载点根目录)。这些是元数据,坏了整个文件系统就挂不上。
② 索引节点 inode —— 一个"文件" 存一个文件的元信息(权限、大小、时间、数据块位置),有唯一编号 i_ino(ls -i 能看到)。它里面有个 union:管道、块设备、字符设备都塞进同一个 inode 抽象——这就是"一切皆文件"在数据结构上的样子。
③ 目录项 dentry —— 路径里的"一个名字"/a/b/c 里的 a、b、c 各是一个 dentry,把"名字"链到对应的 inode;内核用 dentry cache 缓存它们加速查找。一个 inode 被多个 dentry 指向 = 硬链接。
④ 文件对象 file —— 进程"打开的一个实例"open() 时创建,带进程私有的状态,最典型的是 f_pos(当前读写位置)。同一个文件被打开多次 = 多个 file 指向同一个 inode,但各有各的 f_pos。
四、四个对象怎么串起来(这才是关键)
image.pngsuper_block ↔ inode:一个文件系统挂着它所有的 inode;inode ↔ dentry:一个 inode 可被多个 dentry 指向(硬链接);dentry ↔ file:每次 open() 生成一个 file,多次打开 = 多个 file、同一个 inode、各自 f_pos。
一次 open("/a/b/c"):从根 dentry 沿路径逐段查找 → 找到目标 inode → 创建 file → 返回 fd。之后 read/write(fd) 就通过 file 的操作表,分发到具体文件系统的实现。
一句话记忆:
super_block = 一个文件系统|inode = 一个文件|dentry = 一个名字|file = 一次打开
写在最后
VFS 用"四大对象 + 函数指针表",撑起了"一切皆文件"和"任意文件系统都能挂载"。它的精妙,全在数据结构和多态设计里。
而当你 read/write 一个文件,请求会从 VFS 一路往下——经过缓存层、块层、驱动,最后落到硬件(比如 eMMC)。这条完整的路怎么走,就是这个系列后面要讲的。
这是我「Linux 存储栈」系列第 ① 篇。完整系列(VFS → MMC 子系统读写源码 → eMMC 掉电可靠写)+ 我整理的高质量文章,都放在知识星球了(目前可以免费加入,私信我即可)。一起同行,可以点个关注。
觉得有用,点个赞和在看 👇
4d7d1d8e99ed924a86edabd7242361ff.jpg