vfsmountのリスト管理の検証(その2)


マウントのリスト管理の(その1)では、vfsmount構造体のmnt_mounts/mnt_childを検証してみました。ここではmnt_hashについてです。

マウントされているディレクトリを操作する時、そのマウント先のvfsmountを取得するわけですが、この時mnt_hashリストが参照されます。mnt_hashはmant_hashをノードとするヘッドになり、mount_hashtable下PAGE_SIZEの領域を有していて、その中にlist_head構造体が格納されています。list_head構造体は2つのポインタを持つメンバーですから、ページサイズを4K,ポインタサイズを4バイトとすると、500個のキーに対応するヘッドを、格納することが可能ということでしょうか。ハッシュ値はマウント先のvfsmount構造体のアドレスとマウントディレクトリのdentryのアドレスから算出されます。
struct list_head *head = mount_hashtable + hash(mnt, dentry);
パス検索でマウントされているディレクトリに遭遇する(dentryn->d_mount != 0)と、その時のvfsmountとdentryで、瞬時にマウント先vfsmountが取得できるわけです。

実は先の内容と今回の内容にあたって、この事ゆえに検証してみようと思いたちました。500個のハッシュ値を有していて、確かにキーの衝突の可能性はあるものの、マウントという性格上、数百もマウントするようなケースがあるのだろうか?と、なにか他に意図があるのではと。

で、思ったのは、mountのmountとしたケースです。後でmountしたファイルシステムも、指定したマウント先(大元のファイルシステム)dentryのファイルシステム下として、マウントされるものと。そうなれば、この2つハッシュキーは同じになり、それをヘッドとしてリストされる事になります。複数のファイルシステムがマウントされても、リストの最後が最終マウント先として取得することができます。

このような実装だと、後のファイルシステムをmountしたまま、先のファイルシステムをumountできる事になります。

試してみると、最初にマウントしたファイルシステムはumountできませんでした。そうなると、後のマウント先は、最初にmountしたファイルシステムにmountされるのではないかと推測できます。
[root@localhost kitamura]# mount disk1 /mnt/mntpoint
[root@localhost kitamura]# mount disk2 /mnt/mntpoint
[root@localhost kitamura]# umount disk1
umount: cannot unmount /tmp/kitamura/disk1 -- /tmp/kitamura/disk2 is mounted over it on the same point
一つだけのマウントの場合
[root@localhost kitamura]# mount disk1 /mnt/mntpoint
[root@localhost kitamura]# insmod testmod.ko ; dmesg ; rmmod testmod.ko
    :
[  256.725177] ceeeba00:parent mnt point[/]:mnt point[mntpoint]
[  256.725366] cec20698:hash hea
重ねてマウントした場合
[root@localhost kitamura]# mount disk2 /mnt/mntpoint
[root@localhost kitamura]# insmod testmod.ko ; dmesg ; rmmod testmod.ko
    :
[ 1157.846838] ccbeb600:parent mnt point[mntpoint]:mnt point[/]
[ 1157.847170] cec20c68:hash head
重ねてマウントした場合とそうでない場合、hash headが異なっています。そして重ねマウントの親ファイルシステムのマウント先はmntpoint、これは先にマウントしたファイルシステムと言う事です。そしてマウントポイントの/は、先にマウントしたファイルシステムの/にマウントしていると言う事です。

先のソースとほぼ同じです。なおpath_lookup()では最後にマウントしたvfsmountが返ってきます。mnt_hashリストの走査において、ヘッドから行っていません。(実はヘッドからと思いましたが。)ヘッドとなるmount_hashtableはnamespace.cでstatic変数で定義されていて、他から参照できないようになっています。
#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);

static int test_init(void)
{
   struct nameidata nd;

   int err = path_lookup("/mnt/mntpoint", LOOKUP_FOLLOW, &nd);
   if (err) {
       printk("path_look err.\n");
       return -1;
      }
   get_mntinfo(nd.path.mnt);
   path_put(&nd.path);
   return 0;
}

static int get_mntinfo(struct vfsmount  *mnt)
{
   struct vfsmount  *mnt_hash;
   struct list_head *p, *head;
   int		cnt = 0;

   p = head = &mnt->mnt_hash;
   for (;;) {
       mnt_hash = list_entry(p, struct vfsmount, mnt_hash);
       if (p->next == head) {
           printk("%x:%s\n", p, "hash head");
           break;
       }
       printk("%x:parent mnt point[%s]:mnt point[%s]\n", p,  
               mnt_hash->mnt_parent->mnt_mountpoint->d_name.name,
               mnt_hash->mnt_mountpoint->d_name.name);
       p = p->next;
   }
}

static void test_exit(void)
{
}

module_init(test_init);
module_exit(test_exit);

補足

最後にpath_put(&nd.path)を呼び出しているのはumountする上で重要です。path_lookupで取得したstruct nameidata ndのvfsmountに使用中のフラグが設定され、そのファイルシステムがummountできなくなります。何回もrebootとする羽目になってしまいました。

なお、mnt_hashのお陰で、数百のオーダでmountしてるシステムでも、瞬時にマウント先を検索できるわけです。

mnt_hashノードの検索で、リスト故、ループとしていますが、ループとなることは、少なくとも通常の環境では、まず無いと思います。

最終更新 2012/01/23 17:59:42 - north
(2012/01/23 17:44:51 作成)


検索

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