CLONE_NEWPIDをclone(2)のflagsに付けて新しいプロセスを親プロセスと別のpid namaspaceで動かすことができますね。この時にどうやってpidを正しくプロセスに見せているのか知りたかったのでgetpid()を見てみました。
まずこんなコードを動かしてみます。あ、子プロセス側ではprocfsを別途mountしていないので子プロセスからpsすると親プロセスのpid namespaceが見える状況でやってます。
static int tst_func(void *arg) { show_pid("cloned process"); show_uid("cloned process"); mount_proc(); execlp("bash", "bash", NULL); return 0; } int main(int argc, char **argv) { ~略~ int clone_flags = CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWNS | SIGCHLD; stack = make_stack(); if (!stack) { fprintf(stderr, "faild to create stack\n"); return -1; } show_pid("orig process"); show_uid("orig process"); pid = clone(&tst_func, stack, clone_flags, NULL); if (pid == -1) { perror("clone"); exit(-1); } printf("child process id is %d\n", pid); ~略~
実行結果はこうなって子プロセスでは自分のpidは1と見えていますが、親プロセスからはこいつはpid 28615と見えています。
masami@saga:~$ sudo ./a.out [sudo] password for masami: orig process's pid is 28614 orig process's uid is 0 child process id is 28615 cloned process's pid is 1 cloned process's uid is 0 [root@saga masami]# echo $$ 1
このときに別途pstreeなどをするとこんな感じで見えますね。
├─systemd-udevd(199) ├─tmux(819)─┬─bash(820)───ssh(26795) │ ├─bash(14220)───sudo(28596)───a.out(28614)───bash(28615) │ ├─bash(21440)───pstree(28652) │ └─bash(28453)
ではここからgetpid()を読んでいきましょう。 pidを読みだすと言ってもcurrent->pidをそのまま返すわけではなく、pid namespaceの関係で以下のような流れで処理が行われています。
getpid() -> task_tgid_vnr() -> task_tgid() -> pid_vnr() -> task_active_pid_ns() -> task_pid() -> ns_of_pid() -> pid_nr_ns()
getpid()はこのようにtask_tgid_vnr()を呼び出して、その戻り値をそのまま返す。
809 SYSCALL_DEFINE0(getpid) 810 { 811 return task_tgid_vnr(current); 812 } 813
task_tgid_vnr()はpid_vnr()の戻り値を返す。
1764 static inline pid_t task_tgid_vnr(struct task_struct *tsk) 1765 { 1766 return pid_vnr(task_tgid(tsk)); 1767 }
pid_vnr()は引数としてtask_tgid()の戻り値(struct pid *)を渡す。このtask_tgid()はcurrentタスクのgroup_leaderのpidを返す。
1702 static inline struct pid *task_tgid(struct task_struct *task) 1703 { 1704 return task->group_leader->pids[PIDTYPE_PID].pid; 1705 }
pid_vnr()はグループリーダーのpid構造体を受け取り、pid_nr_ns()の戻り値を返す。
509 pid_t pid_vnr(struct pid *pid) 510 { 511 return pid_nr_ns(pid, task_active_pid_ns(current)); 512 }
まずはtask_active_pid_ns()を見てみると、ns_of_pid()が呼ばれる。task_pid()もstruct pid *を返す。
540 struct pid_namespace *task_active_pid_ns(struct task_struct *tsk) 541 { 542 return ns_of_pid(task_pid(tsk)); 543 }
task_pid()を見るとついにcurrentのpidが返る模様。
1697 static inline struct pid *task_pid(struct task_struct *task) 1698 { 1699 return task->pids[PIDTYPE_PID].pid; 1700 }
ns_of_pid()はpid構造体に関連しているpid namespaceを返す。
134 static inline struct pid_namespace *ns_of_pid(struct pid *pid) 135 { 136 struct pid_namespace *ns = NULL; 137 if (pid) 138 ns = pid->numbers[pid->level].ns; 139 return ns; 140 }
ここまででpid_nr_ns()の2番目の引数のpid namespaceが取得できたのでpid_nr_ns()を見る。ここでlevelの比較があるのはプロセスのpid namespaceに応じたpidを返すためでしょうね。
495 pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns) 496 { 497 struct upid *upid; 498 pid_t nr = 0; 499 500 if (pid && ns->level <= pid->level) { 501 upid = &pid->numbers[ns->level]; 502 if (upid->ns == ns) 503 nr = upid->nr; 504 } 505 return nr; 506 }
Docker入門 Immutable Infrastructureを実現する
- 作者: 松原豊,米林正明
- 出版社/メーカー: 技術評論社
- 発売日: 2014/04/25
- メディア: Kindle版
- この商品を含むブログ (4件) を見る