diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-04-24 10:11:18 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-04-24 10:11:23 +0200 |
commit | 416dfdcdb894432547ead4fcb9fa6a36b396059e (patch) | |
tree | 8033fdda07397a59c5fa98c88927040906ce6c1a /ipc/namespace.c | |
parent | 56449f437add737a1e5e1cb7e00f63ac8ead1938 (diff) | |
parent | 091069740304c979f957ceacec39c461d0192158 (diff) | |
download | op-kernel-dev-416dfdcdb894432547ead4fcb9fa6a36b396059e.zip op-kernel-dev-416dfdcdb894432547ead4fcb9fa6a36b396059e.tar.gz |
Merge commit 'v2.6.30-rc3' into tracing/hw-branch-tracing
Conflicts:
arch/x86/kernel/ptrace.c
Merge reason: fix the conflict above, and also pick up the CONFIG_BROKEN
dependency change from upstream so that we can remove it
here.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'ipc/namespace.c')
-rw-r--r-- | ipc/namespace.c | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/ipc/namespace.c b/ipc/namespace.c index 9171d94..4a5e752 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c @@ -9,17 +9,26 @@ #include <linux/rcupdate.h> #include <linux/nsproxy.h> #include <linux/slab.h> +#include <linux/fs.h> +#include <linux/mount.h> #include "util.h" static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns) { struct ipc_namespace *ns; + int err; ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL); if (ns == NULL) return ERR_PTR(-ENOMEM); + atomic_set(&ns->count, 1); + err = mq_init_ns(ns); + if (err) { + kfree(ns); + return ERR_PTR(err); + } atomic_inc(&nr_ipc_ns); sem_init_ns(ns); @@ -34,7 +43,6 @@ static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns) ipcns_notify(IPCNS_CREATED); register_ipcns_notifier(ns); - kref_init(&ns->kref); return ns; } @@ -84,11 +92,34 @@ void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, up_write(&ids->rw_mutex); } -void free_ipc_ns(struct kref *kref) +/* + * put_ipc_ns - drop a reference to an ipc namespace. + * @ns: the namespace to put + * + * If this is the last task in the namespace exiting, and + * it is dropping the refcount to 0, then it can race with + * a task in another ipc namespace but in a mounts namespace + * which has this ipcns's mqueuefs mounted, doing some action + * with one of the mqueuefs files. That can raise the refcount. + * So dropping the refcount, and raising the refcount when + * accessing it through the VFS, are protected with mq_lock. + * + * (Clearly, a task raising the refcount on its own ipc_ns + * needn't take mq_lock since it can't race with the last task + * in the ipcns exiting). + */ +void put_ipc_ns(struct ipc_namespace *ns) { - struct ipc_namespace *ns; + if (atomic_dec_and_lock(&ns->count, &mq_lock)) { + mq_clear_sbinfo(ns); + spin_unlock(&mq_lock); + mq_put_mnt(ns); + free_ipc_ns(ns); + } +} - ns = container_of(kref, struct ipc_namespace, kref); +void free_ipc_ns(struct ipc_namespace *ns) +{ /* * Unregistering the hotplug notifier at the beginning guarantees * that the ipc namespace won't be freed while we are inside the |