2026-05-31 内核社区日报

今天内存子系统的焦点落在两处:khugepaged 迎来"collapse hint"机制,允许用户空间或上层组件提示哪些 VMA 更值得折叠 huge page,有望系统性地提高 THP 覆盖效率;同时 zram/zsmalloc 的锁竞争优化继续推进,新版本收到了 reviewer 的明确认可。

🧠 重点 · 内存

1. khugepaged collapse hint:用户空间可主动指引 huge page 折叠

发生了什么:Luka Bai(腾讯)提交了一组 patch,为 khugepaged 添加 collapse hint 框架。核心思路是允许用户空间或内核组件(如 MGLRU)向 khugepaged 注册"折叠提示"——即哪些虚拟地址范围的 VMA 更值得立即尝试 collapse 为 PMD-mapped THP。patch 包括四个模块:

(1)hint 添加/去重:通过 /sys/kernel/mm/transparent_hugepage/khugepaged/collapse_hint 接口写入地址范围,khugepaged 内部用 red-black tree 管理 hint 条目,添加时自动去重。

(2)使用 slab cache 分配 hint 条目:替换了原来的普通 kmalloc,减少 slab 内部碎片。

(3)统计分离:在 /sys/kernel/mm/transparent_hugepage/khugepaged/collapse_hint_collapsedcollapse_hint_skipped 统计 hint 驱动折叠的成功/跳过次数,与原 scan 统计独立,便于评估 hint 效果。

(4)MGLRU 集成:当 MGLRU 的 refault 检测认为某 folio 集群有访问局部性时,主动向 khugepaged 注册 collapse hint,在 MGLRU 的 eviction 路径中触发。

为什么重要:此前 khugepaged 依赖 mmap_sem 持有期间的页表 young bit 来推测哪些 VMA 适合折叠,启发式准确率有限。collapse hint 提供了一条确定性输入通道——用户空间(如 Android lmkd 已知服务进程的热内存)或内核组件(如 MGLRU 明确知道 refaulted folio 的虚拟地址)可以直接告诉 khugepaged “这里值得立即折叠”,有望显著减少不必要的 VMA 扫描开销,同时提高 THP 命中率。这一改动不影响原有扫描逻辑,也不破坏与其他折叠策略(如 defrag=always)的兼容性。

来源
来源


2. zsmalloc: 在 zs_free() 中提前释放 class 锁,缩短临界区(review 确认)

发生了什么:昨天报道的 zsmalloc 锁竞争优化——在 zs_free() 释放 zspage 前提前释放 class 锁——今天收到了 Nhat Pham 的进一步 review。作者 Joshua Xue 回复确认 reviewer 建议正确,将按照反馈更新代码。关键改动点是:当前 zs_free() 在调用 free_zspage() 之前一直在持有 class spinlock,而后者可能触发 zspage 的完整释放路径(包括归还到 buddy system)。将该锁释放提前到仅保护 obj_tag 操作,随后不持锁完成 free_zspage() 调用,高并发时锁持有时间从数十微秒降至数微秒。

为什么重要:zsmalloc 是 zram 的底层分配器,在 Android 手机上 zram 是唯一 swap backend,高内存压力下 zs_free() 竞争严重。此优化已被 reviewer 确认方向正确,落地后可在多核手机(如 8 核 big.LITTLE)上降低 zsmalloc 锁抖动,预期改善 swapout 延迟。

来源


3. HWPoison: 修复 HugeTLB 页溶解后的 has_hwpoisoned 状态丢失及重复操作

发生了什么:Jiaqi Yan(Google)提交了三连 patch 修复 HWPoison 路径中 HugeTLB 页的 bug:

(1)mm/page_alloc: only free healthy pages in high-order has_hwpoisoned folio:当某个 large folio 中仅部分 page 被标记 HWPoison 时,free_pages_prepare 检查 folio_test_has_hwpoisoned 后,应只释放健康页,而非整个 folio。现有代码可能在释放过程中将带 poison 的 page 归还给 buddy,导致后续分配者拿中毒内存。

