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 @@
#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);
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