2026-06-08 内核社区日报
导读:今天内存子系统有两条设计层面的进展——blk-cgroup 清理队列锁嵌套、virtio 零页优化收到关键审查;eBPF 方面,针对 kptr 析构死锁和 LRU 重入的补丁持续推进。
🧠 重点 · 内存
1. blk-cgroup:移除 queue_lock 在 blkcg 路径中的嵌套
发生了什么: Yu Kuai 提交了 8 个 patch 的系列,目标是解除 blkcg 相关路径中 queue_lock 嵌套在 RCU 或 blkcg->lock 下的问题。逐步改动包括:
- 将 policy data 的释放推迟到 RCU grace period 之后(patch 2),这样
blkcg_print_blkgs()中的prfill()就可以在 RCU 下运行而无需再取queue_lock(patch 3)。 - 在
blkg_lookup_create()(patch 4)和bio_associate_blkg()(patch 5)中,不再在 RCU 临界区内嵌套queue_lock;fast path 用 RCU 直接 lookup,slow path 不需要 RCU。 blkcg_destroy_blkgs()中消除queue_lock嵌套在blkcg->lock下的情况,通过使用 trylock 避免死锁(patch 6)。bio_associate_blkg_from_page()(mm/page_io.c)也不再在 RCU 内嵌套queue_lock(patch 7)。- BFQ 初始化时不需要
queue_lock,因为 request_queue 已被冻结(patch 8)。
为什么重要: queue_lock 嵌套在 RCU 临界区或 blkcg->lock 下是长期存在的锁排序违规,可能引发 lockdep 警告,也增加了死锁风险。该系列完全消除了这些嵌套,使锁依赖图更整洁。per-BFQ 的初始化不再依赖 queue_lock 也减少了不必要的锁开销。
2. mm/virtio:跳过对主机已清零页面的冗余清零(v10 review 深入)
发生了什么: Michael S. Tsirkin 的 virtio 零化跳过系列(v10)今天收到了大量 review 反馈。Lorenzo Stoakes 和 Matthew Wilcox 对设计方向提出了关键质疑:
put_page_zeroed/folio_put_zeroed接口(patch 24):David Hildenbrand 指出,通用化一个“将 zeroed 状态传递回 buddy”的接口风险很大——未映射的用户页面可能在 release 前被重新分配,零化 hint 可能被误用。Lorenzo 建议收缩范围,只对已知安全的场景(如 balloon 迁移)暴露该接口。user_addr传递到 page allocator 的方式(patch 7):Matthew Wilcox 认为通过gfp_mask隐式传递user_addr很别扭,推荐改用明确的结构体参数。Lorenzo 提出先不改变外部 API,仅在内部优化零化(cache-friendly zeroing)。- 内存故障序列化(patch 2):Lorenzo 确认
TestSetPageHWPoison在 zone->lock 下的序列化方案可行,但建议用folio_put_testzero或类似机制替代直接检查 page 计数。
为什么重要: 这是决定该系列能否推进的关键点。put_page_zeroed 接口设计如果过于宽泛,可能导致安全或内存一致性风险。reviewer 要求缩小范围或采用不同方法,意味着下一版可能有重大更改,但概念方向(避免不必要零化)仍被认可。该系列对虚拟化性能(减少 hypervisor 内存重复零化)有直接影响。
3. arm64:在 ptep_try_set() 中补齐 PTE store 屏障
发生了什么: Tejun Heo 提交 v2 patch,修复 ptep_try_set() 在 arm64 上安装内核 PTE 时缺少必要的 barrier。该函数使用 try_cmpxchg() 写入 PTE,但与 __set_pte() 不同,跳过了 arm64 在写入有效内核 PTE 后所需的屏障。缺少屏障可能导致后续访问缺页(fault)而非看到新映射。patch 改为直接调用 emit_pte_barriers() 而非 __set_pte_complete(),因为后者在调用者处于惰性 MMU 模式时会延迟屏障。该修改得到 Catalin Marinas 的反馈。
为什么重要: 原文指出缺少屏障可能导致后续访问缺页,属于正确性修复。确保 PTE 写入后立即发出屏障,避免因屏障缺失导致的缺页问题。
4. mm/gup_test:修复 PIN_LONGTERM_TEST ioctl 竞态
发生了什么: Yunhui Cui 提交 patch,修复 gup_test_release() 与 PIN_LONGTERM_TEST_STOP ioctl 的并发问题。PIN_LONGTERM_TEST 的 helper 函数使用全局变量,在 ioctl 路径下由 pin_longterm_test_mutex 保护,但 gup_test_release() 调用 pin_longterm_test_stop() 时未持有该锁。patch 在 gup_test_release() 中加上 mutex_lock/mutex_unlock,确保释放路径也受同一锁保护。
为什么重要: 消除并发测试时的双重释放和数据损坏风险,使测试基础设施更健壮。
5. mm/swap_state:移除 readahead 路径中不必要的 lru_add_drain()
发生了什么: Usama Arif 提交 patch,删除 swap_cluster_readahead() 和 swap_vma_readahead() 结尾的显式 lru_add_drain() 调用。该 drain 是 2.6.12 时代遗留代码,对调用者无功能性用途:do_swap_page() 忽略 readahead folio 的 LRU 驻留;shmem_swapin_cluster() 立即锁定 folio 并操作;try_to_unuse() 同样不依赖 LRU 存在。readahead 循环新添加到 swap cache 的 folio 位于 per-CPU LRU folio_batch 中,会在 batch 填满、下次 reclaim/compaction 的 lru_add_drain_all() 时自然排空。这是对 commit 1aa43598c03b (“mm: remove unnecessary calls to lru_add_drain”) 清理工作的直接延续。
为什么重要: 在生产环境(176-CPU,内存压力工作负载)中,swap_cluster_readahead() 观察到约 28K/min 的 folio_batch_move_lru() 调用,造成巨大的 LRU 锁竞争。移除这两个 drain 可消除该竞争源,避免强制同步刷出可能未满的 partial batch 带来的额外延迟和锁争用。
6. memcontrol v1:对 soft limit 树使用 nofail 分配
发生了什么: Ruoyu Wang 提交补丁,将 memcg1_init() 中每个 NUMA node 的 soft limit 树节点分配从 kzalloc_node() 改为 GFP_KERNEL | __GFP_NOFAIL。理由是若 kzalloc_node() 失败,后续的 rb_root 和锁初始化会解引用 NULL,导致崩溃。该补丁已发送至 linux-mm 邮件列表。
为什么重要: 避免在初始化阶段因内存分配失败导致的 NULL 解引用崩溃,保证 memcg v1 的 soft limit 树节点在内存紧张时仍能成功分配,从而使 init 路径安全完成。
7. 对 read_cache_folio() 缺少 invalidate_lock 的质疑
发生了什么: Dev Jain 报告,read_cache_folio() 的 kerneldoc 要求调用时持有 mapping->invalidate_lock,但实际调用路径未持有该锁。他在 __filemap_add_folio() 中添加 BUG_ON(!inode_is_locked(mapping->host) && !rwsem_is_locked(&mapping->invalidate_lock)) 后,在 do_read_cache_folio → read_cache_folio → read_part_sector 等调用链上触发了 bug,并给出了完整调用栈。来源
为什么重要: 该 bug 暴露了 read_cache_folio() 接口契约(需持有 invalidate_lock)与当前实现间的矛盾。若调用者未持锁,可能导致并发向 page cache 添加 folio 时的竞争条件,引发不可预期的行为。该报告为修复文档或实现提供了具体线索。
🔧 其它子系统
eBPF
- bpf LRU NMI/tracepoint 重入死锁修复已合入 bpf-next:该系列补丁解决了 NMI 和 tracepoint BPF 程序在同一 CPU 上重入已持有的每-CPU 或全局 LRU 锁导致的 AA-deadlock。修复将每个 LRU 锁站点转换为 rqspinlock_t 并添加了显式恢复逻辑,避免节点泄漏。该系列已被 Alexei Starovoitov 应用至 bpf-next。来源
- bpf kptr dtor 死锁修复系列(v1):Kumar Kartikeya Dwivedi 发送了该系列(包含 Justin Suess 的两个补丁和 Dwivedi 的三个补丁),修复 referenced kptr 销毁可从 tracing/NMI 上下文通过
bpf_obj_drop()及 map value 更新/删除路径到达 NMI 不安全的特殊字段 teardown 导致死锁的问题。方案包括:拒绝来自非迭代器跟踪程序的不安全bpf_obj_drop();限制 map value 回收为 NMI 安全的字段取消;以及相应的 selftest。来源 - bpf 引入全局 percpu 数据(v5):Leon Hwang 提交 v5 系列,允许 BPF 程序通过定义
.percpu段来使用全局 percpu 变量。libbpf 新增.percpu段支持和 feature probe,bpftool 生成骨架支持。该特性可简化 retsnoop/bpfsnoop 等工具的 LBR 处理,无需在 percpu 数据存取时调用bpf_get_smp_processor_id()辅助函数,并简化 tail call/freplace 场景下的 percpu 数据共享。来源 - LoongArch 实现 CONFIG_THREAD_INFO_IN_TASK 并内联 BPF 辅助函数:Tiezhu Yang 提交系列,包含三个补丁:实现
CONFIG_THREAD_INFO_IN_TASK、内联bpf_get_current_task{_btf}()辅助函数、内联bpf_get_smp_processor_id()辅助函数。来源 - bpf: 修复 kfunc implicit arg 类型检测:Yuan Chen 的 v5 补丁修复了在模块 kfunc 声明隐式
struct bpf_prog_aux *参数时,verifier 类型检测不足可能导致无效指针解引用的问题。来源
👀 值得追的讨论 / Patch
- khugepaged mTHP collapse(v19 review):Nico Pache 的系列补丁调整
collapse_huge_page的锁语义,使其进入和退出时均无需持有mmap_read_lock,为后续 mTHP collapse 做准备。该补丁获得 Lorenzo Stoakes 的 Reviewed-by、David Hildenbrand 的 Acked-by 以及 Lance Yang 的 Reviewed-by 签名。来源 - alloc_tag 为 /proc/allocinfo 添加 ioctl(v3 review):Hao Ge 指出代码中
codetag_get_content_id()仅跟踪模块加载,未在卸载时递增,因此用户无法检测模块卸载导致的内容变化。Suren Baghdasaryan 确认该问题,并提出使用独立的seq_count在加载/卸载时均递增。来源 - riscv vmemmap 热插拔后 spurious fault 修复(v3 继续讨论):Vivian Wang 的 v3 引入
vmemmap_populate_finalize()后,David Hildenbrand 要求确认该函数在架构所有路径上都被调用。讨论仍在继续。来源
⚡ 一句话速览
- mm/mmu_notifier 构建修复:当
!CONFIG_MMU_NOTIFIER时,__mmu_notifier_arch_invalidate_secondary_tlbs()的空实现缺少必要头文件,新 patch 添加包含。来源 - mm/migrate 添加原生 folio 函数:yahia 提交补丁,为
movable_ops相关 page 函数添加 folio 层封装,新增folio_movable_ops()、folio_has_movable_ops()以及FOLIO_TEST_FLAG(MovableOpsIsolated)等接口。来源 - DAMON/mtier 参数检查:Zenghui Yu 提交 patch,使 DAMON mtier sample 在地址范围参数无效(start >= end)时提前 fail,避免触发 WARN_ONCE。来源
- 为样本模块 mtier.c 添加边界检查:Zenghui Yu 提议在样本模块 mtier.c 的
damon_new_region()调用前检查地址范围,若addr.start >= addr.end则跳转至free_out避免传入无效区域;SeongJae Park 认为改动简单,但因该模块仅作为示例且不会导致系统崩溃,不急于合入。来源 - selftests/mm 修复 test 分类:Sarthak Sharma 将
ksft_process_madv.sh的测试分类从mmap修正为正确的madv_populate。来源 - memory-failure trace 事件移回 ras 子系统:Xie Yuanbin 提交补丁,将
memory_failure_eventtrace 事件从 memory_failure 子系统移回 ras 子系统,以保持向后兼容性。来源 - bpf: 修复 htab 内部结构释放时 RCU 回调中的 sleep-in-atomic:Luo Gengkun 提交补丁,解决 commit 1da6c4d9140c 的 UAF 修复与 commit 4f375ade6aa9 的 RCU 上下文警告修复之间的冲突。问题在于后者的改动移除了 RCU 延迟,导致
htab_map_free_internal_structs在 RCU_SOFTIRQ 中运行,其中调用cond_resched()触发 “sleeping function called from invalid context” BUG。补丁 revert 4f375ade6aa9 以恢复 VFS RCU 保护,并通过 workqueue 延迟执行实际释放,避免在 RCU 回调中睡眠。来源 - bpftool 生成 skeleton 支持全局 percpu 数据:v5 系列同时更新了 bpftool,使其生成的 skeleton 包含一个专用结构体用于访问 percpu 变量。来源