graph TB
A["应用程序"] --> B["VFS 统一接口\nopen/read/write"]
B --> C["ext4"]
B --> D["NFS"]
B --> E["proc"]
B --> F["tmpfs"]
B --> G["btrfs"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#B5EAD7,stroke:#80CBC4,color:#333
style D fill:#B5EAD7,stroke:#80CBC4,color:#333
style E fill:#FFDAB9,stroke:#FFAB76,color:#333
style F fill:#FFDAB9,stroke:#FFAB76,color:#333
style G fill:#B5EAD7,stroke:#80CBC4,color:#333
没有 VFS:
每个 FS 都要自己的 API
应用开发者要学习多种 FS
难以做统一抽象
有了 VFS:
一个 API 适用于所有 FS
应用无感知
易于添加新 FS
一、VFS 四大核心数据结构
1.1 4 大对象总览
graph TB
A["VFS 四大对象"] --> B["超级块\nsuper_block"]
A --> C["inode\n索引节点"]
A --> D["dentry\n目录项"]
A --> E["file\n打开的文件"]
B --> B1["描述一个文件系统"]
C --> C1["描述一个文件"]
D --> D1["路径中的一个组件"]
E --> E1["进程打开的文件"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#FFB3C6,stroke:#F48FB1,color:#333
style E fill:#B5EAD7,stroke:#80CBC4,color:#333
style B1 fill:#FFF9C4,stroke:#F9A825,color:#333
style C1 fill:#FFF9C4,stroke:#F9A825,color:#333
style D1 fill:#FFF9C4,stroke:#F9A825,color:#333
style E1 fill:#FFF9C4,stroke:#F9A825,color:#333
graph TB
A["/home/user/file.txt"] --> B["dentry\nfile.txt"]
B --> C["inode #12345\n元数据"]
C --> D["super_block\n(/dev/sda1 ext4)"]
C --> E["file\n打开的文件1"]
C --> F["file\n打开的文件2\n(另一进程)"]
B --> B1["父 dentry\n/home/user/"]
B --> B2["父 dentry\n/home/"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#FFDAB9,stroke:#FFAB76,color:#333
style C fill:#FFB3C6,stroke:#F48FB1,color:#333
style D fill:#B5EAD7,stroke:#80CBC4,color:#333
style E fill:#E8D5F5,stroke:#CE93D8,color:#333
style F fill:#E8D5F5,stroke:#CE93D8,color:#333
style B1 fill:#FFF9C4,stroke:#F9A825,color:#333
style B2 fill:#FFF9C4,stroke:#F9A825,color:#333
graph TB
A["mount /dev/sda1 /mnt"] --> B["VFS mount"]
B --> C["调用 fs_type->mount()"]
C --> D["读取磁盘 super_block"]
D --> E["分配 VFS super_block"]
E --> F["读取根 inode"]
F --> G["创建根 dentry"]
G --> H["挂载完成"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#FFB3C6,stroke:#F48FB1,color:#333
style E fill:#B5EAD7,stroke:#80CBC4,color:#333
style F fill:#B5EAD7,stroke:#80CBC4,color:#333
style G fill:#B5EAD7,stroke:#80CBC4,color:#333
style H fill:#B5EAD7,stroke:#80CBC4,color:#333
三、open 系统调用
3.1 用户态调用链
sequenceDiagram
participant User as 用户
participant Lib as glibc
participant Kern as 内核
participant FS as 文件系统
User->>Lib: open("/home/user/file.txt", O_RDONLY)
Lib->>Kern: sys_openat(AT_FDCWD, "file.txt", O_RDONLY, 0)
Kern->>Kern: do_sys_open()
Kern->>Kern: path_lookupat()
Kern->>FS: inode->i_op->lookup() 或 inode->i_op->getattr()
FS-->>Kern: 返回 inode
Kern->>Kern: 分配 file 结构
Kern->>FS: file->f_op->open()
FS-->>Kern: 完成
Kern-->>Lib: 返回 fd
Lib-->>User: 返回 fd
3.2 内核路径解析
graph TB
A["路径 /home/user/file.txt"] --> B["path_init\n当前目录"]
B --> C["link_path_walk\n解析每个组件"]
C --> D["home"]
D --> E["user"]
E --> F["file.txt"]
F --> G{"找到 inode?"}
G -->|"是"| H["do_last"]
G -->|"否"| I["ENOENT"]
H --> J["分配 file"]
J --> K["返回 fd"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#FFF9C4,stroke:#F9A825,color:#333
style E fill:#FFF9C4,stroke:#F9A825,color:#333
style F fill:#FFF9C4,stroke:#F9A825,color:#333
style G fill:#FFB3C6,stroke:#F48FB1,color:#333
style H fill:#B5EAD7,stroke:#80CBC4,color:#333
style I fill:#F48FB1,stroke:#FFB3C6,color:#333
style J fill:#B5EAD7,stroke:#80CBC4,color:#333
style K fill:#B5EAD7,stroke:#80CBC4,color:#333
3.3 dcache 缓存
graph TB
A["路径查找"] --> B["dcache 哈希表"]
B --> C{"命中?"}
C -->|"是"| D["直接返回\ndentry + inode"]
C -->|"否"| E["调用 inode->i_op->lookup"]
E --> F["从磁盘读取"]
F --> G["加入 dcache"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFF9C4,stroke:#F9A825,color:#333
style D fill:#B5EAD7,stroke:#80CBC4,color:#333
style E fill:#FFDAB9,stroke:#FFAB76,color:#333
style F fill:#FFB3C6,stroke:#F48FB1,color:#333
style G fill:#B5EAD7,stroke:#80CBC4,color:#333
dcache 的作用:
缓存路径 → inode 的映射
避免每次路径都查 inode 表
大幅加速 open() / stat()
四、read / write 系统调用
4.1 read 调用链
sequenceDiagram
participant User as 用户进程
participant Kern as 内核
participant VFS as VFS 层
participant FS as 文件系统
participant Cache as page cache
User->>Kern: sys_read(fd, buf, count)
Kern->>VFS: vfs_read(file, buf, count, pos)
VFS->>FS: file->f_op->read_iter() 或 read()
FS->>Cache: filemap_get_pages()
Cache->>Cache: 查找 page
alt 页在 cache 中
Cache-->>FS: 返回页
else 页不在
FS->>FS: 触发磁盘读
FS->>Cache: 加入 page
end
FS-->>VFS: 复制数据到用户 buf
VFS-->>Kern: 返回读字节数
Kern-->>User: 返回
graph TB
A["read(fd)"] --> B["page cache\n内存"]
B --> C{"页在 cache?"}
C -->|"是"| D["直接返回\n零 I/O"]
C -->|"否"| E["磁盘读"]
E --> F["加入 cache"]
F --> D
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFF9C4,stroke:#F9A825,color:#333
style D fill:#B5EAD7,stroke:#80CBC4,color:#333
style E fill:#FFB3C6,stroke:#F48FB1,color:#333
style F fill:#B5EAD7,stroke:#80CBC4,color:#333
graph TB
A["mount /dev/sda1 /mnt"] --> B["VFS"]
B --> C["call mount syscall"]
C --> D["path lookup /mnt"]
D --> E["call FS mount"]
E --> F["FS 读取磁盘\nsuper_block"]
F --> G["创建 VFS super_block"]
G --> H["创建根 inode + dentry"]
H --> I["挂载完成"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#FFF9C4,stroke:#F9A825,color:#333
style E fill:#FFB3C6,stroke:#F48FB1,color:#333
style F fill:#B5EAD7,stroke:#80CBC4,color:#333
style G fill:#B5EAD7,stroke:#80CBC4,color:#333
style H fill:#B5EAD7,stroke:#80CBC4,color:#333
style I fill:#B5EAD7,stroke:#80CBC4,color:#333
6.2 挂载点链表
1 2 3 4 5 6 7 8 9
# 查看所有挂载点 mount
# 输出: # /dev/sda1 on / type ext4 (rw,relatime) # tmpfs on /run type tmpfs (rw,nosuid,nodev,size=...) # /dev/sda2 on /home type ext4 (rw,relatime) # proc on /proc type proc (rw,nosuid,nodev,noexec) # ...
七、Linux 支持的文件系统
graph TB
A["Linux 文件系统"] --> B["磁盘 FS"]
A --> C["网络 FS"]
A --> D["特殊 FS"]
B --> B1["ext4\nxfs\nbtrfs\nzfs"]
C --> C1["NFS\nCIFS\n9P"]
D --> D1["proc\nsysfs\ntmpfs\ndevpts"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#B5EAD7,stroke:#80CBC4,color:#333
style B1 fill:#FFF9C4,stroke:#F9A825,color:#333
style C1 fill:#FFF9C4,stroke:#F9A825,color:#333
style D1 fill:#FFF9C4,stroke:#F9A825,color:#333
graph TB
A["VFS 核心"] --> B["super_block\n文件系统"]
A --> C["inode\n文件元数据"]
A --> D["dentry\n路径缓存"]
A --> E["file\n打开的文件"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#E8D5F5,stroke:#CE93D8,color:#333
style C fill:#FFDAB9,stroke:#FFAB76,color:#333
style D fill:#FFB3C6,stroke:#F48FB1,color:#333
style E fill:#B5EAD7,stroke:#80CBC4,color:#333