
zone_set_pageset_high_and_batch()是 PCPPer-CPU Pages缓存配置更新的决策与协调函数。它负责计算 zone 的新 PCP 参数判断是否需要更新并在需要时通过__zone_set_pageset_high_and_batch()分发到所有 CPU。核心实现static void zone_set_pageset_high_and_batch(struct zone *zone, int cpu_online) { unsigned long new_high_min, new_high_max, new_batch; int old_batch, old_high_min, old_high_max; new_batch max(1, zone_batchsize(zone)); new_high_min zone_highsize(zone, new_batch, cpu_online, 0); new_high_max zone_highsize(zone, new_batch, cpu_online, MIN_PERCPU_PAGELIST_HIGH_FRACTION); old_batch zone-pageset_batch; old_high_min zone-pageset_high_min; old_high_max zone-pageset_high_max; if (new_batch old_batch new_high_min old_high_min new_high_max old_high_max) return; zone-pageset_batch new_batch; zone-pageset_high_min new_high_min; zone-pageset_high_max new_high_max; pr_info(Node %d, zone %8s: pCPUs%d, batch%d, high_min%lu, high_max%lu\n, zone_to_nid(zone), zone-name, cpu_online, new_batch, new_high_min, new_high_max); /* * The zone-lock is acquired here to avoid a race with * zone_pcp_update() which relies on the batch and high * values being visible. */ spin_lock_irq(zone-lock); __zone_set_pageset_high_and_batch(zone, new_high_min, new_high_max, new_batch); spin_unlock_irq(zone-lock); }逐步解析1. 计算新参数new_batch max(1, zone_batchsize(zone)); new_high_min zone_highsize(zone, new_batch, cpu_online, 0); new_high_max zone_highsize(zone, new_batch, cpu_online, MIN_PERCPU_PAGELIST_HIGH_FRACTION);zone_batchsize()根据 zone 大小计算批量大小zone_highsize(..., 0)用默认策略计算high_min基于低水位线zone_highsize(..., MIN_PERCPU_PAGELIST_HIGH_FRACTION)用用户配置上限计算high_max。2. 检查是否需要更新if (new_batch old_batch new_high_min old_high_min new_high_max old_high_max) return;如果三个值都没变直接返回避免无谓的分发和锁操作。这是热插拔路径上的重要优化——CPU 上线/下线时并不总是需要重新计算。3. 更新 zone 级缓存值zone-pageset_batch new_batch; zone-pageset_high_min new_high_min; zone-pageset_high_max new_high_max;把新值存入 zone 的pageset_*字段供后续查询。4. 持锁分发到所有 CPUspin_lock_irq(zone-lock); __zone_set_pageset_high_and_batch(zone, new_high_min, new_high_max, new_batch); spin_unlock_irq(zone-lock);前面讲过的__zone_set_pageset_high_and_batch()遍历所有可能 CPU通过pageset_update()写入新值。这里持有zone-lock是为了避免与zone_pcp_update()的竞态——后者依赖batch和high值可见。调用场景zone 初始化setup_zone_pageset()为每个 populated zone 设置初始 PCP 配置CPU 热插拔CPU 上线/下线时PCP 的 CPU 数量变化需要重新分配份额内存热插拔zone 大小变化时sysctl 修改用户调整vm.percpu_pagelist_high_fraction时。与pcp_batch_high_lock的关系虽然这个函数内部用zone-lock保护分发但它的调用方必须持有pcp_batch_high_lock全局互斥锁mutex_lock(pcp_batch_high_lock); zone_set_pageset_high_and_batch(zone, cpu_online); mutex_unlock(pcp_batch_high_lock);pcp_batch_high_lock保证同一时间只有一个更新者修改 zone 的 pageset 配置而zone-lock则保证分发过程中与zone_pcp_update()等路径的同步。历史演进2023 年zone_set_pageset_high_and_batch()的签名从(struct zone *zone)变为(struct zone *zone, int cpu_online)。新增的cpu_online参数用于处理 CPU 热插拔时的竞态当新 CPU 上线时cpumask_of_node()可能尚未更新导致zone_highsize()计算出的份额偏大。通过显式传入额外 CPU 数量确保计算准确。总结zone_set_pageset_high_and_batch()是 PCP 配置的决策中枢它计算新的batch/high_min/high_max与旧值比较以决定是否需要更新需要时更新 zone 级字段并在zone-lock保护下通过__zone_set_pageset_high_and_batch()分发到所有 CPU。它被 zone 初始化、CPU/内存热插拔和 sysctl 修改路径调用是 PCP 机制自适应系统拓扑和配置变化的关键环节。