一个 compound page 有大量 tail struct page
它们的 vmemmap 内容可以从 head 推导
HugeTLB compound page
head
前几个
真实 vmemmap
tail struct page(大量)
vmemmap 内容可由 head 推导
共享页(写保护)
所有 tail 的 vmemmap 指向这一页
HVO 的结果
省下的 vmemmap 页
被释放
HugeTLB Vmemmap Optimization
即 HVO
同一份内容只存一次
专用路径 · 启动时 HugeTLB 自己预填充 vmemmap
bootmem 阶段的 HugeTLB 大页
走 HVO 优化
HugeTLB 自己预填充优化后的 vmemmap
抢在通用 sparse-vmemmap 填充之前
memmap_init_range() 逐页初始化
又把共享尾页的 struct page 覆盖掉
HugeTLB 事后恢复元数据
把刚刚被覆盖的内容补回来
这条路径留下四处别扭
专用预填充与通用 sparse-vmemmap 填充重复
sparsemem 为它背着 SPARSEMEM_VMEMMAP_PREINIT
启动状态散落在通用内存初始化流程
共享尾页先初始化,又被逐页覆盖
HugeTLB bootmem 大页
分配时只做一次登记
不再自己预填充映射
mem_section
HVO 配置下新增字段
compound_page_order
=
order
配套 helper 把 mem_section 访问留在 sparse helper 内部
一个 section 记一个 compound page order
HugeTLB 只负责登记
compound page 的 PFN 范围
保留 struct page
共享尾页的 vmemmap
偏移超过保留的 struct page 数量
vmemmap_optimizable_pfn()
据此判定共享尾页
PFN 落在保留区之外,它的 vmemmap 就落在共享页上
判别只看 section 元数据
通用代码只读 section 元数据,就能认出共享尾页
通用 sparse-vmemmap 填充路径
按 section 元数据分配或复用共享尾页 vmemmap
共享尾页 struct page 在分配时初始化
填充改由通用路径做
memmap_init_range() 的初始化范围
head 区间
共享尾页
按 order 对齐,直接跳到 compound page 末尾
不再逐页初始化
覆盖与恢复一并消失
pageblock migratetype 初始化
从逐页循环里抽出来
循环结束后:整段统一补做
改动前
HugeTLB 自己预填充 vmemmap
section 与 vmemmap PMD 两级对齐检查
专用填充函数
按 zone 预初始化共享尾页 struct page
SPARSEMEM_VMEMMAP_PREINIT 配置
HUGE_BOOTMEM_HVO 标志
改动后
bootmem 分配时登记 order
通用路径按 section 元数据铺页
通用 sparse-vmemmap 填充路径
共享尾页在分配时初始化
PREINIT 配置整体移除
folio 优化与否看 section 的 order
专用路径消失,HVO 才能被其他 sparse-vmemmap 用户复用
作者未提供性能数据
以下为代码逻辑推断的预期收益
共享尾页 struct page 不再被逐页初始化覆盖
专用填充与通用路径合一,PREINIT 特例移除
section 元数据成为 vmemmap 优化的统一载体
HugeTLB 的启动状态收敛回 hugetlb 私有范围
留给后续系列
device DAX 切换到 section-based
vmemmap 优化路径
更大范围的 HVO 整合
同样走 section 元数据
HVO 泛化的第二个小步:专用启动路径收进 section 元数据
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x