linux/ipc/namespace.c
<<
>>
Prefs
   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
  17static 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
  49struct 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 */
  73void 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 */
 111void 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
 121void 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