2026-06-12 内核社区日报
DAMON 自动调优的 huge page 折叠机制进入第四版,为内存热点区域提供更智能的透明大页管理;huge page split 路径中一个导致内核崩溃的 LRU 异常加入问题引发深度讨论,修复方案逐渐清晰。
🧠 重点 · 内存
1. 大页 split 后丢弃的 tail folio 不加入 LRU:内核崩溃分析
发生了什么: 针对 f2fs 分区接近满时反复报告的内核崩溃,Zhaoyang Huang 提交了 v2 补丁。崩溃原因是:split_folio_to_order() 将大页拆分为单个 folio 后,会将子 folio 重新加入 LRU。对于超出文件末尾(EOF)的 tail folio,split 将其从 page cache 中移除并释放 page-cache 引用,但该 folio 仍以 PG_lru 状态留在 LRU 上,仅持有 split 调用者的临时引用。与此同时,f2fs GC 路径(move_data_block())通过 folio_end_dropbehind() 将该 folio 移出 page cache;而 folio_isolate_lru() 可能并发观察到该 folio 仍有非零 refcount 且 PG_lru 已设置,于是清除 PG_lru 并获取自身引用。若此操作与 split 路径的最终 folio_put() 发生竞态,__folio_put() 看见 PG_lru 已被清除而跳过 lruvec_del_folio(),则 folio 被释放回分配器时其 LRU 链接仍然存在,后续 LRU 操作检测到失效链接并报告链表损坏(list_del corruption、kernel BUG 于 lib/list_debug.c:67)。补丁引入 clear_dropped_split_folio_lru_flags() 函数,在释放被丢弃的 tail folio 前清除其 PG_referenced、PG_active、PG_workingset、PG_unevictable 及 LRU 代/引用掩码等克隆自原始大页的 LRU 状态位,避免游离的 LRU 标志引发后续释放错误。
为什么重要: 该修复消除了因大页 split 与 f2fs GC、LRU 隔离之间的竞态导致的内核 panic(list corruption BUG),使 f2fs 在接近满盘时不再因 LRU 状态不一致而崩溃,提升了文件系统在该压力场景下的稳定性。
2. kmemleak_scan() 长时间 RCU 临界区导致 soft lockup,Lance Yang 提议 RCU 仅在需要时释放
发生了什么: Breno Leitao 报告 kmemleak_scan() 在单个 rcu_read_lock() 内遍历所有线程栈且无 cond_resched(),在大量线程的主机上可能触发 soft lockup。他提议将扫描拆成两部分:先于 RCU 锁下收集任务数组,再对数组对象扫描并允许调度。Lance Yang 则回复提出了另一种方案:仅当 need_resched() 时释放 RCU,通过新增 kmemleak_stack_scan_break() 函数——该函数先 get_task_struct() 增加引用计数,然后释放 RCU、调用 cond_resched()、重新获取 RCU,再检查任务是否仍存活;若任务已死则跳出循环。该补丁附在邮件中。
为什么重要: 该修复可避免 kmemleak 扫描触发 soft lockup,使得 kmemleak 能够在高线程数环境下稳定工作。
3. percpu 分配器考虑 GFP 约束
发生了什么: Kaitao Cheng 提交了 v3 系列(3 个 patch),核心改动包括:在 pcpu_get_vm_areas() 和填充 chunk 时考虑 GFP 约束,以及避免 percpu 后备分配触发 IO/FS 回收。
为什么重要: 这些改动使 percpu 分配路径在指定 GFP 标志时更加严格地遵循约束,防止后备分配中不必要地触发 IO 或文件系统回收,有助于减少内存回收路径的干扰。
4. bootmem gigantic hugepage 分配重构 v4:多项修复与清理
发生了什么: Muchun Song 提交了 bootmem 巨型大页分配重构 v4 系列(19 个 patch)。该系列从更大的「mm: Generalize HVO for HugeTLB and device DAX」系列拆分,专注于 bootmem HugeTLB 路径的修复和准备。关键变更包括:修复 bootmem HVO 处理、vmemmap 注册参数、PowerPC compound-vmemmap 跟踪错误以及 bootmem gigantic HugeTLB struct page 初始化过晚;在将相关 zone 状态准备好后,重新排序稀疏内存和 HugeTLB 早期初始化;重构剩余 bootmem 巨型大页分配路径并移除以废弃代码。
为什么重要: 该系列修复了早期启动阶段与 HVO 功能相关的多个 bug,使系统更加稳定,同时清理了代码结构,为后续将 HVO 泛化至 device DAX 打下基础。
5. 用 RCU 保护无锁内核页表遍历
发生了什么: David Carlier 提交了一个 patch,为内核页表中的无锁遍历(lockless page table walk)添加 RCU 保护。当内核通过 kpte_t 等接口遍历页面(如 /proc/kcore 或某些调试接口)时,若不持有 mmap lock 而仅依赖页表项有效性,可能因并发 hotplug 或 vmalloc 操作导致页表被释放后仍然被读取,造成 use-after-free。该 patch 通过在遍历期间持有 rcu_read_lock() 确保页表所在内存不会被释放,从而安全化无锁访问。
为什么重要: 内核无锁页表遍历是性能关键路径(如 BPF 辅助函数、跟踪),但不加保护在特定条件下可导致内存损坏。RCU 保护将消除这一隐患,同时保持极低开销。
6. shrinker debugfs count 在 RCU 临界区内睡眠的 bug 修复
发生了什么: Shakeel Butt 提交了修复,解决 shrinker_debugfs_count_show() 在 RCU 读临界区内调用可能睡眠的 ->count_objects() 回调(zswap 回调会通过 css_rstat_flush 睡眠)的问题。修复直接移除了包裹该函数的 rcu_read_lock()/rcu_read_unlock(),因为 RCU 锁在此处并非必要:mem_cgroup_iter() 已内部使用 RCU 并返回持有 css 引用的 memcg,而打开的 debugfs 文件本身会阻止 shrinker 被释放(shrinker_free() 通过 debugfs_remove_recursive() 等待正在读的 drain 后才调用 call_rcu)。该修复由 Nhat Pham 建议,Muchun Song 确认。
为什么重要: RCU 临界区内睡眠会导致调度异常甚至死锁,该修复消除了 debugfs 接口的一个潜在内核错误,并使代码逻辑更清晰(不再在不需要 RCU 保护的区域使用它)。
🔧 其它子系统
eBPF / bpf-next
- BPF 移位运算支持非常量源操作数: Tianci Cao 提交 patch,允许 BPF 的
BPF_LSH/BPF_RSH/BPF_ARSH指令在源操作数不是常量但其值在 bounded 范围内时执行,并添加对应的 selftests 测试。[来源](https://lore.kernel.org/bpf/20260612093818.18609-1-ziye@zju.edu.cn/) - LoongArch 实现 THREAD_INFO_IN_TASK:Tiezhu Yang 提交 v3 系列,将 thread_info 从内核栈移入 task_struct,从而可以内联
bpf_get_smp_processor_id()和bpf_get_current_task()等 helper,减少函数调用开销。[来源](https://lore.kernel.org/bpf/20260612011616.27771-1-yangtiezhu@loongson.cn/) - TCP 本地 ECMP 路径重哈希 v13:该系列 v13 在 RTO 或 PLB 触发重新哈希时,添加
__sk_dst_reset()和设置fl6->mp_hash,使 socket 选择不同的本地 ECMP 路径;附带覆盖 10 个场景的测试脚本(包括 SYN、SYN/ACK、RTO、ACK、PLB 重哈希等)。[来源](https://lore.kernel.org/bpf/20260612010047.1377331-1-ntspring@meta.com/) - veth 添加 Byte Queue Limits (BQL):Jesper Dangaard Brouer 提交 v7 系列,为 veth 驱动实现 BQL 以降低延迟,同时引入基于 ethtool tx-usecs(默认 100 微秒)的时间基 BQL 完成合并,解决吞吐量回归并让 DQL 发现更高的有用 limit。
[来源](https://lore.kernel.org/bpf/20260612083530.1650245-1-hawk@kernel.org/) - BPF signed loader 的签名验证方案改动:Daniel Borkmann 提出新方案,不再由 loader 内部做哈希检查,而是让内核在
BPF_PROG_LOAD时、LSM 准入钩子和 verifier 之前,通过fd_array/fd_array_cnt收集独占映射并追加到指令后做 PKCS#7 验证,从而无需新增 UAPI。Paul Moore 将其与 Blaise 之前的工作进行了比较,并认为这是 KP 签名方案的重大改进。来源
网络
- TCP sock_ops cb flags 清理:Sechang Lim 提交 v3 修复:在强制关闭子 socket 前清除继承的 sock_ops callback flags,避免 listener 的回调导致已关闭连接上的数据访问。
[来源](https://lore.kernel.org/bpf/CAAVpQUBL1pFxgVtNjM=YcWuE7YfvBpUf65WBpUBzjVZJgz=hTw@mail.gmail.com/)
👀 值得追的讨论 / Patch
- huge page split 的 LRU 竞争修复讨论:Zhaoyang Huang 提交 v2 补丁修复 split 后 tail folio 因 LRU 竞争导致内核 panic 的问题,但 reviewer Zi Yan 指出补丁有其他问题(如 unbalancing LRU counters),建议暂停发新版,作者同意等待。
[来源](https://lore.kernel.org/linux-mm/CFE7A598-0F5E-4F67-A2C8-2B9FAEC246FA@nvidia.com/) - Proactive zswap writeback 与 swap tiers 接口整合讨论:围绕 Hao 的 proactive zswap writeback 用例,YoungJun Park 提议在 swap tiers 框架下将 zswap 作为第一层,并复用
memory.swap.tiers等接口实现写入回传;Yosry Ahmed 与 Shakeel Butt 讨论是等待 swap tiering 接口成熟后合并,还是先加一个zswap_writeback_only实验性接口。讨论仍在进行。来源 - mm/page_table_check: skip special (PFN-mapped) PTEs:Andrey Smirnov 提交补丁,在 page_table_check 的 PTEs clear 和 set 路径中跳过 pte_special() 的 PTE,以修复特殊 PFN 映射(如 vDSO 的 [vvar] 映射)导致的文件页面计数不平衡问题。该不平衡在 time namespace 创建销毁时触发
__page_table_check_zero中的 BUG_ON,由 syzbot 在 riscv 上独立报告。来源 - percpu: NOFS/NOIO reclaim recursion 修复 v3 发布:Kaitao Cheng 提交了 v3 系列,包括三个补丁:在
mm/vmalloc的pcpu_get_vm_areas()中遵循 GFP 约束、在mm/percpu的 chunk 填充中遵循 GFP 约束,以及避免后备分配中的 IO/FS 回收。[来源](https://lore.kernel.org/r/20260612022648.13008-1-kaitao.cheng@linux.dev)
⚡ 一句话速览
- mm/slub: 引入 struct slab_alloc_context 重构分配参数:Vlastimil Babka 的系列补丁在 mm/slub.c 中引入
struct slab_alloc_context结构体,持有caller_addr和orig_size,以减少函数参数数量。该补丁将alloc_single_from_new_slab()、__slab_alloc_node()和___slab_alloc()改为接受该结构体指针,未引入功能性变化。[来源](https://lore.kernel.org/linux-mm/ait21B7kqfT9XhOs@fedora/) - mm/memblock: 移除 free_unused_memmap() 中的多余 pageblock_align():Zhen Ni 的 cleanup,
prev_end已在之前对齐,无需重复对齐。[来源](https://lore.kernel.org/linux-mm/20260612031105.3350181-1-zhen.ni@easystack.cn/) - tools/mm/page_owner_sort: 修复每记录分配的内存泄漏:Yichong Chen 的 v3,
add_list()分配 comm 和 txt 后 cleanup 路径未释放,导致内存泄漏。[来源](https://lore.kernel.org/linux-mm/610C3A89A09303F8+20260612055017.632263-1-chenyichong@uniontech.com/) - tools/mm/slabinfo: 修正 total_objects 属性名:slabinfo 读取
objects_total但 SLUB 导出的是total_objects,导致始终为零。[来源](https://lore.kernel.org/linux-mm/96556748872BB47E+20260612071359.649946-1-chenyichong@uniontech.com/) - mm/page_alloc: 删除 flag-conversion “优化”:Brendan Jackman 指出将 GFP_ 到 ALLOC_ 的逐位转换并没有实测加速,且增加维护负担,直接移除。
[来源](https://lore.kernel.org/linux-mm/20260612-gfp-pessimisation-v1-1-936eb04202e7@google.com/) - mm: reduce NODE_RECLAIM_xxx 并改为 enum:Petr Tesarik 将
NODE_RECLAIM_*宏改为枚举,并添加NODE_RECLAIM_NONE以区分"未尝试"与"失败"。[来源](https://lore.kernel.org/linux-mm/DJ6ZMH9VU0BE.6Q8EHJIL65DW@linux.dev/) - mm/damon: 添加 walk_control_obsolete 行为的 KUnit 测试:Sailesh Nandanavanam 的 v3,测试
damos_walk()在标记过时时正确拒绝新请求。[来源](https://lore.kernel.org/linux-mm/20260612062337.2459-1-saileshnandanavanam@gmail.com/) - mm/mempool: 解除 CONFIG_SLUB_DEBUG_ON 滥用并改用 static key:Li RongQing 的 patch 将 mempool 的 debug 开关从直接读取 SLUB config 改为使用 static key,避免调试配置影响非调试内核。
[来源](https://lore.kernel.org/linux-mm/d06d13c4aebe44a2abca4aee0083644f@baidu.com/) - kasan: hw_tags: 添加"仅分配时打标签"的启动选项:Dev Jain 的 RFC,为 MTE 方式添加 boot 参数,跳过 free 时的 poisoning 以降低延迟。
[来源](https://lore.kernel.org/r/20260612044425.763060-1-dev.jain@arm.com) - khugepaged 的 shmem mTHP 折叠添加 max_ptes_none 检查:Baolin Wang 的补丁在
collapse_file()中加入与匿名折叠一致的max_ptes_none限制,防止 shmem 过度折叠。Nico Pache 审阅后给出 Reviewed-by。[来源](https://lore.kernel.org/linux-mm/10091ced-d472-4bfe-9cb9-8e7def23c213@redhat.com/) - powerpc: 启用 THP_SWAP 的补丁引发 arm64 交叉编译警告:内核测试机器人报告,在 arm64 随机配置下编译 Ritesh Harjani 的 [PATCH v2 3/3](在 Book3S64 上启用 THP_SWAP)时,出现 sparse 警告:
mm/swapfile.c:133:6: warning: symbol 'swap_table_use_page' was not declared. Should it be static?。[来源](https://lore.kernel.org/linux-mm/202606121305.h0cxjhP2-lkp@intel.com/) - libbpf: 允许 ring buffer 消费时传入回调:Tamir Duberstein 的补丁添加了
ring_buffer__consume_n_cb和ring__consume_n_cbAPI,允许在消费时指定回调与上下文,覆盖管理器已有的回调配置,从而避免为整个管理器生命周期保留可变状态。[来源](https://lore.kernel.org/bpf/20260611-bpf-ringbuf-callback-v1-1-c32b6cb6ce40@kernel.org/)