vfsmountのリスト管理の検証(その1)
システム下のマウントのリスト管理では、vfsmount構造体のstruct list_headのmnt_mounts/mnt_child/mnt_hashの3つのメンバーが重要な役割を担っています。mnt_mountはその配下にマウントされている、ファイルシステムのリストのヘッドとなり、配下のファイルシステムはmnt_childをノードとしてリストされていきます。ここではまずmnt_mounts/mnt_childについてです。
以下のサンプルは、ルートファイルシステムをヘッドとして、mnt_mounts/mnt_childの関係を検証するものです。始めのループバックのマウントは上の検証結果をわかりやすくするためのものです。
get_mntinfo()では、まずは以下のファイルシステムをリストしているヘッドを取得し、それにリストされているvfsmountを求めるだけです。なおこれにリストされているノードは、mnt_mountsでなくmnt_childという事です。mnt_childが見つかる毎に、それでもっとget_mntinfo()をコールするだけです。mnt_child->nextがトップと同じなら、一巡したと言うことで、それ以上ノードはないと言うことです。
しかし、そのような実装にはなっていません。もし上記の実装だと、配下の全子プロセスをチェックする必要があります。また、mountのmountと言った機能が実現できません。mnt_mounts/mnt_childではマウント順序という管理ができていないからです。そこで参照されるのがmnt_hashになります。
以下のサンプルは、ルートファイルシステムをヘッドとして、mnt_mounts/mnt_childの関係を検証するものです。始めのループバックのマウントは上の検証結果をわかりやすくするためのものです。
[root@localhost kitamura]# mkdir /mnt/mntpoint1 [root@localhost kitamura]# mkdir /mnt/mntpoint2 [root@localhost kitamura]# mkdir /mnt/mntpoint3 [root@localhost kitamura]# mkdir /mnt/mntpoint1/mntpoint11 [root@localhost kitamura]# mkdir /mnt/mntpoint1/mntpoint12 [root@localhost kitamura]# mkdir /mnt/mntpoint1/mntpoint13 [root@localhost kitamura]# mkdir /mnt/mntpoint2/mntpoint21 [root@localhost kitamura]# mkdir /mnt/mntpoint2/mntpoint22 [root@localhost kitamura]# mount disk /mnt/mntpoint1 [root@localhost kitamura]# mount disk /mnt/mntpoint2 [root@localhost kitamura]# mount disk /mnt/mntpoint3 [root@localhost kitamura]# mount disk /mnt/mntpoint1/mntpoint11 [root@localhost kitamura]# mount disk /mnt/mntpoint1/mntpoint12 [root@localhost kitamura]# mount disk /mnt/mntpoint1/mntpoint13 [root@localhost kitamura]# mount disk /mnt/mntpoint1/mntpoint21 [root@localhost kitamura]# mount disk /mnt/mntpoint2/mntpoint22 [root@localhost kitamura]# insmod testmod.ko [root@localhost kitamura]# dmesg : : [ 4316.028006] selinux [ 4316.028446] dev [ 4316.028672] / [ 4316.028819] pts [ 4316.028860] shm [ 4316.029077] proc [ 4316.029093] usb [ 4316.029111] binfmt_misc [ 4316.029131] sys [ 4316.029143] boot [ 4316.029568] rpc_pipefs [ 4316.029587] mntpoint1 [ 4316.029600] mntpoint11 [ 4316.029617] mntpoint12 [ 4316.029634] mntpoint13 [ 4316.029653] mntpoint2 [ 4316.029666] mntpoint21 [ 4316.029683] mntpoint22 [ 4316.029702] mntpoint3path_lookup()でルートファイルシステムのvfsmountを取得し、get_mntinfo()をコールします。なおこの関数は再帰処理となっています。
get_mntinfo()では、まずは以下のファイルシステムをリストしているヘッドを取得し、それにリストされているvfsmountを求めるだけです。なおこれにリストされているノードは、mnt_mountsでなくmnt_childという事です。mnt_childが見つかる毎に、それでもっとget_mntinfo()をコールするだけです。mnt_child->nextがトップと同じなら、一巡したと言うことで、それ以上ノードはないと言うことです。
#include <linux/init.h> #include <linux/module.h> #include <linux/namei.h> #include <linux/kernel.h> #include <linux/dcache.h> #include <linux/mnt_namespace.h> #include <linux/mount.h> #include <linux/path.h> #include <linux/fcntl.h> #include <linux/list.h> #include <linux/fs.h> MODULE_LICENSE("GPL"); static int get_mntinfo(struct vfsmount *mnt, int depth); static void prn_space(int space); static int test_init(void) { struct nameidata nd; int err = path_lookup("/", LOOKUP_FOLLOW, &nd); if (err) { printk("path_look err.\n"); return -1; } get_mntinfo(nd.path.mnt, 0); return 0; } static int get_mntinfo(struct vfsmount *mnt, int depth) { struct vfsmount *mnt_child; sruct list_head *p, *head; p = head = &mnt->mnt_mounts; p = p->next; for (;;) { mnt_child = list_entry(p, struct vfsmount, mnt_child); prn_space(depth); printk("%s\n", mnt_child->mnt_mountpoint->d_name.name); if(mnt_child->mnt_mounts.next != &mnt_child->mnt_mounts) { depth = get_mntinfo(mnt_child, ++depth); } p = p->next; if (head == p) break; } return --depth; } static void prn_space(int space) { int i; for(i = 0; i < space; i++) { printk(" "); } } static void test_exit(void) { } module_init(test_init); module_exit(test_exit);ディレクトリを検索で、マウントされているディレクトリに遭遇すると、このようにファイルシステム配下の子ファイルシステムのマウントポイントを調べる事で、マウントされたのディレクトリを渡って行くことができそうです。
しかし、そのような実装にはなっていません。もし上記の実装だと、配下の全子プロセスをチェックする必要があります。また、mountのmountと言った機能が実現できません。mnt_mounts/mnt_childではマウント順序という管理ができていないからです。そこで参照されるのがmnt_hashになります。