一次高阶原子分配
GFP_ATOMIC
order > 0
zone 水位 low/min 之间
alloc_flags 被放宽
ALLOC_HIGHATOMIC
进入重试分配
为什么要预留
高阶原子分配不能睡眠、不能回收
低水位时仍要满足请求
于是先留出可用的 pageblock
预留的目标
zone 管理的约 1%
只给高阶原子分配用
平时不额外挤占正常分配
本文的问题
预留被无谓地扩大,反而挤占正常分配
不是预留本身有错,而是扩容时机错了
旧路径:PCP 命中后还要扩预留
rmqueue()
PCP 命中
prep_new_page()
reserve_highatomic_pageblock()
reserve_highatomic_pageblock()
检查 nr_reserved_highatomic < 1%
取 pageblock 的 migratetype
只转普通可合并块
move_freepages_block(...)
-> MIGRATE_HIGHATOMIC
每次都对 PCP 页做一遍
可 PCP 页偏偏不是它
PCP 页来自 UNMOVABLE 列表
pageblock 类型仍是 UNMOVABLE
MIGRATE_HIGHATOMIC 不在该列表
reserve 检查必然不匹配
于是再转一个新 pageblock
每次命中都扩一点,nr_reserved_highatomic 持续上升
PCP 只跟踪三种迁移类型
UNMOVABLE
内核 slab 等
slab 请求走这里
RECLAIMABLE
可回收页
文件页缓存等
MOVABLE
可移动页
HIGHATOMIC 释放时并入
reserve 看到的是什么
get_pageblock_migratetype(page)
= UNMOVABLE
!= MIGRATE_HIGHATOMIC
所以每次都转换
形成自我维持的循环
PCP 命中 -> reserve
转新块 -> nr_reserved++
仍低于 1% -> 下次继续
块多空闲,正常分配被挤
不是页面类型判断错误,而是检查对象错位
reserve 应只对伙伴路径拿到的页做
PCP 页不会以 HIGHATOMIC 类型出现
调用点搬家
旧:get_page_from_freelist()
rmqueue 返回后调用
PCP 命中也会走到
新:rmqueue_buddy()
伙伴路径成功后再调用
PCP 命中不调用
buddy 路径的顺序
先试 MIGRATE_HIGHATOMIC list
失败再走普通 migratetype
普通页成功后才 reserve_highatomic_pageblock()
扩容只发生在真正需要时
高阶原子 PCP 空时不再 refill
if (alloc_flags & ALLOC_HIGHATOMIC)
return NULL;
rmqueue 回退 rmqueue_buddy
命中仍直接返回
没有新增状态,只移动检查点
预留上限、锁内 recheck 都保持不变
rmqueue() 的两条路
rmqueue_pcplist()
先看 PCP
命中
直接返回
空
rmqueue_buddy()
PCP 命中不扩预留;PCP 空才进入伙伴路径
PCP 命中:快路径不变
不检查预留上限
不调用 reserve
GFP_ATOMIC 仍能快速拿到页
PCP 空:交给伙伴
ALLOC_HIGHATOMIC 直接返回 NULL
不再从 buddy refill PCP
回退 rmqueue_buddy()
判断依据是“这页能不能被 PCP 服务”
能服务,说明暂时不需要扩预留
不能服务,才让 buddy 决定是否扩
旧:每次高阶原子命中
调用点与页来源无关
缓存命中 -> reserve
块被反复转换
上限仍 1%,只是被无谓填满
新:伙伴路径成功
只有 rmqueue_buddy 返回页
才检查并扩预留
PCP 命中不触发
条件仍是 ALLOC_HIGHATOMIC
上限与并发检查不变
1% 上限仍在 reserve 内计算
zone->lock 下 recheck
只改调用时机,不改预留规则
什么时候还会扩?
HIGHATOMIC list 失败时
为后续高阶原子分配补预留
不再无谓扩容
PCP 命中不转块
预留不再虚高
块不再多数空闲
少转一块
少浪费一块
正常分配不被挤
不提前触发回收
水位更健康
真实系统上的观察
GFP_ATOMIC SLUB + 低水位重试
MIGRATE_HIGHATOMIC pageblock 持续累积
修复后测试稳定
预留建到正常水位,无 highatomic 失败
收益口径
作者未提供量化 benchmark
节省的是无谓转换与空闲块
正常分配不再被提前推向回收
一句话记住这次修复
高阶原子 PCP 命中:直接返回
PCP 空:ALLOC_HIGHATOMIC 回退 buddy
buddy 成功:必要时扩预留
上限与锁内检查保持原样
快路径保留,扩容时机纠正
一句话对比
旧:PCP 命中 -> reserve -> 新块
新:PCP 空 -> buddy -> 需要才 reserve
预留回到正常水位
改动很小:PCP 空回退,伙伴路径才扩预留
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x