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

mount namespaceでinit_taskのmnt_nsを設定するところ

linux kernel

Linuxのinit_taskに設定されるmnt_nsはコンパイル時には設定されていなくて実行時に決定されてます。で、それがどこで設定されているのかのメモです。

まず、nsproxy.cでinit_taskはこのように作られていて、mnt_nsはNULLが初期値になっている。

 31 struct nsproxy init_nsproxy = {
 32         .count                  = ATOMIC_INIT(1),
 33         .uts_ns                 = &init_uts_ns,
 34 #if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC)
 35         .ipc_ns                 = &init_ipc_ns,
 36 #endif
 37         .mnt_ns                 = NULL,
 38         .pid_ns_for_children    = &init_pid_ns,
 39 #ifdef CONFIG_NET
 40         .net_ns                 = &init_net,
 41 #endif
 42 };

結論から先にだすと実際に設定をしているのはfs/namespace.cのinit_mount_tree()。 ここまでのフローはというと、このような感じ。

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

init_mount_tree()が大体のことを実行するけど、ここから呼ばれる関数で名前空間関連のところはcreate_mnt_ns()alloc_mnt_ns()。alloc_mnt_ns()のほうはmnt_namespace構造体のインスタンスと作って変数を初期化したりという程度でこれといった処理は無いです。 create_mnt_ns()はalloc_mnt_ns()を呼んでmnt_namespace構造体を初期化したあとに↓の処理をして新しく作成したマウント名前空間のroot(/)に現在のルートファイルシステムを設定してます。

2812                 struct mount *mnt = real_mount(m);
2813                 mnt->mnt_ns = new_ns;
2814                 new_ns->root = mnt;
2815                 list_add(&mnt->mnt_list, &new_ns->list);

ここで使っているmはcreate_mnt_ns()の引数でvfsmount構造体です。これはinit_mount_tree()で以下のように取得しています。

3041         type = get_fs_type("rootfs");
3042         if (!type)
3043                 panic("Can't find rootfs type");
3044         mnt = vfs_kern_mount(type, 0, "rootfs", NULL);

それで、init_mount_tree()はどんな処理をしているかというと、create_mnt_ns()を呼ぶ前までの処理は上に示したルートファイルシステムを取得するくらいです。そして、create_mnt_ns()を呼びmnt_namspace構造体の初期化や、ルートファイルシステムの割当をしてます。あとはcreate_mnt_ns()から戻ったあとにinit_taskのnsproxy->mnt_nsにcreate_mnt_ns()で設定したmnt_namsapsce構造体のインスタンスを設定して完了です。

3049         ns = create_mnt_ns(mnt);
3050         if (IS_ERR(ns))
3051                 panic("Can't allocate initial namespace");
3052 
3053         init_task.nsproxy->mnt_ns = ns;

これでinitの処理が終わってpid1が立ち上がってしまえば、あとはfork(1)などの時にこのmnt_nsが共有されたり分離されたりとなります。

自作エミュレータで学ぶx86アーキテクチャ-コンピュータが動く仕組みを徹底理解!

自作エミュレータで学ぶx86アーキテクチャ-コンピュータが動く仕組みを徹底理解!