パス走査(親ディレクトリ/カレントディレクトリ)


システムファイル構成は、dentry間のリンクで実現していますが、異なるファイルシステムシステム間のリンクはされません。mountでデバイス(ファイルシステム)をバインドすると、マウントポイントのdentry->d_flagsが設定されるだけで、ファイルシステムのrootのdentryとリンクされません。

path検索では、dentryがマウントポイントなら、vfs_mntのリストを走査して、マウントポイントのvfs_mnt->mnt_mountpointと一致するvfs_mnを取得し、そのマウントルートをマウントポイントdentryと差し替えることで実現します。

従って、../の親ディレクトリを走査する場合、カレント及びその親が、マウントポイント(ファイルシステムのルート)なら、path検索とは逆にmntからdentryを取得することになります。

walk_component()で検索パスコンポーネントが、親/カレントディレクトリなら(typeがLAST_DOT/LAST_DOTDOTの時)、handle_dots()がコールされて復帰します。
static inline int walk_component(struct nameidata *nd, struct path *path,
               struct qstr *name, int type, int follow)
{
       struct inode *inode;
       int err;

       if (unlikely(type != LAST_NORM))
               return handle_dots(nd, type);
       err = do_lookup(nd, name, path, &inode);
       if (unlikely(err)) {
               terminate_walk(nd);
               return err;
       }
       if (!inode) {
               path_to_nameidata(path, nd);
               terminate_walk(nd);
               return -ENOENT;
       }
       if (should_follow_link(inode, follow)) {
               if (nd->flags & LOOKUP_RCU) {
                       if (unlikely(unlazy_walk(nd, path->dentry))) {
                               terminate_walk(nd);
                               return -ECHILD;
                       }
               }
               BUG_ON(inode != path->dentry->d_inode);
               return 1;
       }
       path_to_nameidata(path, nd);
       nd->inode = inode;
       return 0;
}
handle_dots()でカレント/親ディレクトリの処理となりますが、実装は親ディレクトリのみです。カレントディレクトリはパス移動の必要はありません。
static inline int handle_dots(struct nameidata *nd, int type)
{
       if (type == LAST_DOTDOT) {
               if (nd->flags & LOOKUP_RCU) {
                       if (follow_dotdot_rcu(nd))
                               return -ECHILD;
               } else
                       follow_dotdot(nd);
       }
       return 0;
}
nd->pathは検索起点のディレクトリです。まず、カレントルートを超えないようset_root()でnd->root=current->fsとします。

nd->pathがカレントルートなら、それ以上cdできません。nd->pathがファイルシステムのrootでないなら、dget_parent()でその親ディレクトリとなります。そうでないならディレクトリはファイルシステムのルートで、マウントポイントを取得するためfollow_up()をコールすることになります。follow_up()の返値が0なら、ルートファイルシステムです。

取得できた親ディレクトリがマウントポイントの場合、follow_mount()でマウント先のファイルシステムのrootが親ディレクトリとなります。
static void follow_dotdot(struct nameidata *nd)
{
       set_root(nd);

       while(1) {
               struct dentry *old = nd->path.dentry;

               if (nd->path.dentry == nd->root.dentry &&
                   nd->path.mnt == nd->root.mnt) {
                       break;
               }
               if (nd->path.dentry != nd->path.mnt->mnt_root) {
                       /* rare case of legitimate dget_parent()... */
                       nd->path.dentry = dget_parent(nd->path.dentry);
                       dput(old);
                       break;
               }
               if (!follow_up(&nd->path))
                       break;
       }
       follow_mount(&nd->path);
       nd->inode = nd->path.dentry->d_inode;
}

struct dentry *dget_parent(struct dentry *dentry)
{
       struct dentry *ret;

repeat:
       rcu_read_lock();
       ret = dentry->d_parent;
       spin_lock(&ret->d_lock);
       if (unlikely(ret != dentry->d_parent)) {
               spin_unlock(&ret->d_lock);
               rcu_read_unlock();
               goto repeat;
       }
       rcu_read_unlock();
       BUG_ON(!ret->d_count);
       ret->d_count++;
       spin_unlock(&ret->d_lock);
       return ret;
}
follow_mount()はpathのファイルシステムからマウントポイントを取得します。
int follow_up(struct path *path)
{
       struct mount *mnt = real_mount(path->mnt);
       struct mount *parent;
       struct dentry *mountpoint;

       br_read_lock(vfsmount_lock);
       parent = mnt->mnt_parent;
       if (&parent->mnt == path->mnt) {
               br_read_unlock(vfsmount_lock);
               return 0;
       }
       mntget(&parent->mnt);
       mountpoint = dget(mnt->mnt_mountpoint);
       br_read_unlock(vfsmount_lock);
       dput(path->dentry);
       path->dentry = mountpoint;
       mntput(path->mnt);
       path->mnt = &parent->mnt;
       return 1;
}
follow_mount()はマウントポイントからマウント先ファイルシステムのルートを取得します。
static void follow_mount(struct path *path)
{
       while (d_mountpoint(path->dentry)) {
               struct vfsmount *mounted = lookup_mnt(path);
               if (!mounted)
                       break;
               dput(path->dentry);
               mntput(path->mnt);
               path->mnt = mounted;
               path->dentry = dget(mounted->mnt_root);
       }
}

備考

親ディレクトリ/カレントディレクトリはext2についていえば、実inodeとして実装されており、walk_component()でhandle_dots()以降の通常のディレクトリ移動の実装でも問題はないかと思います。推測ですが、親ディレクトリ/カレントディレクトリはファイルシステムに依存し、システムによってはバーチャルディレクトリとしての実装(dentryコールバック)もありなのかな。と思います。


最終更新 2015/04/04 23:07:08 - north
(2015/04/04 23:07:08 作成)


検索

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