Skip to content

Commit

Permalink
workqueue: Fix pwq ref leak in rescuer_thread()
Browse files Browse the repository at this point in the history
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+
  • Loading branch information
htejun committed Oct 4, 2019
1 parent c29eb85 commit e66b39a
Showing 1 changed file with 12 additions and 5 deletions.
17 changes: 12 additions & 5 deletions kernel/workqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -2533,8 +2533,14 @@ static int rescuer_thread(void *__rescuer)
*/
if (need_to_create_worker(pool)) {
spin_lock(&wq_mayday_lock);
get_pwq(pwq);
list_move_tail(&pwq->mayday_node, &wq->maydays);
/*
* Queue iff we aren't racing destruction
* and somebody else hasn't queued it already.
*/
if (wq->rescuer && list_empty(&pwq->mayday_node)) {
get_pwq(pwq);
list_add_tail(&pwq->mayday_node, &wq->maydays);
}
spin_unlock(&wq_mayday_lock);
}
}
Expand Down Expand Up @@ -4374,8 +4380,8 @@ void destroy_workqueue(struct workqueue_struct *wq)
for_each_pwq(pwq, wq) {
spin_lock_irq(&pwq->pool->lock);
if (WARN_ON(pwq_busy(pwq))) {
pr_warning("%s: %s has the following busy pwq (refcnt=%d)\n",
__func__, wq->name, pwq->refcnt);
pr_warning("%s: %s has the following busy pwq\n",
__func__, wq->name);
show_pwq(pwq);
spin_unlock_irq(&pwq->pool->lock);
mutex_unlock(&wq->mutex);
Expand Down Expand Up @@ -4670,7 +4676,8 @@ static void show_pwq(struct pool_workqueue *pwq)
pr_info(" pwq %d:", pool->id);
pr_cont_pool_info(pool);

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

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

0 comments on commit e66b39a

Please sign in to comment.