Skip to content

Commit e66b39a

Browse files
committed
workqueue: Fix pwq ref leak in rescuer_thread()
008847f ("workqueue: allow rescuer thread to do more work.") made the rescuer worker requeue the pwq immediately if there may be more work items which need rescuing instead of waiting for the next mayday timer expiration. Unfortunately, it doesn't check whether the pwq is already on the mayday list and unconditionally gets the ref and moves it onto the list. This doesn't corrupt the list but creates an additional reference to the pwq. It got queued twice but will only be removed once. This leak later can trigger pwq refcnt warning on workqueue destruction and prevent freeing of the workqueue. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: "Williams, Gerald S" <gerald.s.williams@intel.com> Cc: NeilBrown <neilb@suse.de> Cc: stable@vger.kernel.org # v3.19+
1 parent c29eb85 commit e66b39a

1 file changed

Lines changed: 12 additions & 5 deletions

File tree

kernel/workqueue.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,8 +2533,14 @@ static int rescuer_thread(void *__rescuer)
25332533
*/
25342534
if (need_to_create_worker(pool)) {
25352535
spin_lock(&wq_mayday_lock);
2536-
get_pwq(pwq);
2537-
list_move_tail(&pwq->mayday_node, &wq->maydays);
2536+
/*
2537+
* Queue iff we aren't racing destruction
2538+
* and somebody else hasn't queued it already.
2539+
*/
2540+
if (wq->rescuer && list_empty(&pwq->mayday_node)) {
2541+
get_pwq(pwq);
2542+
list_add_tail(&pwq->mayday_node, &wq->maydays);
2543+
}
25382544
spin_unlock(&wq_mayday_lock);
25392545
}
25402546
}
@@ -4374,8 +4380,8 @@ void destroy_workqueue(struct workqueue_struct *wq)
43744380
for_each_pwq(pwq, wq) {
43754381
spin_lock_irq(&pwq->pool->lock);
43764382
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);
4383+
pr_warning("%s: %s has the following busy pwq\n",
4384+
__func__, wq->name);
43794385
show_pwq(pwq);
43804386
spin_unlock_irq(&pwq->pool->lock);
43814387
mutex_unlock(&wq->mutex);
@@ -4670,7 +4676,8 @@ static void show_pwq(struct pool_workqueue *pwq)
46704676
pr_info(" pwq %d:", pool->id);
46714677
pr_cont_pool_info(pool);
46724678

4673-
pr_cont(" active=%d/%d%s\n", pwq->nr_active, pwq->max_active,
4679+
pr_cont(" active=%d/%d refcnt=%d%s\n",
4680+
pwq->nr_active, pwq->max_active, pwq->refcnt,
46744681
!list_empty(&pwq->mayday_node) ? " MAYDAY" : "");
46754682

46764683
hash_for_each(pool->busy_hash, bkt, worker, hentry) {

0 commit comments

Comments
 (0)