欢迎光临
我们一直在努力

深入理解 Linux VFS 文件系统框架


本文以 debugfs 为例,深入剖析 Linux VFS 文件系统框架的设计与实现,涵盖 file_system_type、super_block、dentry、inode、file 五大核心数据结构及其关系。

深入理解 Linux VFS 文件系统框架 —— 以 debugfs 为例

摘要

Linux VFS(Virtual File System)是内核中最精妙的抽象层之一,它为上层应用提供统一的文件访问接口,同时允许底层支持 ext4、XFS、NFS 等数十种不同的文件系统实现。本文选取内核中最简洁的 debugfs 作为学习样本,系统性地剖析 VFS 的五层架构:file_system_type、super_block、dentry、inode、file,并详细解释每个数据结构的字段含义、指针指向以及赋值时机。通过本文,读者可以建立起对 Linux 文件系统框架的整体认知,为后续学习 ext4、F2FS 等复杂文件系统打下坚实基础。

关键词:Linux 内核、VFS、文件系统、debugfs、super_block、inode、dentry


1. 为什么选择 debugfs 作为学习样本

在众多 Linux 文件系统中,debugfs 是最适合入门学习的对象,原因如下:

特性说明
纯内存实现 无磁盘 I/O 逻辑,专注于 VFS 接口
代码精简 核心代码约 900 行,易于通读
标准接口 完整实现 VFS 要求的各类操作表
广泛复用 libfs 展示了如何借助内核辅助函数简化开发

debugfs 的源码位于:

fs/debugfs/
├── inode.c # 核心实现:注册、挂载、创建文件/目录
├── file.c # 文件操作:read/write 及各类 helper
└── internal.h # 内部数据结构定义


2. VFS 五层架构总览

Linux VFS 采用分层设计,从上到下依次为:

┌─────────────────────────────────────────────────────────────────────────┐
│ 用户空间 (User Space) │
│ open() / read() / write() / close() │
└───────────────────────────────────┬─────────────────────────────────────┘
│ 系统调用

┌─────────────────────────────────────────────────────────────────────────┐
│ VFS 层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │file_system_ │ │ super_block │ │ dentry │ │ inode │ │
│ │ type │→ │ │→ │ │→ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ↓ │
│ ┌──────────────┐ │
│ │ file │ │
│ └──────────────┘ │
└───────────────────────────────────┬─────────────────────────────────────┘
│ 回调具体文件系统实现

┌─────────────────────────────────────────────────────────────────────────┐
│ 具体文件系统实现 │
│ debugfs / ext4 / xfs / nfs / proc / sysfs … │
└─────────────────────────────────────────────────────────────────────────┘

各层职责如下:

层级数据结构核心职责
第一层 file_system_type 向内核注册文件系统,提供挂载/卸载入口
第二层 super_block 描述已挂载文件系统的全局状态
第三层 dentry 目录项缓存,实现路径名到 inode 的映射
第四层 inode 文件元数据(权限、大小、时间戳等)
第五层 file 进程打开文件的运行时状态

3. 第一层:file_system_type —— 文件系统的"身份证"

3.1 数据结构定义

// include/linux/fs.h
struct file_system_type {
const char *name; // 文件系统名称
int fs_flags; // 标志位
struct dentry *(*mount)(struct file_system_type *, int,
const char *, void *); // 挂载回调
void (*kill_sb)(struct super_block *); // 卸载回调
struct module *owner; // 所属模块
struct file_system_type *next; // 链表指针
struct hlist_head fs_supers; // 该类型所有 super_block
// … 省略锁相关字段
};

3.2 debugfs 的实现

// fs/debugfs/inode.c
static struct file_system_type debug_fs_type = {
.owner = THIS_MODULE,
.name = "debugfs",
.mount = debug_mount,
.kill_sb = kill_litter_super,
};
MODULE_ALIAS_FS("debugfs");

字段解析:

字段值说明
.owner THIS_MODULE 模块引用计数,防止文件系统使用中模块被卸载
.name "debugfs" 挂载命令 mount -t debugfs 中的类型名
.mount debug_mount 挂载时调用,负责创建 super_block 并返回根 dentry
.kill_sb kill_litter_super 卸载时调用,清理内存文件系统的所有 inode/dentry

3.3 注册流程

