ipc,namespace: make ipc namespace allocation wait for pending free
[linux-2.6-block.git] / ipc / namespace.c
index 8316ea5857333d756c4a6741853d92820a0e5d65..a26860a41daca94f4239ad9486967001ac23d7f8 100644 (file)
 
 #include "util.h"
 
+/*
+ * The work queue is used to avoid the cost of synchronize_rcu in kern_unmount.
+ */
+static void free_ipc(struct work_struct *unused);
+static DECLARE_WORK(free_ipc_work, free_ipc);
+
 static struct ucounts *inc_ipc_namespaces(struct user_namespace *ns)
 {
        return inc_ucount(ns, current_euid(), UCOUNT_IPC_NAMESPACES);
@@ -37,9 +43,18 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
        int err;
 
        err = -ENOSPC;
+ again:
        ucounts = inc_ipc_namespaces(user_ns);
-       if (!ucounts)
+       if (!ucounts) {
+               /*
+                * IPC namespaces are freed asynchronously, by free_ipc_work.
+                * If frees were pending, flush_work will wait, and
+                * return true. Fail the allocation if no frees are pending.
+                */
+               if (flush_work(&free_ipc_work))
+                       goto again;
                goto fail;
+       }
 
        err = -ENOMEM;
        ns = kzalloc(sizeof(struct ipc_namespace), GFP_KERNEL_ACCOUNT);
@@ -157,11 +172,6 @@ static void free_ipc(struct work_struct *unused)
                free_ipc_ns(n);
 }
 
-/*
- * The work queue is used to avoid the cost of synchronize_rcu in kern_unmount.
- */
-static DECLARE_WORK(free_ipc_work, free_ipc);
-
 /*
  * put_ipc_ns - drop a reference to an ipc namespace.
  * @ns: the namespace to put