diff --git a/ipc/namespace.c b/ipc/namespace.c index 1e71353bdb..bc06343096 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c @@ -26,6 +26,13 @@ static void free_ipc(struct work_struct *unused); static DECLARE_WORK(free_ipc_work, free_ipc); +/* + * Maximum number of free_ipc_work retries without progress in create_ipc_ns + * before we return failure to userspace. + */ +#define MAX_FREE_IPC_RETRIES 16 +#define FREE_IPC_WAIT_JIFFIES 5 + static struct ucounts *inc_ipc_namespaces(struct user_namespace *ns) { return inc_ucount(ns, current_euid(), UCOUNT_IPC_NAMESPACES); @@ -41,6 +48,7 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, { struct ipc_namespace *ns; struct ucounts *ucounts; + int retries = 0; int err; err = -ENOSPC; @@ -49,12 +57,23 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, 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. + * Bail out if we've failed too many times. + */ + if (retries++ >= MAX_FREE_IPC_RETRIES) + goto fail; + + /* + * Ensure free_ipc_work is running. */ - if (flush_work(&free_ipc_work)) - goto again; - goto fail; + schedule_work(&free_ipc_work); + schedule_timeout_interruptible(FREE_IPC_WAIT_JIFFIES); + + if (signal_pending(current)) { + err = -ERESTARTSYS; + goto fail; + } + + goto again; } err = -ENOMEM;