// fs/debugfs/inode.c
static int __init debugfs_init(void)
{
int retval;

// 在 /sys/kernel/ 下创建挂载点
retval = sysfs_create_mount_point(kernel_kobj, "debug");
if (retval)
return retval;

// 向 VFS 注册文件系统类型
retval = register_filesystem(&debug_fs_type);
if (retval)
sysfs_remove_mount_point(kernel_kobj, "debug");
else
debugfs_registered = true;

return retval;
}
core_initcall(debugfs_init); // 内核启动早期执行

register_filesystem() 将 debug_fs_type 加入全局链表 file_systems,之后用户执行 mount -t debugfs 时,VFS 即可通过名称匹配找到对应的 file_system_type。

3.4 挂载函数的选择

根据文件系统特性,mount 回调通常调用以下辅助函数之一:

辅助函数适用场景示例
mount_single() 全局单例,所有挂载点共享同一 super_block debugfs, securityfs
mount_nodev() 无设备支撑的内存文件系统,每次挂载创建新实例 ramfs, tmpfs
mount_bdev() 块设备文件系统 ext4, xfs, f2fs

debugfs 使用 mount_single(),确保无论挂载多少次,都只有一个 super_block 实例。


4. 第二层:super_block —— 已挂载文件系统的"大脑"

4.1 数据结构定义(关键字段)

// include/linux/fs.h
struct super_block {
struct list_head s_list; // 全局 super_block 链表
dev_t s_dev; // 设备号
unsigned long s_blocksize; // 块大小
unsigned long s_magic; // 魔数,标识文件系统类型
struct dentry *s_root; // 根目录 dentry
struct file_system_type *s_type; // 指向 file_system_type
const struct super_operations *s_op; // 超级块操作表
const struct dentry_operations *s_d_op; // 默认 dentry 操作表
void *s_fs_info; // 文件系统私有数据
// … 更多字段
};

4.2 debugfs 的 fill_super 实现

当用户首次挂载 debugfs 时,mount_single() 会调用 debug_fill_super() 初始化 super_block:

// fs/debugfs/inode.c
static int debug_fill_super(struct super_block *sb, void *data, int silent)
{
static const struct tree_descr debug_files[] = {{""}};
struct debugfs_fs_info *fsi;
int err;

// 1. 分配私有数据结构,存储挂载选项
fsi = kzalloc(sizeof(struct debugfs_fs_info), GFP_KERNEL);
sb->s_fs_info = fsi;
if (!fsi)
return ENOMEM;

// 2. 解析挂载选项 (mount -o uid=1000,gid=1000,mode=0755)
err = debugfs_parse_options(data, &fsi->mount_opts);
if (err)
goto fail;

// 3. 调用 libfs 辅助函数填充基本字段
// 内部会创建根 inode 和根 dentry
err = simple_fill_super(sb, DEBUGFS_MAGIC, debug_files);
if (err)
goto fail;

// 4. 设置操作表
sb->s_op = &debugfs_super_operations; // 超级块操作
sb->s_d_op = &debugfs_dops; // 默认 dentry 操作

// 5. 将挂载选项应用到根 inode
debugfs_apply_options(sb);

return 0;

fail:
kfree(fsi);
sb->s_fs_info = NULL;
return err;
}

4.3 关键字段指向关系

┌───────────────────────────────┐
│ super_block │
├───────────────────────────────┤
s_type ────────→│ debug_fs_type │
├───────────────────────────────┤
s_op ─────────→ │ debugfs_super_operations │
│ .statfs() │
│ .remount_fs() │
│ .show_options() │
│ .destroy_inode() │
├───────────────────────────────┤
s_d_op ───────→ │ debugfs_dops │
│ .d_delete() │
│ .d_release() │
│ .d_automount() │
├───────────────────────────────┤
s_root ───────→ │ 根目录 dentry │
├───────────────────────────────┤
s_fs_info ────→ │ debugfs_fs_info │
│ .mount_opts (uid/gid/mode) │
└───────────────────────────────┘

4.4 super_operations 操作表

// fs/debugfs/inode.c
static const struct super_operations debugfs_super_operations = {
.statfs = simple_statfs, // df 命令
.remount_fs = debugfs_remount, // mount -o remount
.show_options = debugfs_show_options, // cat /proc/mounts
.destroy_inode = debugfs_destroy_inode, // inode 销毁时清理
};

回调函数触发时机实现要点
statfs statfs() 系统调用 / df 命令 debugfs 使用 simple_statfs(),返回 PAGE_SIZE 作为块大小
remount_fs mount -o remount,uid=1000 重新解析选项,更新根 inode 的 uid/gid/mode
show_options 读取 /proc/mounts 输出非默认的挂载参数
destroy_inode inode 引用计数归零 通过 RCU 延迟释放,清理符号链接的 i_link 内存

