Linux VFS 路径名查找
2026/4/24 15:49:30 网站建设 项目流程

路径名查找是将用户态路径字符串(如/home/user/file.txt)转换为内核dentry + inode + vfsmount的核心过程,是open/stat/mkdir等几乎所有文件系统操作的入口,核心代码位于fs/namei.c

核心数据结构

1. struct dentry(目录项)

  • 作用:建立路径分量名 → inode的映射,是 VFS 查找的核心缓存对象。
  • 关键字段:
    • d_name:路径分量名(如homefile.txt
    • d_parent:父目录 dentry
    • d_inode:指向对应 inode(NULL表示负缓存,即该名不存在)
    • d_flags:标记挂载点、自动挂载、需重验证等状态
  • 生命周期:仅在内存中,LRU 淘汰,不持久化到磁盘。

2. struct nameidata(查找上下文)

  • 作用:贯穿查找全程的状态容器,记录当前位置、待处理分量、根目录等 。
  • 关键字段:
    • struct path path:当前 dentry + vfsmount(查找起点 / 当前位置)
    • struct qstr last:待解析的下一个路径分量(非\0结尾)
    • int last_type:分量类型(LAST_NORM/LAST_DOT/LAST_DOTDOT/LAST_ROOT
    • struct path root:有效根目录(防chroot竞争)

3. struct path

  • 封装struct vfsmount *mnt+struct dentry *dentry,表示文件系统中的一个位置。

查找总流程(以/home/user/file.txt为例)

1. 确定查找起点

  • 绝对路径(以/开头):从current->fs->root(进程根目录)开始。
  • 相对路径:从current->fs->pwd(进程当前工作目录)开始。
  • *at()系列(openat):从指定文件描述符对应的目录开始。

2. 路径分量拆分

/分割为多个分量:homeuserfile.txt;连续/视为一个;末尾/需特殊处理。

3. 逐层查找(核心:link_path_walk)

对每个非最终分量,循环执行:

  1. 权限检查:当前目录 dentry 对应的 inode 必须有执行权限(X),否则返回-EACCES
  2. 分量处理
    • .:忽略,保持当前 dentry 不变。
    • ..:调用handle_dots()向上回溯父目录,处理挂载点跨越与根目录边界。
    • 普通名:进入lookup_fast → lookup_slow流程。
  3. 缓存查找(lookup_fast,RCU-walk)
    • 以父 dentry + 分量名计算哈希,查dcache 哈希表
    • 命中:直接返回子 dentry,更新nameidata,进入下一分量。
    • 未命中 / 需重验证(如 NFS):降级到lookup_slow(REF-walk)
  4. 慢速查找(lookup_slow)
    • 持有父目录 inode 的i_rwsem(读写信号量),防止并发修改。
    • 再次查 dcache(避免竞争),仍未命中则调用父 inode 的 i_op->lookup ()(文件系统实现,如 ext4_lookup)。
    • 从磁盘读取目录数据,创建新 dentry,关联 inode,加入 dcache。
  5. 挂载点穿越(follow_managed)
    • 若当前 dentry 标记DCACHE_MOUNTED,调用lookup_mnt()切换到挂载文件系统的根 dentry。
    • 自动挂载点(DCACHE_NEED_AUTOMOUNT)触发d_automount()完成挂载。

4. 最终分量处理

link_path_walk仅处理到倒数第二个分量,最终分量由上层函数处理:

  • path_lookupatstat/chmod):对最终分量执行walk_component,返回目标 dentry。
  • path_openatopen):处理O_CREAT/O_EXCL、末尾/、符号链接等,调用do_last()
  • path_parentatmkdir/rmdir/unlink):返回父目录与最终分量名,用于创建 / 删除。

5. 完成查找

调用complete_walk(),释放 RCU 读锁,返回最终struct path(dentry + vfsmount)。

两种查找模式(性能关键)

1. RCU-walk(快速 / 懒查找)

  • 机制:持有RCU 读锁,无锁遍历 dcache,依赖d_seq序列号验证一致性。
  • 特点:无锁、低延迟、适合热点路径;仅用缓存,不访问磁盘;遇到未命中 / 挂载 / 符号链接时降级到 REF-walk。
  • 核心函数:__d_lookup_rculookup_fast

