Linux中的一个进程在识别一个文件的时候,将文件名传递给VFS层,VFS要根据文件名查找这个文件的索引节点inode,以备后续对该文件的操作。通过文件名查找文件索引节点的过程就叫做路径查找(path lookup)。本文是在阅读目录查找代码时随手记录的笔记,会在不断的学习中不断补充。
路径查找的起始阶段,内核会从某一个特定的dentry开始查起,如果路径名是以‘/’开始,则起始的dentry是current->fs->root;否则,起始的dentry是current->fs->cwd。root和cwd在struct fs_struct中是一个<dentry, vfsmount>对,dentry表示目录对象,vfsmount表示一个文件系统对象。
路径查找开始后,内核从第一个dentry开始,找到它对应的索引节点;然后从磁盘读出包含那个索引节点的目录文件,获得索引节点。。。,反复执行上述操作,直到找到最后的文件。在上面的查找过程中,必须要考虑以下几点:
1,对获取到的inode的权限做审计和验证
2,因为查找目录对应的目录项对象是一个非常频繁且消耗IO的操作,内核在内存中维护了一个目录项高速缓存directory-entry cache,也叫dcache来加速查找目录项的过程。需要注意的是,从2.6版本起,dcache的通过RCU来减少锁竞争的开销,具体见这里http://www.linuxjournal.com/article/7124
3,当路径中遇到非本文件系统的挂载点时,需要扩展到该挂载点对应的文件系统来做目录查找
4,当路径中遇到符号链接时,也要做相应的处理
5,如果系统调用时一个create文件的操作,在查找的同时需要逐步创建各级目录
下面是具体实现的一些摘要
路径查找大代码绝大多数实现在fs/dcache.c fs/namei.c中,目录项对象struct dentry定义在include/linux/dcache.h中,其他一些与目录查找相关的结构体定义在include/linux/namei.h中。
路径名查找是由path_lookup函数执行的,它的调用方式如下:
int path_lookup(const char *name, unsigned int flags, struct nameidata *nd);
name是要解析的文件路径名,flags是一些标志,nd查找成功后的返回结果
struct nameidata {
struct path path; // 结构体path中是目录项对象的地址和文件系统对象的地址
struct qstr last; // 路径名的最后一个分量
struct path root;
struct file *file;
struct inode *inode; /* path.dentry.d_inode */
unsigned int flags;
unsigned seq;
int last_type;
unsigned depth; // 符号链接嵌套的当前级别
char *saved_names[MAX_NESTED_LINKS + 1]; // 与符号链接关联的路径数组
/* Intent data */
union {
struct open_intent open;
} intent;
};
参考文献:
1,linux2.6源代码
2,linux document: ./Document/filesystem/path_lookup.txt