Skip to content

Commit a80c4ad

Browse files
rikvanrielAl Viro
authored andcommitted
ipc,namespace: make ipc namespace allocation wait for pending free
Currently the ipc namespace allocation will fail when there are ipc_namespace structures pending to be freed. This results in the simple test case below, as well as some real world workloads, to get allocation failures even when the number of ipc namespaces in actual use is way below the limit. int main() { int i; for (i = 0; i < 100000; i++) { if (unshare(CLONE_NEWIPC) < 0) error(EXIT_FAILURE, errno, "unshare"); } } Make the allocation of an ipc_namespace wait for pending frees, so it will succeed. real 6m19.197s user 0m0.041s sys 0m1.019s Signed-off-by: Rik van Riel <[email protected]> Reported-by: Chris Mason <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent b7bfaa7 commit a80c4ad

File tree

1 file changed

+16
-6
lines changed

1 file changed

+16
-6
lines changed

ipc/namespace.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919

2020
#include "util.h"
2121

22+
/*
23+
* The work queue is used to avoid the cost of synchronize_rcu in kern_unmount.
24+
*/
25+
static void free_ipc(struct work_struct *unused);
26+
static DECLARE_WORK(free_ipc_work, free_ipc);
27+
2228
static struct ucounts *inc_ipc_namespaces(struct user_namespace *ns)
2329
{
2430
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,
3743
int err;
3844

3945
err = -ENOSPC;
46+
again:
4047
ucounts = inc_ipc_namespaces(user_ns);
41-
if (!ucounts)
48+
if (!ucounts) {
49+
/*
50+
* IPC namespaces are freed asynchronously, by free_ipc_work.
51+
* If frees were pending, flush_work will wait, and
52+
* return true. Fail the allocation if no frees are pending.
53+
*/
54+
if (flush_work(&free_ipc_work))
55+
goto again;
4256
goto fail;
57+
}
4358

4459
err = -ENOMEM;
4560
ns = kzalloc(sizeof(struct ipc_namespace), GFP_KERNEL_ACCOUNT);
@@ -157,11 +172,6 @@ static void free_ipc(struct work_struct *unused)
157172
free_ipc_ns(n);
158173
}
159174

160-
/*
161-
* The work queue is used to avoid the cost of synchronize_rcu in kern_unmount.
162-
*/
163-
static DECLARE_WORK(free_ipc_work, free_ipc);
164-
165175
/*
166176
* put_ipc_ns - drop a reference to an ipc namespace.
167177
* @ns: the namespace to put

0 commit comments

Comments
 (0)