(2)mm/memory-failure: set has_hwpoisoned flags on dissolved HugeTLB folio:HugeTLB 页 dissolve 后,其子 page 的 has_hwpoisoned 标志未正确继承,后续 free 操作无法识别中毒子页。

(3)mm/memory-failure: skip take_page_off_buddy after dissolving HWPoison HugeTLB page:HugeTLB 页 dissolve 后调用 take_page_off_buddy 是冗余且不安全的操作(buddy 已无此范围),应跳过。

为什么重要:HWPoison 用于在线处理不可恢复的硬件内存错误(MCE/UE),HugeTLB 是虚拟化/数据库等场景常见配置。这些 bug 可能导致中毒内存被 buddy system 再次分配、或在 dissolve 后 double-free buddy metadata,是典型的稳定性问题。全部三个 patch 已设计清晰的修复路径,适合稳定内核。

来源
来源
来源


4. 修复 arm64 上 DAMON 因 TLB stale young bit 引发的误判

发生了什么:Kunwu Chan 提交了一篇 RFC patch,fix 了 arm64 架构上 CPU 可能从 TLB 缓存读到 stale 的 AF(Access Flag)位,导致 DAMON 误判页面访问状态的问题。arm64 硬件在页表 walk 时不会自动 flush TLB for AF update——当 DAMON 清除 PTE 的 AF 位后,后续硬件访问虽然会硬件置位 AF,但如果 TLB 条目中残留了旧的状态(AF=0 且未被 invalidate),下一次 DAMON 读取时仍看到 AF=0,从而认为页面未被访问。社区 mainatainer SeongJae Park 回复确认问题真实存在,并提出 TLB flush 的成本不可忽视(尤其在 DAMON 高频采样时),建议采取更精细的 flush 范围或放宽 detection window。

为什么重要:DAMON 的 access detection 准确性直接决定 MGLRU 的 refault 判断和系统内存回收效率。arm64 在服务器和移动端广泛部署,此 bug 会导致 DAMON 低估页面热度,从而过早回收 hot page,劣化性能。目前尚无最终方案,但至少社区对问题有了共识。

来源


5. Live Update 架构重构继续:KHO 集成、限制解除

发生了什么:Pasha Tatashin 发出了 Live Update 相关 patch 的 v4 更新,延续了前日解除 session 和文件数量上限的系列,并进行了更深层的架构清理:

(1)luo_ser 注册为 KHO 子树:完全移除旧的 FDT wrapper,luo_ser 数据结构直接挂在 KHO 全局命名空间下,由 KHO 负责 json 的生成/解析。这意味着 LUO 不再需要自己拼接 FDT,统一了序列化框架。

(2)linked-block 序列化支持:引入 kho_add_linked_block,允许内核模块注册连续物理内存块(如 mmap 的大页区域)作为 KHO 序列化的一部分,而不必抄到 KHO 自己的连续 buffer 中。

(3)延迟 session block 分配:将 session 物理块分配推迟到序列化阶段,避免在系统运行态提前预留不连续的 PA 空间。

(4)移除会话和文件数量上限:原先每个 session 内 file_set->count 为 int 类型,有上限风险;改为 u64 后可靠近 KHO 的总长度上限(通常 4MB 级别)。测试新增了 stress-sessionsstress-files 的 kexec 压力测试。

为什么重要:Live Update 允许内核不经过完整 reboot 就切换新内核,对数据中心和嵌入式不间断服务至关重要。这些变化使 LUO 的 KHO 集成更干净,同时解除了之前人为的扩展性限制(如最多 64 个 session),为生产环境部署铺平道路。

来源
来源
来源


🔧 其它子系统

eBPF / BPF

  • BPF_PROG_QUERY OOB 写漏洞修复合入:v3 版本修复了 BPF_PROG_QUERY 无条件写回 query.revision 字段导致的越界写问题,并向后兼容老版 uattr 大小。已由 Alexei Starovoitov 合入 bpf-next。来源
  • bpf 分配 arena 内存时覆盖 scratch PTE:Tejun Heo 发现 apply_range_set_cb() 在分配 arena 新页时遇到已存在的 PTE(scratch page)会返回 -EBUSY,改为无条件覆盖,避免内核 fault 恢复后的 stale 映射。来源
  • devmap 拒绝克隆 fragment XDP 帧:Zhao Zhang 修复了 devmap broadcast redirect 时克隆 xdp_frame 只复制了线性区、丢失 fragment 数据的问题。来源

