|
大家好,
我有一个关于路径查找的问题希望得到大家的帮助。
假设我们有如下的目录结构:
/home/a/b/c
/home/1/2/3/4/5/6/7
现在我们使用命令 ln -s /home/1/2/3/ /home/a/b/c/d_ln 在/home/a/b/c下生成一个符号连接d_ln, 并让这个连接指向/home/1/2/3.
然后,
cd /home/a/b/c/d_ln/4/5/6/../../../../
这时我们的当前目录被设成了 /home/a/b/c,可是根据代码,我们的当前目录应该是/home/1/2,因为nd->path被current->fs->root覆盖了(请查看do_follow_link()->__do_follow_link()->__vfs_follow_link()->walk_init_root())。那内核是如何回到/home/a/b/c的呢?
下面是一些关键的代码片断(Linux 2.6.26):
static int __link_path_walk(const char *name, struct nameidata *nd)
{
struct path next;
struct inode *inode;
int err;
........
if (this.name[0] == '.') switch (this.len) {
default:
break;
case 2:
if (this.name[1] != '.')
break;
follow_dotdot(nd); inode = nd->path.dentry->d_inode;
/* fallthrough */
case 1:
continue;
}
........
if (inode->i_op->follow_link) {
err = do_follow_link(&next, nd);
.......
}
static __always_inline void follow_dotdot(struct nameidata *nd)
{
.......
if (nd->path.dentry != nd->path.mnt->mnt_root) {
/* 在这里我们会把nd->path.dentry指向其父目录的dentry结构,那么
/home/a/b/c/d_ln/4 的d_parent到底是/home/a/b/c/d_ln 还是
/home/1/2/3 呢?
*/
nd->path.dentry = dget(nd->path.dentry->d_parent); spin_unlock(&dcache_lock);
dput(old);
break;
}
........
}
static inline int do_follow_link(struct path *path, struct nameidata *nd)
{
.......
err = __do_follow_link(path, nd);
......
}
static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd)
{
.......
error = __vfs_follow_link(nd, s);
......
}
static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
{
.......
if (*link == '/') {
path_put(&nd->path);
if (!walk_init_root(link, nd))
......
res = link_path_walk(link, nd);
}
static __always_inline int
walk_init_root(const char *name, struct nameidata *nd)
{
.......
//我们覆盖了之前访问的最后一个dentry(也就是d_ln的父目录c)
nd->path = fs->root;......
} |
|