1 /* 2 * linux/ipc/namespace.c 3 * Copyright (C) 2006 Pavel Emelyanov <xemul@openvz.org> OpenVZ, SWsoft Inc. 4 */ 5 6 #include <linux/ipc.h> 7 #include <linux/msg.h> 8 #include <linux/ipc_namespace.h> 9 #include <linux/rcupdate.h> 10 #include <linux/nsproxy.h> 11 #include <linux/slab.h> 12 #include <linux/fs.h> 13 #include <linux/mount.h> 14 15 #include "util.h" 16 17 static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns) 18 { 19 struct ipc_namespace *ns; 20 int err; 21 22 ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL); 23 if (ns == NULL) 24 return ERR_PTR(-ENOMEM); 25 26 atomic_set(&ns->count, 1); 27 err = mq_init_ns(ns); 28 if (err) { 29 kfree(ns); 30 return ERR_PTR(err); 31 } 32 atomic_inc(&nr_ipc_ns); 33 34 sem_init_ns(ns); 35 msg_init_ns(ns); 36 shm_init_ns(ns); 37 38 /* 39 * msgmni has already been computed for the new ipc ns. 40 * Thus, do the ipcns creation notification before registering that 41 * new ipcns in the chain. 42 */ 43 ipcns_notify(IPCNS_CREATED); 44 register_ipcns_notifier(ns); 45 46 return ns; 47 } 48 49 struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns) 50 { 51 struct ipc_namespace *new_ns; 52 53 BUG_ON(!ns); 54 get_ipc_ns(ns); 55 56 if (!(flags & CLONE_NEWIPC)) 57 return ns; 58 59 new_ns = clone_ipc_ns(ns); 60 61 put_ipc_ns(ns); 62 return new_ns; 63 } 64 65 /* 66 * free_ipcs - free all ipcs of one type 67 * @ns: the namespace to remove the ipcs from 68 * @ids: the table of ipcs to free 69 * @free: the function called to free each individual ipc 70 * 71 * Called for each kind of ipc when an ipc_namespace exits. 72 */ 73 void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, 74 void (*free)(struct ipc_namespace *, struct kern_ipc_perm *)) 75 { 76 struct kern_ipc_perm *perm; 77 int next_id; 78 int total, in_use; 79 80 down_write(&ids->rw_mutex); 81 82 in_use = ids->in_use; 83 84 for (total = 0, next_id = 0; total < in_use; next_id++) { 85 perm = idr_find(&ids->ipcs_idr, next_id); 86 if (perm == NULL) 87 continue; 88 ipc_lock_by_ptr(perm); 89 free(ns, perm); 90 total++; 91 } 92 up_write(&ids->rw_mutex); 93 } 94 95 /* 96 * put_ipc_ns - drop a reference to an ipc namespace. 97 * @ns: the namespace to put 98 * 99 * If this is the last task in the namespace exiting, and 100 * it is dropping the refcount to 0, then it can race with 101 * a task in another ipc namespace but in a mounts namespace 102 * which has this ipcns's mqueuefs mounted, doing some action 103 * with one of the mqueuefs files. That can raise the refcount. 104 * So dropping the refcount, and raising the refcount when 105 * accessing it through the VFS, are protected with mq_lock. 106 * 107 * (Clearly, a task raising the refcount on its own ipc_ns 108 * needn't take mq_lock since it can't race with the last task 109 * in the ipcns exiting). 110 */ 111 void put_ipc_ns(struct ipc_namespace *ns) 112 { 113 if (atomic_dec_and_lock(&ns->count, &mq_lock)) { 114 mq_clear_sbinfo(ns); 115 spin_unlock(&mq_lock); 116 mq_put_mnt(ns); 117 free_ipc_ns(ns); 118 } 119 } 120 121 void free_ipc_ns(struct ipc_namespace *ns) 122 { 123 /* 124 * Unregistering the hotplug notifier at the beginning guarantees 125 * that the ipc namespace won't be freed while we are inside the 126 * callback routine. Since the blocking_notifier_chain_XXX routines 127 * hold a rw lock on the notifier list, unregister_ipcns_notifier() 128 * won't take the rw lock before blocking_notifier_call_chain() has 129 * released the rd lock. 130 */ 131 unregister_ipcns_notifier(ns); 132 sem_exit_ns(ns); 133 msg_exit_ns(ns); 134 shm_exit_ns(ns); 135 kfree(ns); 136 atomic_dec(&nr_ipc_ns); 137 138 /* 139 * Do the ipcns removal notification after decrementing nr_ipc_ns in 140 * order to have a correct value when recomputing msgmni. 141 */ 142 ipcns_notify(IPCNS_REMOVED); 143 } 144