0/2 已展开

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-ID73f632a36560eddd78a0b82db78e4b8d@kernel.org
来源sched-ext
Git tagsched_ext-for-7.2-rc6-fixes
基线0e2f4ab68a89d4a00d61a5c2
合并状态已合并至 torvalds/linux (be76b516e681)

明确目的

这是 sched_ext 子系统为 v7.2-rc6 提交的 bugfix 合并请求,修复四类问题:

  1. 子调度器生命周期缺陷:enable 失败时可能拆毁一个从未被链接的子调度器,与 root scheduler 的 disable 竞争导致 use-after-free;未在 ext class 上的任务仍收到 enable 回调;policy 拒绝路径静默改写运行中任务的调度策略而非中止调度器。
  2. cgroup 与 kernfs 死锁:scheduler enable/disable 与 cgroup 删除及并发 kernfs 权重写入形成锁序死锁。
  3. WAKE_SYNC 空闲追踪错误:sync wakeup 场景下 waker CPU 被错误标记为 idle。
  4. 自测修复:numa 测试中睡眠任务在唤醒前 CPU affinity 发生变化。

遍历代码

修复 1:子调度器生命周期

新的 sub-scheduler 支持引入了多条错误路径:

  • use-after-freeops.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 突出问题

  1. use-after-free 是高危正确性 bug:子调度器生命周期管理是新增功能,enable 失败路径显然缺少充分测试,说明新子系统的错误路径覆盖需要加强。
  2. policy 静默改写是最隐蔽的修复:调度器认为任务在 ext class,但实际策略已被改回 CFS——这种不一致可能导致调度决策完全错误,且难以复现。
  3. 锁序问题需要全链路审计:仅修复了这一处死锁,sched_ext 与 cgroup/kernfs 的其他交互路径是否还有类似问题值得关注。
  4. 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 空闲标记错误和自测问题,已合并进主线。