最近はfork/clone時のプロセス番号の発行あたりを読んできたので、今回はPID名前空間の生成部分を読んでみます。
処理を行うのはcreate_pid_namespace()です。clone(2)の場合、ここに至る流れはこうなっています。
do_fork() -> copy_process() -> copy_namespaces() -> create_new_namespaces() -> copy_pid_ns() -> create_pid_namespace()
PID名前空間が作成されるのは、PID名前空間を既存の名前空間から分離するときです。なので、copy_namespaces()にきて、CLONE_NEWPIPDフラグが立っているのでNSProxyの参照数を増やすのではなくてcreate_new_namespaces()でNSProxyの新規作成に入ります。そして、pid名前空間を処理するcopy_pid_ns()を呼んで、CLONE_NEWPIDフラグが立っているのでPID名前空間の参照数を増やさずにcreate_pid_namespace()を呼んで名前空間の新規作成に入るという感じです。
最初に既存のpid名前空間の階層を1つ足した値をlevelに設定します。そして、pid名前空間の階層数が限度を超えたらエラーとなります。
82 static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns, 83 struct pid_namespace *parent_pid_ns) 84 { 85 struct pid_namespace *ns; 86 unsigned int level = parent_pid_ns->level + 1; 87 int i; 88 int err; 89 90 if (level > MAX_PID_NS_LEVEL) { 91 err = -EINVAL; 92 goto out; 93 } 94
MAX_PID_NS_LEVELはcreate_pid_namespace()のすぐ上で定義されていて、32段階まで可能となっています。
79 /* MAX_PID_NS_LEVEL is needed for limiting size of 'struct pid' */ 80 #define MAX_PID_NS_LEVEL 32
ここは単にpid_namespace構造体のメモリを確保するだけです。
95 err = -ENOMEM; 96 ns = kmem_cache_zalloc(pid_ns_cachep, GFP_KERNEL); 97 if (ns == NULL) 98 goto out; 99
pid_namespace構造体はこのような構造体です。
24 struct pid_namespace { 25 struct kref kref; 26 struct pidmap pidmap[PIDMAP_ENTRIES]; 27 struct rcu_head rcu; 28 int last_pid; 29 unsigned int nr_hashed; 30 struct task_struct *child_reaper; 31 struct kmem_cache *pid_cachep; 32 unsigned int level; 33 struct pid_namespace *parent; 34 #ifdef CONFIG_PROC_FS 35 struct vfsmount *proc_mnt; 36 struct dentry *proc_self; 37 struct dentry *proc_thread_self; 38 #endif 39 #ifdef CONFIG_BSD_PROCESS_ACCT 40 struct fs_pin *bacct; 41 #endif 42 struct user_namespace *user_ns; 43 struct work_struct proc_work; 44 kgid_t pid_gid; 45 int hide_pid; 46 int reboot; /* group exit code if this pidns was rebooted */ 47 struct ns_common ns; 48 };
次はpidを管理するビットマップに使う領域のメモリ確保です。サイズは1PAGE分です。
100 ns->pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL); 101 if (!ns->pidmap[0].page) 102 goto out_free; 103
pidmapはpidmap構造体で空いている数を管理するnr_freeと、pageの2変数があります。
13 struct pidmap { 14 atomic_t nr_free; 15 void *page; 16 };
ここでpid構造体用にslabキャッシュを作ります。この中の処理は前回のfork/clone時に返すpidの設定(2) - φ(・・*)ゞ ウーン カーネルとか弄ったりのメモで軽く見たところです。ここで渡したレベルが、、、
104 ns->pid_cachep = create_pid_cachep(level + 1); 105 if (ns->pid_cachep == NULL) 106 goto out_free_map; 107
このように使われているわけですね。
53 cachep = kmem_cache_create(pcache->name, 54 sizeof(struct pid) + (nr_ids - 1) * sizeof(struct upid), 55 0, SLAB_HWCACHE_ALIGN, NULL);
次の処理はns_alloc_inum()で/proc/$$/ns/pidファイルに使用するinode番号を取得します。そして、proc_ns_operations構造体にpid名前空間のオペレーションを定義した構造体を設定します。これを使うのはsetns(2)で名前空間の移動を行うときです。
108 err = ns_alloc_inum(&ns->ns); 109 if (err) 110 goto out_free_map; 111 ns->ns.ops = &pidns_operations; 112
pidns_operations構造体は以下のように初期化されています。
391 const struct proc_ns_operations pidns_operations = { 392 .name = "pid", 393 .type = CLONE_NEWPID, 394 .get = pidns_get, 395 .put = pidns_put, 396 .install = pidns_install, 397 };
残りは初期化とエラー時のgotoラベルくらいなので読み飛ばします。最後に作成したpid_namespace構造体を返して終了です。
113 kref_init(&ns->kref); 114 ns->level = level; 115 ns->parent = get_pid_ns(parent_pid_ns); 116 ns->user_ns = get_user_ns(user_ns); 117 ns->nr_hashed = PIDNS_HASH_ADDING; 118 INIT_WORK(&ns->proc_work, proc_cleanup_work); 119 120 set_bit(0, ns->pidmap[0].page); 121 atomic_set(&ns->pidmap[0].nr_free, BITS_PER_PAGE - 1); 122 123 for (i = 1; i < PIDMAP_ENTRIES; i++) 124 atomic_set(&ns->pidmap[i].nr_free, BITS_PER_PAGE); 125 126 return ns; 127 128 out_free_map: 129 kfree(ns->pidmap[0].page); 130 out_free: 131 kmem_cache_free(pid_ns_cachep, ns); 132 out: 133 return ERR_PTR(err); 134 }
- 作者: 斉藤賢爾
- 出版社/メーカー: 太郎次郎社エディタス
- 発売日: 2014/07/02
- メディア: Kindle版
- この商品を含むブログを見る