| From 4fe1618ba44766462a602dacfed3925b33ccce5a Mon Sep 17 00:00:00 2001 |
| From: Tejun Heo <tj@kernel.org> |
| Date: Wed, 25 Sep 2019 06:59:15 -0700 |
| Subject: [PATCH] workqueue: Fix pwq ref leak in rescuer_thread() |
| |
| commit e66b39af00f426b3356b96433d620cb3367ba1ff upstream. |
| |
| 008847f66c3 ("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+ |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| [PG: use 5.3.17-stable version instead of mainline version.] |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/kernel/workqueue.c b/kernel/workqueue.c |
| index 73e3ea9e31d3..77d6c203e094 100644 |
| --- a/kernel/workqueue.c |
| +++ b/kernel/workqueue.c |
| @@ -2532,8 +2532,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); |
| } |
| } |
| @@ -4645,7 +4651,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) { |
| -- |
| 2.7.4 |
| |