mount
Rev.2を表示中。最新版はこちら。
mountは「このマウントポイントのディレクトリーは、このファイルシステムのルートですよ。」とカーネルに指定するようなもので、この機能のおかげで、異なるファイルシステム間でも、それを意識することなくファイルを指定することが可能になっています。一見マジックみたいな機能ですが、かかるmount処理は、むしろ、「このディレクトリーは、マウントされてますよ。」と言った方が、的をえているような内容でした。mountのマウントポインタとマウントするファイルシステムの関係の処理は、マウントポインタのディレクトリdentry構造体のd_mountedメンバーをインクリメントしているだけです。それだけです。そしてファイルを検索する側で、もしそのディレクトリのdentry->d_mountedが0でないと、マウントしているファイルシステムを検索し、そのルートのdentryに差し替えることで、ファイルシステムツリー下(namespaceというようです。)で透過的にファイル指定を行うようになっています。
マウントしているファイルシステムは、mount時にハッシュテーブルとして登録されています。またマウントポイントdentryには、先に書いたように、マウントされている。のフラグだけで、実際のマウントしているファイルシステムの情報は設定されません。従ってmount時に、そのファイルシステムをハッシュテーブルに登録し、毎回そこから検索するようになっています。
通常のmountはdo_new_mountがコールされます。do_kern_mountはmountするファイルシステムを管理するvfsmount構造体を作成します。この構造体がマウントするファイルシステムそのもので、異なるファイルシステムの違いを吸収しています。そしてdo_add_mountで実際の処理へとなります。
static noinline int do_new_mount(struct nameidata *nd, char *type, int flags, int mnt_flags, char *name, void *data) { struct vfsmount *mnt; ・・・・・ mnt = do_kern_mount(type, flags, name, data); if (IS_ERR(mnt)) return PTR_ERR(mnt); return do_add_mount(mnt, &nd->path, mnt_flags, NULL); }do_add_mountでは各種エラーチェックをした後、vfsmount構造体をハッシュテーブルに登録したり、また各種リストへ登録しているようです。(この辺り今ひとつ見えません。)そして、mnt_set_mountpointで、マウントするvfsmount構造体の親にマウントポイントの属するvfsmountを、マウントするvfsmount構造体のマウントポイントに、マウントされるマウントポイントのdentryを設定しています。これはマウントされてるvfsmountを検索する際に必要です。そしてマウントポイントのディレクトリーのdentryのd_mountedをインクリメントしています。これが「このディレクトリーはマウントしてますよ。」ということです。
マウントポイントには、どのvfsmountがマウントされているかの情報はセットされません。d_mountedでなく、直接マウント先のvfsmountを設定すれば、vfsmountを検索する手間が省けるのに。と思いますが、マウントは同じマウントポインターに重複してマウントすることが可能となっています。すでにマウントされているマウントポインターに再度マウントすると、上のような処理は、マウントしているファイルシステムのルートディレクトリに施されます。そうすると前のマウントしているファイルシステムは、ただ隠れているだけで、最後にマウントしたファイルシステムをアンマウントすると、再度出現してくれるのです。もしマウントポインタのdentryに直接マウント先情報を設定していると、このようなことが実現できなくなってしまうからだと思います。
void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, struct vfsmount *child_mnt) { child_mnt->mnt_parent = mntget(mnt); child_mnt->mnt_mountpoint = dget(dentry); dentry->d_mounted++; }linuxでファイルを指定するというのは、そのファイルのdentry構造体を求めることです。この処理をおこなうのがlink_path_walk(本体は__link_path_walk)です。link_path_walkは与えられたパスをディレクトリ毎に切り出して、do_lookup関数で順番にそのdentryを求めながら、最終のディレクトリのdentryを取得するものです。そして、このdo_lookup内で取得したdentryが、マウントされているかどうかを __follow_mountでチェックしています。
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;__follow_mountではdentry->d_mountedが0でないなら、それはマウントディレクトリとして、対応するvfsmount構造体を取得し(ハッシュキーとしてマウントディレクトリのvfsmountとdentryのアドレス)、そのルートのdentryとvfsmountで設定しなおすことで、異なるファイルシステム間で透過的なファイル取得を実現しています。
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; }