マウントの検索
Rev.1を表示中。最新版はこちら。
パスの検索は、__link_path_walk()で指定されたパスの先頭からのdentryを、順次取得することで行っていました。そのパス区切りのdentryを取得するのがdo_lookup()です。ndは目的のパスの親で、nameが取得するパス、そしてpathにはそのdentry等の結果が設定されます。__d_lookup()はdentryのハッシュリストからnameのdentryの取得します。取得できない場合、goto need_lookupとreal_lookup()で実デバイスを読み込むことでdentryを取得します。どちらにしろdone:ラベル以降に処理が進みます。(マウントポイントの場合は__d_lookup()で必ず取得できると思われます。)
取得したdentryを結果を返す引数の、path->mnt/path->dentryに設定しています。そしてこのdentryがマウントされているかのチェックが__follow_mount()で行われます。この関数でこのdentryがマウントポジションかどうかということです。
static int do_lookup(struct nameidata *nd, struct qstr *name, struct path *path) { struct vfsmount *mnt = nd->path.mnt; struct dentry *dentry = __d_lookup(nd->path.dentry, name); if (!dentry) goto need_lookup; if (dentry->d_op && dentry->d_op->d_revalidate) goto need_revalidate; done: path->mnt = mnt; path->dentry = dentry; __follow_mount(path); return 0; need_lookup: dentry = real_lookup(nd->path.dentry, name, nd); if (IS_ERR(dentry)) goto fail; goto done; : }dentryがマウントされているかどうかは、d_mountpoint()で行い、dentry->d_mountedが0でないならマウントポイントと言うことです。なおmountされるたびにd_mountedはインクリメントされます。
補足(推測です。)
dentryはキャッシュで、これはその時のシステムの動作環境に依存するわけです。したがってこの内容はinodeに反映されません。これはマウントポイントがinodeに反映されないことを意味します。もし反映されたら、そのハードディスクを別のシステムで動作させる場合、不都合が起きてしまいます。したがってマウントされたdentryは、システムが稼動中、キャッシュから破棄されることは無いと考えられます。dentryがマウントポイントならlookup_mnt()でマウントしているファイルシステムを取得し、path->mnt = mountedでマウント先のファイルシステムを、path->dentry = dget(mounted->mnt_root)でマウント先(通常はルート)を設定します。なおwhileでループしているのはマウント先がマウントポイントも有り得るからです。
static int __follow_mount(struct path *path) { int res = 0; while (d_mountpoint(path->dentry)) { struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry); if (!mounted) break; dput(path->dentry); if (res) mntput(path->mnt); path->mnt = mounted; path->dentry = dget(mounted->mnt_root); res = 1; } return res; } static inline int d_mountpoint(struct dentry *dentry) { return dentry->d_mounted; }lookup_mnt()は_lookup_mnt()をコールする事で、マウント先のファイルシステムを取得します。__lookup_mnt()は、マウントポジションのdentryおよび、そのの属するvfsmntをキーとするハッシュテーブルを、親vfsmnt/マウントポイントが、引数で指定されたmnt/dentryと同じものを取得することで行っています。
struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) { struct vfsmount *child_mnt; spin_lock(&vfsmount_lock); if ((child_mnt = __lookup_mnt(mnt, dentry, 1))) mntget(child_mnt); spin_unlock(&vfsmount_lock); return child_mnt; } struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, int dir) { struct list_head *head = mount_hashtable + hash(mnt, dentry); struct list_head *tmp = head; struct vfsmount *p, *found = NULL; for (;;) { tmp = dir ? tmp->next : tmp->prev; p = NULL; if (tmp == head) break; p = list_entry(tmp, struct vfsmount, mnt_hash); if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) { found = p; break; } } return found; }