Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux
[pandora-kernel.git] / kernel / workqueue.c
index 5abf42f..9a3128d 100644 (file)
@@ -1032,7 +1032,10 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
        cwq = get_cwq(gcwq->cpu, wq);
        trace_workqueue_queue_work(cpu, cwq, work);
 
-       BUG_ON(!list_empty(&work->entry));
+       if (WARN_ON(!list_empty(&work->entry))) {
+               spin_unlock_irqrestore(&gcwq->lock, flags);
+               return;
+       }
 
        cwq->nr_in_flight[cwq->work_color]++;
        work_flags = work_color_to_flags(cwq->work_color);
@@ -1210,8 +1213,13 @@ static void worker_enter_idle(struct worker *worker)
        } else
                wake_up_all(&gcwq->trustee_wait);
 
-       /* sanity check nr_running */
-       WARN_ON_ONCE(gcwq->nr_workers == gcwq->nr_idle &&
+       /*
+        * Sanity check nr_running.  Because trustee releases gcwq->lock
+        * between setting %WORKER_ROGUE and zapping nr_running, the
+        * warning may trigger spuriously.  Check iff trustee is idle.
+        */
+       WARN_ON_ONCE(gcwq->trustee_state == TRUSTEE_DONE &&
+                    gcwq->nr_workers == gcwq->nr_idle &&
                     atomic_read(get_gcwq_nr_running(gcwq->cpu)));
 }
 
@@ -1810,7 +1818,9 @@ __acquires(&gcwq->lock)
         * lock freed" warnings as well as problems when looking into
         * work->lockdep_map, make a copy and use that here.
         */
-       struct lockdep_map lockdep_map = work->lockdep_map;
+       struct lockdep_map lockdep_map;
+
+       lockdep_copy_map(&lockdep_map, &work->lockdep_map);
 #endif
        /*
         * A single work shouldn't be executed concurrently by
@@ -2506,6 +2516,9 @@ bool flush_work(struct work_struct *work)
 {
        struct wq_barrier barr;
 
+       lock_map_acquire(&work->lockdep_map);
+       lock_map_release(&work->lockdep_map);
+
        if (start_flush_work(work, &barr, true)) {
                wait_for_completion(&barr.done);
                destroy_work_on_stack(&barr.work);