summaryrefslogtreecommitdiff
path: root/kernel/workqueue.c
diff options
context:
space:
mode:
authorBreno Leitao <leitao@debian.org>2026-08-19 07:37:36 -0700
committerTejun Heo <tj@kernel.org>2026-08-31 12:08:03 -1000
commite92329ef60a8961a71028b7b9ca356c0b07bcc26 (patch)
tree0a3fd2a3b04661b8f2224d054ec50ba6fa6b3b07 /kernel/workqueue.c
parent8386ed68ae041b4d0919d851ec5300e41c1c2195 (diff)
downloadlinux-next-e92329ef60a8961a71028b7b9ca356c0b07bcc26.tar.gz
linux-next-e92329ef60a8961a71028b7b9ca356c0b07bcc26.zip
workqueue: resolve the backing pool in alloc_pwq()
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@debian.org> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r--kernel/workqueue.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index acd985ae2ac6..f4d8cf0b6d51 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -5385,22 +5385,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;
}
@@ -5408,6 +5420,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
@@ -5509,7 +5528,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;
@@ -5519,7 +5538,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;
}
@@ -5664,7 +5683,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);