2. REF-walk(慢速 / 引用查找)

  • 机制:持有dentry 引用计数 + 锁d_lock/i_rwsem),确保数据稳定。
  • 特点:安全、处理所有复杂场景(磁盘 I/O、符号链接、挂载);性能低于 RCU-walk。
  • 核心函数:lookup_slowwalk_component

符号链接处理(关键扩展)

  • 遇到符号链接 dentry 时,读取链接内容(新路径字符串),递归执行路径查找。
  • 内核限制最大嵌套深度(默认 40 层),防止死循环。
  • 绝对链接:从根目录重新开始;相对链接:从当前目录继续。

关键机制与优化

1. dentry 缓存(dcache)

  • 全局哈希表,按父 dentry + 分量名哈希索引。
  • 负缓存:记录 “不存在” 的名称,避免重复磁盘查找。
  • 并发安全:rename_lock(seqlock)检测重命名竞争,d_lock保护单个 dentry 结构。

2. 并发与锁

  • d_lockref:原子自旋锁 + 引用计数,高效管理 dentry 生命周期。
  • i_rwsem:目录级读写锁,串行化目录修改与查找。
  • mount_lock:全局 seqlock,保护挂载表变更。

3. 权限与边界

  • 每步检查目录执行权限(X),确保可进入目录。
  • ..不能越出进程根目录(chroot约束)。
  • 路径末尾/要求目标必须是目录

核心函数调用链

用户态 open("/home/user/file.txt") ↓ sys_open ↓ do_sys_open ↓ filename_lookup ↓ path_lookupat ↓ link_path_walk # 处理 home → user ↓ walk_component # 逐层查找 ↓ lookup_fast/RCU-walk → lookup_slow/REF-walk ↓ follow_managed # 处理挂载点 ↓ do_last # 处理最终分量 file.txt ↓ 返回 struct path(dentry + vfsmount)

path_lookupat

  • 头文件:include/linux/namei.h
  • 实现文件:fs/namei.c
  • 内核版本:Linux 4.17+ 标准化,替代旧版path_lookup/path_lookup_noexport,是现代 VFS 路径查找唯一标准入口

函数原型

int path_lookupat(int dfd, const char *path, unsigned int flags, struct path *path);

参数说明

参数作用
dfd目录文件描述符;AT_FDCWD表示相对当前工作目录
path目标路径字符串(用户态 / 内核态)
flags查找控制标志LOOKUP_*系列
path出参,存放解析结果:struct dentry + struct vfsmount

核心作用

把「字符串路径」解析为内核 VFS 可直接操作的struct path(dentry + 挂载实例),是 Linux 内核所有文件路径解析的统一入口

核心调用层级

path_lookupat └── do_path_lookup ├── path_init // 初始化 nameidata、查找起点 ├── link_path_walk // 遍历中间路径组件(核心) ├── lookup_last // 处理最后一个路径分量 └── complete_walk // 收尾、释放锁、清理nd

核心能力

  1. 相对 / 绝对路径统一解析,支持AT_FDCWD相对当前目录、或指定 fd 作为起始目录,适配 openat/statat 系列系统调用。
  2. 逐级路径遍历,/拆分多级目录,逐个解析中间路径分量。
  3. 内置复杂规则处理,自动处理:./..符号链接递归解析、挂载点跨越、chroot 隔离。
  4. 双模式高速查找,优先 RCU 无锁快速查找(性能高),缓存未命中自动降级加锁慢速读取磁盘。
  5. 权限与安全控制,通过 lookup 标志限制:不许跨挂载、不许跳出父目录、不跟随软链接等,支撑容器 / 沙箱隔离。

关键依赖结构

struct nameidata

路径查找上下文容器,贯穿全程:

  • 起始 / 当前struct path
  • 查找标志、符号链接递归栈
  • 序列锁、RCU 上下文、权限检查状态

struct path

struct path { struct vfsmount *mnt; struct dentry *dentry; };

VFS 定位文件的唯一核心句柄

与旧接口区别

  1. 废弃path_lookup()
    • 不支持dfd相对目录、不支持 modern 路径隔离 flag
  2. path_lookupat优势
    • 支持at 系列语义(兼容openat/statat
    • 细粒度权限控制、容器 / 沙箱 目录隔离能力
    • 统一 RCU/REF 双查找模式

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

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

立即咨询