[PATCH 2/5] workqueue: resolve the backing pool in alloc_pwq()

From: Breno Leitao

Date: Wed Aug 19 2026 - 10:38:27 EST


Unify the pool allocation in alloc_pwq(), instead of only getting the unbound
pool, and add a new parameter for the CPU.

Create a helper for unbound allocations (alloc_unbound_pwq()).

Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx>
---
kernel/workqueue.c | 37 ++++++++++++++++++++++++++++---------
1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 632d3f75f0c96..7feefe0a4a5ff 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -5376,22 +5376,34 @@ static struct worker_pool *get_percpu_pool(struct workqueue_struct *wq, int cpu)
return &per_cpu_ptr(pools, cpu)[highpri];
}

-/* obtain a pool matching @attr and create a pwq associating the pool and @wq */
+/*
+ * Obtain the pool backing @wq on @cpu and create a pwq associating the two.
+ * A WQ_PERCPU workqueue is backed by the static per-cpu pool of @cpu,
+ * everything else by a pool matching @attrs. @cpu < 0 is always unbound.
+ */
static struct pool_workqueue *alloc_pwq(struct workqueue_struct *wq,
- const struct workqueue_attrs *attrs)
+ const struct workqueue_attrs *attrs,
+ int cpu)
{
struct worker_pool *pool;
struct pool_workqueue *pwq;

lockdep_assert_held(&wq_pool_mutex);

- pool = get_unbound_pool(attrs);
- if (!pool)
- return NULL;
+ WARN_ON_ONCE((wq->flags & WQ_PERCPU) && cpu < 0);
+
+ if (cpu >= 0 && (wq->flags & WQ_PERCPU)) {
+ pool = get_percpu_pool(wq, cpu);
+ } else {
+ pool = get_unbound_pool(attrs);
+ if (!pool)
+ return NULL;
+ }

pwq = kmem_cache_alloc_node(pwq_cache, GFP_KERNEL, pool->node);
if (!pwq) {
- put_unbound_pool(pool);
+ if (!is_percpu_pool(pool))
+ put_unbound_pool(pool);
return NULL;
}

@@ -5399,6 +5411,13 @@ static struct pool_workqueue *alloc_pwq(struct workqueue_struct *wq,
return pwq;
}

+/* create a pwq backed by an unbound pool matching @attrs */
+static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq,
+ const struct workqueue_attrs *attrs)
+{
+ return alloc_pwq(wq, attrs, -1);
+}
+
/**
* wq_calc_pod_cpumask - calculate a wq_attrs' cpumask for a pod
* @attrs: the wq_attrs of the default pwq of the target workqueue
@@ -5500,7 +5519,7 @@ apply_wqattrs_prepare(struct workqueue_struct *wq,
copy_workqueue_attrs(new_attrs, attrs);
wqattrs_actualize_cpumask(new_attrs, unbound_cpumask);
cpumask_copy(new_attrs->__pod_cpumask, new_attrs->cpumask);
- ctx->dfl_pwq = alloc_pwq(wq, new_attrs);
+ ctx->dfl_pwq = alloc_unbound_pwq(wq, new_attrs);
if (!ctx->dfl_pwq)
goto out_free;

@@ -5510,7 +5529,7 @@ apply_wqattrs_prepare(struct workqueue_struct *wq,
ctx->pwq_tbl[cpu] = ctx->dfl_pwq;
} else {
wq_calc_pod_cpumask(new_attrs, cpu);
- ctx->pwq_tbl[cpu] = alloc_pwq(wq, new_attrs);
+ ctx->pwq_tbl[cpu] = alloc_unbound_pwq(wq, new_attrs);
if (!ctx->pwq_tbl[cpu])
goto out_free;
}
@@ -5655,7 +5674,7 @@ static void unbound_wq_update_pwq(struct workqueue_struct *wq, int cpu)
return;

/* create a new pwq */
- pwq = alloc_pwq(wq, target_attrs);
+ pwq = alloc_unbound_pwq(wq, target_attrs);
if (!pwq) {
pr_warn("workqueue: allocation failed while updating CPU pod affinity of \"%s\"\n",
wq->name);

--
2.53.0-Meta