diff options
| author | Andrew Morton <akpm@osdl.org> | 2004-04-26 08:55:31 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-04-26 08:55:31 -0700 |
| commit | 35f4fc9f6bb92dc2d425c472971927ced12547d4 (patch) | |
| tree | 0023fdae0fcfb25401273b2612ce71ef500e9d51 /kernel/kmod.c | |
| parent | bf9e688d76438678a6d5a902a2a57f7d866e2b51 (diff) | |
[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
Diffstat (limited to 'kernel/kmod.c')
| -rw-r--r-- | kernel/kmod.c | 36 |
1 files changed, 17 insertions, 19 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c index 0002fcd4c554..8754003bbbf2 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -35,10 +35,13 @@ #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); |
