2026-07-08 内核社区日报
HugeTLB vmemmap 优化(HVO)在 arm64 上落下最后一颗棋子——James Houghton 今天抛出的 18 补丁系列,利用 Access Flag 技巧避开了 block→table 分裂时的安全窗口,从此 HVO 不再被 arm64 的特有页表修改限制所阻。另一边,Baoquan He 的 zswap「Pointer entry」方案拿到首轮测试结果兼 syzbot 反馈,但 Yosry 对间接查找的开销心存疑虑。
🧠 重点 · 内存
1. arm64 终获 HugeTLB vmemmap 优化(HVO)支持
发生了什么: James Houghton 发送了一个 18 补丁的完整 series,使 arm64 能启用 hugetlb_vmemmap_optimization(HVO)。核心难点在于 arm64 的 vmemmap 页表更新必须使用 break-before-make(BBM)序列,这会在 block→table 切换时引入一段窗口——恰好 vmemmap_remap_free() / vmemmap_remap_alloc() 操作的是正在被其他 CPU 活跃访问的页表,传统 set_pte_at() 无法安全替换 in-use 的 PTE/PMD 条目。
该 series 的应对方案是利用 arm64 的 Hardware Access Flag:通过暂时清除 PTE 的 AF 位来标记"正在更新",CPU 后续访问会触发 fault 并重试,借此避免竞态。具体地:
try_update_vmemmap_pte()使用 AF trick 安全替换 in-use PTE;try_populate_vmemmap_pmd()在 PMD 级别做同样的事,使得 arm64 不再要求 BBML2_NOABORT(Block-based BBM Level 2 no abort)的 CPU 特性——这大幅扩展了兼容的硬件范围。- 此外,该系列引入了运行时 HVO 兼容性检测(
system_supports_hvo)、允许后期上线的不兼容 CPU 在 HVO 未使用时正常上线、以及部分优化失败时保持部分 HVO 状态而不回滚整个 folio 等机制。
为什么重要: HVO 在 x86 上早已可用,可为每个 2MB+ huge page 节省约 1 个 4KB page 的 vmemmap 内存。arm64 数据中心/云场景下 HugeTLB 使用广泛,该优化能直接降低 vmemmap 占用,尤其对内存密度大的环境意义显著。这是 HVO 在 arm64 上的首个完整实现提案,也是社区多年努力的结果。
2. RFC: 将 zswap entries 存入 swap table(Pointer entries)
发生了什么: Baoquan He 发起了 RFC 系列,提出在 swap table 中引入 Pointer entry(类型为 SWAP_POINTER),把 zswap 原本存储在 per-swap-device xarray 中的压缩条目直接挂载到 swap table 的 swp_entry_t 中。这样:
- 不再需要
zswap_find()的 xarray 查找,压缩条目的定位变成一次 swap table 查询; - 为后续的 ghost swapfile 与 Redirect entry 等机制打下数据结构基础。
今天收到了多轮 review。Yosry Ahmed 指出:将 zswap 元数据和压缩数据放在 swap table 中虽然有局部性优势,但会增大 swap entry 的大小,且间接查找(从 swap table 读取 Pointer entry 再指向压缩页)不一定比当前 xarray 快。Nhat Pham 提出是否可以考虑不替换整个 xarray,而是将 Pointer entry 作为补充路径。
syzbot ci 已经测试了这个 series,没有触发新 bug,但强调了性能基线的重要性。
为什么重要: 这是 zswap 自引入以来最大幅度的内部重构尝试之一,如果成功,可以消除一个间接查找层,潜在地改善压缩交换时的访存局部性。当前讨论集中在性能与实现复杂度的权衡上,值得关注后续版本和实测数据。
3. 匿名 mTHP folio 加入 deferred split 列表,防止内存浪费
发生了什么: Joanne Koong 发送 V1 系列,解决未充分利用的匿名 mTHP 大页在内存压力下无法被 shrinker 拆分的问题。目前,PMD 级的 THP 在变为 mostly-zero 时会被 deferred_split_shrinker 拆分成 4KB 基础页释放 unused 部分;但 mTHP folio(如 64KB、32KB 等 order)没有被加入 deferred split 列表,导致即使在写时分解(COW 或写保护)之后,这些 mTHP folio 仍以整体存在,内存无法被有效回收。
该系列:
- 扩展
thp_underused()检查,使其能判断 mTHP folio 是否有大量零填充或多余有效数据; - 在
wp_can_reuse_anon_folio()及其它写时路径中,将符合条件的 mTHP folio 加入 deferred split 列表。
为什么重要: 在 Meta 的服务器场景中,大量匿名大页在生命周期后期会变为 mostly-zero。当前这种行为对于 PMD THP 已有 shrinker 处理,但对 mTHP 缺失,导致约 5–10% 的 RSS 浪费。该改动使 mTHP 与 PMD THP 行为一致,改善内存实际利用率。
4. HMM 新增 mmap lock-drop 容错支持(v7)
发生了什么: Stanislav Kinsburskii 发送 v7 系列,将 hmm_range_fault() 中的 page fault 处理移出 page-table walk callback,并新增 hmm_range_fault_unlocked_timeout() 函数,允许调用者在 fault 期间临时释放 mmap_read_lock。该系列在 mshv、nouveau、RDMA/umem、accel/amdxdna 和 drm/gpusvm 五个驱动中采用了新接口,并附带 selftests。
为什么重要: 该系列使 HMM framework 能够在 page fault 处理过程中释放 mmap_read_lock,从而避免因长时间持有锁导致的潜在阻塞,提升了 framework 的健壮性与灵活性。
5. hugetlbfs 改用 generic_file_read_iter() 减少重复代码
发生了什么: Matthew Wilcox(Willy)发送 4 补丁系列,使 hugetlbfs 的 read 路径复用通用的 generic_file_read_iter() 实现,而非保持独立的老路径。为此需要:
- 在 hugetlbfs address_space 中设置正确的
mapping->folio_order; - 修正
is_page_hwpoison()中对 hugetlb 页面的判断,使其能正确识别 HWPoison folio; - 调整
do_sync_mmap_readahead()等通用辅助函数对 hugetlb 的适配。
为什么重要: 这是 folio 化进程的一部分——eliminate hugetlbfs 的特殊 read 路径,减少长期维护成本。同时,通用路径可能间接带来性能提升(如 readahead 统一)和未来新特性(如同步 read/write 优化)的自动继承。
6. fork() 时 hugetlb uffd-wp 清空导致 swap entry 损坏的修复
发生了什么: Kiryl Shutsemau 提交 v1 补丁,修复 copy_hugetlb_page_range() 在 fork 时对 hwpoison 和 migration swap entries 错误地使用 huge_pte_clear_uffd_wp() 的问题。该函数操作的是 Present PTE 的 bit 位置,而 swap entry 使用其他位保存 uffd-wp 状态;对其调用会破坏 swap payload(例如在 x86-64 上使编码的 PFN 偏移两页)。补丁将调用替换为适用于 swap entry 的 pte_swp_clear_uffd_wp()。David Hildenbrand 则质疑 hwpoison 分支是否需要任何 uffd-wp 清除,认为可能本就不需要。Kiryl 回应表示倾向在后续清理补丁中移除该代码。
为什么重要: 该 bug 导致 fork() 子进程的 hugetlb swap entry 损坏,虽多数路径能自愈,但在 hugetlb_change_protection() 等重新编码偏移的场景下会传播,且 hwpoison entry 会因此指向错误的页面。
7. HVO 清理废弃 bootmem_info 基础设施
发生了什么: David Hildenbrand 提交系列补丁,移除 HugeTLB vmemmap 优化(HVO)中遗留的 bootmem_info 相关代码。具体包括:在 mm/hugetlb_vmemmap.c 中删除 #include <linux/bootmem_info.h> 及 register_page_bootmem_memmap() 调用,改用 free_reserved_page();随后在 mm/bootmem_info.c 及 include/linux/bootmem_info.h 中彻底移除 CONFIG_HAVE_BOOTMEM_INFO_NODE 配置及其整个基础设施,并清理 x86 架构下 arch/x86/mm/init_64.c 中对应的 register_page_bootmem_info_node() 调用。
为什么重要: 该清理表明 HVO 已不再依赖 bootmem_info 机制来管理释放的 vmemmap 页。移除废弃代码减少了内核配置选项和约 170 行代码,降低了维护负担,并消除了 mm/hugetlb_vmemmap.c 中一个不必要的函数调用,使 HVO 的页释放路径更简洁。
8. DAMON 大页折叠自动调优补丁系列讨论
发生了什么: 在 DAMON 大页折叠自动调优补丁系列的讨论中,SJ Park 指出提案者 Gutierrez Asier 未回复其关于 prctl、模块参数命名及测试数据展示的评论。双方就参数命名(例如 quota_percentage_hugepage 改为 hugepage_mem_bp)、测试数据库规模及结果理论解释进行了交流。SJ Park 建议展示有明确理论支撑的测试数据,并强调参数命名的一致性和准确性。
为什么重要: 该讨论明确了补丁系列设计中的关键方向:参数命名需直观一致,测试数据应能清晰证明机制有效性而非仅呈现随机结果。这直接影响补丁的可合并性及后续用户使用的易用性和可靠性。
9. block→table 分裂时的安全窗口
发生了什么: migrate_vma_collect_pmd() 在 PMD 大页分裂为 PTE 页表时,若 PMD 变为大页或清空,代码未正确处理重启路径,可能导致 migrate->dst 和 migrate->src 数组溢出。Zi Yan 的修复通过两点解决:1) 若已有部分收集完成,则避免调用 migrate_vma_collect_huge_pmd();2) 若 PMD 不再指向 PTE 页表,则跳过剩余范围。
为什么重要: 修复了 PMD 大页分裂后重启时数组溢出的问题,确保设备页迁移的数组边界安全。
10. shmem_getattr() 数据竞争与 inode 时间戳访问器修复
发生了什么: Jaeyeon Lee 提交补丁,在 shmem_getattr() 中对 info->alloced、info->swapped 和 i_mapping->nrpages 的读取添加 data_race() 标注,以消除 KCSAN 误报。这些字段在无锁情况下读取仅用于判断是否调用 shmem_recalc_inode(),后者会在持有 info->lock 时重新计算,因此读取陈旧值仅影响优化路径。同时,Yu Peng 提交补丁,在 fill_mg_cmtime() 与 inode_set_ctime_to_ts() 的并发场景下,为 inode->i_ctime_{sec,nsec} 的访问添加 READ_ONCE()/WRITE_ONCE(),并改用 ctime 访问器,修复 syzbot 报告的 KCSAN 竞争。
为什么重要: 这两项修复直接响应 syzbot 反馈,通过精确标注或原子化访问消除 KCSAN 误报,避免开发者被非实质性竞争干扰,同时不改变原有语义。前者针对 tmpfs 属性读取路径,后者覆盖通用 inode 时间戳访问器,影响面广,有助于提升内核并发分析工具的可用性。
11. Yosry 对 zswap 与 swap 表合并方案的复杂性提出质疑
发生了什么: Yosry Ahmed 在 [RFC PATCH 0/7] mm: store zswap entries in swap table (Pointer entry) 讨论中指出,该系列声称的简化具有误导性,因为大量复杂性实际上被隐藏在该优化补丁系列的另一部分中。他建议若真的担心 xarray 开销,可改用 vmalloc array 数据结构。
为什么重要: 该讨论揭示了 zswap 数据路径合并方案中简化声明与实际实现复杂性的矛盾——Yosry 认为当前设计可能并不比现有 xarray 实现更简单,并提出了替代数据结构(vmalloc array)作为潜在优化方向,这影响后续 zswap 查找路径的架构选择。
🔧 其它子系统
文件系统 / VFS
- NFS direct I/O 改用 folio 系列讨论继续:Pranjal Shrivastava 的 v2 系列将
nfs_direct_IO()从pageAPI 迁移到folioAPI,Matthew Wilcox 在 review 中建议如果后续改动清晰,可将 folio 迁移部分拆为独立补丁以加速合并。来源
内核基础设施
- meminspect 新子系统遭遇强烈 NAK:Mukesh Ojha 的 v3 24+ 补片系列试图引入统一的内存/数据结构检测框架,但 Lorenzo Stoakes 连发多篇 NAK,认为这本质上是为导出未 EXPORT 的内核符号而设计的 workaround,且通过 driver 访问
init_mm、irq_desc等内部结构不可接受。来源
调度器
- proactive reclaim 的冻结特性讨论:Shakeel Butt 质疑 proactive reclaim 的特殊性,指出全球或 memcg reclaim 的目标批次很小(SWAP_CLUSTER_MAX 32 页),允许任务让出或检查信号,kswapd 是可冻结内核线程;而 proactive reclaim 的批次由用户定义且可能极大,内循环无信号检查,可能导致连续扫描数秒。来源
👀 值得追的讨论 / Patch
meminspect 系列——Lorenzo Stoakes 提出代码质量与设计质疑
Lorenzo Stoakes 在 review v5 时对 meminspect 系列给出强烈负面评价,认为该机制本质上是对未导出符号的变通(workaround),并担忧内存生命周期(物理/虚拟范围可能变化)以及向驱动暴露此类信息的安全隐患。他还批评单 commit 新增 934 行、文档与核心代码混在一起的提交质量,指出 commit message 未描述具体改动且内容模糊,要求明确解释该机制相比现有手段的优势。来源
- slub:
free_to_pcs_bulk()中丢失本地对象:hu.shengming 报告通过代码审查发现的问题,当remote_objects[]填满到PCS_BATCH_MAX时,未正确处理剩余本地对象导致泄漏。Vlastimil Babka 分析认为当前用户(如 maple_node)无法触发此路径,但为防未来更改而合并了修复并加注 stable。该补丁在扫描过程中就地释放完整远程批次,然后继续处理压缩后的数组,使所有本地对象保持在正常快速路径上,消除了潜在泄漏。 来源
⚡ 一句话速览
- slab 代码清理:Vlastimil Babka 提取
free_to_pcs_bulk()中的批量清理步骤为__free_to_pcs_batch(),简化控制流。 来源 - DAMON 翻译更新:Doehyun Baek 的 v6 系列将 DAMON 中文文档同步至最新上游(含 DAMON_STAT 等新增页面)。 来源
- PAGEMAP_SCAN 写入状态修复:Kiryl Shutsemau v2 修复了
fs/proc/task_mmu中PAGEMAP_SCAN对未填充 PTE 的错误PAGE_IS_WRITTEN报告。 来源 - migrate_device: 修复在 non-present PTE 上调用 pte_pfn/pte_dirty: Kefeng Wang v2 补丁确保在 non-present PTE(例如 device-private entries)上不调用
pte_pfn()和pte_dirty(),这两个函数在 non-present 入口上行为未定义,可能导致崩溃或错误地标记 folio 脏。补丁通过在调用前添加pte_present()检查来修复。来源 - GUP-fast folio fallback 修复:John Hubbard v2 修复了
NULLmapping order-0 folio 的 GUP-fast fallback 路径中处理有误的问题。 来源 - collect_procs_ksm 优化:xu.xin 的补丁在
collect_procs_ksm中将addr的初始化移出循环(只在循环外初始化一次),类似此前对rmap_walk_ksm的优化,避免循环内重复计算addr。 来源 - MADV_COLD/PAGEOUT 遗漏 device-private PMD 处理:Usama Arif 补丁在
madvise_cold_or_pageout_pte_range()中对pmd_trans_huge_lock()返回后、!pmd_present()检查前增加pmd_is_device_private_entry()判断并跳转,防止 HMM GPU 驱动与madvise(MADV_COLD/MADV_PAGEOUT)竞态时触发VM_BUG_ON崩溃。 来源 - slub bulk remote free 本地对象丢失:Shengming Hu 修复了
free_to_pcs_bulk()中批量 remote free 时因远程批次填满跳转到 flush_remote 导致本地对象永久丢失的 bug;Vlastimil 将该修复合并到 slab/for-next-fixes,并添加了 stable 标记。来源 - folio LRU 与 swap 声明清理 v8:Jianyue Wu v8 将
swap.c重命名为folio.c,将 reclaim 内部声明移出swap.h,并让 page-cluster sysctl 与 swap readahead 定义放置在一起。 来源 - puptables RCU 释放防 ptdump UAF:David C. 的 v8 补丁讨论继续,Lorenzo 表示会接手调整后重发,并保留原作者署名。来源
- syzbot 报告 zswap test 失败:cgroup/test_zswap 中
zswpout未增加,Nhat Pham 和 Yosry Ahmed 在排查原因。 来源