5. 第三层:dentry —— 路径名到 inode 的桥梁

5.1 dentry 的作用

dentry(directory entry)是 VFS 中最巧妙的设计之一。它解决了一个核心问题:如何高效地将路径名(如 /sys/kernel/debug/my_file)解析为对应的 inode?

Linux 维护一个全局的 dentry 缓存(dcache),将已解析过的路径名组件缓存起来,避免重复查找。

5.2 数据结构定义(关键字段)

// include/linux/dcache.h
struct dentry {
unsigned int d_flags; // 标志位
struct dentry *d_parent; // 父目录的 dentry
struct qstr d_name; // 名称
struct inode *d_inode; // 关联的 inode(NULL 表示负向缓存)
const struct dentry_operations *d_op; // dentry 操作表
struct super_block *d_sb; // 所属 super_block
void *d_fsdata; // 文件系统私有数据
struct list_head d_subdirs; // 子目录/文件链表
struct list_head d_child; // 链接到父目录的 d_subdirs
// … 更多字段
};

5.3 dentry 操作表

// fs/debugfs/inode.c
static const struct dentry_operations debugfs_dops = {
.d_delete = always_delete_dentry, // 不缓存 dentry
.d_release = debugfs_release_dentry, // 释放 d_fsdata
.d_automount = debugfs_automount, // 自动挂载支持
};

回调函数触发时机debugfs 实现
d_delete dentry 引用计数归零时决定是否保留在缓存 always_delete_dentry() 返回 1,表示立即删除,不做缓存
d_release dentry 真正释放时 释放 d_fsdata 中存储的 debugfs_fsdata 结构
d_automount 路径解析遇到自动挂载点时 支持 tracefs 等子文件系统的自动挂载

5.4 创建目录的完整流程

以 debugfs_create_dir() 为例:

// fs/debugfs/inode.c
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
{
struct dentry *dentry = start_creating(name, parent);
struct inode *inode;

if (IS_ERR(dentry))
return NULL;

// 分配 inode
inode = debugfs_get_inode(dentry->d_sb);
if (unlikely(!inode))
return failed_creating(dentry);

// 配置 inode 为目录类型
inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;

// 目录的硬链接数初始为 2(自身 + "." 条目)
inc_nlink(inode);

// 关键:绑定 dentry 和 inode
d_instantiate(dentry, inode);

// 父目录硬链接数 +1(因为新增了一个子目录)
inc_nlink(d_inode(dentry->d_parent));

fsnotify_mkdir(d_inode(dentry->d_parent), dentry);
return end_creating(dentry);
}

核心函数解析:

函数作用
start_creating() 确保 debugfs 已挂载,在父目录下查找/创建 dentry,锁定父 inode
debugfs_get_inode() 分配新 inode,设置 i_ino 和时间戳
d_instantiate() 将 dentry 与 inode 绑定(dentry->d_inode = inode)
end_creating() 释放父 inode 锁

6. 第四层:inode —— 文件的"元数据仓库"

6.1 数据结构定义(关键字段)

// include/linux/fs.h
struct inode {
umode_t i_mode; // 文件类型 + 权限
unsigned long i_ino; // inode 编号
kuid_t i_uid; // 所有者 UID
kgid_t i_gid; // 所有者 GID
loff_t i_size; // 文件大小
struct timespec64 i_atime; // 最后访问时间
struct timespec64 i_mtime; // 最后修改时间
struct timespec64 i_ctime; // 元数据修改时间
unsigned int i_nlink; // 硬链接计数
const struct inode_operations *i_op; // inode 操作表
const struct file_operations *i_fop; // 文件操作表
struct super_block *i_sb; // 所属 super_block
void *i_private; // 文件系统私有数据
char *i_link; // 符号链接目标路径
// … 更多字段
};

6.2 debugfs 的 inode 分配

// fs/debugfs/inode.c
static struct inode *debugfs_get_inode(struct super_block *sb)
{
struct inode *inode = new_inode(sb);
if (inode) {
inode->i_ino = get_next_ino(); // 分配唯一 inode 号
inode->i_atime = inode->i_mtime =
inode->i_ctime = current_time(inode);
}
return inode;
}

6.3 不同文件类型的 inode 配置

