Linux VFS 完整篇:从path_openat、dentry/inode 到page cache 与挂载排障
2026/9/5 10:46:23 网站建设 项目流程

open返回诡异 errno、海量小文件把内存打满、O_DIRECT对齐失败、容器 overlay 写放大被误判成「磁盘慢」——根因多半落在VFS 对象模型与挂载/缓存策略,而不是某一个具体 FS 的业务逻辑。本文把路径查找、打开绑定、读写与 page cache、挂载选项与观测命令合成一篇闭环,便于对照源码与strace/findmnt验证。


源码锚点

路径作用
fs/namei.cpath_openatlink_path_walk、lookup 快/慢路径
fs/open.cdo_sys_open/do_filp_openvfs_open
fs/read_write.cvfs_read/vfs_writevfs_iter_*
fs/dcache.cdentry 缓存、negative dentry、回收协作
fs/inode.cinode 生命周期、权限相关入口
fs/super.csuper_block、挂载/卸载协作
mm/filemap.cpage cache:filemap_read/generic_file_*
include/linux/fs.hinodefilefile_operationssuper_operations
include/linux/dcache.hstruct dentry
Documentation/filesystems/vfs.rstVFS 方法表总览

打开后用户态 fd 对应的内核对象:

/* include/linux/fs.h */structfile{conststructfile_operations*f_op;structinode*f_inode;void*private_data;loff_tf_pos;/* … */};structfile_operations{structmodule*owner;ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);ssize_t(*read_iter)(structkiocb*,structiov_iter*);int(*open)(structinode*,structfile*);/* … */};

路径打开逻辑骨架(版本细节以树内符号为准):

/* 用户态 openat → 系统调用 → fs/namei.c / fs/open.c */path_openat(...)→ link_path_walk/* 逐组件 */lookup_fast(dcache)lookup_slow(→ inode->i_op->lookup)→ 处理 O_CREAT/O_TRUNC/尾随斜线等 → vfs_open → file->f_op=fops_get(inode->i_fop)→ f_op->open(inode,file)/* 具体 FS 或设备 fops */

调用链

打开与读写主路径

命中

未命中

openat(dfd, path, flags)

do_sys_open / do_filp_open

path_openat

link_path_walk

dcache 命中?

lookup_fast

lookup_slow → i_op->lookup

权限 / 标志处理

vfs_open

绑定 file->f_op = inode->i_fop

f_op->open

read → vfs_read / read_iter

page cache?

直接拷贝用户态

generic_file_* → FS → 块层

对象分层与缓存协作

缓存与后端

VFS对象

用户态

进程 fd 表

struct file

struct dentry

struct inode

struct super_block

dcache

page cache / i_mapping

具体 FS: ext4/XFS/...

块层 bio


重点知识

1. 四件套分工先分清,再谈「慢」

对象职责排障信号
dentry路径组件缓存(含 negative)找不到路径、海量小文件内存涨
inode元数据 +i_op/i_fop+i_mapping权限/大小/时间戳异常
file一次打开会话(位置、模式、private_data打开后读写/ioctl 失败
super_block一个挂载实例的 FS 全局状态挂载只读、配额、冻结

故障先归类:路径找不到(dentry/权限)还是打开后读写失败(f_op/块层),避免一上来改 FS 调优参数。

2.file->f_op在 open 时钉死

后续read/write/ioctl都走这张表。设备节点会在字符/块层替换 fops(如chrdev_open);普通文件则是具体 FS 的file_operations。挂错类型、overlay 层错乱、错误的 inode,都会进错操作集。

3. dcache、negative dentry 与内存压力

海量小文件遍历会堆 dentry/inode;vm.vfs_cache_pressure影响回收积极性。negative dentry 加速「反复查不存在路径」,也能在并发创建场景下制造短暂「看不见刚创建的文件」的错觉——结合业务与strace看是 ENOENT 还是竞态。

4. page cache、回写与O_DIRECT

  • 缓冲 I/O:命中i_mapping则少读盘;脏页经 writeback 回盘。
  • O_DIRECT:绕过 page cache,偏移/长度需按逻辑块对齐,否则常见EINVAL
  • 观测脏页与回写:/proc/meminfoDirty/Writeback,配合iostat -x

5. 挂载选项与容器场景

findmnt-T/path/to/filemount|grep<mp># 常见:noatime 降元数据写;ro/nodev/nosuid 安全边界cat/proc/sys/vm/vfs_cache_pressure
场景建议常见坑
数据库数据目录单独挂载、评估noatimeatime 更新放大写
容器 rootfs理解 overlay 上层写放大误判底层磁盘慢
SSDdiscard/fstrim策略明确盲目 discard 拖延迟
只读根ro+ 可写目录分离应用写日志失败

6. 挂载与超级块:VFS 的另一半入口

打开路径管「文件」,挂载路径管「一棵树挂到哪里」。用户态mount最终落到 VFS 的挂载点与super_block装配:类型、标志(MS_RDONLY等)、选项字符串交给具体 FS 的fill_super/get_tree一类入口(现代用 fs_context)。排障时:

  • findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS -T <path>看实际生效选项;
  • 只读根上写失败先看挂载 flags,再看应用路径是否写到只读层;
  • 绑定挂载/rbind容易造成「同一 inode 多个路径」的认知错乱,删文件前先findmnt

7. 写路径与回写(和读对称)

write → vfs_write / write_iter → 缓冲写:标记 page dirty → 稍后 writeback → FS → bio → O_SYNC/fdatasync:在返回前推进完整性语义(细节随 FS)

脏页过高时,应用线程可能被卡住参与回写——表象是「业务变慢」,根因在写放大或落盘瓶颈。配合Dirty/Writeback与 FS journal 模式(如 ext4 data=ordered)一起看。

8. 观测与排障命令

strace-eopenat,open,stat,read,writecat/path/to/filecat/proc/meminfo|grep-E'Cached|Dirty|Writeback'iostat-x1slabtop-o|head# 关注 dentry/inode 相关 slab# 权限与挂载namei-l/path/to/filels-ld$(dirname/path/to/file)
现象优先怀疑核对点
ENOENT/EACCES路径/权限/挂载nameifindmnt
EINVALon direct I/O对齐块大小、缓冲地址
内存持续升高dentry/inode/page cacheslabtopvfs_cache_pressure
写延迟尖刺脏页回写/日志Dirty、journal、iostat
容器内写爆盘overlay 上层df分层、docker system df

Checklist

  • 能口述path_openat→ dentry lookup →vfs_openf_op->open的链
  • 分清故障在路径查找、权限、还是f_op/块层
  • strace的 open 标志与 errno 能对应到 VFS 分支
  • 理解 dentry/inode/file/super_block 各自职责
  • 海量小文件场景评估过vfs_cache_pressure与目录布局
  • O_DIRECT/挂载选项(noatime等)按业务验证,而非照抄博客
  • 容器 overlay 写放大与底层磁盘延迟能区分排查

小结

VFS 的设计意图是:用统一对象模型让 ext4/XFS/NFS/proc 共享系统调用入口。排障按「路径 → 绑定 f_op → 缓存/块层 → 挂载选项」分层推进;调优先改可观测、可回滚的挂载与压力参数,再碰具体 FS 内部。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询