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

IPC名前空間を調べる(1)

kernel linux

IPC名前空間で使う構造体とか読んでいきます。まずは簡単に全体像を把握するところからです。

まずはipc_namespace構造体。ファイルはinclude/linux/ipc_namespace.hです。

 21 struct ipc_namespace {
 22         atomic_t        count;
 23         struct ipc_ids  ids[3];
 24 
 25         int             sem_ctls[4];
 26         int             used_sems;
 27 
 28         unsigned int    msg_ctlmax;
 29         unsigned int    msg_ctlmnb;
 30         unsigned int    msg_ctlmni;
 31         atomic_t        msg_bytes;
 32         atomic_t        msg_hdrs;
 33 
 34         size_t          shm_ctlmax;
 35         size_t          shm_ctlall;
 36         unsigned long   shm_tot;
 37         int             shm_ctlmni;
 38         /*
 39          * Defines whether IPC_RMID is forced for _all_ shm segments regardless
 40          * of shmctl()
 41          */
 42         int             shm_rmid_forced;
 43 
 44         struct notifier_block ipcns_nb;
 45 
 46         /* The kern_mount of the mqueuefs sb.  We take a ref on it */
 47         struct vfsmount *mq_mnt;
 48 
 49         /* # queues in this ns, protected by mq_lock */
 50         unsigned int    mq_queues_count;
 51 
 52         /* next fields are set through sysctl */
 53         unsigned int    mq_queues_max;   /* initialized to DFLT_QUEUESMAX */
 54         unsigned int    mq_msg_max;      /* initialized to DFLT_MSGMAX */
 55         unsigned int    mq_msgsize_max;  /* initialized to DFLT_MSGSIZEMAX */
 56         unsigned int    mq_msg_default;
 57         unsigned int    mq_msgsize_default;
 58 
 59         /* user_ns which owns the ipc ns */
 60         struct user_namespace *user_ns;
 61 
 62         struct ns_common ns;
 63 };

ipc_ids構造体はこれです。

 13 struct ipc_ids {
 14         int in_use;
 15         unsigned short seq;
 16         struct rw_semaphore rwsem;
 17         struct idr ipcs_idr;
 18         int next_id;
 19 };

ipc_namespace構造体には色々と変数がありますが、PID 1に設定されるIPC名前空間に使われるinit_ipc_nsでは以下の変数のみが初期化されています。

 27  * The next 2 defines are here bc this is the only file
 28  * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE
 29  * and not CONFIG_IPC_NS.
 30  */
 31 struct ipc_namespace init_ipc_ns = {
 32         .count          = ATOMIC_INIT(1),
 33         .user_ns = &init_user_ns,
 34         .ns.inum = PROC_IPC_INIT_INO,
 35 #ifdef CONFIG_IPC_NS
 36         .ns.ops = &ipcns_operations,
 37 #endif
 38 };

これだけ見るとIPC関連のリソースが全く設定されていませんね。実際に初期化しているのはipc_init()です。

 84 static int __init ipc_init(void)
 85 {
 86         sem_init();
 87         msg_init();
 88         shm_init();
 89         return 0;
 90 }
 91 device_initcall(ipc_init);

例えばsem_init()の場合、以下のようにinit_ipc_nsを対象としてセマフォの初期化をしています。

191 void __init sem_init(void)
192 {
193         sem_init_ns(&init_ipc_ns);
194         ipc_init_proc_interface("sysvipc/sem",
195                                 "       key      semid perms      nsems   uid   gid  cuid  cgid      otime      ctime\n",
196                                 IPC_SEM_IDS, sysvipc_sem_proc_show);
197 }

共有メモリの場合はipc_ns_init()で別途初期化されてます。

111 static int __init ipc_ns_init(void)
112 {
113         shm_init_ns(&init_ipc_ns);
114         return 0;
115 }
116 
117 pure_initcall(ipc_ns_init);

あと、POSIX Message Queue filesystemの初期化がinit_mqueue_fs()で行われます。

1428 static int __init init_mqueue_fs(void)
1429 {
~~~略
1460 }
1461 
1462 device_initcall(init_mqueue_fs);
1463 

clone(2)とかで名前空間を分離する場合はcreate_ipc_ns()でこのようにIPCリソースを初期化します。

 36         atomic_set(&ns->count, 1);
 37         err = mq_init_ns(ns);
 38         if (err) {
 39                 ns_free_inum(&ns->ns);
 40                 kfree(ns);
 41                 return ERR_PTR(err);
 42         }
 43         atomic_inc(&nr_ipc_ns);
 44 
 45         sem_init_ns(ns);
 46         msg_init_ns(ns);
 47         shm_init_ns(ns);

というわけで、実際にIPCのリソースを設定しているのはxxx_init_ns()のところですね。ついでなのでcreate_ipc_ns()を全部見ておきます。該当のファイルはipc/namespace.cです。xxx_init_ns()の内容を気にしないで、ここだけ見ると特に変わったことはしていません。

 19 static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
 20                                            struct ipc_namespace *old_ns)
 21 {
 22         struct ipc_namespace *ns;
 23         int err;
 24 
 25         ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
 26         if (ns == NULL)
 27                 return ERR_PTR(-ENOMEM);
 28 
 29         err = ns_alloc_inum(&ns->ns);
 30         if (err) {
 31                 kfree(ns);
 32                 return ERR_PTR(err);
 33         }
 34         ns->ns.ops = &ipcns_operations;
 35 
 36         atomic_set(&ns->count, 1);
 37         err = mq_init_ns(ns);
 38         if (err) {
 39                 ns_free_inum(&ns->ns);
 40                 kfree(ns);
 41                 return ERR_PTR(err);
 42         }
 43         atomic_inc(&nr_ipc_ns);
 44 
 45         sem_init_ns(ns);
 46         msg_init_ns(ns);
 47         shm_init_ns(ns);
 48 
 49         ns->user_ns = get_user_ns(user_ns);
 50 
 51         return ns;
 52 }
  • 最初に作成するipc_namespace構造体のメモリを確保。
  • 次に、/proc//ns/ipcファイルに使用するinode番号を取得。
  • ipc_namespace構造体のns_common構造体にsetns(2)で使用するinstall()とかが設定されたIPC名前空間用のproc_ns_operations構造体を設定。
  • IPC名前空間の参照カウントを初期化
  • POSIXのmessage queue file systemに関するリソースを初期化
  • カーネル内にあるIPC名前空間の数をインクリメント。この変数はipc/msgutil.cにあります。
 40 atomic_t nr_ipc_ns = ATOMIC_INIT(1);
  • セマフォのリソース初期化
  • POSIXメッセージキューリソースの初期化
  • 共有メモリのリソース初期化
  • ユーザ名前空間を設定

今日はこの辺で。

ソフトウェアエンジニアのための ITインフラ監視[実践]入門 (Software Design plus)

ソフトウェアエンジニアのための ITインフラ監視[実践]入門 (Software Design plus)