Currently, all kthread_stop calls are serialized. If something calls
kthread_stop on a kthread, no other kthread will be able to be
brought down until the first kthread_stop returns. A "rogue" kthread
could therefore prevent other kthreads from ever coming down.

This patch makes it so that kthread_stop calls can be done in parallel.
To do this, it adds a new pointer to the task struct. This works, but
I'd prefer to use an existing pointer that's never used for kthreads
rather than adding a new one. I'm just not sure what pointer would be
a good candidate for this.

This is really an RFC at this point, so comments and suggestions
are appreciated...

Signed-off-by: Jeff Layton <[EMAIL PROTECTED]>
---
 include/linux/sched.h |    2 ++
 kernel/kthread.c      |   33 +++++++++++++--------------------
 2 files changed, 15 insertions(+), 20 deletions(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index ac3d496..bc38574 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1178,6 +1178,8 @@ struct task_struct {
        int make_it_fail;
 #endif
        struct prop_local_single dirties;
+
+       struct kthread_stop_info *kthread_stop_info;
 };
 
 /*
diff --git a/kernel/kthread.c b/kernel/kthread.c
index dcfe724..12594fa 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -35,26 +35,23 @@ struct kthread_create_info
 
 struct kthread_stop_info
 {
-       struct task_struct *k;
        int err;
        struct completion done;
 };
 
-/* Thread stopping is done by setthing this var: lock serializes
- * multiple kthread_stop calls. */
-static DEFINE_MUTEX(kthread_stop_lock);
-static struct kthread_stop_info kthread_stop_info;
-
 /**
  * kthread_should_stop - should this kthread return now?
  *
  * When someone calls kthread_stop() on your kthread, it will be woken
  * and this will return true.  You should then return, and your return
  * value will be passed through to kthread_stop().
+ *
+ * In this implementation, setting the kthread_stop_info pointer to
+ * a non-NULL value means that it should stop.
  */
 int kthread_should_stop(void)
 {
-       return (kthread_stop_info.k == current);
+       return (current->kthread_stop_info != NULL);
 }
 EXPORT_SYMBOL(kthread_should_stop);
 
@@ -68,6 +65,7 @@ static int kthread(void *_create)
        /* Copy data: it's on kthread's stack */
        threadfn = create->threadfn;
        data = create->data;
+       current->kthread_stop_info = NULL;
 
        /* OK, tell user we're spawned, wait for stop or wakeup */
        __set_current_state(TASK_UNINTERRUPTIBLE);
@@ -79,8 +77,8 @@ static int kthread(void *_create)
 
        /* It might have exited on its own, w/o kthread_stop.  Check. */
        if (kthread_should_stop()) {
-               kthread_stop_info.err = ret;
-               complete(&kthread_stop_info.done);
+               current->kthread_stop_info->err = ret;
+               complete(&current->kthread_stop_info->done);
        }
        return 0;
 }
@@ -104,7 +102,7 @@ static void create_kthread(struct kthread_create_info 
*create)
 
 /**
  * kthread_create - create a kthread.
- * @threadfn: the function to run until signal_pending(current).
+ * @threadfn: the function to run until kthread_should_stop()
  * @data: data ptr for @threadfn.
  * @namefmt: printf-style name for the thread.
  *
@@ -188,29 +186,24 @@ EXPORT_SYMBOL(kthread_bind);
  */
 int kthread_stop(struct task_struct *k)
 {
-       int ret;
-
-       mutex_lock(&kthread_stop_lock);
+       struct kthread_stop_info kstop_info;
 
        /* 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);
+       init_completion(&kstop_info.done);
        smp_wmb();
 
        /* Now set kthread_should_stop() to true, and wake it up. */
-       kthread_stop_info.k = k;
+       k->kthread_stop_info = &kstop_info;
        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;
-       mutex_unlock(&kthread_stop_lock);
+       wait_for_completion(&kstop_info.done);
 
-       return ret;
+       return kstop_info.err;
 }
 EXPORT_SYMBOL(kthread_stop);
 
-- 
1.5.3.7

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to