文件类型i_modei_opi_fopi_private
普通文件 S_IFREG | 0644 默认 用户提供的 fops 用户数据指针
目录 S_IFDIR | 0755 simple_dir_inode_operations simple_dir_operations
符号链接 S_IFLNK | 0777 simple_symlink_inode_operations 无(使用 i_link)

6.4 i_private 的妙用

debugfs 的一大特色是允许用户在创建文件时传入私有数据指针:

// 创建文件时
debugfs_create_file("my_value", 0644, parent, &my_data, &my_fops);
^^^^^^^^
存入 inode->i_private

// 在 file_operations 中访问
static ssize_t my_read(struct file *file, char __user *buf, ...)
{
int *data = file->private_data; // 由 simple_open() 从 i_private 复制而来
// 使用 data …
}

这种设计模式极大简化了内核模块向用户空间暴露数据的过程。


7. 第五层:file —— 进程打开文件的"会话状态"

7.1 inode 与 file 的关系

一个关键概念:inode 代表文件本身,file 代表一次打开操作。

  • 同一个文件被多个进程打开,共享同一个 inode,但各有独立的 file
  • file 记录了打开方式(只读/读写)、当前偏移量等会话状态

进程 A 进程 B
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│ file │ │ file │
│ f_pos=0 │ │f_pos=100│
└────┬────┘ └─────┬───┘
│ │
└───────────┬───────────────────┘

┌──────────┐
│ inode │ (共享)
│ i_size= │
│ 1024 │
└──────────┘

7.2 数据结构定义(关键字段)

// include/linux/fs.h
struct file {
struct path f_path; // 包含 dentry 和 vfsmount
struct inode *f_inode; // 缓存的 inode 指针
const struct file_operations *f_op; // 文件操作表
unsigned int f_flags; // 打开标志 (O_RDONLY 等)
fmode_t f_mode; // 访问模式 (FMODE_READ 等)
loff_t f_pos; // 当前偏移量
void *private_data; // file_operations 的私有数据
// … 更多字段
};

7.3 debugfs 的 Proxy 模式

debugfs 实现了一个精巧的 Proxy 模式,用于解决模块卸载时的竞态问题:

问题场景:用户进程正在读取 debugfs 文件,此时模块被卸载,file_operations 指向的函数地址变为无效内存。

解决方案:在 open 时包装真实的 fops,在每次操作时检查文件是否仍有效。

// fs/debugfs/file.c
static int full_proxy_open(struct inode *inode, struct file *filp)
{
struct dentry *dentry = filp->f_path.dentry;
const struct file_operations *real_fops;
struct file_operations *proxy_fops;

// 1. 增加活跃用户计数,阻止 debugfs_remove() 完成
if (debugfs_file_get(dentry))
return ENOENT;

// 2. 从 d_fsdata 获取真实的 file_operations
real_fops = debugfs_real_fops(filp);

// 3. 分配 proxy fops,包装真实操作
proxy_fops = kzalloc(sizeof(*proxy_fops), GFP_KERNEL);
if (real_fops->read)
proxy_fops->read = full_proxy_read;
if (real_fops->write)
proxy_fops->write = full_proxy_write;
// …

// 4. 替换 file 的 f_op
replace_fops(filp, proxy_fops);

// 5. 调用真实的 open
if (real_fops->open)
real_fops->open(inode, filp);

debugfs_file_put(dentry);
return 0;
}

每次 read/write 操作都会经过 proxy 函数:

// 伪代码
static ssize_t full_proxy_read(struct file *filp, char __user *buf, ...)
{
debugfs_file_get(dentry); // 检查文件是否仍有效
real_fops->read(filp, buf, ...); // 调用真实实现
debugfs_file_put(dentry); // 释放保护
}


8. 完整调用链路图解

8.1 挂载流程

用户执行: mount -t debugfs debugfs /sys/kernel/debug


┌────────────────────────────────────────────────────────────────┐
│ VFS: do_mount() │
│ 1. 根据 "debugfs" 查找 file_system_type │
│ 2. 调用 debug_fs_type.mount = debug_mount() │
└────────────────────────────────┬───────────────────────────────┘


┌────────────────────────────────────────────────────────────────┐
│ debug_mount() │
│ return mount_single(fs_type, flags, data, debug_fill_super); │
└────────────────────────────────┬───────────────────────────────┘


