v5 2026-11-01

热插拔分配器竞态修复 · v5

修复内存热插拔重建 zonelist 时分配器竞态,涉及 zone 快照、pageset 保留与分配重试。

原始补丁链接

子 Patch(12)

1/12
mm/page_alloc: reset can_retry_reserves when the slowpath restarts
Commit 2c4c3e29897d (“mm/page_alloc: simplify __alloc_pages_slowpath() flow”) retries an allocation once with reserve_flags when the caller becomes eligible for reserves, guarded by can_retry_reserves
2/12
mm/page_alloc: keep the pagesets of an empty zone
From: Josef Bacik josef@toxicpanda.com When the last memory of a zone goes offline, zone_pcp_reset() frees zone->per_cpu_pageset and zone->per_cpu_zonestats. Nothing waits for those who found the z
3/12
mm, page_alloc: pass zone pointer to trace_reclaim_retry_zone
From: Josef Bacik josef@toxicpanda.com should_reclaim_retry() walks a zonelist and passes the zoneref pointer to the reclaim_retry_zone tracepoint, which loads the zone from the entry again to find
4/12
mm/page_alloc: detect zonelist rebuilds from memory hot-add
The zonelist_update_seq retry was limited to CONFIG_MEMORY_HOTREMOVE, presumably because only hot-remove takes zones out of a zonelist. However, build_zonerefs_node() rewrites the zonelists in place,
5/12
mm/mmzone: read the zoneref slot once in zonelist_zone()
Memory hotplug rebuilds zonelists in place while allocations walk them, so a zoneref slot can change between two loads of it. zonelist_zone() loads the slot with a plain access. The compiler may loa
6/12
mm/page_alloc: snapshot the preferred zone against shrink rebuilds
get_page_from_freelist() and alloc_pages_bulk_noprof() reread ac->preferred_zoneref->zone at every use. Offlining a zone’s last block rebuilds the zonelists in place, and the shrunk list’s NULL termin
7/12
mm/mmzone: read each zoneref slot once when filtering by nodemask
__next_zones_zonelist() tests a slot’s zone for NULL, then reads the slot again to look up the zone’s node. Offlining a zone’s last block rebuilds the zonelists in place, so the second read can return
8/12
mm/page_alloc: retry allocations that raced with a zonelist rebuild
Onlining the first block of a zone rebuilds every zonelist in place, shifting the slots after the new zone. The iterator approves a slot, then the allocator loads the zone from it, so a GFP_KERNEL re
9/12
mm/hugetlb: retry the pool walk when the zonelist is rebuilt
Onlining the first block of a zone rebuilds every zonelist in place, shifting the slots after the new zone. dequeue_hugetlb_folio_nodemask() approves a slot by its node, then loads the zone from it,
10/12
mm/page_alloc: retry alloc_contig_pages() when the zonelist is rebuilt
Onlining the first block of a zone rebuilds every zonelist in place, shifting the slots after the new zone. alloc_contig_frozen_pages_noprof() approves a slot by the caller’s gfp and nodemask, then lo
11/12
mm/mempolicy: read the zoneref slot once in mempolicy_slab_node()
For a bind or preferred-many policy, mempolicy_slab_node() tests the first matching slot’s zone for NULL, then reads the slot again to look up the zone’s node. Offlining a zone’s last block rebuilds t
12/12
mm/mmzone: remove zonelist_node_idx()
zonelist_node_idx() looks like it returns a field of the zoneref, as zonelist_zone_idx() does, but it loads the zone from the slot again. Memory hotplug rewrites zonelists in place, so a caller that