upgrade to fedora-2.6.12-1.1398.FC4 + vserver 2.0.rc7
[linux-2.6.git] / kernel / kthread.c
index fc0767d..43fa039 100644 (file)
 #include <linux/module.h>
 #include <asm/semaphore.h>
 
+/*
+ * We dont want to execute off keventd since it might
+ * hold a semaphore our callers hold too:
+ */
+static struct workqueue_struct *helper_wq;
+
 struct kthread_create_info
 {
        /* Information passed to kthread() from keventd. */
@@ -126,12 +132,13 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
        init_completion(&create.started);
        init_completion(&create.done);
 
-       /* If we're being called to start the first workqueue, we
-        * can't use keventd. */
-       if (!keventd_up())
+       /*
+        * The workqueue needs to start up first:
+        */
+       if (!helper_wq)
                work.func(work.data);
        else {
-               schedule_work(&work);
+               queue_work(helper_wq, &work);
                wait_for_completion(&create.done);
        }
        if (!IS_ERR(create.result)) {
@@ -167,7 +174,7 @@ int kthread_stop(struct task_struct *k)
 
        /* Must init completion *before* thread sees kthread_stop_info.k */
        init_completion(&kthread_stop_info.done);
-       wmb();
+       smp_wmb();
 
        /* Now set kthread_should_stop() to true, and wake it up. */
        kthread_stop_info.k = k;
@@ -183,3 +190,13 @@ int kthread_stop(struct task_struct *k)
        return ret;
 }
 EXPORT_SYMBOL(kthread_stop);
+
+static __init int helper_init(void)
+{
+       helper_wq = create_singlethread_workqueue("kthread");
+       BUG_ON(!helper_wq);
+
+       return 0;
+}
+core_initcall(helper_init);
+