RBINDオプションでのmount


rbindのmountはmountフラグのMS_BINDにMS_RECが付加されdo_loopback()をTRUEでコールする事で、bindのclone_mnt()をcopy_tree()でその配下のmountも実装されます。

mountは、そのdentryがdentry->d_flags | DCACHE_MOUNTEDで、dentryが属するmnt/dentryをハッシュキーとしてmount_hashtable[]に登録する事で実装されます。取得したmntからそのmnt->root_mntを次の走査元のdentryとして捜査します。結果的にシンボリックリンクと同じですが、シンボリックされたdentryのmntは元のmntですが、bindのmntは元のmntと違うという事で、配下のdentryはdentry->d_flags | DCACHE_MOUNTEDとなっているものの、そのmntはmount_hashtable[]に登録されていないため、mount先え参照できません。

__follow_mount_rcu()はpath走査時、各dentry毎にmountされているかチェックするためにコールされます。
static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                              struct inode **inode)
{
       for (;;) {
               struct mount *mounted;

               if (unlikely(managed_dentry_might_block(path->dentry)))
                       return false;

               if (!d_mountpoint(path->dentry))
                       break;

               mounted = __lookup_mnt(path->mnt, path->dentry, 1);
               if (!mounted)
                       break;
               path->mnt = &mounted->mnt;
               path->dentry = mounted->mnt.mnt_root;
               nd->flags |= LOOKUP_JUMPED;
               nd->seq = read_seqcount_begin(&path->dentry->d_seq);

               *inode = path->dentry->d_inode;
       }
       return true;
}

static inline bool d_mountpoint(struct dentry *dentry)
{
       return dentry->d_flags & DCACHE_MOUNTED;
}

struct mount *__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 mount *p, *found = NULL;

       for (;;) {
               tmp = dir ? tmp->next : tmp->prev;
               p = NULL;
               if (tmp == head)
                       break;
               p = list_entry(tmp, struct mount, mnt_hash);
               if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) {
                       found = p;
                       break;
               }
       }
       return found;
}
copy_tree()はmnt配下(mnt->mnt_child)のdentry配下のmountもclone_mnt()でバーチャルファイルシステムのmntを作成し、attach_mnt()でバーチャルファイルシステムのmntとして、元のdentryにmountします。
struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
                                       int flag)
{
       struct mount *res, *p, *q, *r;
       struct path path;

       if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt))
               return NULL;

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

       p = mnt;
       list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) {
               struct mount *s;
               if (!is_subdir(r->mnt_mountpoint, dentry))
                       continue;

               for (s = r; s; s = next_mnt(s, r)) {
                       if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(s)) {
                               s = skip_mnt_tree(s);
                               continue;
                       }
                       while (p != s->mnt_parent) {
                               p = p->mnt_parent;
                               q = q->mnt_parent;
                       }
                       p = s;
                       path.mnt = &q->mnt;
                       path.dentry = p->mnt_mountpoint;
                       q = clone_mnt(p, p->mnt.mnt_root, flag);
                       if (!q)
                               goto Enomem;
                       br_write_lock(vfsmount_lock);
                       list_add_tail(&q->mnt_list, &res->mnt_list);
                       attach_mnt(q, &path);
                       br_write_unlock(vfsmount_lock);
               }
       }
       return res;
Enomem:
       if (res) {
               LIST_HEAD(umount_list);
               br_write_lock(vfsmount_lock);
               umount_tree(res, 0, &umount_list);
               br_write_unlock(vfsmount_lock);
               release_mounts(&umount_list);
       }
       return NULL;
}

static void attach_mnt(struct mount *mnt, struct path *path)
{
       mnt_set_mountpoint(real_mount(path->mnt), path->dentry, mnt);
       list_add_tail(&mnt->mnt_hash, mount_hashtable +
                       hash(path->mnt, path->dentry));
       list_add_tail(&mnt->mnt_child, &real_mount(path->mnt)->mnt_mounts);
}
サンプル
[root@localhost loopdev]# ls /mnt/loop1/
submnt
[root@localhost loopdev]# ls /mnt/loop1/submnt/
babakaka.txt

[root@localhost loopdev]# mount -o loop loopfile1 /mnt/loop1/submnt/
[root@localhost loopdev]# ls /mnt/loop1/submnt/
lost+found

[root@localhost loopdev]# mount --bind /mnt/loop1 /mnt/loop2
[root@localhost loopdev]# ls /mnt/loop2
submnt
[root@localhost loopdev]# ls /mnt/loop2/submnt/
babakaka.txt

[root@localhost loopdev]# mount --rbind /mnt/loop1 /mnt/loop3
[root@localhost loopdev]# ls /mnt/loop3
submnt
[root@localhost loopdev]# ls /mnt/loop3/submnt/
lost+found

補足

BIND後にmountするケースにも言えて、bind元にmountすればmntの違うbind先では参照できません。SHARE属性はそのための物です。、


最終更新 2016/06/14 17:36:50 - north
(2013/06/14 23:19:46 作成)


検索

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