Skip to content

Commit 9391ede

Browse files
committed
Merge branch 'for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
Pull workqueue updates from Tejun Heo: "There have been sporadic reports of sanity checks in destroy_workqueue() failing spuriously over the years. This contains the fix and its follow-up changes / fixes. There's also a RCU annotation improvement" * 'for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq: workqueue: Add RCU annotation for pwq list walk workqueue: Fix pwq ref leak in rescuer_thread() workqueue: more destroy_workqueue() fixes workqueue: Minor follow-ups to the rescuer destruction change workqueue: Fix missing kfree(rescuer) in destroy_workqueue() workqueue: Fix spurious sanity check failures in destroy_workqueue()
2 parents 0acefef + 49e9d1a commit 9391ede

File tree

1 file changed

+65
-25
lines changed

1 file changed

+65
-25
lines changed

kernel/workqueue.c

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ struct workqueue_struct {
248248
struct list_head flusher_overflow; /* WQ: flush overflow list */
249249

250250
struct list_head maydays; /* MD: pwqs requesting rescue */
251-
struct worker *rescuer; /* I: rescue worker */
251+
struct worker *rescuer; /* MD: rescue worker */
252252

253253
int nr_drainers; /* WQ: drain in progress */
254254
int saved_max_active; /* WQ: saved pwq max_active */
@@ -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>
@@ -425,7 +426,8 @@ static void workqueue_sysfs_unregister(struct workqueue_struct *wq);
425426
* ignored.
426427
*/
427428
#define for_each_pwq(pwq, wq) \
428-
list_for_each_entry_rcu((pwq), &(wq)->pwqs, pwqs_node) \
429+
list_for_each_entry_rcu((pwq), &(wq)->pwqs, pwqs_node, \
430+
lockdep_is_held(&wq->mutex)) \
429431
if (({ assert_rcu_or_wq_mutex(wq); false; })) { } \
430432
else
431433

@@ -2532,8 +2534,14 @@ static int rescuer_thread(void *__rescuer)
25322534
*/
25332535
if (need_to_create_worker(pool)) {
25342536
spin_lock(&wq_mayday_lock);
2535-
get_pwq(pwq);
2536-
list_move_tail(&pwq->mayday_node, &wq->maydays);
2537+
/*
2538+
* Queue iff we aren't racing destruction
2539+
* and somebody else hasn't queued it already.
2540+
*/
2541+
if (wq->rescuer && list_empty(&pwq->mayday_node)) {
2542+
get_pwq(pwq);
2543+
list_add_tail(&pwq->mayday_node, &wq->maydays);
2544+
}
25372545
spin_unlock(&wq_mayday_lock);
25382546
}
25392547
}
@@ -4314,6 +4322,22 @@ struct workqueue_struct *alloc_workqueue(const char *fmt,
43144322
}
43154323
EXPORT_SYMBOL_GPL(alloc_workqueue);
43164324

4325+
static bool pwq_busy(struct pool_workqueue *pwq)
4326+
{
4327+
int i;
4328+
4329+
for (i = 0; i < WORK_NR_COLORS; i++)
4330+
if (pwq->nr_in_flight[i])
4331+
return true;
4332+
4333+
if ((pwq != pwq->wq->dfl_pwq) && (pwq->refcnt > 1))
4334+
return true;
4335+
if (pwq->nr_active || !list_empty(&pwq->delayed_works))
4336+
return true;
4337+
4338+
return false;
4339+
}
4340+
43174341
/**
43184342
* destroy_workqueue - safely terminate a workqueue
43194343
* @wq: target workqueue
@@ -4325,31 +4349,51 @@ void destroy_workqueue(struct workqueue_struct *wq)
43254349
struct pool_workqueue *pwq;
43264350
int node;
43274351

4352+
/*
4353+
* Remove it from sysfs first so that sanity check failure doesn't
4354+
* lead to sysfs name conflicts.
4355+
*/
4356+
workqueue_sysfs_unregister(wq);
4357+
43284358
/* drain it before proceeding with destruction */
43294359
drain_workqueue(wq);
43304360

