☰
page_alloc zone_pcp_enable
2026/10/21 2:30:53 网站建设 项目流程

PCP(Per-CPU Pages)缓存的禁用与启用函数,用于在内存热插拔等需要“冻结”PCP 缓存的场景中,临时关闭某个 zone 的 PCP 机制。


一、zone_pcp_disable()—— 禁用 zone 的 PCP 缓存

void zone_pcp_disable(struct zone *zone) { mutex_lock(&pcp_batch_high_lock); __zone_set_pageset_high_and_batch(zone, 0, 0, 1); __drain_all_pages(zone, true); }

逐步解析

1. 获取全局互斥锁

mutex_lock(&pcp_batch_high_lock);
  • 前面讲过的pcp_batch_high_lock:保护 PCP 的high/batch字段更新。

  • 获取它确保在禁用期间,没有其他更新者并发修改 PCP 配置。

  • 注意:这把锁在zone_pcp_enable()中才释放,形成disable/enable 的配对临界区。

2. 把 PCP 配置设为“禁用”状态

__zone_set_pageset_high_and_batch(zone, 0, 0, 1);
  • 前面讲过的__zone_set_pageset_high_and_batch():遍历所有 CPU,更新 PCP 的high_min、high_max、batch。

  • 参数(0, 0, 1)的含义:

    • high_min = 0、high_max = 0:高水位为 0,意味着 PCP 缓存不能保留任何页——一旦有页放入,立即触发批量归还。

    • batch = 1:批量大小为 1,每次只处理一页。

  • 效果:PCP 缓存形同虚设,所有分配/释放几乎直接走伙伴系统。

3. 强制排空所有 CPU 的 PCP 缓存

__drain_all_pages(zone, true);
  • 前面讲过的__drain_all_pages(zone, force_all_cpus):排空指定 zone 在所有 CPU 上的 PCP 缓存。

  • force_all_cpus = true:强制在所有 CPU 上执行排空,跳过“非空检查”的竞态优化。

  • 这是为了确保彻底清空——因为内存热插拔要求该 zone 的 PCP 缓存中不能有任何页残留,否则隔离/下线会失败。

为什么需要force_all_cpus = true?

前面讲__drain_all_pages()时提到过:普通的非空检查存在竞态——一个 CPU 的 PCP 看起来是空的,但另一个 CPU 正好在释放页到该 PCP 且尚未增加count。内存热插拔对“彻底清空”有强要求,所以必须强制排空所有 CPU。


二、zone_pcp_enable()—— 重新启用 zone 的 PCP 缓存

void zone_pcp_enable(struct zone *zone) { __zone_set_pageset_high_and_batch(zone, zone->pageset_high_min, zone->pageset_high_max, zone->pageset_batch); mutex_unlock(&pcp_batch_high_lock); }

逐步解析

1. 恢复 zone 的正常 PCP 配置

__zone_set_pageset_high_and_batch(zone, zone->pageset_high_min, zone->pageset_high_max, zone->pageset_batch);
  • 从 zone 的pageset_*字段中取回禁用前的正常配置:

    • zone->pageset_high_min/pageset_high_max:该 zone 的高水位范围;

    • zone->pageset_batch:批量大小。

  • 这些值是在zone_set_pageset_high_and_batch()中计算并保存的。

  • 通过__zone_set_pageset_high_and_batch()重新分发到所有 CPU 的 PCP 结构。

2. 释放全局互斥锁

mutex_unlock(&pcp_batch_high_lock);
  • 释放pcp_batch_high_lock,结束 disable/enable 的临界区。

  • 之后其他更新者可以正常修改 PCP 配置。


三、disable/enable 的配对使用

这两个函数必须成对调用:

zone_pcp_disable(zone); // 加锁,禁用 PCP,排空 /* ... 执行需要 PCP 无残留的操作,如内存隔离、下线 ... */ zone_pcp_enable(zone); // 恢复 PCP,解锁

典型使用场景

1. 内存热插拔下线

offline_pages()在隔离 pageblock 之前,需要确保 PCP 缓存中没有该 zone 的页,否则这些页可能“躲过”隔离。所以先zone_pcp_disable(),下线完成后再zone_pcp_enable()。

2. CMA 分配

alloc_contig_range()在需要大块连续内存时,可能通过zone_pcp_disable()确保 PCP 缓存不干扰隔离。

3. 内存规整

某些极端场景下,规整需要 PCP 缓存无残留。


四、与前面内容的呼应

前面出现过的这里的关联
pcp_batch_high_lockdisable 时获取,enable 时释放
__zone_set_pageset_high_and_batch()两函数都调用它更新 PCP 配置
__drain_all_pages(zone, true)disable 时强制排空
zone->pageset_high_min/pageset_high_max/pageset_batchenable 时恢复这些值
page_alloc_cpu_online()/page_alloc_cpu_dead()CPU 热插拔也涉及 PCP 配置
内存热插拔offline_pages()典型调用场景

五、小结表

函数操作锁
zone_pcp_disable(zone)设置 PCP 为high=0, batch=1(禁用)+ 强制排空所有 CPU获取pcp_batch_high_lock
zone_pcp_enable(zone)恢复 zone 的正常high_min/high_max/batch释放pcp_batch_high_lock

一句话总结

zone_pcp_disable()和zone_pcp_enable()是 PCP 缓存的禁用/启用配对函数:disable 时获取pcp_batch_high_lock,把 zone 的 PCP 配置设为high=0, batch=1使其形同虚设,并强制排空所有 CPU 的 PCP 缓存以确保无页残留;enable 时从 zone 保存的pageset_*字段恢复正常配置并释放锁。它们用于内存热插拔、CMA 分配等需要 PCP 缓存彻底清空的场景,确保隔离和迁移操作不受 PCP 中滞留页的干扰。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询