Re: [PATCH v5 05/36] mm: add ZONELIST_PRIVATE(_NOFALLBACK) for N_MEMORY_PRIVATE nodes.
From: Gregory Price
Date: Wed Jul 22 2026 - 09:35:32 EST
On Wed, Jul 22, 2026 at 09:00:51PM +0800, Richard Cheng wrote:
> On Mon, Jul 20, 2026 at 03:33:59PM +0800, Gregory Price wrote:
> > static void build_zonelists(pg_data_t *pgdat)
> > {
> > static int node_order[MAX_NUMNODES];
> > + nodemask_t tier_nodes;
> > int local_node = pgdat->node_id;
> > int node, nr_nodes = 0;
> >
> > memset(node_order, 0, sizeof(node_order));
> >
> > + /*
> > + * Zonelists: FALLBACK, NOFALLBACK, PRIVATE
> > + *
> > + * FALLBACK: Allocation order for all nodes. Private nodes have lists
> > + * but never appear as an entry in any list. Allocations
> > + * targeting a private node w/ FALLBACK land on N_MEMORY.
> > + *
> > + * NOFALLBACK: A list for each node containing only itself.
> > + * Allocations targeting a private node w/ NOFALLBACK
> > + * will always fail (their NOFALLBACK is empty)
> > + *
> > + * PRIVATE: (N_MEMORY | N_MEMORY_PRIVATE) - allows access to
> > + * private nodes, and falls back to normal memory unless
> > + * __GFP_THISNODE otherwise constrains it.
> > + */
> > +
> > build_node_zonelist(pgdat, &node_states[N_MEMORY], ZONELIST_FALLBACK,
> > true, node_order, &nr_nodes);
> > build_thisnode_zonelists(pgdat);
> > @@ -5912,6 +5957,10 @@ static void build_zonelists(pg_data_t *pgdat)
> > for (node = 0; node < nr_nodes; node++)
> > pr_cont("%d ", node_order[node]);
> > pr_cont("\n");
> > +
> > + nodes_or(tier_nodes, node_states[N_MEMORY], node_states[N_MEMORY_PRIVATE]);
>
> Hi Gregory,
>
> A question about this part, if my understanding is right,
> ZONELIST_PRIVATE contains all private nodes, should we use some explicit target
> nodemask here to make sure only the targeting owner's private node can be touched?
>
> Otherwise it might fall back into a different owner's private node.
>
> --Richard
>
Zonelists and the constructors here is a bit difficult to understand,
and I see I actually did a poor job of explaining what's going on in
the comments here. I will fix that up in v6.
Lets say we have the following nodes:
N_MEMORY : 0 1
N_MEMORY_PRIVATE : 2 3
The following zonelists would exist:
ZONELIST_FALLBACK[0] = {0,1}
ZONELIST_FALLBACK[1] = {1,0}
ZONELIST_FALLBACK[2] = {0,1}
ZONELIST_FALLBACK[3] = {0,1}
ZONELIST_NOFALLBACK[0] = {0}
ZONELIST_NOFALLBACK[1] = {1}
ZONELIST_NOFALLBACK[2] = {}
ZONELIST_NOFALLBACK[3] = {}
ZONELIST_PRIVATE[0] = {0,1}
ZONELIST_PRIVATE[1] = {1,0}
ZONELIST_PRIVATE[2] = {2,0,1} <- no fallback to 3
ZONELIST_PRIVATE[3] = {3,0,1} <- no fallback to 2
ZONELIST_PRIVATE_NOFALLBACK[0] = {0}
ZONELIST_PRIVATE_NOFALLBACK[1] = {1}
ZONELIST_PRIVATE_NOFALLBACK[2] = {2} <- __GFP_THISNODE
ZONELIST_PRIVATE_NOFALLBACK[3] = {3} <- __GFP_THISNODE
In the current design, we actually can never fallback to another private
node, and instead if you wanted to - for example - interleave across
said nodes you'd have to do so manually.
I think it's reasonable to later extend zonelist construction to support
such a think like:
ZONELIST_PRIVATE[2] = {2,0,1,3}
Later if such a need arises, but I would say wait for the use case.
~Gregory