diff options
Diffstat (limited to 'ipc/util.c')
-rw-r--r-- | ipc/util.c | 42 |
1 files changed, 19 insertions, 23 deletions
diff --git a/ipc/util.c b/ipc/util.c index 72fd0785ac94..464a8abd779f 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
@@ -122,6 +122,7 @@ void ipc_init_ids(struct ipc_ids *ids) | |||
122 | 122 | ||
123 | ids->in_use = 0; | 123 | ids->in_use = 0; |
124 | ids->seq = 0; | 124 | ids->seq = 0; |
125 | ids->next_id = -1; | ||
125 | { | 126 | { |
126 | int seq_limit = INT_MAX/SEQ_MULTIPLIER; | 127 | int seq_limit = INT_MAX/SEQ_MULTIPLIER; |
127 | if (seq_limit > USHRT_MAX) | 128 | if (seq_limit > USHRT_MAX) |
@@ -251,7 +252,8 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | |||
251 | { | 252 | { |
252 | kuid_t euid; | 253 | kuid_t euid; |
253 | kgid_t egid; | 254 | kgid_t egid; |
254 | int id, err; | 255 | int id; |
256 | int next_id = ids->next_id; | ||
255 | 257 | ||
256 | if (size > IPCMNI) | 258 | if (size > IPCMNI) |
257 | size = IPCMNI; | 259 | size = IPCMNI; |
@@ -259,16 +261,21 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | |||
259 | if (ids->in_use >= size) | 261 | if (ids->in_use >= size) |
260 | return -ENOSPC; | 262 | return -ENOSPC; |
261 | 263 | ||
264 | idr_preload(GFP_KERNEL); | ||
265 | |||
262 | spin_lock_init(&new->lock); | 266 | spin_lock_init(&new->lock); |
263 | new->deleted = 0; | 267 | new->deleted = 0; |
264 | rcu_read_lock(); | 268 | rcu_read_lock(); |
265 | spin_lock(&new->lock); | 269 | spin_lock(&new->lock); |
266 | 270 | ||
267 | err = idr_get_new(&ids->ipcs_idr, new, &id); | 271 | id = idr_alloc(&ids->ipcs_idr, new, |
268 | if (err) { | 272 | (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0, |
273 | GFP_NOWAIT); | ||
274 | idr_preload_end(); | ||
275 | if (id < 0) { | ||
269 | spin_unlock(&new->lock); | 276 | spin_unlock(&new->lock); |
270 | rcu_read_unlock(); | 277 | rcu_read_unlock(); |
271 | return err; | 278 | return id; |
272 | } | 279 | } |
273 | 280 | ||
274 | ids->in_use++; | 281 | ids->in_use++; |
@@ -277,9 +284,14 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) | |||
277 | new->cuid = new->uid = euid; | 284 | new->cuid = new->uid = euid; |
278 | new->gid = new->cgid = egid; | 285 | new->gid = new->cgid = egid; |
279 | 286 | ||
280 | new->seq = ids->seq++; | 287 | if (next_id < 0) { |
281 | if(ids->seq > ids->seq_max) | 288 | new->seq = ids->seq++; |
282 | ids->seq = 0; | 289 | if (ids->seq > ids->seq_max) |
290 | ids->seq = 0; | ||
291 | } else { | ||
292 | new->seq = ipcid_to_seqx(next_id); | ||
293 | ids->next_id = -1; | ||
294 | } | ||
283 | 295 | ||
284 | new->id = ipc_buildid(id, new->seq); | 296 | new->id = ipc_buildid(id, new->seq); |
285 | return id; | 297 | return id; |
@@ -299,19 +311,10 @@ static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, | |||
299 | struct ipc_ops *ops, struct ipc_params *params) | 311 | struct ipc_ops *ops, struct ipc_params *params) |
300 | { | 312 | { |
301 | int err; | 313 | int err; |
302 | retry: | ||
303 | err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL); | ||
304 | |||
305 | if (!err) | ||
306 | return -ENOMEM; | ||
307 | 314 | ||
308 | down_write(&ids->rw_mutex); | 315 | down_write(&ids->rw_mutex); |
309 | err = ops->getnew(ns, params); | 316 | err = ops->getnew(ns, params); |
310 | up_write(&ids->rw_mutex); | 317 | up_write(&ids->rw_mutex); |
311 | |||
312 | if (err == -EAGAIN) | ||
313 | goto retry; | ||
314 | |||
315 | return err; | 318 | return err; |
316 | } | 319 | } |
317 | 320 | ||
@@ -368,8 +371,6 @@ static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, | |||
368 | struct kern_ipc_perm *ipcp; | 371 | struct kern_ipc_perm *ipcp; |
369 | int flg = params->flg; | 372 | int flg = params->flg; |
370 | int err; | 373 | int err; |
371 | retry: | ||
372 | err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL); | ||
373 | 374 | ||
374 | /* | 375 | /* |
375 | * Take the lock as a writer since we are potentially going to add | 376 | * Take the lock as a writer since we are potentially going to add |
@@ -381,8 +382,6 @@ retry: | |||
381 | /* key not used */ | 382 | /* key not used */ |
382 | if (!(flg & IPC_CREAT)) | 383 | if (!(flg & IPC_CREAT)) |
383 | err = -ENOENT; | 384 | err = -ENOENT; |
384 | else if (!err) | ||
385 | err = -ENOMEM; | ||
386 | else | 385 | else |
387 | err = ops->getnew(ns, params); | 386 | err = ops->getnew(ns, params); |
388 | } else { | 387 | } else { |
@@ -405,9 +404,6 @@ retry: | |||
405 | } | 404 | } |
406 | up_write(&ids->rw_mutex); | 405 | up_write(&ids->rw_mutex); |
407 | 406 | ||
408 | if (err == -EAGAIN) | ||
409 | goto retry; | ||
410 | |||
411 | return err; | 407 | return err; |
412 | } | 408 | } |
413 | 409 | ||