RBINDオプションでのmount


Rev.3を表示中。最新版はこちら

BINDマウントは、マウントするファイルシステム下にマウントされているファイルシステムを参照する事はできません。

/tmp/hogehogeに/をbindマウント(/sysはsysfsがマウントされていています。)
[root@localhost tmp]# mount --bind / hogehoge/
/は/tmp/hogehoge/にマウントされている
[root@localhost tmp]# ls /
bin      dev   lib         mnt   proc    run   srv      tmp  var
boot     etc   lost+found  mnt1  pstore  sbin  sys      usr
debugfs  home  media       opt   root    sd    sysroot  va

[root@localhost tmp]# ls hogehoge/
bin      dev   lib         mnt   proc    run   srv      tmp  var
boot     etc   lost+found  mnt1  pstore  sbin  sys      usr
debugfs  home  media       opt   root    sd    sysroot  va
/hogehoge/sysはマウントされていない。
[root@localhost tmp]# ls /sys
block  class  devices   fs      module
bus    dev    firmware  kernel  power

[root@localhost tmp]# ls hogehoge/sys
[root@localhost tmp]#
これは、path_lookup()のパス検索において、dentryがマウントされていると、follow_mount()からlookup_mnt()とコールされ、検索するmntとdentryのハッシュキーをインデックスとするmount_hashtable[]をヘッドするリストを走査することでmntを検索しているからです。/sysと/tmp/hogehogeのdentryは別物で、/sys下のマウントリンクは、/tmp/hogehogeをハッシュとするヘッドにリストされてないからです。

bindマウントにおいて、マウントするファイルシステム下にマウントされているファイルシステムも、改めてマウントし直すことで、新しい参照されるdentryでハッシュテーブルにリストされ、従ってサブマウントされているファイルシステム下のファイルも参照することが可能となります。これを実現するのがrbindです。下記のように/tmp/hogehogeに/をrbindマウントさせれば/sysもマウントされ、それを参照することが可能となります。
[root@localhost tmp]# mount --rbind / hogehoge/

[root@localhost tmp]# ls /sys
block  class  devices   fs      module
bus    dev    firmware  kernel  power
[root@localhost tmp]# ls hogehoge/sys
block  class  devices   fs      module
bus    dev    firmware  kernel  power
rbindでmountすると、sys_mountシステムコールのフラグに、MS_BINDとMS_RECが設定され、do_mount()をコールされ、do_loopback()の第3パラメータが1でコールされます。
long do_mount(char * dev_name, char * dir_name, char *type_page,
                 unsigned long flags, void *data_page)
{
  :
       if (flags & MS_REMOUNT)
               retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
                                   data_page);
       else if (flags & MS_BIND)
               retval = do_loopback(&nd, dev_name, flags & MS_REC);
       else if (flags & MS_MOVE)
               retval = do_move_mount(&nd, dev_name);
       else
               retval = do_add_mount(&nd, type_page, flags, mnt_flags,
                                     dev_name, data_page);
dput_out:
       path_release(&nd);
       return retval;
}
do_loopback()は、マウントされるパスのstruct nameidataのmntとdentryで、新規にvfsmntを作成し、graft_tree()で、このvfsmntをそれぞれにリスト化し、マウント先のdentryにバインドすることにあります。

ここで、RBIND時は recurse=1となります。この時copy_tree()によりvfsmntを取得します。
static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
{
       struct nameidata old_nd;
       struct vfsmount *mnt = NULL;
       int err = mount_is_safe(nd);
       if (err)
               return err;
       if (!old_name || !*old_name)
               return -EINVAL;
       err = path_lookup(old_name, LOOKUP_FOLLOW, &old_nd);
       if (err)
               return err;

       down_write(&current->namespace->sem);
       err = -EINVAL;
       if (check_mnt(nd->mnt) && (!recurse || check_mnt(old_nd.mnt))) {
               err = -ENOMEM;
               if (recurse)
                       mnt = copy_tree(old_nd.mnt, old_nd.dentry);
               else
                       mnt = clone_mnt(old_nd.mnt, old_nd.dentry);
       }

       if (mnt) {
               err = graft_tree(mnt, nd);
               if (err) {
                       spin_lock(&vfsmount_lock);
                       umount_tree(mnt);
                       spin_unlock(&vfsmount_lock);
               } else
                       mntput(mnt);
       }

       up_write(&current->namespace->sem);
       path_release(&old_nd);
       return err;
}
clone_mnt()は、マウントするパスの属するvfsmountをそのまま設定し、スーパブロックの参照カウンタをインクリメントているに過ぎません。なお、mnt_mountpointはgraft_tree()で、マウント先dentryに更新されます。
static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root)
{
       struct super_block *sb = old->mnt_sb;
       struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);

       if (mnt) {
               mnt->mnt_flags = old->mnt_flags;
               atomic_inc(&sb->s_active);
               mnt->mnt_sb = sb;
               mnt->mnt_root = dget(root);
               mnt->mnt_mountpoint = mnt->mnt_root;
               mnt->mnt_parent = mnt;
       }
       return mnt;
}
copy_tree()は、ターゲットとなるファイルシステムにぶらさがる全てのファイルシステムを走査し、その1つ1つをまた、走査しながら、マウントされていないファイルシステムに行き着いて、それをclone_mnt()で新規にvfsmountを取得し、改めてマウントしているようです。これをマウント先のdentryをハッシュとしてリスト化され、このdentryからファイルシステムを検索する事が可能となるわけです。
static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry)
{
       struct vfsmount *res, *p, *q, *r, *s;
       struct list_head *h;
       struct nameidata nd;

       res = q = clone_mnt(mnt, dentry);
       if (!q)
               goto Enomem;
       q->mnt_mountpoint = mnt->mnt_mountpoint;

       p = mnt;
       for (h = mnt->mnt_mounts.next; h != &mnt->mnt_mounts; h = h->next) {
               r = list_entry(h, struct vfsmount, mnt_child);
               if (!lives_below_in_same_fs(r->mnt_mountpoint, dentry))
                       continue;

               for (s = r; s; s = next_mnt(s, r)) {
                       while (p != s->mnt_parent) {
                               p = p->mnt_parent;
                               q = q->mnt_parent;
                       }
                       p = s;
                       nd.mnt = q;
                       nd.dentry = p->mnt_mountpoint;
                       q = clone_mnt(p, p->mnt_root);
                       if (!q)
                               goto Enomem;
                       spin_lock(&vfsmount_lock);
                       list_add_tail(&q->mnt_list, &res->mnt_list);
                       attach_mnt(q, &nd);
                       spin_unlock(&vfsmount_lock);
               }
       }
       return res;
Enomem:
       if (res) {
               spin_lock(&vfsmount_lock);
               umount_tree(res);
               spin_unlock(&vfsmount_lock);
       }
       return NULL;
}
正直vfsmountのリスト管理の扱いが、今ひとつ読みきれていません。


最終更新 2013/06/14 23:24:34 - north
(2013/06/14 23:19:46 作成)


検索

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