]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] Use workqueue for call_usermodehelper
authorAndrew Morton <akpm@osdl.org>
Mon, 26 Apr 2004 15:55:31 +0000 (08:55 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 26 Apr 2004 15:55:31 +0000 (08:55 -0700)
From: Rusty Russell <rusty@rustcorp.com.au>

call_usermodehelper uses keventd to create a thread, guaranteeing a nice,
clean kernel thread.  Unfortunately, there is a case where
call_usermodehelper is called with &bus->subsys.rwsem held (via
bus_add_driver()), but keventd could be running bus_add_device(), which is
blocked on the same lock.  The result is deadlock, and it comes from using
keventd for both.

In this case, it can be fixed by using a completely independent thread for
call_usermodehelper, or an independent workqueue.  Workqueues have the
infrastructure we need, so we use one.

Move EXPORT_SYMBOL while we're there, too.

akpm fixes: Make it compile with !CONFIG_KMOD

kernel/kmod.c

index 0002fcd4c5543a4a816a66869d994f243bc9838b..8754003bbbf2c641aad3c3c6182f72c92c0e5221 100644 (file)
 #include <linux/security.h>
 #include <linux/mount.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 
 extern int max_threads;
 
+static struct workqueue_struct *khelper_wq;
+
 #ifdef CONFIG_KMOD
 
 /*
@@ -109,6 +112,7 @@ int request_module(const char *fmt, ...)
        atomic_dec(&kmod_concurrent);
        return ret;
 }
+EXPORT_SYMBOL(request_module);
 #endif /* CONFIG_KMOD */
 
 #ifdef CONFIG_HOTPLUG
@@ -197,9 +201,7 @@ static int wait_for_helper(void *data)
        return 0;
 }
 
-/*
- * This is run by keventd.
- */
+/* This is run by khelper thread  */
 static void __call_usermodehelper(void *data)
 {
        struct subprocess_info *sub_info = data;
@@ -249,26 +251,22 @@ int call_usermodehelper(char *path, char **argv, char **envp, int wait)
        };
        DECLARE_WORK(work, __call_usermodehelper, &sub_info);
 
-       if (system_state != SYSTEM_RUNNING)
+       if (!khelper_wq)
                return -EBUSY;
 
        if (path[0] == '\0')
-               goto out;
-
-       if (current_is_keventd()) {
-               /* We can't wait on keventd! */
-               __call_usermodehelper(&sub_info);
-       } else {
-               schedule_work(&work);
-               wait_for_completion(&done);
-       }
-out:
+               return 0;
+
+       queue_work(khelper_wq, &work);
+       wait_for_completion(&done);
        return sub_info.retval;
 }
-
 EXPORT_SYMBOL(call_usermodehelper);
 
-#ifdef CONFIG_KMOD
-EXPORT_SYMBOL(request_module);
-#endif
-
+static __init int usermodehelper_init(void)
+{
+       khelper_wq = create_singlethread_workqueue("khelper");
+       BUG_ON(!khelper_wq);
+       return 0;
+}
+__initcall(usermodehelper_init);