sched-ext discussion
[GIT PULL] sched_ext: Fixes for v7.2-rc6
LLM 分析
sched_ext: Fixes for v7.2-rc6 — 技术分析
系列基线信息
| 字段 | 内容 |
|---|---|
| 标题 | [GIT PULL] sched_ext: Fixes for v7.2-rc6 |
| 作者 | Tejun Heo |
| 版本 | v7.2-rc6 修复批次 |
| 规模 | 4 类修复,含 Kuba Piecuch 的 2 个 patch |
| Message-ID | 73f632a36560eddd78a0b82db78e4b8d@kernel.org |
| 来源 | sched-ext |
| Git tag | sched_ext-for-7.2-rc6-fixes |
| 基线 | 0e2f4ab68a89 → d4a00d61a5c2 |
| 合并状态 | 已合并至 torvalds/linux (be76b516e681) |
明确目的
这是 sched_ext 子系统为 v7.2-rc6 提交的 bugfix 合并请求,修复四类问题:
- 子调度器生命周期缺陷:enable 失败时可能拆毁一个从未被链接的子调度器,与 root scheduler 的 disable 竞争导致 use-after-free;未在 ext class 上的任务仍收到 enable 回调;policy 拒绝路径静默改写运行中任务的调度策略而非中止调度器。
- cgroup 与 kernfs 死锁:scheduler enable/disable 与 cgroup 删除及并发 kernfs 权重写入形成锁序死锁。
- WAKE_SYNC 空闲追踪错误:sync wakeup 场景下 waker CPU 被错误标记为 idle。
- 自测修复:numa 测试中睡眠任务在唤醒前 CPU affinity 发生变化。
遍历代码
修复 1:子调度器生命周期
新的 sub-scheduler 支持引入了多条错误路径:
- use-after-free:
ops.enable()失败时,teardown 代码对一个从未完成 link 的子调度器执行清理,而 root scheduler 的 disable 路径可能同时也在操作同一对象——两者竞争导致访问已释放内存。 - 错误 enable 回调:任务尚未切换到 ext sched class 时就收到了
ops.enable()回调,违反了"只有 ext class 任务才触发回调"的约定。 - 静默策略改写:policy 拒绝路径(如 cgroup 约束不允许切换)没有 abort 调度器,而是直接改写了运行中任务的 scheduling policy,导致调度器与任务实际策略不一致。
修复 2:cgroup/kernfs 死锁
锁序冲突(修复前):
CPU A: scheduler enable/disable → 持有 sched_ext 内部锁 → 等待 cgroup_mutex
CPU B: cgroup removal + kernfs weight write → 持有 cgroup_mutex/kernfs 锁 → 等待 sched_ext 内部锁
修复方式:重新排列锁获取顺序,确保 sched_ext 内部锁与 cgroup_mutex/kernfs 锁的嵌套方向一致。
修复 3:WAKE_SYNC 空闲标记
当 WAKE_SYNC 选择 waker CPU 作为目标时,内置的 idle-CPU 追踪逻辑没有将 waker CPU 标记为 busy。后果:后续唤醒可能反复选择同一个"空闲"CPU,导致负载不均衡。
修复:在 WAKE_SYNC 路径中,当 waker CPU 被选为目标时,显式标记其为 busy。
修复 4:numa 自测
睡眠任务在唤醒前 CPU affinity 被改变,测试没有处理这种情况,导致断言失败。
ASCII 流程图
=== Sub-scheduler lifecycle (修复前) ===
ops.enable() root disable
| |
v v
[enable fail] [teardown]
| |
v v
teardown sub-sched <---+---> USE-AFTER-FREE !
=== Sub-scheduler lifecycle (修复后) ===
ops.enable() root disable
| |
v v
[enable fail] [teardown]
| |
v v
check: linked? (only linked
NO -> skip teardown sub-scheds)
=== cgroup/kernfs deadlock (修复前) ===
CPU A: lock(A) ---> lock(B) (sched_ext -> cgroup)
CPU B: lock(B) ---> lock(A) (cgroup -> sched_ext)
^^ DEADLOCK ^^
=== cgroup/kernfs deadlock (修复后) ===
CPU A: lock(B) ---> lock(A) (统一锁序)
CPU B: lock(B) ---> lock(A) (统一锁序)
OK - 顺序一致
=== WAKE_SYNC idle tracking ===
[waker CPU] --WAKE_SYNC--> [select waker as target]
|
(修复前) | (修复后)
idle mark | busy mark
| | |
v | v
下次还选它 | 下次正确跳过
概念类比
把 sched_ext 想象成一家连锁餐厅的管理系统:
- 子调度器像是新开的一家分店。如果分店开业手续(enable)失败,但总部已经发了拆除通知(disable),两边同时去拆同一栋楼——这就是 use-after-free。修复后,开业失败的分店根本没挂上连锁牌子,拆除队不会去拆它。
- cgroup/kernfs 死锁像是两个部门都要同时拿到"仓库钥匙"和"办公室钥匙"才能干活,但一个部门先拿仓库再拿办公室,另一个反过来——谁也等不到对方。修复后统一规定"先拿仓库、再拿办公室",就不会卡住。
- WAKE_SYNC 空闲标记像是服务员把刚接单的工位标记为"空闲",导致下一单又派给同一个还在忙的人。修复后,接单的工位立刻标为"忙碌"。
Highlight 突出问题
- use-after-free 是高危正确性 bug:子调度器生命周期管理是新增功能,enable 失败路径显然缺少充分测试,说明新子系统的错误路径覆盖需要加强。
- policy 静默改写是最隐蔽的修复:调度器认为任务在 ext class,但实际策略已被改回 CFS——这种不一致可能导致调度决策完全错误,且难以复现。
- 锁序问题需要全链路审计:仅修复了这一处死锁,sched_ext 与 cgroup/kernfs 的其他交互路径是否还有类似问题值得关注。
- idle-CPU 追踪错误影响负载均衡:WAKE_SYNC 是高频路径,错误标记可能在高负载下导致明显的不均衡和性能退化。
版本演进
本线程为单一 git pull 请求,无多版本迭代。
与其他相关 patch 系列的关联
- 基线 commit
0e2f4ab68a89("Skip ops.set_weight() for disabled tasks")是上一轮修复,说明 sub-scheduler 支持引入后仍在持续修复生命周期问题。 - 子调度器支持是 sched_ext 较新的功能扩展,本批修复反映了该功能上线后的稳定性收敛。
一句话总结
sched_ext v7.2-rc6 修复批次解决了子调度器生命周期 use-after-free、cgroup 死锁、WAKE_SYNC 空闲标记错误和自测问题,已合并进主线。