4331-
/* sanity checks */
4332-
mutex_lock(&wq->mutex);
4333-
for_each_pwq(pwq, wq) {
4334-
int i;
4361+
/* kill rescuer, if sanity checks fail, leave it w/o rescuer */
4362+
if (wq->rescuer) {
4363+
struct worker *rescuer = wq->rescuer;
43354364

4336-
for (i = 0; i < WORK_NR_COLORS; i++) {
4337-
if (WARN_ON(pwq->nr_in_flight[i])) {
4338-
mutex_unlock(&wq->mutex);
4339-
show_workqueue_state();
4340-
return;
4341-
}
4342-
}
4365+
/* this prevents new queueing */
4366+
spin_lock_irq(&wq_mayday_lock);
4367+
wq->rescuer = NULL;
4368+
spin_unlock_irq(&wq_mayday_lock);
4369+
4370+
/* rescuer will empty maydays list before exiting */
4371+
kthread_stop(rescuer->task);
4372+
kfree(rescuer);
4373+
}
43434374

4344-
if (WARN_ON((pwq != wq->dfl_pwq) && (pwq->refcnt > 1)) ||
4345-
WARN_ON(pwq->nr_active) ||
4346-
WARN_ON(!list_empty(&pwq->delayed_works))) {
4375+
/*
4376+
* Sanity checks - grab all the locks so that we wait for all
4377+
* in-flight operations which may do put_pwq().
4378+
*/
4379+
mutex_lock(&wq_pool_mutex);
4380+
mutex_lock(&wq->mutex);
4381+
for_each_pwq(pwq, wq) {
4382+
spin_lock_irq(&pwq->pool->lock);
4383+
if (WARN_ON(pwq_busy(pwq))) {
4384+
pr_warning("%s: %s has the following busy pwq\n",
4385+
__func__, wq->name);
4386+
show_pwq(pwq);
4387+
spin_unlock_irq(&pwq->pool->lock);
43474388
mutex_unlock(&wq->mutex);
4389+
mutex_unlock(&wq_pool_mutex);
43484390
show_workqueue_state();
43494391
return;
43504392
}
4393+
spin_unlock_irq(&pwq->pool->lock);
43514394
}
43524395
mutex_unlock(&wq->mutex);
4396+
mutex_unlock(&wq_pool_mutex);
43534397

43544398
/*
43554399
* wq list is used to freeze wq, remove from list after
@@ -4359,11 +4403,6 @@ void destroy_workqueue(struct workqueue_struct *wq)
43594403
list_del_rcu(&wq->list);
43604404
mutex_unlock(&wq_pool_mutex);
43614405

4362-
workqueue_sysfs_unregister(wq);
4363-
4364-
if (wq->rescuer)
4365-
kthread_stop(wq->rescuer->task);
4366-
43674406
if (!(wq->flags & WQ_UNBOUND)) {
43684407
wq_unregister_lockdep(wq);
43694408
/*
@@ -4638,7 +4677,8 @@ static void show_pwq(struct pool_workqueue *pwq)
46384677
pr_info(" pwq %d:", pool->id);
46394678
pr_cont_pool_info(pool);
46404679

4641-
pr_cont(" active=%d/%d%s\n", pwq->nr_active, pwq->max_active,
4680+
pr_cont(" active=%d/%d refcnt=%d%s\n",
4681+
pwq->nr_active, pwq->max_active, pwq->refcnt,
46424682
!list_empty(&pwq->mayday_node) ? " MAYDAY" : "");
46434683

46444684
hash_for_each(pool->busy_hash, bkt, worker, hentry) {
@@ -4657,7 +4697,7 @@ static void show_pwq(struct pool_workqueue *pwq)
46574697

46584698
pr_cont("%s %d%s:%ps", comma ? "," : "",
46594699
task_pid_nr(worker->task),
4660-
worker == pwq->wq->rescuer ? "(RESCUER)" : "",
4700+
worker->rescue_wq ? "(RESCUER)" : "",
46614701
worker->current_func);
46624702
list_for_each_entry(work, &worker->scheduled, entry)
46634703
pr_cont_work(false, work);

0 commit comments

Comments
 (0)