aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorJack Miller <millerjo@us.ibm.com>2014-08-08 17:23:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-08 18:57:26 -0400
commit83293c0f5a6130bf7d60b7b406f4a4de0cadd3d8 (patch)
tree9800879dfd131c263d57276c29494b06deac7f70 /ipc
parentab602f799159393143d567e5c04b936fec79d6bd (diff)
shm: allow exit_shm in parallel if only marking orphans
If shm_rmid_force (the default state) is not set then the shmids are only marked as orphaned and does not require any add, delete, or locking of the tree structure. Seperate the sysctl on and off case, and only obtain the read lock. The newly added list head can be deleted under the read lock because we are only called with current and will only change the semids allocated by this task and not manipulate the list. This commit assumes that up_read includes a sufficient memory barrier for the writes to be seen my others that later obtain a write lock. Signed-off-by: Milton Miller <miltonm@bga.com> Signed-off-by: Jack Miller <millerjo@us.ibm.com> Cc: Davidlohr Bueso <davidlohr@hp.com> Cc: Manfred Spraul <manfred@colorfullife.com> Cc: Anton Blanchard <anton@samba.org> 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/shm.c67
1 files changed, 35 insertions, 32 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index 1fc3a61b443b..7fc9f9f3a26b 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -269,32 +269,6 @@ static void shm_close(struct vm_area_struct *vma)
269} 269}
270 270
271/* Called with ns->shm_ids(ns).rwsem locked */ 271/* Called with ns->shm_ids(ns).rwsem locked */
272static void shm_mark_orphan(struct shmid_kernel *shp, struct ipc_namespace *ns)
273{
274 if (WARN_ON(shp->shm_creator != current)) /* Remove me when it works */
275 return;
276
277 /*
278 * Mark it as orphaned to destroy the segment when
279 * kernel.shm_rmid_forced is changed.
280 * It is noop if the following shm_may_destroy() returns true.
281 */
282 shp->shm_creator = NULL;
283
284 /*
285 * Don't even try to destroy it. If shm_rmid_forced=0 and IPC_RMID
286 * is not set, it shouldn't be deleted here.
287 */
288 if (!ns->shm_rmid_forced)
289 return;
290
291 if (shm_may_destroy(ns, shp)) {
292 shm_lock_by_ptr(shp);
293 shm_destroy(ns, shp);
294 }
295}
296
297/* Called with ns->shm_ids(ns).rwsem locked */
298static int shm_try_destroy_orphaned(int id, void *p, void *data) 272static int shm_try_destroy_orphaned(int id, void *p, void *data)
299{ 273{
300 struct ipc_namespace *ns = data; 274 struct ipc_namespace *ns = data;
@@ -325,20 +299,49 @@ void shm_destroy_orphaned(struct ipc_namespace *ns)
325 up_write(&shm_ids(ns).rwsem); 299 up_write(&shm_ids(ns).rwsem);
326} 300}
327 301
328 302/* Locking assumes this will only be called with task == current */
329void exit_shm(struct task_struct *task) 303void exit_shm(struct task_struct *task)
330{ 304{
331 struct ipc_namespace *ns = task->nsproxy->ipc_ns; 305 struct ipc_namespace *ns = task->nsproxy->ipc_ns;
332 struct shmid_kernel *shp, *n; 306 struct shmid_kernel *shp, *n;
333 307
334 if (shm_ids(ns).in_use == 0) 308 if (list_empty(&task->sysvshm.shm_clist))
309 return;
310
311 /*
312 * If kernel.shm_rmid_forced is not set then only keep track of
313 * which shmids are orphaned, so that a later set of the sysctl
314 * can clean them up.
315 */
316 if (!ns->shm_rmid_forced) {
317 down_read(&shm_ids(ns).rwsem);
318 list_for_each_entry(shp, &task->sysvshm.shm_clist, shm_clist)
319 shp->shm_creator = NULL;
320 /*
321 * Only under read lock but we are only called on current
322 * so no entry on the list will be shared.
323 */
324 list_del(&task->sysvshm.shm_clist);
325 up_read(&shm_ids(ns).rwsem);
335 return; 326 return;
327 }
336 328
337 /* Destroy all already created segments, but not mapped yet */ 329 /*
330 * Destroy all already created segments, that were not yet mapped,
331 * and mark any mapped as orphan to cover the sysctl toggling.
332 * Destroy is skipped if shm_may_destroy() returns false.
333 */
338 down_write(&shm_ids(ns).rwsem); 334 down_write(&shm_ids(ns).rwsem);
339 list_for_each_entry_safe(shp, n, &task->sysvshm.shm_clist, shm_clist) 335 list_for_each_entry_safe(shp, n, &task->sysvshm.shm_clist, shm_clist) {
340 shm_mark_orphan(shp, ns); 336 shp->shm_creator = NULL;
341 /* remove the list head from any segments still attached */ 337
338 if (shm_may_destroy(ns, shp)) {
339 shm_lock_by_ptr(shp);
340 shm_destroy(ns, shp);
341 }
342 }
343
344 /* Remove the list head from any segments still attached. */
342 list_del(&task->sysvshm.shm_clist); 345 list_del(&task->sysvshm.shm_clist);
343 up_write(&shm_ids(ns).rwsem); 346 up_write(&shm_ids(ns).rwsem);
344} 347}