👀 值得追的讨论 / Patch

zswap 大页换入 RFC v2 仍处于活跃评审中

昨天报道的 fujunjie 提交的 zswap 侧 large folio swapin RFC v2(mm: support zswap-backed large folio swapin)今天继续讨论。Nhat Pham 提出了几个关键问题:

(1)zswap_range_fully_backed 接口在 swap cache 尚未构建时无法检查到 swap entry 是否被 zswap 覆盖——zswap 的 entry 存储在 xarray,而 swap cache 也在同一 xarray 中,但 zswap 优先剔除不参与 swap cache 的页时,状态不一致。建议用 swp_entry 直接查询 zswap tree 而非依赖 swap cache。

(2)anon locality 判断:Kairui Song 指出当前 patch 依赖 folio_test_swapcache 来推测相邻页是否可一起换入,但 zswap 不保证所有连续 swap slot 都有对应 entry;应改用 zswap 自身的 zswap_loaded 位图或 tree walk 来精确确定"range 内完全有 backing"。

(3)性能数据不足:讨论中要求提供真实工作负载下(如 memcg pressure 较高的场景)的 THP 命中率提升和 latency 影响。

现状:patch 系列需要较大幅度重新设计 swapin policy 的上层通知机制,目前在细化中。来源

vmsplice 退化为 preadv2/pwritev2 包装提案

Askar Safin 提交了 3-patch 系列,将 vmsplice 重新实现为 preadv2/pwritev2 的包装,取消原有的 pipe 注入 gift 机制和 PIPE_BUF_FLAG_GIFT。目的是消除 vmsplice 历史上多个高危漏洞的根源(CVE-2020-29374 等)。社区初步反馈正面,但 Christoph Hellwig 和 Al Viro 关注到销毁 struct page 引用的竞争问题以及用户空间内存与 pipe buffer 转换的成本。继续讨论中。来源


⚡ 一句话速览

  • memblock: 修复 memblock_free_late() 重构引入的 regression,回退至直接调用 memblock_free() 并额外检查 arch 是否 need memblock_free_late()来源
  • KHO/liveupdate: Pasha 修复了两个 regression:luo 文件描述符检索路径中的 goto+guard 混用,以及 KHO 会话 block 分配时机问题。来源
  • zram: 修复 partial I/O config check 中使用 IS_ENABLED 错误传递了非 Kconfig 符号的问题,改为直接使用 CONFIG_ZRAM_PARTIAL_IO来源
  • mm/damon: Kunwu Chan 还提交了 5 个 DAMON selftests 修复,包括 DamonCtx.__init__ 的 mutable default、memcg filter 路径处理、tried_regions 测试空循环和 dead code。来源
  • filesystem/dax: John Groves 提交了一组 dax/fsdev 的 bug 修复和清理:修正 multi-range offset 在 memory_failure handler 中的错误;修复静态 pgmap probe 中 vmemmap_shift 未清零等问题。来源
  • syzbot: 报告了 page_cache_ra_order 中的可能 deadlock,发生在 page_cache_ra_unbounded 中请求内存时与 shrinker 形成了锁反转。来源
  • fuse: 报告了 commit c9ba789dad15(VFS: introduce start_creating_noperm)引入的 regression——FUSE_NOTIFY_INVAL_ENTRY 后留下的 stale 负 dentry。来源
  • vfs: Jori Koolstra 提交了 O_CREAT/O_DIRECTORY 支持(RFC v6),允许 open() 直接创建并打开目录,消除 rename 竞态与临时目录泄漏风险。来源
  • bpf: Tejun Heo 修复 arena PTE 建立时的 break-before-make 问题(未先 clear 再 set)导致硬件 TLB 不一致。来源