setup_zone_pageset()是 PCP(Per-CPU Pages)缓存初始化流程中的关键函数,负责为一个 populated zone动态分配并初始化正式的 per-CPU pageset 结构,替换掉启动阶段使用的boot_pageset占位结构。
核心实现
void __meminit setup_zone_pageset(struct zone *zone) { struct per_cpu_zonestat *pzstats; int cpu; /* 分配正式的 per_cpu_pages 数组 */ zone->per_cpu_pageset = alloc_percpu(struct per_cpu_pages); zone->per_cpu_zonestats = alloc_percpu(struct per_cpu_zonestat); for_each_possible_cpu(cpu) { struct per_cpu_pages *pcp; struct per_cpu_zonestat *pzstats; pcp = per_cpu_ptr(zone->per_cpu_pageset, cpu); pzstats = per_cpu_ptr(zone->per_cpu_zonestats, cpu); per_cpu_pages_init(pcp, pzstats); } zone_set_pageset_high_and_batch(zone, 0); }逐步解析
1. 动态分配 per-CPU pageset
zone->per_cpu_pageset = alloc_percpu(struct per_cpu_pages); zone->per_cpu_zonestats = alloc_percpu(struct per_cpu_zonestat);
alloc_percpu():为每个可能的 CPU 分配一份struct per_cpu_pages和struct per_cpu_zonestat。在此之前,zone 使用的是静态定义的
boot_pageset/boot_zonestats(前面讲过的)。现在内存子系统已就绪,可以分配真正的 per-CPU 结构了。
2. 初始化每个 CPU 的 PCP
for_each_possible_cpu(cpu) { pcp = per_cpu_ptr(zone->per_cpu_pageset, cpu); pzstats = per_cpu_ptr(zone->per_cpu_zonestats, cpu); per_cpu_pages_init(pcp, pzstats); }前面讲过的per_cpu_pages_init():清零结构体、初始化锁和空闲链表、设置 boot 安全的batch/high值。
3. 设置 PCP 的 batch/high 配置
zone_set_pageset_high_and_batch(zone, 0);
前面讲过的zone_set_pageset_high_and_batch():计算该 zone 的batch、high_min、high_max,并分发到所有 CPU。参数cpu_online = 0表示这是初始化阶段,没有额外的 CPU 上线事件。
调用场景
它被zone_pcp_init()或free_area_init_core()等初始化路径调用,为每个 populated zone建立正式的 pageset:
free_area_init_core() └── for each zone: if (populated_zone(zone)) setup_zone_pageset(zone) // ← 这里 ├── alloc_percpu(per_cpu_pages) ├── alloc_percpu(per_cpu_zonestat) ├── per_cpu_pages_init() for each cpu └── zone_set_pageset_high_and_batch(zone, 0)
__meminit的含义
函数标记为
__meminit,表示它主要用于内存初始化/热插拔阶段。函数体在内存初始化完成后可被卸载(如果 CONFIG_MEMORY_HOTPLUG 允许)。
内存热插拔时,新上线的 zone 也会调用它来建立 pageset。
与启动阶段的对比
| 阶段 | pageset | batch/high |
|---|---|---|
| 启动早期 | boot_pageset(静态占位) | HIGH=0,BATCH=1(禁用 PCP) |
setup_zone_pageset()后 | 动态分配的正式 pageset | 由zone_set_pageset_high_and_batch()计算 |
总结
setup_zone_pageset()是 PCP 缓存的正式初始化函数:它为 populated zone 动态分配 per-CPU 的per_cpu_pages和per_cpu_zonestat数组,用per_cpu_pages_init()初始化每个 CPU 的结构,最后通过zone_set_pageset_high_and_batch()计算出该 zone 的 batch/high 配置并分发。它标志着 zone 从启动阶段的boot_pageset占位切换到真正的 PCP 缓存管理,是内存子系统初始化的重要步骤。