路径名查找是将用户态路径字符串(如/home/user/file.txt)转换为内核dentry + inode + vfsmount的核心过程,是open/stat/mkdir等几乎所有文件系统操作的入口,核心代码位于fs/namei.c
核心数据结构
1. struct dentry(目录项)
- 作用:建立路径分量名 → inode的映射,是 VFS 查找的核心缓存对象。
- 关键字段:
d_name:路径分量名(如home、file.txt)d_parent:父目录 dentryd_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. 路径分量拆分
按/分割为多个分量:home→user→file.txt;连续/视为一个;末尾/需特殊处理。
3. 逐层查找(核心:link_path_walk)
对每个非最终分量,循环执行:
- 权限检查:当前目录 dentry 对应的 inode 必须有执行权限(
X),否则返回-EACCES。 - 分量处理:
.:忽略,保持当前 dentry 不变。..:调用handle_dots()向上回溯父目录,处理挂载点跨越与根目录边界。- 普通名:进入lookup_fast → lookup_slow流程。
- 缓存查找(lookup_fast,RCU-walk):
- 以父 dentry + 分量名计算哈希,查dcache 哈希表。
- 命中:直接返回子 dentry,更新
nameidata,进入下一分量。 - 未命中 / 需重验证(如 NFS):降级到lookup_slow(REF-walk)。
- 慢速查找(lookup_slow):
- 持有父目录 inode 的
i_rwsem(读写信号量),防止并发修改。 - 再次查 dcache(避免竞争),仍未命中则调用父 inode 的 i_op->lookup ()(文件系统实现,如 ext4_lookup)。
- 从磁盘读取目录数据,创建新 dentry,关联 inode,加入 dcache。
- 持有父目录 inode 的
- 挂载点穿越(follow_managed):
- 若当前 dentry 标记
DCACHE_MOUNTED,调用lookup_mnt()切换到挂载文件系统的根 dentry。 - 自动挂载点(
DCACHE_NEED_AUTOMOUNT)触发d_automount()完成挂载。
- 若当前 dentry 标记
4. 最终分量处理
link_path_walk仅处理到倒数第二个分量,最终分量由上层函数处理:
path_lookupat(stat/chmod):对最终分量执行walk_component,返回目标 dentry。path_openat(open):处理O_CREAT/O_EXCL、末尾/、符号链接等,调用do_last()。path_parentat(mkdir/rmdir/unlink):返回父目录与最终分量名,用于创建 / 删除。
5. 完成查找
调用complete_walk(),释放 RCU 读锁,返回最终struct path(dentry + vfsmount)。
两种查找模式(性能关键)
1. RCU-walk(快速 / 懒查找)
- 机制:持有RCU 读锁,无锁遍历 dcache,依赖
d_seq序列号验证一致性。 - 特点:无锁、低延迟、适合热点路径;仅用缓存,不访问磁盘;遇到未命中 / 挂载 / 符号链接时降级到 REF-walk。
- 核心函数:
__d_lookup_rcu、lookup_fast。
2. REF-walk(慢速 / 引用查找)
- 机制:持有dentry 引用计数 + 锁(
d_lock/i_rwsem),确保数据稳定。 - 特点:安全、处理所有复杂场景(磁盘 I/O、符号链接、挂载);性能低于 RCU-walk。
- 核心函数:
lookup_slow、walk_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核心能力
- 相对 / 绝对路径统一解析,支持
AT_FDCWD相对当前目录、或指定 fd 作为起始目录,适配 openat/statat 系列系统调用。 - 逐级路径遍历,按
/拆分多级目录,逐个解析中间路径分量。 - 内置复杂规则处理,自动处理:
./..、符号链接递归解析、挂载点跨越、chroot 隔离。 - 双模式高速查找,优先 RCU 无锁快速查找(性能高),缓存未命中自动降级加锁慢速读取磁盘。
- 权限与安全控制,通过 lookup 标志限制:不许跨挂载、不许跳出父目录、不跟随软链接等,支撑容器 / 沙箱隔离。
关键依赖结构
struct nameidata
路径查找上下文容器,贯穿全程:
- 起始 / 当前
struct path - 查找标志、符号链接递归栈
- 序列锁、RCU 上下文、权限检查状态
struct path
struct path { struct vfsmount *mnt; struct dentry *dentry; };VFS 定位文件的唯一核心句柄。
与旧接口区别
- 废弃
path_lookup()- 不支持
dfd相对目录、不支持 modern 路径隔离 flag
- 不支持
path_lookupat优势- 支持at 系列语义(兼容
openat/statat) - 细粒度权限控制、容器 / 沙箱 目录隔离能力
- 统一 RCU/REF 双查找模式
- 支持at 系列语义(兼容