summaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'ipc')
-rw-r--r--ipc/shm.c75
1 files changed, 39 insertions, 36 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index 89fc354156cb..7fc9f9f3a26b 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -178,6 +178,7 @@ static void shm_rcu_free(struct rcu_head *head)
178 178
179static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s) 179static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
180{ 180{
181 list_del(&s->shm_clist);
181 ipc_rmid(&shm_ids(ns), &s->shm_perm); 182 ipc_rmid(&shm_ids(ns), &s->shm_perm);
182} 183}
183 184
@@ -268,37 +269,6 @@ static void shm_close(struct vm_area_struct *vma)
268} 269}
269 270
270/* Called with ns->shm_ids(ns).rwsem locked */ 271/* Called with ns->shm_ids(ns).rwsem locked */
271static int shm_try_destroy_current(int id, void *p, void *data)
272{
273 struct ipc_namespace *ns = data;
274 struct kern_ipc_perm *ipcp = p;
275 struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
276
277 if (shp->shm_creator != current)
278 return 0;
279
280 /*
281 * Mark it as orphaned to destroy the segment when
282 * kernel.shm_rmid_forced is changed.
283 * It is noop if the following shm_may_destroy() returns true.
284 */
285 shp->shm_creator = NULL;
286
287 /*
288 * Don't even try to destroy it. If shm_rmid_forced=0 and IPC_RMID
289 * is not set, it shouldn't be deleted here.
290 */
291 if (!ns->shm_rmid_forced)
292 return 0;
293
294 if (shm_may_destroy(ns, shp)) {
295 shm_lock_by_ptr(shp);
296 shm_destroy(ns, shp);
297 }
298 return 0;
299}
300
301/* Called with ns->shm_ids(ns).rwsem locked */
302static int shm_try_destroy_orphaned(int id, void *p, void *data) 272static int shm_try_destroy_orphaned(int id, void *p, void *data)
303{ 273{
304 struct ipc_namespace *ns = data; 274 struct ipc_namespace *ns = data;
@@ -329,18 +299,50 @@ void shm_destroy_orphaned(struct ipc_namespace *ns)
329 up_write(&shm_ids(ns).rwsem); 299 up_write(&shm_ids(ns).rwsem);
330} 300}
331 301
332 302/* Locking assumes this will only be called with task == current */
333void exit_shm(struct task_struct *task) 303void exit_shm(struct task_struct *task)
334{ 304{
335 struct ipc_namespace *ns = task->nsproxy->ipc_ns; 305 struct ipc_namespace *ns = task->nsproxy->ipc_ns;
306 struct shmid_kernel *shp, *n;
336 307
337 if (shm_ids(ns).in_use == 0) 308 if (list_empty(&task->sysvshm.shm_clist))
338 return; 309 return;
339 310
340 /* Destroy all already created segments, but not mapped yet */ 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);
326 return;
327 }
328
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 */
341 down_write(&shm_ids(ns).rwsem); 334 down_write(&shm_ids(ns).rwsem);
342 if (shm_ids(ns).in_use) 335 list_for_each_entry_safe(shp, n, &task->sysvshm.shm_clist, shm_clist) {
343 idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns); 336 shp->shm_creator = NULL;
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. */
345 list_del(&task->sysvshm.shm_clist);
344 up_write(&shm_ids(ns).rwsem); 346 up_write(&shm_ids(ns).rwsem);
345} 347}
346 348
@@ -561,6 +563,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
561 shp->shm_nattch = 0; 563 shp->shm_nattch = 0;
562 shp->shm_file = file; 564 shp->shm_file = file;
563 shp->shm_creator = current; 565 shp->shm_creator = current;
566 list_add(&shp->shm_clist, &current->sysvshm.shm_clist);
564 567
565 /* 568 /*
566 * shmid gets reported as "inode#" in /proc/pid/maps. 569 * shmid gets reported as "inode#" in /proc/pid/maps.