[PATCH 1/3] workqueue: Add for_each_node_with_fallback()

From: Tejun Heo

Date: Tue Sep 01 2026 - 17:18:34 EST


Per-node arrays in workqueue carry an extra slot at nr_node_ids for
NUMA_NO_NODE, and iterating them open-codes for_each_node() plus separate
handling of that slot. Add for_each_node_with_fallback() and convert
alloc/free_node_nr_active().

Signed-off-by: Tejun Heo <tj@xxxxxxxxxx>
---
kernel/workqueue.c | 37 ++++++++++++++++++++++++-------------
1 file changed, 24 insertions(+), 13 deletions(-)

diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index d4d6bb8a23f5..9c69efcf5e2e 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -622,6 +622,26 @@ static void show_one_worker_pool(struct worker_pool *pool);
list_for_each_entry_rcu((pwq), &(wq)->pwqs, pwqs_node, \
lockdep_is_held(&(wq->mutex)))

+/*
+ * Per-node arrays in this file carry an extra slot at nr_node_ids serving
+ * NUMA_NO_NODE. Return the slot after all nodes.
+ */
+static int next_node_with_fallback(int node)
+{
+ if (node >= nr_node_ids)
+ return nr_node_ids + 1;
+
+ node = next_node(node, node_possible_map);
+ if (node >= nr_node_ids)
+ return nr_node_ids;
+ return node;
+}
+
+#define for_each_node_with_fallback(node) \
+ for ((node) = first_node(node_possible_map); \
+ (node) <= nr_node_ids; \
+ (node) = next_node_with_fallback(node))
+
#ifdef CONFIG_DEBUG_OBJECTS_WORK

static const struct debug_obj_descr work_debug_descr;
@@ -5052,13 +5072,10 @@ static void free_node_nr_active(struct wq_node_nr_active **nna_ar)
{
int node;

- for_each_node(node) {
+ for_each_node_with_fallback(node) {
kfree(nna_ar[node]);
nna_ar[node] = NULL;
}
-
- kfree(nna_ar[nr_node_ids]);
- nna_ar[nr_node_ids] = NULL;
}

static void init_node_nr_active(struct wq_node_nr_active *nna)
@@ -5078,21 +5095,15 @@ static int alloc_node_nr_active(struct wq_node_nr_active **nna_ar)
struct wq_node_nr_active *nna;
int node;

- for_each_node(node) {
- nna = kzalloc_node(sizeof(*nna), GFP_KERNEL, node);
+ for_each_node_with_fallback(node) {
+ nna = kzalloc_node(sizeof(*nna), GFP_KERNEL,
+ node < nr_node_ids ? node : NUMA_NO_NODE);
if (!nna)
goto err_free;
init_node_nr_active(nna);
nna_ar[node] = nna;
}

- /* [nr_node_ids] is used as the fallback */
- nna = kzalloc_node(sizeof(*nna), GFP_KERNEL, NUMA_NO_NODE);
- if (!nna)
- goto err_free;
- init_node_nr_active(nna);
- nna_ar[nr_node_ids] = nna;
-
return 0;

err_free:
--
2.55.0