diff options
Diffstat (limited to 'kernel/workqueue.c')
| -rw-r--r-- | kernel/workqueue.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 8ee6ec82f88a..11869faa6819 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
| @@ -768,7 +768,11 @@ static inline void worker_clr_flags(struct worker *worker, unsigned int flags) | |||
| 768 | 768 | ||
| 769 | worker->flags &= ~flags; | 769 | worker->flags &= ~flags; |
| 770 | 770 | ||
| 771 | /* if transitioning out of NOT_RUNNING, increment nr_running */ | 771 | /* |
| 772 | * If transitioning out of NOT_RUNNING, increment nr_running. Note | ||
| 773 | * that the nested NOT_RUNNING is not a noop. NOT_RUNNING is mask | ||
| 774 | * of multiple flags, not a single flag. | ||
| 775 | */ | ||
| 772 | if ((flags & WORKER_NOT_RUNNING) && (oflags & WORKER_NOT_RUNNING)) | 776 | if ((flags & WORKER_NOT_RUNNING) && (oflags & WORKER_NOT_RUNNING)) |
| 773 | if (!(worker->flags & WORKER_NOT_RUNNING)) | 777 | if (!(worker->flags & WORKER_NOT_RUNNING)) |
| 774 | atomic_inc(get_gcwq_nr_running(gcwq->cpu)); | 778 | atomic_inc(get_gcwq_nr_running(gcwq->cpu)); |
| @@ -1840,7 +1844,7 @@ __acquires(&gcwq->lock) | |||
| 1840 | spin_unlock_irq(&gcwq->lock); | 1844 | spin_unlock_irq(&gcwq->lock); |
| 1841 | 1845 | ||
| 1842 | work_clear_pending(work); | 1846 | work_clear_pending(work); |
| 1843 | lock_map_acquire(&cwq->wq->lockdep_map); | 1847 | lock_map_acquire_read(&cwq->wq->lockdep_map); |
| 1844 | lock_map_acquire(&lockdep_map); | 1848 | lock_map_acquire(&lockdep_map); |
| 1845 | trace_workqueue_execute_start(work); | 1849 | trace_workqueue_execute_start(work); |
| 1846 | f(work); | 1850 | f(work); |
| @@ -2384,8 +2388,18 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr, | |||
| 2384 | insert_wq_barrier(cwq, barr, work, worker); | 2388 | insert_wq_barrier(cwq, barr, work, worker); |
| 2385 | spin_unlock_irq(&gcwq->lock); | 2389 | spin_unlock_irq(&gcwq->lock); |
| 2386 | 2390 | ||
| 2387 | lock_map_acquire(&cwq->wq->lockdep_map); | 2391 | /* |
| 2392 | * If @max_active is 1 or rescuer is in use, flushing another work | ||
| 2393 | * item on the same workqueue may lead to deadlock. Make sure the | ||
| 2394 | * flusher is not running on the same workqueue by verifying write | ||
| 2395 | * access. | ||
| 2396 | */ | ||
| 2397 | if (cwq->wq->saved_max_active == 1 || cwq->wq->flags & WQ_RESCUER) | ||
| 2398 | lock_map_acquire(&cwq->wq->lockdep_map); | ||
| 2399 | else | ||
| 2400 | lock_map_acquire_read(&cwq->wq->lockdep_map); | ||
| 2388 | lock_map_release(&cwq->wq->lockdep_map); | 2401 | lock_map_release(&cwq->wq->lockdep_map); |
| 2402 | |||
| 2389 | return true; | 2403 | return true; |
| 2390 | already_gone: | 2404 | already_gone: |
| 2391 | spin_unlock_irq(&gcwq->lock); | 2405 | spin_unlock_irq(&gcwq->lock); |
