sched discussion
FAILED: patch "[PATCH] sched/core: Make core-sched flips wait for in-flight" failed to apply to 6.18-stable tree
LLM 分析
sched/core:让 core-sched 翻转等待 in-flight 选择
系列概况
- 标题:FAILED: patch "[PATCH] sched/core: Make core-sched flips wait for in-flight" failed to apply to 6.18-stable tree
- 作者:原始补丁 Tejun Heo tj@kernel.org;本邮件由 gregkh (Greg Kroah-Hartman) 代发,报告 stable 树回植失败
- 版本:单补丁 cherry-pick 尝试,无独立版本号(上游对应 commit f3629c63a4af3e491381780bc6c123cb498c4c40)
- 规模:2 个文件,约 15 行新增
- 修改文件:kernel/sched/core.c、kernel/sched/sched.h
- 代码统计:
sched.h+1 行(struct rq 新字段);core.c+12 行(翻转等待循环 + 计数加减 + 字段初始化 + deactivate 处理) - Message-ID:2026090310-surround-endnote-4269@gregkh
- 完整性:完整 —— 邮件含 diff 片段和上游原始 commit 的 commit message 与 body,签名行齐全(Signed-off-by / Acked-by / Cc stable)
补丁目的
核心调度(core scheduling)的 pick_next_task() 在一把共享的 core-wide 锁内对所有 SMT sibling rq 做选择。
部分 ->pick_task() 实现会临时 drop 掉 rq 锁,这给了 __sched_core_flip(false) 一个窗口:
它趁机完成翻转,把 rq_lockp() 重新绑定到拆分后的 per-CPU 锁。
选择流程随后在拆开的锁上恢复运行,触碰到它本不应再保护的兄弟 rq 状态;
__schedule() 最终释放一把从未持有的锁、泄漏原本持有的那把。
补丁目标:在 leader 的 rq->core_pick_in_flight 上对正在进行中的 core-wide 选择计数,
让 __sched_core_flip() 在翻转前等待计数排空,从根上消除"屋内有人盘点却被换锁"的竞态。
旧流程的问题
旧流程里 __sched_core_flip() 只做:
sched_core_lock(cpu, &flags);
for_each_cpu(t, smt_mask)
cpu_rq(t)->core_enabled = enabled;
sched_core_unlock(cpu, &flags);
翻转全程持有 shared core lock。问题在于:持有这把共享锁并不意味着 sibling 全部空闲。
正在执行 core-wide selection 的 CPU 把 rq 锁 drop 掉的瞬间,其他 sibling 的 __lock 短暂空闲,
flip 趁虚完成、把 rq_lockp() 切到 per-CPU 锁。
selection 在拆开的锁上恢复后状态正确性被破坏,unlock 计数器错位。
新流程
引入 core_pick_in_flight 计数后,__sched_core_flip() 增加一段轮询:
while (cpu_rq(cpu)->core->core_pick_in_flight) {
sched_core_unlock(cpu, &flags);
cpu_relax();
sched_core_lock(cpu, &flags);
}
计数只在 shared core lock 下被加减,与 flip 的采样点是同一把锁,不需额外 barrier。
翻转本身是 cookie 生命周期事件,频率极低,等待重叠选择的开销可接受。
pick_next_task() 进入 core-wide 选择路径前 ++,退出路径 --;
sched_core_cpu_deactivate() 把计数 move 到新 leader,避免 stale 副本 bias;
sched_init() 启动时把字段初始化为 0。
关键实现
/* sched.h */
struct rq {
...
unsigned int core_pick_in_flight;
};
/* core.c: __sched_core_flip() 头部 */
while (cpu_rq(cpu)->core->core_pick_in_flight) {
sched_core_unlock(cpu, &flags);
cpu_relax();
sched_core_lock(cpu, &flags);
}
/* core.c: pick_next_task() 进入/退出 core 选择路径 */
rq->core->core_pick_in_flight++;
...
rq->core->core_pick_in_flight--;
/* core.c: sched_core_cpu_deactivate() */
core_rq->core_pick_in_flight = rq->core->core_pick_in_flight;
rq->core_pick_in_flight = 0;
/* core.c: sched_init() */
rq->core_pick_in_flight = 0;
流程示意
+----------------------+ shared core lock held
| pick_next_task() |---------------------------------+
| entry: ++in_flight | |
| ... select ... | <-- rq lock may drop here |
| exit: --in_flight | v
+----------------------+ +------------------+
| __sched_core_flip|
+----------------------+ | loop while |
| CPU B: __sched_core_ |------------------------>| count != 0 |
| flip() | | unlock + relax |
+----------------------+ | relock |
| end loop |
| rebind rq_lockp |
+------------------+
sched_core_cpu_deactivate
-------------------------
old leader rq --. .--> new core_rq
| |
in_flight = N +--move (assign)->+ in_flight = N
| |
in_flight = 0 +--clear---------+ in_flight = 0 (was old)
类比
把 core-wide selection 想成银行金库的现金盘点:经理带着全部现金逐个核对账目,期间会短时离开桌面(lock drop)。
若此时有人执行"换锁"操作把金库门锁换成另一把备用锁,经理回来时就会去交还一把他从未拿过的钥匙,而真正那把钥匙已丢失。
补丁相当于在金库门上挂一个计数器:盘点开始 +1、结束 -1;
换锁看到非零就退到门外 cpu_relax() 等一拍再回来,从根上消除"屋内有人还在盘点却被换锁"的竞态。
deactivate 时 move 而不是 copy,等同于把计数器从即将关闭的金库门搬到新门,旧门归零,避免下一次该 CPU 又当 leader 时被旧值持续干扰。
Highlight:风险与注意点
- stable 回植失败:本邮件本身就是 stable robot 报告,6.18.y 上
__sched_core_flip()周边上下文已漂移,需要手工三向合并;后续回植者需关注pick_next_task()多入口是否都能被 hunks 覆盖。 - ++/-- 必须成对:
pick_next_task()在 SMT 域上有多条可能进入 core-wide 选择的路径,遗漏一处会让计数永远 >0,造成翻转卡死;回植时务必把所有入口审计一遍。 - deactivate 必须是 move:copy 留下的副本会让 CPU 之后再次成为 leader 时计数永久偏离,commit message 已显式强调这一点。
- 优先级反转:等待翻转的 CPU 可能正是被等待的 selection 所需 target,在调度域较深拓扑下需观察 tail latency 与调度周期是否被拉长。
- 行为变化点:Fixes tag 指向 v5.14 引入 core scheduling 的 commit,意味着 v5.14+ 都需要这个修复;stable 落点较广,6.18.y 是首个 stable 落点(本次失败),需关注后续 stable 维护者回植结果。
- 可观察信号:修复前后可通过 tracepoint /
rq->core->core_pick_in_flight采样验证翻转等待频率;正常负载下应非常稀疏。
一句话总结
通过在 leader rq 上记录 in-flight core-wide selection 数量,让 __sched_core_flip() 在翻转前等待选择排空,修复 core-sched 翻转与 ->pick_task() lock drop 之间的锁重绑竞态;stable 回植需要手工解决 6.18.y 的上下文漂移。