【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > walk_component
点击(此处)折叠或打开
...
-
err = lookup_fast(nd, path, &inode);
-
if (unlikely(err)) {
-
if (err < 0)
-
goto out_err;
-
-
err = lookup_slow(nd, path);
-
if (err < 0)
-
goto out_err;
-
-
inode = path->dentry->d_inode;
-
}
-
err = -ENOENT;
-
if (!inode || d_is_negative(path->dentry))
-
goto out_path_put;
...
我们这就进入 lookup_fast,看看它到底有多快。
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > walk_component > lookup_fast
点击(此处)折叠或打开
-
static int lookup_fast(struct nameidata *nd,
-
struct path *path, struct inode **inode)
- {
...
-
if (nd->flags & LOOKUP_RCU) {
-
unsigned seq;
-
dentry = __d_lookup_rcu(parent, &nd->last, &seq);
-
if (!dentry)
-
goto unlazy;
...
-
*inode = dentry->d_inode;
-
if (read_seqcount_retry(&dentry->d_seq, seq))
-
return -ECHILD;
...
-
if (__read_seqcount_retry(&parent->d_seq, nd->seq))
-
return -ECHILD;
-
nd->seq = seq;
...
-
path->mnt = mnt;
-
path->dentry = dentry;
-
if (unlikely(!__follow_mount_rcu(nd, path, inode)))
-
goto unlazy;
-
if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
-
goto unlazy;
-
return 0;
-
unlazy:
-
if (unlazy_walk(nd, dentry))
-
return -ECHILD;
- } else {
...
如果顺利找到了目标 dentry 则还需要进行一系列的检查(1381、1391)确保在我们做读取操作的期间没有人对这些结构进行改动。然后就是更新临时变量 path,为啥不更新 nd 呢?别忘了 nd 是很有脾气的,挂载点和符号链接人家都看不上,非真正目录不嫁。而这个时候还不知道这个目标是不是一个挂载点,如果是挂载点则还需要沿着被挂载的 mount 结构走到真正的目标上;退一步来说,就算这个目标不是挂载点,但它要是具备自动挂载特性呢(1407);再退一步来说,它是不是符号链接我们也不知道,所以现在先不忙着更新 nd。紧接着就通过 __follow_mount_rcu 跨过挂载点这些“伪目标”(1405),这个函数和上一篇里 follow_dotdot_rcu 的第二部分很相似我们就不深入进去了,有兴趣的同学结合代码自己研究一下就好了。如果一切顺利返回 0,请参考上面 walk_component 的代码,如果返回 0 就会跳过 1535 行那个 if,这也就是说在 rcu-walk 模式下是不会启动 lookup_slow 的。
那么什么时候才会启动 lookup_slow 呢?咱们接着往下看:
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > walk_component > lookup_fast
点击(此处)折叠或打开
...
-
unlazy:
-
if (unlazy_walk(nd, dentry))
-
return -ECHILD;
-
} else {
-
dentry = __d_lookup(parent, &nd->last);
-
}
-
-
if (unlikely(!dentry))
-
goto need_lookup;
...
-
path->mnt = mnt;
-
path->dentry = dentry;
-
err = follow_managed(path, nd->flags);
-
if (unlikely(err < 0)) {
-
path_put_conditional(path, nd);
-
return err;
-
}
-
if (err)
-
nd->flags |= LOOKUP_JUMPED;
-
*inode = path->dentry->d_inode;
-
return 0;
-
-
need_lookup:
-
return 1;
- }
接下来我们就来看看 lookup_slow:
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > walk_component > lookup_slow
点击(此处)折叠或打开
-
static int lookup_slow(struct nameidata *nd, struct path *path)
- {
...
-
mutex_lock(&parent->d_inode->i_mutex);
-
dentry = __lookup_hash(&nd->last, parent, nd->flags);
- mutex_unlock(&parent->d_inode->i_mutex);
...
- }
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > walk_component > lookup_slow > __lookup_hash
点击(此处)折叠或打开
-
static struct dentry *__lookup_hash(struct qstr *name,
-
struct dentry *base, unsigned int flags)
-
{
-
bool need_lookup;
-
struct dentry *dentry;
-
-
dentry = lookup_dcache(name, base, flags, &need_lookup);
-
if (!need_lookup)
-
return dentry;
-
-
return lookup_real(base->d_inode, dentry, flags);
- }
lookup_slow 剩下的工作和 fast 差不多,这里就不重复了。现在回到 walk_component:
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > link_path_walk > walk_component
点击(此处)折叠或打开
...
-
if (should_follow_link(path->dentry, follow)) {
-
if (nd->flags & LOOKUP_RCU) {
-
if (unlikely(unlazy_walk(nd, path->dentry))) {
-
err = -ECHILD;
-
goto out_err;
-
}
-
}
-
BUG_ON(inode != path->dentry->d_inode);
-
return 1;
-
}
-
path_to_nameidata(path, nd);
-
nd->inode = inode;
-
return 0;
...
- }
既然退出 rcu-walk 就可以睡眠了,那我们也休息一下,明天再接着去游览有趣的符号链接。