build_zonerefs_node()是 zonelist 初始化过程中的核心辅助函数,负责将一个 NUMA 节点内所有已填充(populated)的 zone 依次加入zoneref数组。
核心作用与背景
在 NUMA 系统中,每个节点的内存分配顺序由zonelist定义。当构建某个节点的 zonelist 时,需要先把本地节点内的各个 zone(按 zone 类型从高到低)填充进去,再去填充远程节点的 zone。
build_zonerefs_node()就是完成“填充单个节点”这一步的函数。它遍历一个pg_data_t上的所有 zone 类型,把有内存的 zone 通过zoneref_set_zone()写入调用方提供的zonerefs数组,并返回实际加入的 zone 数量。
核心逻辑
该函数的典型实现如下:
static int build_zonerefs_node(pg_data_t *pgdat, struct zoneref *zonerefs) { struct zone *zone; enum zone_type zone_type = MAX_NR_ZONES; int nr_zones = 0; do { zone_type--; zone = pgdat->node_zones + zone_type; if (populated_zone(zone)) { zoneref_set_zone(zone, &zonerefs[nr_zones++]); check_highest_zone(zone_type); } } while (zone_type); return nr_zones; }关键点解析
1. 从高 zone 类型向低遍历
循环从MAX_NR_ZONES开始递减,即先处理ZONE_MOVABLE、ZONE_HIGHMEM,最后处理ZONE_DMA。这与分配时优先使用高端 zone的策略一致。
2. 使用populated_zone()判断
这是该函数在 2022 年修复的关键点。此前使用的是managed_zone(),它要求 zone当前有被 buddy 分配器管理的页。这会导致一个问题:当一个 zone 的内存全部被 balloon 走(如 Xen guest 中),managed_zone()返回假,该 zone 会被完全排除出 zonelist,后续分配和回收都无法触及它。
修复后改用populated_zone(),它只要求 zone在物理上存在且有内存段,不要求当前有空闲页。这样即使 zone 暂时被 balloon 耗尽,它仍保留在 zonelist 中,后续 balloon 归还内存时能立即被使用。
3.check_highest_zone()的副作用
每加入一个 zone,就调用check_highest_zone(zone_type),用于更新全局的highest_zoneidx(或policy_zone),确保系统知道当前可用的最高 zone 类型。
4. 返回值:加入的 zone 数量
函数返回nr_zones,调用方据此推进zonerefs数组的起始位置,继续填充下一个节点的 zone。
在 zonelist 构建中的位置
build_zonerefs_node()被build_zonelists()反复调用,用于按“从近到远”的顺序填充每个节点的 zone:
build_zonelists(pgdat) ├── build_zonerefs_node(pgdat, zonerefs) // 本地节点 │ └── zonerefs += 返回的 nr_zones ├── build_zonerefs_node(NODE_DATA(node+1), zonerefs) // 邻近节点 └── ...
命名与历史演进
该函数原名build_zonelists_node,在 2017 年 Michal Hocko 的补丁(commit9d3be21bf9c0)中被重命名为build_zonerefs_node,同时移除了它原本接收和返回“数组索引”的参数,改为直接操作zonerefs数组指针,只返回加入的 zone 数量。
总结
build_zonerefs_node()是 zonelist 构建的单节点填充器:它从最高 zone 类型向低遍历pgdat->node_zones[],用populated_zone()判断 zone 是否应纳入 zonelist,通过zoneref_set_zone()写入数组并调用check_highest_zone()更新全局信息,返回加入的 zone 数量供调用方推进数组。2022 年从managed_zone()到populated_zone()的修复,确保了内存被 balloon 耗尽的 zone 不会从 zonelist 中消失。