軽くnsproxyと初期化周りのめもを。
Linuxでは名前空間の管理にはnsproxy構造体が使われていて定義はinclude/linux/nsproxy.hにある。 中身はこのような形で5つの名前空間が管理されている。
29 struct nsproxy { 30 atomic_t count; 31 struct uts_namespace *uts_ns; 32 struct ipc_namespace *ipc_ns; 33 struct mnt_namespace *mnt_ns; 34 struct pid_namespace *pid_ns_for_children; 35 struct net *net_ns; 36 };
これらの名前空間は基本的にはdo_fork()の時に親プロセスのものがコピーされる。基本的にはと言ったので基本的じゃない場合としてはclone(2)で明示的に名前空間を分ける場合、例えばCLONE_NEWPIDをフラグに指定してpid名前空間を親プロセスと分けるということもあるし、unshare(2)で後からmount名前空間を分けるということも可能。
ここでfork(2)でコピーされる名前空間の大元はinclude/linux/nsproxy.hにあるinit_nsproxy。
37 extern struct nsproxy init_nsproxy;
この変数はkernel/nsproxy.cでこのように設定される。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 };
init_nsproxyはまずinit_taskへ設定される。
17 /* Initial task structure */ 18 struct task_struct init_task = INIT_TASK(init_task); 19 EXPORT_SYMBOL(init_task);
INIT_TASKマクロによってこのように展開される。
210 .nsproxy = &init_nsproxy,
fork()系の処理で親プロセスのnsproxyを子プロセスへコピーするのはarch_dup_task_struct()で実施。x86_64の場合はarch/x86/kernel/process.cのarch_dup_task_struct()でsrcをdstにコピーしている部分が該当。
65 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) 66 { 67 int ret; 68 69 *dst = *src; 70 if (fpu_allocated(&src->thread.fpu)) { 71 memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu)); 72 ret = fpu_alloc(&dst->thread.fpu); 73 if (ret) 74 return ret; 75 fpu_copy(dst, src); 76 } 77 return 0; 78 } 79
流れとしてはこのような形。
copy_process() -> dup_task_struct() -> arch_dup_task_struct()
さて、arch_dup_task_struct()で親プロセスの名前空間が子プロセスにコピーされたけどまだ処理としてhこれだけではなくて、copy_namespaces()による処理がある。
この処理はcopy_process()から呼び出される。
1349 retval = copy_namespaces(clone_flags, p);
copy_namespaces()はkernel/nsproxy.cにあり、比較的短い処理。
最初にflags(do_fock()での引数名だとclone_flags)のチェックで、新規に名前空間を作る必要がない場合はget_nsproxy()でinit_nsproxy構造体のcount変数をインクリメントして参照数を増やして終了。
124 int copy_namespaces(unsigned long flags, struct task_struct *tsk) 125 { 126 struct nsproxy *old_ns = tsk->nsproxy; 127 struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns); 128 struct nsproxy *new_ns; 129 130 if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | 131 CLONE_NEWPID | CLONE_NEWNET)))) { 132 get_nsproxy(old_ns); 133 return 0; 134 } 135
次はケーパビリティのチェック。
136 if (!ns_capable(user_ns, CAP_SYS_ADMIN)) 137 return -EPERM; 138
flagsでCLONE_NEWIPCがセットされていた場合のチェック。
139 /* 140 * CLONE_NEWIPC must detach from the undolist: after switching 141 * to a new ipc namespace, the semaphore arrays from the old 142 * namespace are unreachable. In clone parlance, CLONE_SYSVSEM 143 * means share undolist with parent, so we must forbid using 144 * it along with CLONE_NEWIPC. 145 */ 146 if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) == 147 (CLONE_NEWIPC | CLONE_SYSVSEM)) 148 return -EINVAL; 149
ここまでで特に問題が内容なら新規に名前空間を作るためにcreate_new_namespaces()を呼び出す。
150 new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs); 151 if (IS_ERR(new_ns)) 152 return PTR_ERR(new_ns); 153 154 tsk->nsproxy = new_ns; 155 return 0; 156 }
ここまでがfork()系の関数で名前空間に関する設定をしている部分の大枠。
【改訂新版】Linuxエンジニア養成読本 [クラウド時代も、システムの基礎と基盤はLinux! ] (Software Design plus)
- 作者: 養成読本編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2014/03/18
- メディア: 大型本
- この商品を含むブログ (1件) を見る