init_on_alloc
分配页先清零
防止旧内容泄漏
安全选项
分配路径
alloc_pages
拿到 order 页块
init_on_alloc=1
清零再交出
清零助手
kernel_init_pages()
page, 1 << order
按页处理
每次分配都走
目标
清零不能省
但可以更快
旧路径 · 逐页清零
kernel_init_pages()
for i < numpages
clear_highpage...
循环
page + i
一次一页
numpages = 1 << order
大块也拆开
每页动作
kmap_local_page
clear_page
kunmap_local
KASAN 标签复位
旧实现
逐页映射
逐页清零
代价 · 为什么慢
连续页本可整段清
却按页拆开
每页都有固定开销
per-page 开销
kmap_local_page
kunmap_local
每页一次映射
开销无法摊薄
架构原语
clear_page(addr)
每次只一页
REP STOSB 可用
但只覆盖一页
浪费
连续内存的优势
被逐页拆掉
方案 · 整段批量
新增批量 helper
clear_highpages_kasan_tagged
一次覆盖整个 order
整段范围
page_address(page)
连续 numpages
传给 clear_pages
架构一次处理
仍然安全
kasan_disable_current
kasan_reset_tag
清完再 enable
标签语义保留
关键
清的是同一段内存
只是少绕路
实现 · !HIGHMEM 快路
没有 HIGHMEM
page_address 直接可用
不需要 kmap
地址
page_address(page)
kasan_reset_tag()
void *addr
整段起点
批量清零
clear_pages(addr, n)
n = numpages
REP STOSB / memset
覆盖整段
快路
无逐页 kmap
架构原语覆盖整段
回退 · HIGHMEM 逐页
HIGHMEM 页需映射
不能直接 page_address
保留逐页路径
条件
CONFIG_HIGHMEM
IS_ENABLED()
走 else 分支
语义不变
逐页
clear_highpage...
kmap_local_page
kunmap_local
每页一次
边界
快路只对 !HIGHMEM
HIGHMEM 回退
替换 · 两个调用点
kernel_init_pages 删除
直接调新 helper
两个 init 路径
释放路径
__free_pages_prepare
if (init)
clear_highpages...
1 << order
分配路径
post_alloc_hook
init_on_alloc
clear_highpages...
1 << order
行为
还是同一个清零点
只是批量实现
收益与边界
init_on_alloc=1
16GB HugeTLB
kernel time (sys)
micro-benchmark
0.445s → 0.166s
-62.7%
2.68x faster
8192 × 2MB
workload kernel time
Graph500 64C128T -50.3%
Graph500 16C32T -39.0%
Pagerank 32T -38.5%
Pagerank 128T -35.7%
范围
只测该配置
不是所有 workload
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x