[PATCH RFC v2 5/8] workqueue: add workqueue_set_affn_scope()
From: Chuck Lever
Date: Wed Sep 02 2026 - 16:06:06 EST
An unbound workqueue's affinity scope can be changed only through
sysfs. A module whose workqueue contends on the pool lock at the
default scope has no in-kernel way to select a finer one, because
alloc_workqueue_attrs() and apply_workqueue_attrs() are not
exported. Exporting them would also invite a caller to apply freshly
allocated attributes, which resets the nice level, cpumask, and
strict affinity the workqueue already carries.
Add workqueue_set_affn_scope(), which copies the workqueue's current
attributes, replaces only the scope, and applies the result under
wq_pool_mutex, as the sysfs affinity_scope store does. Export it so
that SUNRPC and NFS can set the scope of their workqueues when they
create them.
Signed-off-by: Chuck Lever <cel@xxxxxxxxxx>
---
include/linux/workqueue.h | 2 ++
kernel/workqueue.c | 37 +++++++++++++++++++++++++++++++++++++
2 files changed, 39 insertions(+)
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index c8a36423cb34..585c32d8dc98 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -618,6 +618,8 @@ struct workqueue_attrs *alloc_workqueue_attrs_noprof(void);
void free_workqueue_attrs(struct workqueue_attrs *attrs);
int apply_workqueue_attrs(struct workqueue_struct *wq,
const struct workqueue_attrs *attrs);
+int workqueue_set_affn_scope(struct workqueue_struct *wq,
+ enum wq_affn_scope affn_scope);
extern int workqueue_unbound_housekeeping_update(const struct cpumask *hk);
extern bool queue_work_on(int cpu, struct workqueue_struct *wq,
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 3c034cbc5bb3..0c2b8e87cd59 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -5610,6 +5610,43 @@ int apply_workqueue_attrs(struct workqueue_struct *wq,
return ret;
}
+/**
+ * workqueue_set_affn_scope - change the affinity scope of an unbound workqueue
+ * @wq: the target unbound workqueue
+ * @affn_scope: the new scope, or %WQ_AFFN_DFL for the system default
+ *
+ * Reapply @wq's current attributes with only the affinity scope
+ * replaced, so the nice level, cpumask, and strict affinity the
+ * workqueue already carries survive. Pool-workqueue replacement
+ * proceeds as for apply_workqueue_attrs().
+ *
+ * Context: Process context. Takes wq_pool_mutex and performs
+ * GFP_KERNEL allocations.
+ *
+ * Return: 0 on success and -errno on failure.
+ */
+int workqueue_set_affn_scope(struct workqueue_struct *wq,
+ enum wq_affn_scope affn_scope)
+{
+ struct workqueue_attrs *attrs;
+ int ret = -ENOMEM;
+
+ if ((unsigned int)affn_scope >= WQ_AFFN_NR_TYPES)
+ return -EINVAL;
+
+ mutex_lock(&wq_pool_mutex);
+ attrs = alloc_workqueue_attrs();
+ if (attrs) {
+ copy_workqueue_attrs(attrs, wq->attrs);
+ attrs->affn_scope = affn_scope;
+ ret = apply_workqueue_attrs_locked(wq, attrs);
+ }
+ mutex_unlock(&wq_pool_mutex);
+ free_workqueue_attrs(attrs);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(workqueue_set_affn_scope);
+
/**
* unbound_wq_update_pwq - update a pwq slot for CPU hot[un]plug
* @wq: the target workqueue
--
2.55.0