Skip to content

Commit c29eb85

Browse files
committed
workqueue: more destroy_workqueue() fixes
destroy_workqueue() warnings still, at a lower frequency, trigger spuriously. The problem seems to be in-flight operations which haven't reached put_pwq() yet. * Make sanity check grab all the related locks so that it's synchronized against operations which puts pwq at the end. * Always print out the offending pwq. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: "Williams, Gerald S" <gerald.s.williams@intel.com>
1 parent 30ae2fc commit c29eb85

1 file changed

Lines changed: 31 additions & 14 deletions

File tree

kernel/workqueue.c

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ EXPORT_SYMBOL_GPL(system_freezable_power_efficient_wq);
355355

356356
static int worker_thread(void *__worker);
357357
static void workqueue_sysfs_unregister(struct workqueue_struct *wq);
358+
static void show_pwq(struct pool_workqueue *pwq);
358359

359360
#define CREATE_TRACE_POINTS
360361
#include <trace/events/workqueue.h>
@@ -4314,6 +4315,22 @@ struct workqueue_struct *alloc_workqueue(const char *fmt,
43144315
}
43154316
EXPORT_SYMBOL_GPL(alloc_workqueue);
43164317

4318+
static bool pwq_busy(struct pool_workqueue *pwq)
4319+
{
4320+
int i;
4321+
4322+
for (i = 0; i < WORK_NR_COLORS; i++)
4323+
if (pwq->nr_in_flight[i])
4324+
return true;
4325+
4326+
if ((pwq != pwq->wq->dfl_pwq) && (pwq->refcnt > 1))
4327+
return true;
4328+
if (pwq->nr_active || !list_empty(&pwq->delayed_works))
4329+
return true;
4330+
4331+
return false;
4332+
}
4333+
43174334
/**
43184335
* destroy_workqueue - safely terminate a workqueue
43194336
* @wq: target workqueue
@@ -4348,28 +4365,28 @@ void destroy_workqueue(struct workqueue_struct *wq)
43484365
kfree(rescuer);
43494366
}
43504367

4351-
/* sanity checks */
4368+
/*
4369+
* Sanity checks - grab all the locks so that we wait for all
4370+
* in-flight operations which may do put_pwq().
4371+
*/
4372+
mutex_lock(&wq_pool_mutex);
43524373
mutex_lock(&wq->mutex);
43534374
for_each_pwq(pwq, wq) {
4354-
int i;
4355-
4356-
for (i = 0; i < WORK_NR_COLORS; i++) {
4357-
if (WARN_ON(pwq->nr_in_flight[i])) {
4358-
mutex_unlock(&wq->mutex);
4359-
show_workqueue_state();
4360-
return;
4361-
}
4362-
}
4363-
4364-
if (WARN_ON((pwq != wq->dfl_pwq) && (pwq->refcnt > 1)) ||
4365-
WARN_ON(pwq->nr_active) ||
4366-
WARN_ON(!list_empty(&pwq->delayed_works))) {
4375+
spin_lock_irq(&pwq->pool->lock);
4376+
if (WARN_ON(pwq_busy(pwq))) {
4377+
pr_warning("%s: %s has the following busy pwq (refcnt=%d)\n",
4378+
__func__, wq->name, pwq->refcnt);
4379+
show_pwq(pwq);
4380+
spin_unlock_irq(&pwq->pool->lock);
43674381
mutex_unlock(&wq->mutex);
4382+
mutex_unlock(&wq_pool_mutex);
43684383
show_workqueue_state();
43694384
return;
43704385
}
4386+
spin_unlock_irq(&pwq->pool->lock);
43714387
}
43724388
mutex_unlock(&wq->mutex);
4389+
mutex_unlock(&wq_pool_mutex);
43734390

43744391
/*
43754392
* wq list is used to freeze wq, remove from list after

0 commit comments

Comments
 (0)