リンクの検索


Rev.1を表示中。最新版はこちら

パスの検索の処理の本体は__link_path_walk()となります。引数のnameは検索するパスで、ndは検索対象となっているパスの情報(dentryとか)が設定されています。この処理nameをパスごとに区切りながら、順にdentryを求めていくものです。なお、./および../の処置とか、キャッシュ上にあるdentryの検索を高速にするため、そのパスのハッシュを設定する処理があったりしています。ここではリンクの処理に限定しています。

__link_path_walk()のforループの上段で、nameから順に区切ったパスがthisに設定され、do_lookup()をコールします。do_lookup()ではndのdentry下でthisのパスをキャシュないし実デバイスを読み込むことで検索します。検索した結果はnextに設定されます。

検索したnextのinodeを調べます。inode->i_op->follow_linkが0でないなら、このdentryはリンクということになります。そしてdo_follow_link()をコールします。ここではnextを展開してその結果がndに設定されてきます。そしてこのndでもって次のパス区切りを検索するということです。
static int __link_path_walk(const char *name, struct nameidata *nd)
{
   :
       for(;;) {
               err = exec_permission_lite(inode);
               if (err == -EAGAIN)
                       err = vfs_permission(nd, MAY_EXEC);
               if (err)
                       break;
   :
               err = do_lookup(nd, &this, &next);
               if (err)
                       break;

               err = -ENOENT;
               inode = next.dentry->d_inode;
   :
               if (inode->i_op->follow_link) {
                       err = do_follow_link(&next, nd);
                       if (err)
                               goto return_err;
                       err = -ENOENT;
                       inode = nd->path.dentry->d_inode;
                       if (!inode)
                               break;
                       err = -ENOTDIR; 
                       if (!inode->i_op)
                               break;
               } else
  :

}
do_follow_link()はリンク処理にトップ関数となります。ここではまず、current->link_count/current->total_link_countによるチェックが行われています。リンクの実際の処理は下段の__do_follow_link()です。この関数をコールする前に先の2つのカウンターはインクリメントされています。そして__do_follow_link()から戻ると、current->link_countのみデクリメントしています。

__do_follow_link()はリンク先がリンクの場合、再帰的にコールされます。そのためのチェックがcurrent->link_countカウンタです。従ってリンク先がリンク、そしてその先がリンクというのは、MAX_NESTED_LINKS=8を超えて設定できないということです。

current->total_link_countは全リンク数です。トップ関数で指定されたパスのリンク数は40を超えてはならないということです。
enum { MAX_NESTED_LINKS = 8 };
static inline int do_follow_link(struct path *path, struct nameidata *nd)
{
       int err = -ELOOP;
       if (current->link_count >= MAX_NESTED_LINKS)
               goto loop;
       if (current->total_link_count >= 40)
               goto loop;
       BUG_ON(nd->depth >= MAX_NESTED_LINKS);
       cond_resched();
       err = security_inode_follow_link(path->dentry, nd);
       if (err)
               goto loop;
       current->link_count++;
       current->total_link_count++;
       nd->depth++;
       err = __do_follow_link(path, nd);
       current->link_count--;
       nd->depth--;
       return err;
loop:
       path_put_conditional(path, nd);
       path_put(&nd->path);
       return err;
}
__do_follow_link()で実リンク先を読み込みます。これはinodeオペレーションのfollow_linkコールバック関数をコールする事で行っています。この関数はinodeを取得する時に、ファイルシステムおよびハードリンク/シンボリックリンクに応じたコールバック関数が設定されていて、結果はdentryのキャッシュページおよび、リンク先がまたリンクなら、そのリンク先がnd->saved_names[]に返されます。

nd_get_link()でnd->saved_names[]のリンク先を取得します。NULLで無いならリンク先はリンクです。__vfs_follow_link()コールし、そこから再度link_path_walk()を再帰的にコールしています。
static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd)
{
       int error;
       void *cookie;
       struct dentry *dentry = path->dentry;

       touch_atime(path->mnt, dentry);
       nd_set_link(nd, NULL);

       if (path->mnt != nd->path.mnt) {
               path_to_nameidata(path, nd);
               dget(dentry);
       }
       mntget(path->mnt);
       cookie = dentry->d_inode->i_op->follow_link(dentry, nd);
       error = PTR_ERR(cookie);
       if (!IS_ERR(cookie)) {
               char *s = nd_get_link(nd);
               error = 0;
               if (s)
                       error = __vfs_follow_link(nd, s);
               if (dentry->d_inode->i_op->put_link)
                       dentry->d_inode->i_op->put_link(dentry, nd, cookie);
       }
       path_put(path);

       return error;
}

static inline char *nd_get_link(struct nameidata *nd)
{
       return nd->saved_names[nd->depth];
}

static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
{
       int res = 0;
       char *name;
       if (IS_ERR(link))
               goto fail;

       if (*link == '/') {
               path_put(&nd->path);
               walk_init_root(link, nd);
       }
       res = link_path_walk(link, nd);
   :
}

補足

__link_path_walk()でパス区切りを一つづつチェックする祭、MAY_EXEC属性をチェックしています。ディレクトリの実行属性とは、先のパスを検索できるかどうかのようです。


最終更新 2011/08/09 16:20:11 - north
(2011/08/09 16:20:11 作成)


検索

アクセス数
3689562
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。