zone_pcp_init()是 PCP(Per-CPU Pages)缓存的启动早期占位初始化函数,标记为__meminit,用于在正式 pageset 就绪之前,将 zone 指向静态的boot_pageset。
核心实现
__meminit void zone_pcp_init(struct zone *zone) { /* * per_cpu field name is historical. It is actually a per * zone, per cpu structure. We should support data from * "Per CPU pageset" in /proc/zoneinfo. */ zone->per_cpu_pageset = &boot_pageset; zone->per_cpu_zonestats = &boot_zonestats; if (populated_zone(zone)) pr_debug(" %s zone: %lu pages, LIFO batch:%u\n", zone->name, zone->present_pages, zone_batchsize(zone)); }逐步解析
1. 指向静态 boot pageset
zone->per_cpu_pageset = &boot_pageset; zone->per_cpu_zonestats = &boot_zonestats;
boot_pageset和boot_zonestats是前面讲过的静态 per-CPU 占位结构。这里让 zone 暂时指向它们,使 zone 在正式 pageset 分配之前也能正常工作。
boot_pageset的high=0、batch=1,实际上禁用了 PCP 缓存,所有分配/释放直接走伙伴系统。
2. 打印调试信息
if (populated_zone(zone)) pr_debug(" %s zone: %lu pages, LIFO batch:%u\n", zone->name, zone->present_pages, zone_batchsize(zone));只有 populated zone 才打印信息。
输出 zone 名称、当前页数、以及由
zone_batchsize()计算的初始批量大小。pr_debug只在调试配置下输出。
在 PCP 初始化流程中的位置
启动早期: free_area_init_core() └── zone_pcp_init(zone) // ← 这里,指向 boot_pageset 稍后: setup_per_cpu_pageset() └── setup_zone_pageset(zone) // 分配正式 pageset,替换 boot_pageset
zone_pcp_init():第一阶段,用静态占位结构让 zone 可用;setup_zone_pageset():第二阶段,动态分配正式 pageset,真正启用 PCP 缓存。
__meminit的含义
函数放在
.meminit.text段。在内存初始化完成后可被卸载(如果 CONFIG_MEMORY_HOTPLUG 允许)。
内存热插拔时,新上线的 zone 也可能调用它进行早期占位。
与boot_pageset的关系
boot_pageset是所有 zone 在启动早期共享的占位结构(每 CPU 一份)。由于high=0,它实际上不缓存任何页,所有操作直接转交伙伴系统。这避免了在内存子系统完全就绪前引入 PCP 缓存带来的复杂性。
总结
zone_pcp_init()是 PCP 机制的启动早期占位初始化:它让 zone 的per_cpu_pageset指向静态的boot_pageset,使 zone 在正式 pageset 分配前也能正常工作;同时为 populated zone 打印调试信息。它由free_area_init_core()在 zone 初始化时调用,是setup_per_cpu_pageset()之前的第一阶段初始化,标志着 PCP 机制从“未启用”进入“占位就绪”状态。