Commit 35f4fc9f authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Use workqueue for call_usermodehelper

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
parent bf9e688d
...@@ -35,10 +35,13 @@ ...@@ -35,10 +35,13 @@
#include <linux/security.h> #include <linux/security.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
extern int max_threads; extern int max_threads;
static struct workqueue_struct *khelper_wq;
#ifdef CONFIG_KMOD #ifdef CONFIG_KMOD
/* /*
...@@ -109,6 +112,7 @@ int request_module(const char *fmt, ...) ...@@ -109,6 +112,7 @@ int request_module(const char *fmt, ...)
atomic_dec(&kmod_concurrent); atomic_dec(&kmod_concurrent);
return ret; return ret;
} }
EXPORT_SYMBOL(request_module);
#endif /* CONFIG_KMOD */ #endif /* CONFIG_KMOD */
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
...@@ -197,9 +201,7 @@ static int wait_for_helper(void *data) ...@@ -197,9 +201,7 @@ static int wait_for_helper(void *data)
return 0; return 0;
} }
/* /* This is run by khelper thread */
* This is run by keventd.
*/
static void __call_usermodehelper(void *data) static void __call_usermodehelper(void *data)
{ {
struct subprocess_info *sub_info = data; struct subprocess_info *sub_info = data;
...@@ -249,26 +251,22 @@ int call_usermodehelper(char *path, char **argv, char **envp, int wait) ...@@ -249,26 +251,22 @@ int call_usermodehelper(char *path, char **argv, char **envp, int wait)
}; };
DECLARE_WORK(work, __call_usermodehelper, &sub_info); DECLARE_WORK(work, __call_usermodehelper, &sub_info);
if (system_state != SYSTEM_RUNNING) if (!khelper_wq)
return -EBUSY; return -EBUSY;
if (path[0] == '\0') if (path[0] == '\0')
goto out; return 0;
if (current_is_keventd()) { queue_work(khelper_wq, &work);
/* We can't wait on keventd! */ wait_for_completion(&done);
__call_usermodehelper(&sub_info);
} else {
schedule_work(&work);
wait_for_completion(&done);
}
out:
return sub_info.retval; return sub_info.retval;
} }
EXPORT_SYMBOL(call_usermodehelper); EXPORT_SYMBOL(call_usermodehelper);
#ifdef CONFIG_KMOD static __init int usermodehelper_init(void)
EXPORT_SYMBOL(request_module); {
#endif khelper_wq = create_singlethread_workqueue("khelper");
BUG_ON(!khelper_wq);
return 0;
}
__initcall(usermodehelper_init);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment