背景

THP 把 512 个连续的 4 KiB 小页合并成一个 2 MiB 的 PMD 映射大页,减少 TLB miss 与页表遍历开销。shmem(tmpfs 与匿名共享内存)的大页策略不走全局 enabled,而是有独立的一套开关:tmpfs 挂载选项 huge=、顶层 shmem_enabled,以及 mTHP 引入后按尺寸划分的 hugepages-kB/shmem_enabled。后者默认只把 PMD 尺寸设为 inherit(继承顶层设置),其余尺寸一律 never。

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 行为统一,与文档承诺一致