do_migrate_range() excludes the source node from node_states[N_MEMORY] and adds it back only when the nmask is empty. With private nodes in N_MEMORY, this can leave a nonempty nmask containing only private nodes, when the system has only one public node and others are private nodes. Ordinary migration allocations use the public fallback zonelist, so none of those nodes can satisfy the allocation. Build the nmask from N_MEMORY_PUBLIC so that private nodes do not prevent this fallback. For HugeTLB migration during memory offlining, this also excludes other private nodes from the nmask when the source node is private and public nodes are present. Signed-off-by: Zimo.Lu Assisted-by: LLM --- Should we use public targets for private-source HugeTLB migration during memory offlining as well, or should this fix be limited to the same-node fallback problem on a public source node? Based on the author's node_features_v6 WIP snapshot (base below). This is not a patch against mainline or the posted v5 series. Private-source HugeTLB migration has not been tested. mm/memory_hotplug.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 22d20ee96bb1..8a95ba26552d 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1937,7 +1937,7 @@ put_folio: folio_put(folio); } if (!list_empty(&source)) { - nodemask_t nmask = node_states[N_MEMORY]; + nodemask_t nmask = node_states[N_MEMORY_PUBLIC]; struct migration_target_control mtc = { .nmask = &nmask, .gfp_mask = GFP_KERNEL | __GFP_MOVABLE | __GFP_RETRY_MAYFAIL, @@ -1953,8 +1953,8 @@ put_folio: /* * try to allocate from a different node but reuse this node - * if there are no other online nodes to be used (e.g. we are - * offlining a part of the only existing node) + * if there are no other public nodes to be used (e.g. we are + * offlining a part of the only public node) */ node_clear(mtc.nid, nmask); if (nodes_empty(nmask)) base-commit: 38c7f48162aa282dc6a9edfb7011378594057c10