0/4 已展开

LLM 分析

sched:允许 PREEMPT_RT 下使用 sleeping spinlock(KVM MMU notifier invalid context 修复)

系列概况

  • 标题:[syzbot] [mm?] BUG: sleeping function called from invalid context in kvm_mmu_notifier_invalidate_range_start
  • 作者:David Woodhouse(补丁作者,dwmw2@infradead.org);syzbot 自动化测试;Aleksandr Nogikh(syzkaller 维护者,介入排查测试环境问题)
  • 版本:单 patch,位于 dwmw2/linux.gitseb-nonblock-rt-test 分支,测试 commit f902e69c "sched: Allow sleeping spinlocks on PREEMPT_RT"
  • 规模:4 封邮件;3 封为 syzbot 测试报告或人工介入回复,1 封为 David Woodhouse 触发新测试;线程本身未嵌入 hunk
  • 修改文件 / 代码统计:无法从邮件正文得到(hunk 在 git tree 中,邮件仅引用分支名)
  • Message-IDb434f7828a4d7b24de76aa5609dadda2871a932a.camel@infradead.org(thread_key);首封为 6a8d8f7a.a5a502ce.31d34.0068.GAE@google.com
  • 完整性:邮件正文完整,无截断;但 patch hunk 未随邮件投递,只能从 commit message 与分支名推断意图

补丁目的

syzbot 在 PREEMPT_RT 配置下复现了一个 BUG:kvm_mmu_notifier_invalidate_range_start 路径触发了 sleeping function called from invalid context

  • 在 PREEMPT_RT 中,普通 spinlock 变成不可睡眠的 atomic 上下文;而某些原本在非 RT 下能睡眠的代码路径仍然在 spinlock_t 保护的临界区中执行,触发告警。
  • 该路径是 KVM 的 MMU notifier invalidation,会在 mmu_lock 等锁内执行;当某个回调(如 shrinker / 内存回收路径)尝试睡眠时,调度器就会打印 invalid context 警告并可能 panic。
  • 补丁 sched: Allow sleeping spinlocks on PREEMPT_RT 的目标是把 PREEMPT_RT 下特定路径上的 spinlock_t 切换为 rt_spin_lock_t(sleeping spinlock),允许持锁时睡眠,从而消除告警。

旧流程的问题

非 RT 配置下,spinlock 在持锁期间可以短暂阻塞但不睡眠;PREEMPT_RT 下被替换为禁用抢占 + 关中断的 atomic 上下文。

Old flow (non-RT)              Old flow (PREEMPT_RT)
----------------               ---------------------
acquire spinlock               acquire spinlock
  -> short blocking OK          -> enter atomic context
  -> no invalid-context         -> shrinker callback sleep
                                  -> BUG: sleeping function
                                     from invalid context
                                  -> may WARN / BUG

新流程

sched: Allow sleeping spinlocks on PREEMPT_RT 在被标记为可睡眠的路径上把 spinlock_t 替换为 rt_spin_lock_t,使得 KVM MMU notifier invalidation 在持锁时进入 rt_mutex-backed sleeping lock 路径,允许调度。

New flow (PREEMPT_RT + patch)
-----------------------------
acquire rt_spin_lock (sleeping)
  -> schedule / sleep allowed
  -> shrinker / reclaim can block
  -> invalid-context warning gone

Patch 概览

  • 单 commit:f902e69c sched: Allow sleeping spinlocks on PREEMPT_RT
  • 提交者:David Woodhouse
  • 分支:dwmw2/linux.gitseb-nonblock-rt-test(远在 infradead.org)
  • 邮件正文仅引用分支与 commit,不含 hunk;实际 diff 需要从 git tree 获取

关键实现

由于 hunk 未在邮件中投递,只能从 commit 标题与讨论上下文推断:

  • kernel/sched/kernel/locking/ 路径下,把被 #ifdef CONFIG_PREEMPT_RT 包裹的关键 spinlock 调用替换为对应的 rt_spin_lock 变体,或在调用前显式标记允许睡眠。
  • KVM 侧 mmu_notifier_invalidate_range_start 的 callbacks 通过持有 rt-spinlock 进入,从而在 PREEMPT_RT 下不再触发 invalid-context 警告。
  • "Allow sleeping spinlocks" 是这类修复的常见表述:它不是把所有 spinlock 都换成 rt_spinlock,而是把那些已知可能进入 sleeping 路径的特定锁打开睡眠通道。

类比

想象一个图书馆自习室(CPU 核心)。

  • 非 RT 模式下,自习室入口有一个门禁(spinlock),进入后只能站着翻书,不能躺下休息。
  • PREEMPT_RT 把门禁改成"一旦进入就锁门、不能离开"(atomic context)。如果你在自习室里接到一个需要回去家里(sleep)才能完成的任务,就只能强行闯门,触发告警。
  • 这个补丁的做法是:把自习室里某些特定的"站立区"改造成可以放折叠床的"休息区"(sleeping spinlock / rt_spin_lock)。这样当 KVM 收到"需要回家拿书"的任务时,可以正常放人离开并锁门,不再报警。

Highlight:风险与注意点

  • 测试基础设施问题而非代码 bug:前两次 syzbot 测试因 URL 用错协议(先写 https://,syzkaller 报 "could not determine hash algorithm; is this a git repository?")失败;David Woodhouse 改为 git:// 后第三次成功。说明 syzbot 的 fetch 协议处理对协议前缀敏感,文档/触发命令需要明确。
  • patch 内容未在邮件中:线程只包含 syzbot 测试往返和提交命令,hunk 不在邮件正文里,要确认实际改了哪些锁、是否影响调度延迟,需要直接查看 dwmw2/linux.git seb-nonblock-rt-test 分支。
  • sleeping spinlock 与调度延迟:把 spinlock 变成 sleeping spinlock 会让持锁时间"显形"——临界区内的睡眠会真正反映为调度延迟,需要确认 KVM mmu invalidation 路径上不会引入不可接受的尾延迟。
  • PREEMPT_RT 边界:补丁标题的 Allow 暗示是有条件放开,不是全局改造;后续若发现更多路径误用 sleeping,需要继续核对 spin_lock vs rt_spin_lock 的语义边界。
  • 可继续观察:是否还有其他 mm/sched 路径在 PREEMPT_RT 下复现同类 invalid context 警告,以及本补丁是否会与其他 sleeping-spinlock 系列(如 rt_mutex/local_lock 改造)冲突。

版本变化

线程内只有一次提交与一次 syzbot 测试,没有 vN→vN+1 的演进。

与其他相关 patch 系列的关联

  • 同属 PREEMPT_RT "sleeping spinlocks" 大主题:包括 rt_spin_locklocal_lock、各种"convert spinlock to rt_mutex" 系列;本补丁是该主题下的一个具体补丁。
  • 与 KVM MMU notifier 相关:mmu_notifier_invalidate_range_start 是 KVM 与 mm 子系统的边界,PREEMPT_RT 适配经常需要跨子系统协调(sched + mm + kvm)。

一句话总结

David Woodhouse 用 sched: Allow sleeping spinlocks on PREEMPT_RT 修复 syzbot 报告的"KVM MMU notifier 在 PREEMPT_RT 下 invalid context 睡眠"BUG;前两次 syzbot 因克隆协议写错(https/http)而拉取失败,第三次改用 git:// 后成功,reproducer 不再触发问题。