summaryrefslogtreecommitdiff
path: root/kernel/kmod.c
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-04-26 08:55:31 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-04-26 08:55:31 -0700
commit35f4fc9f6bb92dc2d425c472971927ced12547d4 (patch)
tree0023fdae0fcfb25401273b2612ce71ef500e9d51 /kernel/kmod.c
parentbf9e688d76438678a6d5a902a2a57f7d866e2b51 (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.c36
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);