【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk
点击(此处)折叠或打开
...
-
if (err) {
-
err = nested_symlink(&next, nd);
-
if (err)
-
return err;
- }
...
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > nested_symlink
点击(此处)折叠或打开
-
static inline int nested_symlink(struct path *path, struct nameidata *nd)
-
{
-
int res;
-
-
if (unlikely(current->link_count >= MAX_NESTED_LINKS)) {
-
path_put_conditional(path, nd);
-
path_put(&nd->path);
-
return -ELOOP;
-
}
-
BUG_ON(nd->depth >= MAX_NESTED_LINKS);
-
-
nd->depth++;
-
current->link_count++;
...
回到我们的旅程,这里先检查嵌套层数,一共有两个地方来对嵌套进行控制:一个是进程(1581);另一个是当前的“路径行走”(1586)。没问题的话就可以进行下一步了:
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > nested_symlink
点击(此处)折叠或打开
...
-
do {
-
struct path link = *path;
-
void *cookie;
-
-
res = follow_link(&link, nd, &cookie);
-
if (res)
-
break;
-
res = walk_component(nd, path, LOOKUP_FOLLOW);
-
put_link(nd, &link, cookie);
-
} while (res > 0);
...
现在就来验证我们的猜测:
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > nested_symlink > follow_link
点击(此处)折叠或打开
-
static __always_inline int
-
follow_link(struct path *link, struct nameidata *nd, void **p)
- {
...
-
error = -ELOOP;
-
if (unlikely(current->total_link_count >= 40))
-
goto out_put_nd_path;
-
-
cond_resched();
-
current->total_link_count++;
-
-
touch_atime(link);
-
nd_set_link(nd, NULL);
...
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > nested_symlink > follow_link
点击(此处)折叠或打开
...
-
nd->last_type = LAST_BIND;
-
*p = dentry->d_inode->i_op->follow_link(dentry, nd);
-
error = PTR_ERR(*p);
-
if (IS_ERR(*p))
- goto out_put_nd_path;
...
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > nested_symlink > follow_link
点击(此处)折叠或打开
...
-
error = 0;
-
s = nd_get_link(nd);
-
if (s) {
-
if (unlikely(IS_ERR(s))) {
-
path_put(&nd->path);
-
put_link(nd, link, *p);
-
return PTR_ERR(s);
-
}
-
if (*s == '/') {
-
set_root(nd);
-
path_put(&nd->path);
-
nd->path = nd->root;
-
path_get(&nd->root);
-
nd->flags |= LOOKUP_JUMPED;
-
}
-
nd->inode = nd->path.dentry->d_inode;
-
error = link_path_walk(s, nd);
-
if (unlikely(error))
-
put_link(nd, link, *p);
-
}
-
-
return error;
...
- }
举个例子,比如现在有一个符号链接“a”它指向一个目录“/tmp/dir/”,就像这样“a -> /tmp/dir/”。这个目录下还有一个文件“/tmp/dir/file”,这时有另一个符号链接“b”,我们把它指向“a/file”,就像这样“b -> a/file”。如果这时访问“b”,就会递归一次,因为“b”所指的路径中“a/”就是一个符号链接且是一个子路径。
通过这样的解释,大家应该了解在什么情况下会发生嵌套(递归)了吧。从 link_path_walk 返回之后,nd 应该已经“站在”最终目录等待着对最终目标的处理了。这正好应证了刚开始我们的猜测,接下来队最终目标的处理就会交给 walk_component,如果这个最终目标也是一个符号链接那么 walk_component 就会返回 1 并再一次 nested_symlink 里的 do-while 循环。
当最终目标不是符号链接的时候,nested_symlink 的使命也就完成了:
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > nested_symlink
点击(此处)折叠或打开
...
-
current->link_count--;
-
nd->depth--;
-
return res;
- }
现在符号链接我们也参观完毕了,那么 link_path_walk 也就结束了,接下来就要对打开最终目标了。