Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / kernel / kthread.c
index 2e60249..c18d7c7 100644 (file)
 #include <linux/err.h>
 #include <linux/unistd.h>
 #include <linux/file.h>
+#include <linux/module.h>
+#include <linux/mutex.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. */
@@ -34,14 +42,14 @@ struct kthread_stop_info
 
 /* Thread stopping is done by setthing this var: lock serializes
  * multiple kthread_stop calls. */
-static DECLARE_MUTEX(kthread_stop_lock);
+static DEFINE_MUTEX(kthread_stop_lock);
 static struct kthread_stop_info kthread_stop_info;
 
 int kthread_should_stop(void)
 {
        return (kthread_stop_info.k == current);
 }
-
+EXPORT_SYMBOL(kthread_should_stop);
 
 static void kthread_exit_files(void)
 {
@@ -64,7 +72,6 @@ static int kthread(void *_create)
        void *data;
        sigset_t blocked;
        int ret = -EINTR;
-       cpumask_t mask = CPU_MASK_ALL;
 
        kthread_exit_files();
 
@@ -78,7 +85,7 @@ static int kthread(void *_create)
        flush_signals(current);
 
        /* By default we can run anywhere, unlike keventd. */
-       set_cpus_allowed(current, mask);
+       set_cpus_allowed(current, CPU_MASK_ALL);
 
        /* OK, tell user we're spawned, wait for stop or wakeup */
        __set_current_state(TASK_INTERRUPTIBLE);
@@ -108,7 +115,9 @@ static void keventd_create_kthread(void *_create)
                create->result = ERR_PTR(pid);
        } else {
                wait_for_completion(&create->started);
-               create->result = find_task_by_pid(pid);
+               read_lock(&tasklist_lock);
+               create->result = find_task_by_real_pid(pid);
+               read_unlock(&tasklist_lock);
        }
        complete(&create->done);
 }
@@ -126,12 +135,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)) {
@@ -144,6 +154,7 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
 
        return create.result;
 }
+EXPORT_SYMBOL(kthread_create);
 
 void kthread_bind(struct task_struct *k, unsigned int cpu)
 {
@@ -153,30 +164,51 @@ void kthread_bind(struct task_struct *k, unsigned int cpu)
        set_task_cpu(k, cpu);
        k->cpus_allowed = cpumask_of_cpu(cpu);
 }
+EXPORT_SYMBOL(kthread_bind);
 
 int kthread_stop(struct task_struct *k)
+{
+       return kthread_stop_sem(k, NULL);
+}
+EXPORT_SYMBOL(kthread_stop);
+
+int kthread_stop_sem(struct task_struct *k, struct semaphore *s)
 {
        int ret;
 
-       down(&kthread_stop_lock);
+       mutex_lock(&kthread_stop_lock);
 
        /* It could exit after stop_info.k set, but before wake_up_process. */
        get_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;
-       wake_up_process(k);
+       if (s)
+               up(s);
+       else
+               wake_up_process(k);
        put_task_struct(k);
 
        /* Once it dies, reset stop ptr, gather result and we're done. */
        wait_for_completion(&kthread_stop_info.done);
        kthread_stop_info.k = NULL;
        ret = kthread_stop_info.err;
-       up(&kthread_stop_lock);
+       mutex_unlock(&kthread_stop_lock);
 
        return ret;
 }
+EXPORT_SYMBOL(kthread_stop_sem);
+
+static __init int helper_init(void)
+{
+       helper_wq = create_singlethread_workqueue("kthread");
+       BUG_ON(!helper_wq);
+
+       return 0;
+}
+core_initcall(helper_init);
+