sched discussion
Re: [syzbot] [mm?] BUG: sleeping function called from invalid context in kvm_mmu_notifier_invalidate_range_start
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.git的seb-nonblock-rt-test分支,测试 commitf902e69c "sched: Allow sleeping spinlocks on PREEMPT_RT" - 规模:4 封邮件;3 封为 syzbot 测试报告或人工介入回复,1 封为 David Woodhouse 触发新测试;线程本身未嵌入 hunk
- 修改文件 / 代码统计:无法从邮件正文得到(hunk 在 git tree 中,邮件仅引用分支名)
- Message-ID:
b434f7828a4d7b24de76aa5609dadda2871a932a.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.git的seb-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_lockvsrt_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_lock、local_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 不再触发问题。