usermodehelper: kill the kmod_thread_locker logic
authorOleg Nesterov <oleg@redhat.com>
Wed, 10 Dec 2014 23:54:42 +0000 (15:54 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 11 Dec 2014 01:41:17 +0000 (17:41 -0800)
Now that we do not call kernel_thread(CLONE_VFORK) from the worker
thread we can not deadlock if do_execve() in turn triggers another
call_usermodehelper(), we can remove the kmod_thread_locker code.

Note: we should probably kill khelper_wq and simply use one of the
global workqueues, say, system_unbound_wq, this special wq for umh buys
nothing nowadays.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
kernel/kmod.c

index 4621771..2777f40 100644 (file)
@@ -47,13 +47,6 @@ extern int max_threads;
 
 static struct workqueue_struct *khelper_wq;
 
-/*
- * kmod_thread_locker is used for deadlock avoidance.  There is no explicit
- * locking to protect this global - it is private to the singleton khelper
- * thread and should only ever be modified by that thread.
- */
-static const struct task_struct *kmod_thread_locker;
-
 #define CAP_BSET       (void *)1
 #define CAP_PI         (void *)2
 
@@ -273,13 +266,6 @@ out:
        do_exit(0);
 }
 
-static int call_helper(void *data)
-{
-       /* Worker thread started blocking khelper thread. */
-       kmod_thread_locker = current;
-       return ____call_usermodehelper(data);
-}
-
 /* Keventd can't block, but this (a child) can. */
 static int wait_for_helper(void *data)
 {
@@ -327,11 +313,9 @@ static void __call_usermodehelper(struct work_struct *work)
        if (sub_info->wait & UMH_WAIT_PROC)
                pid = kernel_thread(wait_for_helper, sub_info,
                                    CLONE_FS | CLONE_FILES | SIGCHLD);
-       else {
-               pid = kernel_thread(call_helper, sub_info, SIGCHLD);
-               /* Worker thread stopped blocking khelper thread. */
-               kmod_thread_locker = NULL;
-       }
+       else
+               pid = kernel_thread(____call_usermodehelper, sub_info,
+                                   SIGCHLD);
 
        if (pid < 0) {
                sub_info->retval = pid;
@@ -564,17 +548,6 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
                retval = -EBUSY;
                goto out;
        }
-       /*
-        * Worker thread must not wait for khelper thread at below
-        * wait_for_completion() if the thread was created with CLONE_VFORK
-        * flag, for khelper thread is already waiting for the thread at
-        * wait_for_completion() in do_fork().
-        */
-       if (wait != UMH_NO_WAIT && current == kmod_thread_locker) {
-               retval = -EBUSY;
-               goto out;
-       }
-
        /*
         * Set the completion pointer only if there is a waiter.
         * This makes it possible to use umh_complete to free