┌────────────────────────────────────────────────────────────────┐
│ debug_fill_super() │
├────────────────────────────────────────────────────────────────┤
│ fsi = kzalloc(debugfs_fs_info) │
│ sb->s_fs_info = fsi │
│ debugfs_parse_options(data, &fsi->mount_opts) │
│ simple_fill_super(sb, DEBUGFS_MAGIC, …) │
│ └─→ 创建根 inode │
│ └─→ sb->s_root = d_make_root(root_inode) │
│ sb->s_op = &debugfs_super_operations │
│ sb->s_d_op = &debugfs_dops │
│ debugfs_apply_options(sb) │
└────────────────────────────────────────────────────────────────┘

8.2 创建文件流程

内核模块调用: debugfs_create_file("my_var", 0644, parent, &data, &fops)


┌────────────────────────────────────────────────────────────────┐
│ start_creating() │
│ 1. simple_pin_fs() – 确保 debugfs 已挂载 │
│ 2. 若 parent 为 NULL,使用根 dentry │
│ 3. inode_lock(d_inode(parent)) │
│ 4. lookup_one_len() – 在父目录查找/创建 dentry │
└────────────────────────────────┬───────────────────────────────┘


┌────────────────────────────────────────────────────────────────┐
│ debugfs_get_inode() │
│ inode = new_inode(sb) │
│ inode->i_ino = get_next_ino() │
│ inode->i_atime = inode->i_mtime = inode->i_ctime = now │
└────────────────────────────────┬───────────────────────────────┘


┌────────────────────────────────────────────────────────────────┐
│ 配置 inode │
│ inode->i_mode = S_IFREG | 0644 │
│ inode->i_private = &data ← 用户数据 │
│ inode->i_fop = proxy_fops ← 代理操作表 │
│ dentry->d_fsdata = &fops | BIT ← 真实操作表(带标记位) │
└────────────────────────────────┬───────────────────────────────┘


┌────────────────────────────────────────────────────────────────┐
│ d_instantiate(dentry, inode) – 绑定 dentry 与 inode │
│ fsnotify_create(…) – 通知文件创建事件 │
│ end_creating() – 释放父目录锁 │
│ return dentry │
└────────────────────────────────────────────────────────────────┘

8.3 用户空间访问流程

用户执行: cat /sys/kernel/debug/my_var


┌──────────────────────────────────────────────────────────────────┐
│ open() 系统调用 │
├──────────────────────────────────────────────────────────────────┤
│ 1. path_lookup() – 解析路径,找到 dentry │
│ 2. 分配 struct file │
│ 3. file->f_inode = dentry->d_inode │
│ 4. file->f_op = inode->i_fop (= proxy_fops) │
│ 5. 调用 file->f_op->open() = full_proxy_open() │
│ └─→ 获取 real_fops,包装为新的 proxy │
│ └─→ 调用 real_fops->open() (= simple_open) │
│ └─→ file->private_data = inode->i_private │
│ 6. 返回文件描述符 fd │
└──────────────────────────────────────────────────────────────────┘


┌──────────────────────────────────────────────────────────────────┐
│ read() 系统调用 │
├──────────────────────────────────────────────────────────────────┤
│ 1. 根据 fd 找到 struct file │
│ 2. 调用 file->f_op->read() = full_proxy_read() │
│ └─→ debugfs_file_get() – 开始保护 │
│ └─→ real_fops->read() – 执行真实读取 │
│ └─→ debugfs_file_put() – 结束保护 │
│ 3. 数据复制到用户空间 │
└──────────────────────────────────────────────────────────────────┘


┌──────────────────────────────────────────────────────────────────┐
│ close() 系统调用 │
├──────────────────────────────────────────────────────────────────┤
│ 1. 调用 file->f_op->release() = full_proxy_release() │
│ └─→ real_fops->release() │
│ └─→ kfree(proxy_fops) │
│ └─→ fops_put(real_fops) │
│ 2. 释放 struct file │
└──────────────────────────────────────────────────────────────────┘


9. 动手实践:实现一个最小文件系统

基于对 debugfs 的理解,下面是实现一个最小内存文件系统的模板:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/init.h>

#define MYFS_MAGIC 0x4D594653 // "MYFS"

/* ==================== inode 操作 ==================== */

static struct inode *myfs_get_inode(struct super_block *sb,
const struct inode *dir,
umode_t mode)
{
struct inode *inode = new_inode(sb);
if (!inode)
return NULL;

inode->i_ino = get_next_ino();
inode->i_mode = mode;
inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);

switch (mode & S_IFMT) {
case S_IFREG:
inode->i_fop = &simple_dir_operations; // 简化:使用通用实现
break;
case S_IFDIR:
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
inc_nlink(inode);
break;
}

return inode;
}

