“一切皆文件” 不是口号——ext4、btrfs、procfs、sysfs、FUSE、网络 socket 都通过同一套 VFS 接口暴露给用户。VFS 用四层抽象 + 操作表把具体实现和通用语义分开。
一、先看图
flowchart TD
APP[用户 open/read/write] --> FD[struct file<br/>fd 表项]
FD --> DENTRY[struct dentry<br/>目录项缓存]
DENTRY --> INODE[struct inode<br/>元数据]
INODE --> SB[struct super_block<br/>文件系统实例]
SB --> FS[具体 FS 实现<br/>ext4/btrfs/xfs...]
FD -.f_op.-> FOP[file_operations<br/>read/write/mmap...]
INODE -.i_op.-> IOP[inode_operations<br/>lookup/create/link...]
SB -.s_op.-> SOP[super_operations<br/>alloc_inode/sync_fs...]
classDef vfs fill:#388bfd22,stroke:#388bfd,color:#adbac7;
classDef ops fill:#a371f722,stroke:#a371f7,color:#adbac7;
class FD,DENTRY,INODE,SB vfs
class FOP,IOP,SOP ops
二、superblock
每个挂载的文件系统实例一个 super_block:
struct super_block {
struct list_head s_list; // 全局链表
dev_t s_dev; // 设备号
unsigned long s_blocksize;
struct file_system_type *s_type;
const struct super_operations *s_op;
struct dentry *s_root; // 根目录
struct hlist_bl_head s_roots;
...
};s_op 包含
alloc_inode、destroy_inode、sync_fs、statfs
等。
三、inode
每个文件/目录/符号链接一个 inode(内存中的):
struct inode {
umode_t i_mode; // 权限 + 类型
kuid_t i_uid; kgid_t i_gid;
loff_t i_size;
struct timespec64 i_atime, i_mtime, i_ctime;
const struct inode_operations *i_op;
const struct file_operations *i_fop;
struct super_block *i_sb;
struct address_space *i_mapping; // 页缓存
unsigned long i_ino;
...
};i_op:lookup、create、mkdir、rename、permission…i_fop:open 时复制给struct file
inode 缓存(inode_cache)在 slab 里,hash
索引。
四、dentry
dentry 缓存路径组件 → inode 的映射:
struct dentry {
struct dentry *d_parent;
struct qstr d_name; // 组件名 hash + len + name
struct inode *d_inode; // NULL = negative dentry
const struct dentry_operations *d_op;
struct super_block *d_sb;
struct hlist_bl_node d_hash; // dcache hash 桶
struct list_head d_subdirs;
...
};dcache
全局 hash 表 dentry_hashtable:按 (parent,
name_hash) 查。命中 dcache
的路径查找只需内存操作,不碰磁盘。
negative dentry
d_inode = NULL 表示”这个名字不存在”——缓存
ENOENT,避免重复磁盘查找。
cat /proc/sys/fs/dentry-state
# nr_dentry nr_unused age_limit want_pages nr_negative五、struct file
open() 创建一个
struct file:
struct file {
struct path f_path; // {vfsmount, dentry}
struct inode *f_inode;
const struct file_operations *f_op;
atomic_long_t f_count; // 引用计数
unsigned int f_flags; // O_RDONLY/O_WRONLY/O_RDWR...
fmode_t f_mode;
loff_t f_pos; // 当前偏移
struct address_space *f_mapping;
...
};file 是”打开实例”——同一 inode 可有多个 file(多次 open)。
六、操作表模式
VFS 的设计模式:每层一个操作表(函数指针结构体),具体 FS 填充实现。
// ext4 注册
static const struct inode_operations ext4_dir_inode_operations = {
.create = ext4_create,
.lookup = ext4_lookup,
.link = ext4_link,
.mkdir = ext4_mkdir,
...
};这是经典的”C 语言面向对象”。
七、mount 与 vfsmount
struct vfsmount {
struct dentry *mnt_root;
struct super_block *mnt_sb;
int mnt_flags;
};mount -t ext4 /dev/sda1 /mnt → 创建
super_block + vfsmount + 根 dentry。
mount namespace 隔离不同进程看到的挂载树。
八、RCU 路径查找
路径查找(path_lookup)的 RCU
模式(LOOKUP_RCU):
- 不加任何锁
- RCU 保护 dcache 读
- 每步验证 d_seq(sequence count)
- 成功 → 零锁路径解析
- 验证失败 →
降级到加锁模式(
LOOKUP_LOCK)
这让 stat() / access()
等频繁操作几乎无开销。
九、观察
# dcache/inode cache 大小
cat /proc/slabinfo | grep -E 'dentry|inode_cache'
# 挂载点
cat /proc/mounts
# 文件系统类型
cat /proc/filesystems
# VFS 统计
cat /proc/sys/fs/file-nr
# allocated unused max十、小结
- VFS 四层:superblock(FS 实例)→ inode(文件元数据)→ dentry(路径缓存)→ file(打开实例)
- ops 表是 C 语言的多态
- dcache + negative dentry 让路径查找命中内存
- RCU lookup 让热路径零锁
参考文献
Documentation/filesystems/vfs.rst(最权威)- Bovet & Cesati, “Understanding the Linux Kernel” 3rd §12
- Robert Love, “Linux Kernel Development” 3rd §13
include/linux/fs.h、include/linux/dcache.h
工具
/proc/slabinfo(dentry/inode_cache)/proc/mountsmountstatsperf stat -e dcache_*
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【存储工程】文件系统基础:inode、目录与 VFS
磁盘是一个线性的块数组,但没有人愿意用"第 48372 号扇区"来定位自己的文档。文件系统(File System)就是那个把"名字"映射到"数据"的翻译层——它把一片平坦的块空间组织成人类可以理解的层级结构,同时维护着每个文件的权限、大小、时间戳等元数据(Metadata)。
【操作系统百科】VFS I/O 路径全景
一次 read(fd, buf, n) 从用户态到磁盘要穿过多少层?本文追踪 VFS read/write 全路径——file_operations、iter_iov、iomap、页缓存命中与 miss、直接 I/O 旁路、块层提交、fsnotify 插桩。
【操作系统百科】内存回收
Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。
【操作系统百科】交换
swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。