背景
THP 把 512 个连续的 4 KiB 小页合并成一个 2 MiB 的 PMD 映射大页,减少 TLB miss 与页表遍历开销。shmem(tmpfs 与匿名共享内存)的大页策略不走全局 enabled,而是有独立的一套开关:tmpfs 挂载选项 huge=、顶层 shmem_enabled,以及 mTHP 引入后按尺寸划分的 hugepages-
MADV_COLLAPSE 是用户主动发起的同步 collapse:不要求 VMA 标记 MADV_HUGEPAGE,由调用者明确指定范围,内核立即把范围内的小页合并成 PMD 级大页。文档承诺它忽略全部 THP 与 mTHP sysfs 配置,即使所有开关都设为 never 也照常 collapse。memfd、SysV shm 这类匿名 shmem(mmap 时已解除链接的共享内存)正是 MADV_COLLAPSE 的典型使用场景。
collapse 与否取决于资格判定:madvise_collapse() 先调 collapse_possible() 确认 VMA 允许 PMD 级 order,shmem 文件会转入 shmem_allowable_huge_orders()。v6.11 为匿名 shmem 接入 mTHP 的每尺寸判定后,该函数内部按映射类型分流:tmpfs 映射提前返回全局判定结果,不碰每尺寸 sysfs;匿名 shmem 则继续把各档 sysfs 掩码合成最终结果。
资格判定按 shmem 映射类型分流
┌────────────────────┐
│ shmem 大页资格判定 │
└─────────┬──────────┘
┌────────────────────┴────────────────────┐
▼ ▼
┌──────────────────────────────────┐ ┌─────────────────────────────────┐
│ tmpfs 映射提前返回全局判定结果, │ │ 匿名 shmem 继续合成每尺寸 sysfs │
│ 不碰每尺寸 sysfs 配置 │ │ 掩码 │
└──────────────────────────────────┘ └─────────────────────────────────┘
问题
- 匿名 shmem 的强制 collapse 误入每尺寸 sysfs 掩码合成路径
- PMD 级 order 能否保留取决于 PMD 档 shmem_enabled 保持 inherit
- 管理员一旦把它改成 never 等其它值,MADV_COLLAPSE 直接返回 -EINVAL
- 应用依赖的 2 MiB collapse 静默失效,造成用户可见的性能回退
方案
强制 collapse 与常规分配的分水岭是 shmem_huge_force 标志:只有 MADV_COLLAPSE 路径(TVA_FORCED_COLLAPSE)把它置真,缺页分配等常规路径一律为假。方案把该标志并入提前返回条件,强制 collapse 与 tmpfs 一样直接返回全局判定结果,不再进入每尺寸 sysfs 掩码合成:
/*
* Tmpfs huge pages allocation or forced collapse ignores
* sysfs configs.
*/
if (!vma || !vma_is_anon_shmem(vma) || shmem_huge_force)
return global_orders;
全局判定来自 shmem_huge_global_enabled():强制 collapse 时它直接给出 PMD 级 order,与 tmpfs 挂载选项、顶层 shmem_enabled 的策略取值、每尺寸 shmem_enabled 全部无关。匿名 shmem 的常规缺页分配行为不变,仍按每尺寸 sysfs 合成掩码,khugepaged 的 collapse 策略也不受影响。
修复后的判定分流
┌────────────────────┐
│ shmem 大页资格判定 │
└─────────┬──────────┘
┌────────────────────┴────────────────────┐
▼ ▼
┌───────────────────────────────────┐ ┌───────────────────────────────────┐
│ tmpfs 映射或强制 collapse,直接返 │ │ 匿名 shmem 常规分配,仍合成每尺寸 │
│ 回全局判定的 PMD 级 order │ │ sysfs 掩码 │
└───────────────────────────────────┘ └───────────────────────────────────┘
忽略的只是策略配置,硬性禁止仍然生效:VMA 标记 MADV_NOHUGEPAGE 或进程通过 prctl 完全禁用 THP 时,资格判定在入口就被拒绝;顶层 shmem_enabled 设为 deny 时全局判定返回 0。除此之外,即使所有策略开关都是 never,MADV_COLLAPSE 也照常拿到 PMD 级 order,与文档承诺一致。
强制 collapse 的放行与拒绝
┌──────────────────────────────────┐
│ MADV_COLLAPSE 强制 collapse 请求 │
└────────────────┬─────────────────┘
┌────────────────────┴────────────────────┐
▼ ▼
┌──────────────────────────────────┐ ┌──────────────────────────────────┐
│ MADV_NOHUGEPAGE 或进程级禁用或顶 │ │ 其余一律放行 PMD 级 collapse,忽 │
│ 层 deny,拒绝 │ │ 略所有策略配置 │
└──────────────────────────────────┘ └──────────────────────────────────┘
判定放行后,madvise_collapse() 把目标范围按 2 MiB 对齐,逐段完成 collapse。
收益
作者未提供性能数据,从代码逻辑推断的预期收益:
- 匿名 shmem 上的 MADV_COLLAPSE 恢复稳定生效,不再被每尺寸 sysfs 配置静默否决
- memfd、SysV shm 等共享内存后端的应用重新可靠获得 2 MiB 大页
- tmpfs 与匿名 shmem 的强制 collapse 行为统一,与文档承诺一致