Skip to content

Commit def98c8

Browse files
committed
workqueue: Fix spurious sanity check failures in destroy_workqueue()
Before actually destrying a workqueue, destroy_workqueue() checks whether it's actually idle. If it isn't, it prints out a bunch of warning messages and leaves the workqueue dangling. It unfortunately has a couple issues. * Mayday list queueing increments pwq's refcnts which gets detected as busy and fails the sanity checks. However, because mayday list queueing is asynchronous, this condition can happen without any actual work items left in the workqueue. * Sanity check failure leaves the sysfs interface behind too which can lead to init failure of newer instances of the workqueue. This patch fixes the above two by * If a workqueue has a rescuer, disable and kill the rescuer before sanity checks. Disabling and killing is guaranteed to flush the existing mayday list. * Remove sysfs interface before sanity checks. Signed-off-by: Tejun Heo <[email protected]> Reported-by: Marcin Pawlowski <[email protected]> Reported-by: "Williams, Gerald S" <[email protected]> Cc: [email protected]
1 parent f60c55a commit def98c8

File tree

1 file changed

+19
-5
lines changed

1 file changed

+19
-5
lines changed

kernel/workqueue.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4325,9 +4325,28 @@ void destroy_workqueue(struct workqueue_struct *wq)
43254325
struct pool_workqueue *pwq;
43264326
int node;
43274327

4328+
/*
4329+
* Remove it from sysfs first so that sanity check failure doesn't
4330+
* lead to sysfs name conflicts.
4331+
*/
4332+
workqueue_sysfs_unregister(wq);
4333+
43284334
/* drain it before proceeding with destruction */
43294335
drain_workqueue(wq);
43304336

4337+
/* kill rescuer, if sanity checks fail, leave it w/o rescuer */
4338+
if (wq->rescuer) {
4339+
struct worker *rescuer = wq->rescuer;
4340+
4341+
/* this prevents new queueing */
4342+
spin_lock_irq(&wq_mayday_lock);
4343+
wq->rescuer = NULL;
4344+
spin_unlock_irq(&wq_mayday_lock);
4345+
4346+
/* rescuer will empty maydays list before exiting */
4347+
kthread_stop(rescuer->task);
4348+
}
4349+
43314350
/* sanity checks */
43324351
mutex_lock(&wq->mutex);
43334352
for_each_pwq(pwq, wq) {
@@ -4359,11 +4378,6 @@ void destroy_workqueue(struct workqueue_struct *wq)
43594378
list_del_rcu(&wq->list);
43604379
mutex_unlock(&wq_pool_mutex);
43614380

4362-
workqueue_sysfs_unregister(wq);
4363-
4364-
if (wq->rescuer)
4365-
kthread_stop(wq->rescuer->task);
4366-
43674381
if (!(wq->flags & WQ_UNBOUND)) {
43684382
wq_unregister_lockdep(wq);
43694383
/*

0 commit comments

Comments
 (0)