diff options
-rw-r--r-- | ipc/shm.c | 67 |
1 files changed, 35 insertions, 32 deletions
@@ -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 */ |
272 | static 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 */ | ||
298 | static int shm_try_destroy_orphaned(int id, void *p, void *data) | 272 | static 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 */ | |
329 | void exit_shm(struct task_struct *task) | 303 | void 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 | } |