読者です 読者をやめる 読者になる 読者になる

linux namespace: mnt_nsが最初に作られる流れ

kernel linux

mnt_nsはinit_nsproxyにあるデータの中で唯一コンパイル時に値が入っていないので、どのようデータが設定されていくのかを見てみる。mnt_nsの作成はcreate_mnt_ns()で実施していて、以前のエントリー「φ(・・*)ゞ ウーン mount namespaceめも - φ(・・*)ゞ ウーン カーネルとか弄ったりのメモ」で見た部分ではあるけど、最初はどうやっているのかを見てなかったんですね。

ブート処理の場合は以下のようにstart_kernel()の中から初期化される。

start_kernel() @init/main.c
  --> vfs_caches_init() @fs/dcache.c
    --> mnt_init() fs/namespace.c
      --> init_mount_tree() @fs/namespace.c
        --> create_mnt_ns() @fs/namespace.c

ここで、namespaceが絡んでくるのはinit_mount_tree()からなのでその辺を。
最初にroot filesystemのマウント処理を行う。

2804 static void __init init_mount_tree(void)
2805 {
2806         struct vfsmount *mnt;
2807         struct mnt_namespace *ns;
2808         struct path root;
2809         struct file_system_type *type;
2810 
2811         type = get_fs_type("rootfs");
2812         if (!type)
2813                 panic("Can't find rootfs type");
2814         mnt = vfs_kern_mount(type, 0, "rootfs", NULL);
2815         put_filesystem(type);
2816         if (IS_ERR(mnt))
2817                 panic("Can't create rootfs");
2818 

次にマウントしたファイルシステムのデータを引数としてcreate_mnt_ns()を呼ぶ。create_mnt_ns()が終わったらinit_taskのnsproxt(init_nsproxt)にnamespaceを設定し、mnt_nsの参照カウンタを一つ増やすところまでがnamespaceの処理。

2819         ns = create_mnt_ns(mnt);
2820         if (IS_ERR(ns))
2821                 panic("Can't allocate initial namespace");
2822 
2823         init_task.nsproxy->mnt_ns = ns;
2824         get_mnt_ns(ns);

create_mnt_ns()は最初にalloc_mnt_ns()でインスタンスの作成。これは以前のエントリを参照。エラーが無ければif文の中が実行される。

2572 /**
2573  * create_mnt_ns - creates a private namespace and adds a root filesystem
2574  * @mnt: pointer to the new root filesystem mountpoint
2575  */
2576 static struct mnt_namespace *create_mnt_ns(struct vfsmount *m)
2577 {
2578         struct mnt_namespace *new_ns = alloc_mnt_ns(&init_user_ns);
2579         if (!IS_ERR(new_ns)) {
2580                 struct mount *mnt = real_mount(m);
2581                 mnt->mnt_ns = new_ns;
2582                 new_ns->root = mnt;
2583                 list_add(&mnt->mnt_list, &new_ns->list);
2584         } else {
2585                 mntput(m);
2586         }
2587         return new_ns;
2588 }
2589 

real_mount()はcontainer_ofマクロを使ってstruct vfsmount構造体からstruct mountの変数にアクセスする。 そして、マウントポイントのstruct mountにあるnamespaceに作成したnew_nsを設定し、new_nsのルートファイルシステムにmntを設定。最後にnew_nsのリストにmntが繋がれる。

mnt_namespaceはこのような構造体でfs/mount.hにて定義。

  5 struct mnt_namespace {
  6         atomic_t                count;
  7         unsigned int            proc_inum;
  8         struct mount *  root;
  9         struct list_head        list;
 10         struct user_namespace   *user_ns;
 11         u64                     seq;    /* Sequence number to prevent loops */
 12         wait_queue_head_t poll;
 13         u64 event;
 14 };

fs/namespace.cだとこの構造体のリストにデータを追加するのはcopy_mnt_nsくらいだけど他でも操作があるのかどうか。。。