/* ==================== super_block 操作 ==================== */

static const struct super_operations myfs_super_ops = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
};

static int myfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *root_inode;

sb->s_magic = MYFS_MAGIC;
sb->s_blocksize = PAGE_SIZE;
sb->s_blocksize_bits = PAGE_SHIFT;
sb->s_op = &myfs_super_ops;

root_inode = myfs_get_inode(sb, NULL, S_IFDIR | 0755);
if (!root_inode)
return ENOMEM;

sb->s_root = d_make_root(root_inode);
if (!sb->s_root)
return ENOMEM;

return 0;
}

/* ==================== 挂载/卸载 ==================== */

static struct dentry *myfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return mount_nodev(fs_type, flags, data, myfs_fill_super);
}

static struct file_system_type myfs_type = {
.owner = THIS_MODULE,
.name = "myfs",
.mount = myfs_mount,
.kill_sb = kill_litter_super,
};

/* ==================== 模块入口 ==================== */

static int __init myfs_init(void)
{
return register_filesystem(&myfs_type);
}

static void __exit myfs_exit(void)
{
unregister_filesystem(&myfs_type);
}

module_init(myfs_init);
module_exit(myfs_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A minimal in-memory filesystem");

使用方法:

# 编译模块
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

# 加载模块
sudo insmod myfs.ko

# 挂载
sudo mount -t myfs none /mnt/myfs

# 查看
mount | grep myfs

# 卸载
sudo umount /mnt/myfs
sudo rmmod myfs


10. 常用 libfs 辅助函数速查表

内核在 fs/libfs.c 中提供了大量辅助函数,可极大简化简单文件系统的实现:

函数用途典型使用场景
simple_fill_super() 初始化 super_block 基本字段并创建根 dentry fill_super 回调
simple_statfs() 返回基本的文件系统统计信息 super_operations.statfs
simple_lookup() 目录查找,返回负向 dentry inode_operations.lookup
simple_dir_operations 目录的通用 file_operations 目录 inode 的 i_fop
simple_dir_inode_operations 目录的通用 inode_operations 目录 inode 的 i_op
simple_open() 将 inode->i_private 复制到 file->private_data file_operations.open
simple_read_from_buffer() 从内核缓冲区读取到用户空间 实现 read 回调
simple_write_to_buffer() 从用户空间写入到内核缓冲区 实现 write 回调
simple_link() 创建硬链接 inode_operations.link
simple_unlink() 删除文件 inode_operations.unlink
simple_rmdir() 删除目录 inode_operations.rmdir
simple_rename() 重命名 inode_operations.rename
generic_delete_inode() 立即删除 inode super_operations.drop_inode
d_make_root() 从 inode 创建根 dentry fill_super 中创建根目录
d_instantiate() 绑定 dentry 和 inode 创建新文件/目录后

11. 总结与进阶建议

本文以 debugfs 为例,系统地介绍了 Linux VFS 的五层架构:

  • file_system_type:文件系统的"身份证",定义挂载/卸载入口
  • super_block:已挂载文件系统的"大脑",存储全局状态
  • dentry:路径解析的"缓存层",连接名称与 inode
  • inode:文件的"元数据仓库",存储权限、大小、时间等
  • file:打开操作的"会话状态",记录偏移量、访问模式等
  • 进阶学习建议:

    阶段学习目标推荐文件系统
    入门 理解 VFS 接口 debugfs, ramfs
    进阶 理解目录操作、缓存 procfs, sysfs
    深入 理解块设备 I/O minix, ext2
    精通 理解日志、extent ext4, f2fs

    推荐阅读源码:

    • fs/libfs.c – VFS 辅助函数,必读
    • fs/ramfs/inode.c – 最简单的完整文件系统实现
    • fs/proc/ – 理解动态生成内容的 proc 文件系统
    • Documentation/filesystems/vfs.rst – 官方 VFS 文档

    参考资料

  • Linux Kernel Source Code v5.10

    • fs/debugfs/ – debugfs 实现
    • fs/libfs.c – VFS 辅助函数
    • include/linux/fs.h – VFS 核心数据结构
  • 《Understanding the Linux Kernel》, 3rd Edition, O’Reilly

  • 《Linux Kernel Development》, 3rd Edition, Robert Love

  • Kernel.org Documentation


  • 本文基于 Linux Kernel 5.10 源码分析,如有错误欢迎指正。

    赞(0)
    未经允许不得转载:171主机测评 » 深入理解 Linux VFS 文件系统框架
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址