aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorGuillaume Knispel <guillaume.knispel@supersonicimagine.com>2017-09-08 19:17:55 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-08 21:26:51 -0400
commit0cfb6aee70bddbef6ec796b255f588ce0e126766 (patch)
treef83b1e24d55b1aef178169f1d747d404d665be83 /ipc
parente4243b8062c13b8cb3d91695dc353cb9e6a0da25 (diff)
ipc: optimize semget/shmget/msgget for lots of keys
ipc_findkey() used to scan all objects to look for the wanted key. This is slow when using a high number of keys. This change adds an rhashtable of kern_ipc_perm objects in ipc_ids, so that one lookup cease to be O(n). This change gives a 865% improvement of benchmark reaim.jobs_per_min on a 56 threads Intel(R) Xeon(R) CPU E5-2695 v3 @ 2.30GHz with 256G memory [1] Other (more micro) benchmark results, by the author: On an i5 laptop, the following loop executed right after a reboot took, without and with this change: for (int i = 0, k=0x424242; i < KEYS; ++i) semget(k++, 1, IPC_CREAT | 0600); total total max single max single KEYS without with call without call with 1 3.5 4.9 µs 3.5 4.9 10 7.6 8.6 µs 3.7 4.7 32 16.2 15.9 µs 4.3 5.3 100 72.9 41.8 µs 3.7 4.7 1000 5,630.0 502.0 µs * * 10000 1,340,000.0 7,240.0 µs * * 31900 17,600,000.0 22,200.0 µs * * *: unreliable measure: high variance The duration for a lookup-only usage was obtained by the same loop once the keys are present: total total max single max single KEYS without with call without call with 1 2.1 2.5 µs 2.1 2.5 10 4.5 4.8 µs 2.2 2.3 32 13.0 10.8 µs 2.3 2.8 100 82.9 25.1 µs * 2.3 1000 5,780.0 217.0 µs * * 10000 1,470,000.0 2,520.0 µs * * 31900 17,400,000.0 7,810.0 µs * * Finally, executing each semget() in a new process gave, when still summing only the durations of these syscalls: creation: total total KEYS without with 1 3.7 5.0 µs 10 32.9 36.7 µs 32 125.0 109.0 µs 100 523.0 353.0 µs 1000 20,300.0 3,280.0 µs 10000 2,470,000.0 46,700.0 µs 31900 27,800,000.0 219,000.0 µs lookup-only: total total KEYS without with 1 2.5 2.7 µs 10 25.4 24.4 µs 32 106.0 72.6 µs 100 591.0 352.0 µs 1000 22,400.0 2,250.0 µs 10000 2,510,000.0 25,700.0 µs 31900 28,200,000.0 115,000.0 µs [1] http://lkml.kernel.org/r/20170814060507.GE23258@yexl-desktop Link: http://lkml.kernel.org/r/20170815194954.ck32ta2z35yuzpwp@debix Signed-off-by: Guillaume Knispel <guillaume.knispel@supersonicimagine.com> Reviewed-by: Marc Pardo <marc.pardo@supersonicimagine.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Kees Cook <keescook@chromium.org> Cc: Manfred Spraul <manfred@colorfullife.com> Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: "Peter Zijlstra (Intel)" <peterz@infradead.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Cc: Serge Hallyn <serge@hallyn.com> Cc: Andrey Vagin <avagin@openvz.org> Cc: Guillaume Knispel <guillaume.knispel@supersonicimagine.com> Cc: Marc Pardo <marc.pardo@supersonicimagine.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/msg.c10
-rw-r--r--ipc/namespace.c20
-rw-r--r--ipc/sem.c11
-rw-r--r--ipc/shm.c12
-rw-r--r--ipc/util.c100
-rw-r--r--ipc/util.h21
6 files changed, 124 insertions, 50 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 2c38f10d1483..df82bc9a5531 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -1011,7 +1011,7 @@ SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
1011} 1011}
1012 1012
1013 1013
1014void msg_init_ns(struct ipc_namespace *ns) 1014int msg_init_ns(struct ipc_namespace *ns)
1015{ 1015{
1016 ns->msg_ctlmax = MSGMAX; 1016 ns->msg_ctlmax = MSGMAX;
1017 ns->msg_ctlmnb = MSGMNB; 1017 ns->msg_ctlmnb = MSGMNB;
@@ -1019,7 +1019,7 @@ void msg_init_ns(struct ipc_namespace *ns)
1019 1019
1020 atomic_set(&ns->msg_bytes, 0); 1020 atomic_set(&ns->msg_bytes, 0);
1021 atomic_set(&ns->msg_hdrs, 0); 1021 atomic_set(&ns->msg_hdrs, 0);
1022 ipc_init_ids(&ns->ids[IPC_MSG_IDS]); 1022 return ipc_init_ids(&ns->ids[IPC_MSG_IDS]);
1023} 1023}
1024 1024
1025#ifdef CONFIG_IPC_NS 1025#ifdef CONFIG_IPC_NS
@@ -1027,6 +1027,7 @@ void msg_exit_ns(struct ipc_namespace *ns)
1027{ 1027{
1028 free_ipcs(ns, &msg_ids(ns), freeque); 1028 free_ipcs(ns, &msg_ids(ns), freeque);
1029 idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr); 1029 idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr);
1030 rhashtable_destroy(&ns->ids[IPC_MSG_IDS].key_ht);
1030} 1031}
1031#endif 1032#endif
1032 1033
@@ -1058,11 +1059,12 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
1058} 1059}
1059#endif 1060#endif
1060 1061
1061void __init msg_init(void) 1062int __init msg_init(void)
1062{ 1063{
1063 msg_init_ns(&init_ipc_ns); 1064 const int err = msg_init_ns(&init_ipc_ns);
1064 1065
1065 ipc_init_proc_interface("sysvipc/msg", 1066 ipc_init_proc_interface("sysvipc/msg",
1066 " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", 1067 " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
1067 IPC_MSG_IDS, sysvipc_msg_proc_show); 1068 IPC_MSG_IDS, sysvipc_msg_proc_show);
1069 return err;
1068} 1070}
diff --git a/ipc/namespace.c b/ipc/namespace.c
index 7af6e6b883b9..fc850c526698 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -54,16 +54,28 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
54 ns->user_ns = get_user_ns(user_ns); 54 ns->user_ns = get_user_ns(user_ns);
55 ns->ucounts = ucounts; 55 ns->ucounts = ucounts;
56 56
57 err = mq_init_ns(ns); 57 err = sem_init_ns(ns);
58 if (err) 58 if (err)
59 goto fail_put; 59 goto fail_put;
60 err = msg_init_ns(ns);
61 if (err)
62 goto fail_destroy_sem;
63 err = shm_init_ns(ns);
64 if (err)
65 goto fail_destroy_msg;
60 66
61 sem_init_ns(ns); 67 err = mq_init_ns(ns);
62 msg_init_ns(ns); 68 if (err)
63 shm_init_ns(ns); 69 goto fail_destroy_shm;
64 70
65 return ns; 71 return ns;
66 72
73fail_destroy_shm:
74 shm_exit_ns(ns);
75fail_destroy_msg:
76 msg_exit_ns(ns);
77fail_destroy_sem:
78 sem_exit_ns(ns);
67fail_put: 79fail_put:
68 put_user_ns(ns->user_ns); 80 put_user_ns(ns->user_ns);
69 ns_free_inum(&ns->ns); 81 ns_free_inum(&ns->ns);
diff --git a/ipc/sem.c b/ipc/sem.c
index 4c0cfaad560c..013c7981f3c7 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -183,14 +183,14 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
183#define sc_semopm sem_ctls[2] 183#define sc_semopm sem_ctls[2]
184#define sc_semmni sem_ctls[3] 184#define sc_semmni sem_ctls[3]
185 185
186void sem_init_ns(struct ipc_namespace *ns) 186int sem_init_ns(struct ipc_namespace *ns)
187{ 187{
188 ns->sc_semmsl = SEMMSL; 188 ns->sc_semmsl = SEMMSL;
189 ns->sc_semmns = SEMMNS; 189 ns->sc_semmns = SEMMNS;
190 ns->sc_semopm = SEMOPM; 190 ns->sc_semopm = SEMOPM;
191 ns->sc_semmni = SEMMNI; 191 ns->sc_semmni = SEMMNI;
192 ns->used_sems = 0; 192 ns->used_sems = 0;
193 ipc_init_ids(&ns->ids[IPC_SEM_IDS]); 193 return ipc_init_ids(&ns->ids[IPC_SEM_IDS]);
194} 194}
195 195
196#ifdef CONFIG_IPC_NS 196#ifdef CONFIG_IPC_NS
@@ -198,15 +198,18 @@ void sem_exit_ns(struct ipc_namespace *ns)
198{ 198{
199 free_ipcs(ns, &sem_ids(ns), freeary); 199 free_ipcs(ns, &sem_ids(ns), freeary);
200 idr_destroy(&ns->ids[IPC_SEM_IDS].ipcs_idr); 200 idr_destroy(&ns->ids[IPC_SEM_IDS].ipcs_idr);
201 rhashtable_destroy(&ns->ids[IPC_SEM_IDS].key_ht);
201} 202}
202#endif 203#endif
203 204
204void __init sem_init(void) 205int __init sem_init(void)
205{ 206{
206 sem_init_ns(&init_ipc_ns); 207 const int err = sem_init_ns(&init_ipc_ns);
208
207 ipc_init_proc_interface("sysvipc/sem", 209 ipc_init_proc_interface("sysvipc/sem",
208 " key semid perms nsems uid gid cuid cgid otime ctime\n", 210 " key semid perms nsems uid gid cuid cgid otime ctime\n",
209 IPC_SEM_IDS, sysvipc_sem_proc_show); 211 IPC_SEM_IDS, sysvipc_sem_proc_show);
212 return err;
210} 213}
211 214
212/** 215/**
diff --git a/ipc/shm.c b/ipc/shm.c
index 8828b4c3a190..8fc97beb5234 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -72,14 +72,14 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp);
72static int sysvipc_shm_proc_show(struct seq_file *s, void *it); 72static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
73#endif 73#endif
74 74
75void shm_init_ns(struct ipc_namespace *ns) 75int shm_init_ns(struct ipc_namespace *ns)
76{ 76{
77 ns->shm_ctlmax = SHMMAX; 77 ns->shm_ctlmax = SHMMAX;
78 ns->shm_ctlall = SHMALL; 78 ns->shm_ctlall = SHMALL;
79 ns->shm_ctlmni = SHMMNI; 79 ns->shm_ctlmni = SHMMNI;
80 ns->shm_rmid_forced = 0; 80 ns->shm_rmid_forced = 0;
81 ns->shm_tot = 0; 81 ns->shm_tot = 0;
82 ipc_init_ids(&shm_ids(ns)); 82 return ipc_init_ids(&shm_ids(ns));
83} 83}
84 84
85/* 85/*
@@ -95,7 +95,7 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
95 if (shp->shm_nattch) { 95 if (shp->shm_nattch) {
96 shp->shm_perm.mode |= SHM_DEST; 96 shp->shm_perm.mode |= SHM_DEST;
97 /* Do not find it any more */ 97 /* Do not find it any more */
98 shp->shm_perm.key = IPC_PRIVATE; 98 ipc_set_key_private(&shm_ids(ns), &shp->shm_perm);
99 shm_unlock(shp); 99 shm_unlock(shp);
100 } else 100 } else
101 shm_destroy(ns, shp); 101 shm_destroy(ns, shp);
@@ -106,13 +106,15 @@ void shm_exit_ns(struct ipc_namespace *ns)
106{ 106{
107 free_ipcs(ns, &shm_ids(ns), do_shm_rmid); 107 free_ipcs(ns, &shm_ids(ns), do_shm_rmid);
108 idr_destroy(&ns->ids[IPC_SHM_IDS].ipcs_idr); 108 idr_destroy(&ns->ids[IPC_SHM_IDS].ipcs_idr);
109 rhashtable_destroy(&ns->ids[IPC_SHM_IDS].key_ht);
109} 110}
110#endif 111#endif
111 112
112static int __init ipc_ns_init(void) 113static int __init ipc_ns_init(void)
113{ 114{
114 shm_init_ns(&init_ipc_ns); 115 const int err = shm_init_ns(&init_ipc_ns);
115 return 0; 116 WARN(err, "ipc: sysv shm_init_ns failed: %d\n", err);
117 return err;
116} 118}
117 119
118pure_initcall(ipc_ns_init); 120pure_initcall(ipc_ns_init);
diff --git a/ipc/util.c b/ipc/util.c
index 069bb22c9f64..78755873cc5b 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -83,27 +83,46 @@ struct ipc_proc_iface {
83 */ 83 */
84static int __init ipc_init(void) 84static int __init ipc_init(void)
85{ 85{
86 sem_init(); 86 int err_sem, err_msg;
87 msg_init(); 87
88 err_sem = sem_init();
89 WARN(err_sem, "ipc: sysv sem_init failed: %d\n", err_sem);
90 err_msg = msg_init();
91 WARN(err_msg, "ipc: sysv msg_init failed: %d\n", err_msg);
88 shm_init(); 92 shm_init();
89 return 0; 93
94 return err_msg ? err_msg : err_sem;
90} 95}
91device_initcall(ipc_init); 96device_initcall(ipc_init);
92 97
98static const struct rhashtable_params ipc_kht_params = {
99 .head_offset = offsetof(struct kern_ipc_perm, khtnode),
100 .key_offset = offsetof(struct kern_ipc_perm, key),
101 .key_len = FIELD_SIZEOF(struct kern_ipc_perm, key),
102 .locks_mul = 1,
103 .automatic_shrinking = true,
104};
105
93/** 106/**
94 * ipc_init_ids - initialise ipc identifiers 107 * ipc_init_ids - initialise ipc identifiers
95 * @ids: ipc identifier set 108 * @ids: ipc identifier set
96 * 109 *
97 * Set up the sequence range to use for the ipc identifier range (limited 110 * Set up the sequence range to use for the ipc identifier range (limited
98 * below IPCMNI) then initialise the ids idr. 111 * below IPCMNI) then initialise the keys hashtable and ids idr.
99 */ 112 */
100void ipc_init_ids(struct ipc_ids *ids) 113int ipc_init_ids(struct ipc_ids *ids)
101{ 114{
115 int err;
102 ids->in_use = 0; 116 ids->in_use = 0;
103 ids->seq = 0; 117 ids->seq = 0;
104 ids->next_id = -1; 118 ids->next_id = -1;
105 init_rwsem(&ids->rwsem); 119 init_rwsem(&ids->rwsem);
120 err = rhashtable_init(&ids->key_ht, &ipc_kht_params);
121 if (err)
122 return err;
106 idr_init(&ids->ipcs_idr); 123 idr_init(&ids->ipcs_idr);
124 ids->tables_initialized = true;
125 return 0;
107} 126}
108 127
109#ifdef CONFIG_PROC_FS 128#ifdef CONFIG_PROC_FS
@@ -147,28 +166,20 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
147 * Returns the locked pointer to the ipc structure if found or NULL 166 * Returns the locked pointer to the ipc structure if found or NULL
148 * otherwise. If key is found ipc points to the owning ipc structure 167 * otherwise. If key is found ipc points to the owning ipc structure
149 * 168 *
150 * Called with ipc_ids.rwsem held. 169 * Called with writer ipc_ids.rwsem held.
151 */ 170 */
152static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) 171static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
153{ 172{
154 struct kern_ipc_perm *ipc; 173 struct kern_ipc_perm *ipcp = NULL;
155 int next_id;
156 int total;
157
158 for (total = 0, next_id = 0; total < ids->in_use; next_id++) {
159 ipc = idr_find(&ids->ipcs_idr, next_id);
160
161 if (ipc == NULL)
162 continue;
163 174
164 if (ipc->key != key) { 175 if (likely(ids->tables_initialized))
165 total++; 176 ipcp = rhashtable_lookup_fast(&ids->key_ht, &key,
166 continue; 177 ipc_kht_params);
167 }
168 178
179 if (ipcp) {
169 rcu_read_lock(); 180 rcu_read_lock();
170 ipc_lock_object(ipc); 181 ipc_lock_object(ipcp);
171 return ipc; 182 return ipcp;
172 } 183 }
173 184
174 return NULL; 185 return NULL;
@@ -221,13 +232,13 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
221{ 232{
222 kuid_t euid; 233 kuid_t euid;
223 kgid_t egid; 234 kgid_t egid;
224 int id; 235 int id, err;
225 int next_id = ids->next_id; 236 int next_id = ids->next_id;
226 237
227 if (size > IPCMNI) 238 if (size > IPCMNI)
228 size = IPCMNI; 239 size = IPCMNI;
229 240
230 if (ids->in_use >= size) 241 if (!ids->tables_initialized || ids->in_use >= size)
231 return -ENOSPC; 242 return -ENOSPC;
232 243
233 idr_preload(GFP_KERNEL); 244 idr_preload(GFP_KERNEL);
@@ -246,6 +257,15 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
246 (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0, 257 (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0,
247 GFP_NOWAIT); 258 GFP_NOWAIT);
248 idr_preload_end(); 259 idr_preload_end();
260
261 if (id >= 0 && new->key != IPC_PRIVATE) {
262 err = rhashtable_insert_fast(&ids->key_ht, &new->khtnode,
263 ipc_kht_params);
264 if (err < 0) {
265 idr_remove(&ids->ipcs_idr, id);
266 id = err;
267 }
268 }
249 if (id < 0) { 269 if (id < 0) {
250 spin_unlock(&new->lock); 270 spin_unlock(&new->lock);
251 rcu_read_unlock(); 271 rcu_read_unlock();
@@ -377,6 +397,20 @@ static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
377 return err; 397 return err;
378} 398}
379 399
400/**
401 * ipc_kht_remove - remove an ipc from the key hashtable
402 * @ids: ipc identifier set
403 * @ipcp: ipc perm structure containing the key to remove
404 *
405 * ipc_ids.rwsem (as a writer) and the spinlock for this ID are held
406 * before this function is called, and remain locked on the exit.
407 */
408static void ipc_kht_remove(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
409{
410 if (ipcp->key != IPC_PRIVATE)
411 rhashtable_remove_fast(&ids->key_ht, &ipcp->khtnode,
412 ipc_kht_params);
413}
380 414
381/** 415/**
382 * ipc_rmid - remove an ipc identifier 416 * ipc_rmid - remove an ipc identifier
@@ -391,10 +425,25 @@ void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
391 int lid = ipcid_to_idx(ipcp->id); 425 int lid = ipcid_to_idx(ipcp->id);
392 426
393 idr_remove(&ids->ipcs_idr, lid); 427 idr_remove(&ids->ipcs_idr, lid);
428 ipc_kht_remove(ids, ipcp);
394 ids->in_use--; 429 ids->in_use--;
395 ipcp->deleted = true; 430 ipcp->deleted = true;
396} 431}
397 432
433/**
434 * ipc_set_key_private - switch the key of an existing ipc to IPC_PRIVATE
435 * @ids: ipc identifier set
436 * @ipcp: ipc perm structure containing the key to modify
437 *
438 * ipc_ids.rwsem (as a writer) and the spinlock for this ID are held
439 * before this function is called, and remain locked on the exit.
440 */
441void ipc_set_key_private(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
442{
443 ipc_kht_remove(ids, ipcp);
444 ipcp->key = IPC_PRIVATE;
445}
446
398int ipc_rcu_getref(struct kern_ipc_perm *ptr) 447int ipc_rcu_getref(struct kern_ipc_perm *ptr)
399{ 448{
400 return refcount_inc_not_zero(&ptr->refcount); 449 return refcount_inc_not_zero(&ptr->refcount);
@@ -485,7 +534,7 @@ void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out)
485} 534}
486 535
487/** 536/**
488 * ipc_obtain_object 537 * ipc_obtain_object_idr
489 * @ids: ipc identifier set 538 * @ids: ipc identifier set
490 * @id: ipc id to look for 539 * @id: ipc id to look for
491 * 540 *
@@ -499,6 +548,9 @@ struct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids *ids, int id)
499 struct kern_ipc_perm *out; 548 struct kern_ipc_perm *out;
500 int lid = ipcid_to_idx(id); 549 int lid = ipcid_to_idx(id);
501 550
551 if (unlikely(!ids->tables_initialized))
552 return ERR_PTR(-EINVAL);
553
502 out = idr_find(&ids->ipcs_idr, lid); 554 out = idr_find(&ids->ipcs_idr, lid);
503 if (!out) 555 if (!out)
504 return ERR_PTR(-EINVAL); 556 return ERR_PTR(-EINVAL);
diff --git a/ipc/util.h b/ipc/util.h
index c692010e6f0a..80c9f51c3f07 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -15,8 +15,8 @@
15 15
16#define SEQ_MULTIPLIER (IPCMNI) 16#define SEQ_MULTIPLIER (IPCMNI)
17 17
18void sem_init(void); 18int sem_init(void);
19void msg_init(void); 19int msg_init(void);
20void shm_init(void); 20void shm_init(void);
21 21
22struct ipc_namespace; 22struct ipc_namespace;
@@ -30,17 +30,17 @@ static inline void mq_put_mnt(struct ipc_namespace *ns) { }
30#endif 30#endif
31 31
32#ifdef CONFIG_SYSVIPC 32#ifdef CONFIG_SYSVIPC
33void sem_init_ns(struct ipc_namespace *ns); 33int sem_init_ns(struct ipc_namespace *ns);
34void msg_init_ns(struct ipc_namespace *ns); 34int msg_init_ns(struct ipc_namespace *ns);
35void shm_init_ns(struct ipc_namespace *ns); 35int shm_init_ns(struct ipc_namespace *ns);
36 36
37void sem_exit_ns(struct ipc_namespace *ns); 37void sem_exit_ns(struct ipc_namespace *ns);
38void msg_exit_ns(struct ipc_namespace *ns); 38void msg_exit_ns(struct ipc_namespace *ns);
39void shm_exit_ns(struct ipc_namespace *ns); 39void shm_exit_ns(struct ipc_namespace *ns);
40#else 40#else
41static inline void sem_init_ns(struct ipc_namespace *ns) { } 41static inline int sem_init_ns(struct ipc_namespace *ns) { return 0; }
42static inline void msg_init_ns(struct ipc_namespace *ns) { } 42static inline int msg_init_ns(struct ipc_namespace *ns) { return 0; }
43static inline void shm_init_ns(struct ipc_namespace *ns) { } 43static inline int shm_init_ns(struct ipc_namespace *ns) { return 0; }
44 44
45static inline void sem_exit_ns(struct ipc_namespace *ns) { } 45static inline void sem_exit_ns(struct ipc_namespace *ns) { }
46static inline void msg_exit_ns(struct ipc_namespace *ns) { } 46static inline void msg_exit_ns(struct ipc_namespace *ns) { }
@@ -79,7 +79,7 @@ struct ipc_ops {
79struct seq_file; 79struct seq_file;
80struct ipc_ids; 80struct ipc_ids;
81 81
82void ipc_init_ids(struct ipc_ids *); 82int ipc_init_ids(struct ipc_ids *);
83#ifdef CONFIG_PROC_FS 83#ifdef CONFIG_PROC_FS
84void __init ipc_init_proc_interface(const char *path, const char *header, 84void __init ipc_init_proc_interface(const char *path, const char *header,
85 int ids, int (*show)(struct seq_file *, void *)); 85 int ids, int (*show)(struct seq_file *, void *));
@@ -104,6 +104,9 @@ int ipc_get_maxid(struct ipc_ids *);
104/* must be called with both locks acquired. */ 104/* must be called with both locks acquired. */
105void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *); 105void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
106 106
107/* must be called with both locks acquired. */
108void ipc_set_key_private(struct ipc_ids *, struct kern_ipc_perm *);
109
107/* must be called with ipcp locked */ 110/* must be called with ipcp locked */
108int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg); 111int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
109 112