【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 就可以睡眠了,那我們也休息一下,明天再接着去遊覽有趣的符號鏈接。