[RFC PATCH v4 04/27] mm/page_alloc: Add private node handling to build_zonelists

Gregory Price
2026-02-22T08:49:12Z

N_MEMORY fallback lists should not include N_MEMORY_PRIVATE nodes, at
worst this would allow allocation from them in some scenarios, and at
best it causes iterations over nodes that aren't eligible.

Private node primary fallback lists do include N_MEMORY nodes so
kernel/slab allocations made on behalf of the private node can
fall back to DRAM when __GFP_PRIVATE is not set.

The nofallback list contains only the node's own zones, restricting
__GFP_THISNODE allocations to the private node.

Signed-off-by: Gregory Price <gourry@gourry.net>
---
mm/page_alloc.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 47f2619d3840..5a1b35421d78 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5683,6 +5683,26 @@ static void build_zonelists(pg_data_t *pgdat)
local_node = pgdat->node_id;
prev_node = local_node;

+ /*
+ * Private nodes need N_MEMORY nodes as fallback for kernel allocations
+ * (e.g., slab objects allocated on behalf of this node).
+ */
+ if (node_state(local_node, N_MEMORY_PRIVATE)) {
+ node_order[nr_nodes++] = local_node;
+ node_set(local_node, used_mask);
+
+ while ((node = find_next_best_node(local_node, &used_mask)) >= 0)
+ node_order[nr_nodes++] = node;
+
+ build_zonelists_in_node_order(pgdat, node_order, nr_nodes);
+ build_thisnode_zonelists(pgdat);
+ pr_info("Fallback order for Node %d (private):", local_node);
+ for (node = 0; node < nr_nodes; node++)
+ pr_cont(" %d", node_order[node]);
+ pr_cont("\n");
+ return;
+ }
+
memset(node_order, 0, sizeof(node_order));
while ((node = find_next_best_node(local_node, &used_mask)) >= 0) {
/*
--
2.53.0