TenForward

技術ブログ。はてなダイアリーから移転しました

4.12 で nsfs の見た目がちょっと変わった

4.12 で nsfs に変更が加わってますね。

nsfs ってのは /proc/$PID/ns 以下の、そのプロセスがどの Namespace に所属しているのかを表している特殊なリンクがあるディレクトリです。

4.11 まではこんな感じ。

# ls -l /proc/self/ns
total 0
lrwxrwxrwx 1 root root 0 Jul  4 17:14 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Jul  4 17:14 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Jul  4 17:14 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Jul  4 17:14 net -> net:[4026531957]
lrwxrwxrwx 1 root root 0 Jul  4 17:14 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Jul  4 17:14 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jul  4 17:14 uts -> uts:[4026531838]

サポートしている Namespace それぞれの Namespace を表しています。

4.12 は

# ls -l /proc/self/ns
total 0
lrwxrwxrwx 1 root root 0 Jul  4 17:00 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Jul  4 17:00 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Jul  4 17:00 mnt -> mnt:[4026532397]
lrwxrwxrwx 1 root root 0 Jul  4 17:00 net -> net:[4026531961]
lrwxrwxrwx 1 root root 0 Jul  4 17:00 pid -> pid:[4026532399]
lrwxrwxrwx 1 root root 0 Jul  4 17:00 pid_for_children -> pid:[4026532399]
lrwxrwxrwx 1 root root 0 Jul  4 17:00 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jul  4 17:00 uts -> uts:[4026531838]

こんな感じ。pid_for_children というファイルが加わっています。CRIU 方面で必要だからということのようです (よく知りません)。kernel のコミットでいうと、

これは、PID Namespace だけちょっと特殊な部分があるからでしょうね。この辺りは Masami Ichikawa さんの、

の 28 ページ辺りをご覧になるのがよろしいかと。(nsfs についても 35 ページ辺りに言及があります)

つまり新しいプロセスを生成しない限りは、新しい PID Namespace に所属できません。unshare(2) とか setns(2) でも CLONE_NEWPID は指定できますが、指定した新しい PID Namespace に所属するのはその子プロセスからです。

お気軽コンテナコマンド unshare コマンドも --pid だけ指定してもエラーになります。--fork を同時に指定する必要があります。

ということは、プロセスの状態として、子供用に PID Namespace を持っていながら、自身は元の Namespace に所属しているという状態があるということですね。そういうプロセスの「子供用 PID Namespace を知る」ための機能ということでしょうか。

カーネルの Namespace を実現するための構造体、nsproxy

    30 struct nsproxy {
    31         atomic_t count;
    32         struct uts_namespace *uts_ns;
    33         struct ipc_namespace *ipc_ns;
    34         struct mnt_namespace *mnt_ns;
    35         struct pid_namespace *pid_ns_for_children;
    36         struct net »         *net_ns;
    37         struct cgroup_namespace *cgroup_ns;
    38 };

という風に pid_namespace *pid_ns_for_children となってますね。これを表示しているのかな (たぶん)。

試してみました。

# unshare --mount --pid --mount-proc --fork
# ls -l /proc/self/ns | grep pid
lrwxrwxrwx 1 root root 0 Jul  4 17:27 pid -> pid:[4026532399]
lrwxrwxrwx 1 root root 0 Jul  4 17:27 pid_for_children -> pid:[4026532399]

↑は新しい PID Namespace 内で調べてるのでまあこんな感じ。元の PID Namespace から見てみましょう。

# pgrep unshare
5354
# pstree -p 5354
unshare(5354)───bash(5355)

unshare コマンド (pid: 5354) の子プロセスとして bash が pid: 5355 で起動していますね。

# ls -l /proc/5354/ns | grep pid
lrwxrwxrwx 1 root root 0  7月  4日  17:00 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0  7月  4日  17:00 pid_for_children -> pid:[4026532399]
# ls -l /proc/5355/ns | grep pid
lrwxrwxrwx 1 root root 0  7月  4日  17:00 pid -> pid:[4026532399]
lrwxrwxrwx 1 root root 0  7月  4日  17:04 pid_for_children -> pid:[4026532399]

というわけで、unshare コマンド自身の pid_for_children は、子プロセスの bashpid (PID Namespace) と一致していますね。でも unshare コマンド自身の pid (PID Namespace) はそれとは異なります。

というわけで、4.12 でちょっと nsfs に変わったのを調べてみました。(間違いの指摘歓迎!!)

nsproxy まわりについても同じく Ichikawa さんのブログが参考になります