* [PATCH v5 1/2] workqueue: Make alloc_workqueue() unbound by default
2026-11-02 11:00 [PATCH v5 0/2] workqueue: Make WQ_UNBOUND the default behavior Marco Crivellari
@ 2026-11-02 11:00 ` Marco Crivellari
2026-11-02 11:00 ` [PATCH v5 2/2] workqueue: doc: Update WQ_UNBOUND and WQ_BH documentation Marco Crivellari
1 sibling, 0 replies; 3+ messages in thread
From: Marco Crivellari @ 2026-11-02 11:00 UTC (permalink / raw)
To: linux-kernel
Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
Breno Leitao
Currently alloc_workqueue() ensures that one among WQ_PERCPU or WQ_UNBOUND
is present. Now every user has one among these two flags and if nothing
is specified the default is WQ_PERCPU.
This default is suboptimal: most workloads benefit from unbound queues,
allowing the scheduler to place worker threads where they're needed and
reducing noise when CPUs are isolated.
In order to achieve the future goal of removing WQ_UNBOUND from the code,
start changing the default behavior making alloc_workqueue() act this way:
- if WQ_PERCPU and WQ_UNBOUND are present: remove WQ_PERCPU (as before)
- if neither are present: add WQ_UNBOUND
BH workqueues (WQ_BH) are always per-CPU and can't be unbound, so
WQ_PERCPU is now unconditionally forced for them before the above
defaulting logic runs.
The WARN_ONCE() when neither flag is present has been removed: from now
on, every alloc_workqueue() user without WQ_PERCPU will be considered
unbound.
The defaulting now happens before the workqueue is allocated, since
unbound workqueues need the node_nr_active[] array. Doing it before the
WQ_POWER_EFFICIENT override also makes sure that callers passing both
WQ_PERCPU and WQ_UNBOUND get the warning regardless of
wq_power_efficient.
Update the WQ_POWER_EFFICIENT comment accordingly.
Link: https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/
Suggested-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
Reviewed-by: Breno Leitao <leitao@debian.org>
---
include/linux/workqueue.h | 4 ++--
kernel/workqueue.c | 32 ++++++++++++++++----------------
2 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index c8a36423cb34..da18debf424d 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -392,8 +392,8 @@ enum wq_flags {
* turn may lead to more scheduling choices which are sub-optimal
* in terms of power consumption.
*
- * Workqueues marked with WQ_POWER_EFFICIENT are per-cpu by default
- * but become unbound if workqueue.power_efficient kernel param is
+ * Workqueues marked with WQ_POWER_EFFICIENT and WQ_PERCPU become
+ * unbound if workqueue.power_efficient kernel param is
* specified. Per-cpu workqueues which are identified to
* contribute significantly to power-consumption are identified and
* marked with this flag and enabling the power_efficient mode
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index c1cb328bce3c..747c48582ceb 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -5892,6 +5892,7 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,
unsigned int flags,
int max_active, va_list args)
{
+ bool wq_dropped_percpu = false;
struct workqueue_struct *wq;
size_t wq_size;
int name_len;
@@ -5901,6 +5902,18 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,
return NULL;
if (WARN_ON_ONCE(max_active))
return NULL;
+ flags |= WQ_PERCPU;
+ }
+
+ /*
+ * Do this before computing wq_size and before WQ_POWER_EFFICIENT
+ * can drop WQ_PERCPU.
+ */
+ if (!(flags & (WQ_UNBOUND | WQ_PERCPU))) {
+ flags |= WQ_UNBOUND;
+ } else if (unlikely((flags & WQ_PERCPU) && (flags & WQ_UNBOUND))) {
+ flags &= ~WQ_PERCPU;
+ wq_dropped_percpu = true;
}
/* see the comment above the definition of WQ_POWER_EFFICIENT */
@@ -5927,22 +5940,9 @@ static struct workqueue_struct *__alloc_workqueue(const char *fmt,
pr_warn_once("workqueue: name exceeds WQ_NAME_LEN. Truncating to: %s\n",
wq->name);
- /*
- * One among WQ_PERCPU and WQ_UNBOUND must be set, but not both.
- * - If neither is set, default to WQ_PERCPU
- * - If both are set, default to WQ_UNBOUND
- *
- * This code can be removed after workqueue are unbound by default
- */
- if (unlikely(!(flags & (WQ_UNBOUND | WQ_PERCPU)))) {
- WARN_ONCE(1, "workqueue: %s is using neither WQ_PERCPU or WQ_UNBOUND. "
- "Setting WQ_PERCPU.\n", wq->name);
- flags |= WQ_PERCPU;
- } else if (unlikely((flags & WQ_PERCPU) && (flags & WQ_UNBOUND))) {
- WARN_ONCE(1, "workqueue: %s uses both WQ_PERCPU and WQ_UNBOUND. "
- "Dropped WQ_PERCPU, keeping WQ_UNBOUND.\n", wq->name);
- flags &= ~WQ_PERCPU;
- }
+ WARN_ONCE(wq_dropped_percpu,
+ "workqueue: %s uses both WQ_PERCPU and WQ_UNBOUND. "
+ "Dropped WQ_PERCPU, keeping WQ_UNBOUND.\n", wq->name);
if (flags & WQ_BH) {
/*
--
2.56.0
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH v5 2/2] workqueue: doc: Update WQ_UNBOUND and WQ_BH documentation
2026-11-02 11:00 [PATCH v5 0/2] workqueue: Make WQ_UNBOUND the default behavior Marco Crivellari
2026-11-02 11:00 ` [PATCH v5 1/2] workqueue: Make alloc_workqueue() unbound by default Marco Crivellari
@ 2026-11-02 11:00 ` Marco Crivellari
1 sibling, 0 replies; 3+ messages in thread
From: Marco Crivellari @ 2026-11-02 11:00 UTC (permalink / raw)
To: linux-kernel
Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
Breno Leitao
When WQ_PERCPU is not present the default behavior is now WQ_UNBOUND,
so update the documentation accordingly, including the guideline that
recommended bound workqueues.
WQ_BH workqueues are the exception: they are always per-CPU, so
WQ_PERCPU is implied for them and WQ_UNBOUND is rejected. Update the
WQ_BH section accordingly, as WQ_HIGHPRI is no longer the only allowed
additional flag.
Link: https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/
Suggested-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
Reviewed-by: Breno Leitao <leitao@debian.org>
---
Documentation/core-api/workqueue.rst | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/workqueue.rst
index bb770f556568..c14aa5555171 100644
--- a/Documentation/core-api/workqueue.rst
+++ b/Documentation/core-api/workqueue.rst
@@ -177,8 +177,9 @@ resources, scheduled and executed.
workqueues are always per-CPU and all BH work items are executed in the
queueing CPU's softirq context in the queueing order.
- All BH workqueues must have 0 ``max_active`` and ``WQ_HIGHPRI`` is the
- only allowed additional flag.
+ All BH workqueues must have 0 ``max_active``. ``WQ_HIGHPRI`` and
+ ``WQ_PERCPU`` are the only allowed additional flags. ``WQ_PERCPU`` is
+ implied, as BH workqueues cannot be unbound.
BH work items cannot sleep. All other features such as delayed queueing,
flushing and canceling are supported.
@@ -190,6 +191,9 @@ resources, scheduled and executed.
This flag is the complement of ``WQ_UNBOUND``.
``WQ_UNBOUND``
+ Workqueues without ``WQ_PERCPU`` are unbound by default, except for
+ ``WQ_BH`` workqueues, which are always per-CPU.
+
Work items queued to an unbound wq are served by the special
worker-pools which host workers which are not bound to any
specific CPU. This makes the wq behave as a simple execution
@@ -368,9 +372,9 @@ Guidelines
wq and potentially lead to deadlock. It should utilize its own
dedicated workqueue rather than the system wq.
-* Unless work items are expected to consume a huge amount of CPU
- cycles, using a bound wq is usually beneficial due to the increased
- level of locality in wq operations and work item execution.
+* Use ``WQ_PERCPU`` only if work items benefit from the increased level
+ of locality in wq operations and work item execution. Otherwise, the
+ default unbound wq is usually the better choice.
Affinity Scopes
--
2.56.0
^ permalink raw reply [flat|nested] 3+ messages in thread