diff options
author | Guillaume Knispel <guillaume.knispel@supersonicimagine.com> | 2017-09-08 19:17:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-08 21:26:51 -0400 |
commit | 0cfb6aee70bddbef6ec796b255f588ce0e126766 (patch) | |
tree | f83b1e24d55b1aef178169f1d747d404d665be83 /ipc | |
parent | e4243b8062c13b8cb3d91695dc353cb9e6a0da25 (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.c | 10 | ||||
-rw-r--r-- | ipc/namespace.c | 20 | ||||
-rw-r--r-- | ipc/sem.c | 11 | ||||
-rw-r--r-- | ipc/shm.c | 12 | ||||
-rw-r--r-- | ipc/util.c | 100 | ||||
-rw-r--r-- | ipc/util.h | 21 |
6 files changed, 124 insertions, 50 deletions
@@ -1011,7 +1011,7 @@ SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz, | |||
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | 1013 | ||
1014 | void msg_init_ns(struct ipc_namespace *ns) | 1014 | int 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 | ||
1061 | void __init msg_init(void) | 1062 | int __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 | ||
73 | fail_destroy_shm: | ||
74 | shm_exit_ns(ns); | ||
75 | fail_destroy_msg: | ||
76 | msg_exit_ns(ns); | ||
77 | fail_destroy_sem: | ||
78 | sem_exit_ns(ns); | ||
67 | fail_put: | 79 | fail_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); |
@@ -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 | ||
186 | void sem_init_ns(struct ipc_namespace *ns) | 186 | int 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 | ||
204 | void __init sem_init(void) | 205 | int __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 | /** |
@@ -72,14 +72,14 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp); | |||
72 | static int sysvipc_shm_proc_show(struct seq_file *s, void *it); | 72 | static int sysvipc_shm_proc_show(struct seq_file *s, void *it); |
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | void shm_init_ns(struct ipc_namespace *ns) | 75 | int 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 | ||
112 | static int __init ipc_ns_init(void) | 113 | static 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 | ||
118 | pure_initcall(ipc_ns_init); | 120 | pure_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 | */ |
84 | static int __init ipc_init(void) | 84 | static 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 | } |
91 | device_initcall(ipc_init); | 96 | device_initcall(ipc_init); |
92 | 97 | ||
98 | static 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 | */ |
100 | void ipc_init_ids(struct ipc_ids *ids) | 113 | int 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 | */ |
152 | static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key) | 171 | static 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 | */ | ||
408 | static 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 | */ | ||
441 | void 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 | |||
398 | int ipc_rcu_getref(struct kern_ipc_perm *ptr) | 447 | int 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 | ||
18 | void sem_init(void); | 18 | int sem_init(void); |
19 | void msg_init(void); | 19 | int msg_init(void); |
20 | void shm_init(void); | 20 | void shm_init(void); |
21 | 21 | ||
22 | struct ipc_namespace; | 22 | struct 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 |
33 | void sem_init_ns(struct ipc_namespace *ns); | 33 | int sem_init_ns(struct ipc_namespace *ns); |
34 | void msg_init_ns(struct ipc_namespace *ns); | 34 | int msg_init_ns(struct ipc_namespace *ns); |
35 | void shm_init_ns(struct ipc_namespace *ns); | 35 | int shm_init_ns(struct ipc_namespace *ns); |
36 | 36 | ||
37 | void sem_exit_ns(struct ipc_namespace *ns); | 37 | void sem_exit_ns(struct ipc_namespace *ns); |
38 | void msg_exit_ns(struct ipc_namespace *ns); | 38 | void msg_exit_ns(struct ipc_namespace *ns); |
39 | void shm_exit_ns(struct ipc_namespace *ns); | 39 | void shm_exit_ns(struct ipc_namespace *ns); |
40 | #else | 40 | #else |
41 | static inline void sem_init_ns(struct ipc_namespace *ns) { } | 41 | static inline int sem_init_ns(struct ipc_namespace *ns) { return 0; } |
42 | static inline void msg_init_ns(struct ipc_namespace *ns) { } | 42 | static inline int msg_init_ns(struct ipc_namespace *ns) { return 0; } |
43 | static inline void shm_init_ns(struct ipc_namespace *ns) { } | 43 | static inline int shm_init_ns(struct ipc_namespace *ns) { return 0; } |
44 | 44 | ||
45 | static inline void sem_exit_ns(struct ipc_namespace *ns) { } | 45 | static inline void sem_exit_ns(struct ipc_namespace *ns) { } |
46 | static inline void msg_exit_ns(struct ipc_namespace *ns) { } | 46 | static inline void msg_exit_ns(struct ipc_namespace *ns) { } |
@@ -79,7 +79,7 @@ struct ipc_ops { | |||
79 | struct seq_file; | 79 | struct seq_file; |
80 | struct ipc_ids; | 80 | struct ipc_ids; |
81 | 81 | ||
82 | void ipc_init_ids(struct ipc_ids *); | 82 | int ipc_init_ids(struct ipc_ids *); |
83 | #ifdef CONFIG_PROC_FS | 83 | #ifdef CONFIG_PROC_FS |
84 | void __init ipc_init_proc_interface(const char *path, const char *header, | 84 | void __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. */ |
105 | void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *); | 105 | void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *); |
106 | 106 | ||
107 | /* must be called with both locks acquired. */ | ||
108 | void 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 */ |
108 | int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg); | 111 | int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg); |
109 | 112 | ||