aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/namespace.c')
-rw-r--r--ipc/namespace.c41
1 files changed, 35 insertions, 6 deletions
diff --git a/ipc/namespace.c b/ipc/namespace.c
index 4b4dc6d847f1..4a5e752a9276 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -9,23 +9,31 @@
9#include <linux/rcupdate.h> 9#include <linux/rcupdate.h>
10#include <linux/nsproxy.h> 10#include <linux/nsproxy.h>
11#include <linux/slab.h> 11#include <linux/slab.h>
12#include <linux/fs.h>
13#include <linux/mount.h>
12 14
13#include "util.h" 15#include "util.h"
14 16
15static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns) 17static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)
16{ 18{
17 struct ipc_namespace *ns; 19 struct ipc_namespace *ns;
20 int err;
18 21
19 ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL); 22 ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
20 if (ns == NULL) 23 if (ns == NULL)
21 return ERR_PTR(-ENOMEM); 24 return ERR_PTR(-ENOMEM);
22 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 }
23 atomic_inc(&nr_ipc_ns); 32 atomic_inc(&nr_ipc_ns);
24 33
25 sem_init_ns(ns); 34 sem_init_ns(ns);
26 msg_init_ns(ns); 35 msg_init_ns(ns);
27 shm_init_ns(ns); 36 shm_init_ns(ns);
28 mq_init_ns(ns);
29 37
30 /* 38 /*
31 * msgmni has already been computed for the new ipc ns. 39 * msgmni has already been computed for the new ipc ns.
@@ -35,7 +43,6 @@ static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)
35 ipcns_notify(IPCNS_CREATED); 43 ipcns_notify(IPCNS_CREATED);
36 register_ipcns_notifier(ns); 44 register_ipcns_notifier(ns);
37 45
38 kref_init(&ns->kref);
39 return ns; 46 return ns;
40} 47}
41 48
@@ -85,11 +92,34 @@ void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
85 up_write(&ids->rw_mutex); 92 up_write(&ids->rw_mutex);
86} 93}
87 94
88void free_ipc_ns(struct kref *kref) 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 */
111void put_ipc_ns(struct ipc_namespace *ns)
89{ 112{
90 struct ipc_namespace *ns; 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}
91 120
92 ns = container_of(kref, struct ipc_namespace, kref); 121void free_ipc_ns(struct ipc_namespace *ns)
122{
93 /* 123 /*
94 * Unregistering the hotplug notifier at the beginning guarantees 124 * Unregistering the hotplug notifier at the beginning guarantees
95 * that the ipc namespace won't be freed while we are inside the 125 * that the ipc namespace won't be freed while we are inside the
@@ -102,7 +132,6 @@ void free_ipc_ns(struct kref *kref)
102 sem_exit_ns(ns); 132 sem_exit_ns(ns);
103 msg_exit_ns(ns); 133 msg_exit_ns(ns);
104 shm_exit_ns(ns); 134 shm_exit_ns(ns);
105 mq_exit_ns(ns);
106 kfree(ns); 135 kfree(ns);
107 atomic_dec(&nr_ipc_ns); 136 atomic_dec(&nr_ipc_ns);
108 137