kthread: detect when a kthread work is used by more workers
[deliverable/linux.git] / kernel / kthread.c
index 3dc7f26d84d72198250042ca1539eef03c78175e..48002a46b647a6264e71d45ef487ea441c8d4790 100644 (file)
@@ -574,6 +574,9 @@ EXPORT_SYMBOL_GPL(__kthread_init_worker);
  * The works are not allowed to keep any locks, disable preemption or interrupts
  * when they finish. There is defined a safe point for freezing when one work
  * finishes and before a new one is started.
+ *
+ * Also the works must not be handled by more than one worker at the same time,
+ * see also kthread_queue_work().
  */
 int kthread_worker_fn(void *worker_ptr)
 {
@@ -710,12 +713,21 @@ kthread_create_worker_on_cpu(int cpu, const char namefmt[], ...)
 }
 EXPORT_SYMBOL(kthread_create_worker_on_cpu);
 
+static void kthread_insert_work_sanity_check(struct kthread_worker *worker,
+                                            struct kthread_work *work)
+{
+       lockdep_assert_held(&worker->lock);
+       WARN_ON_ONCE(!list_empty(&work->node));
+       /* Do not use a work with >1 worker, see kthread_queue_work() */
+       WARN_ON_ONCE(work->worker && work->worker != worker);
+}
+
 /* insert @work before @pos in @worker */
 static void kthread_insert_work(struct kthread_worker *worker,
-                              struct kthread_work *work,
-                              struct list_head *pos)
+                               struct kthread_work *work,
+                               struct list_head *pos)
 {
-       lockdep_assert_held(&worker->lock);
+       kthread_insert_work_sanity_check(worker, work);
 
        list_add_tail(&work->node, pos);
        work->worker = worker;
@@ -731,6 +743,9 @@ static void kthread_insert_work(struct kthread_worker *worker,
  * Queue @work to work processor @task for async execution.  @task
  * must have been created with kthread_worker_create().  Returns %true
  * if @work was successfully queued, %false if it was already pending.
+ *
+ * Reinitialize the work if it needs to be used by another worker.
+ * For example, when the worker was stopped and started again.
  */
 bool kthread_queue_work(struct kthread_worker *worker,
                        struct kthread_work *work)
@@ -775,16 +790,13 @@ void kthread_flush_work(struct kthread_work *work)
        struct kthread_worker *worker;
        bool noop = false;
 
-retry:
        worker = work->worker;
        if (!worker)
                return;
 
        spin_lock_irq(&worker->lock);
-       if (work->worker != worker) {
-               spin_unlock_irq(&worker->lock);
-               goto retry;
-       }
+       /* Work must not be used with >1 worker, see kthread_queue_work(). */
+       WARN_ON_ONCE(work->worker != worker);
 
        if (!list_empty(&work->node))
                kthread_insert_work(worker, &fwork.work, work->node.next);
This page took 0.026703 seconds and 5 git commands to generate.