sched-ext discussion
[GIT PULL] sched_ext: Fixes for v7.2-rc3
LLM 分析
sched_ext: Fixes for v7.2-rc3 — GIT PULL 分析
系列基线信息
| 字段 | 内容 |
|---|---|
| 标题 | [GIT PULL] sched_ext: Fixes for v7.2-rc3 |
| 作者 | Tejun Heo |
| 版本 | v7.2-rc3 fixes |
| 规模 | 多个 bugfix 补丁集合,含 Andrea Righi 的 4 个补丁 |
| Message-ID | 876d09cb8d47617d382a7e2af7a7fd6b@kernel.org |
| 来源 | sched-ext 频道 |
| 合入状态 | 已合入 torvalds/linux (f7574d3f906a963d7b70f01beff731ee0351d5c5) |
明确目的
这是一个 rc3 阶段的 bugfix GIT PULL,由 Tejun Heo 向 Linus 提交,汇集了 sched_ext 子系统在本开发周期中积累的多类修复。
目标:在 v7.2-rc3 合入窗口前,一次性把 sched_ext 已发现的所有缺陷修掉,保证正式发布时的稳定性。
解决的具体问题可归纳为五大类:
- 子调度器生命周期缺陷 — 新增的 sub-scheduler 支持引入了两个 use-after-free 以及一个 enable 失败路径留下半初始化子调度器仍挂链的问题。
- dispatch 路径锁缺陷 — 迁移竞争导致虚假调度器 abort; stale runqueue-lock tracking 引发 lockdep splat。
- 回调与任务状态缺陷 — 任务离开 SCX 时残留调度器私有状态; weight 回调在 disable 之后仍执行; core-scheduling forced idle 上的虚假 warning。
- nohz_full tick 缺陷 — finite-slice 任务在 nohz_full 模式下可能错过过期 slice 的 tick。
- 小修复 — 用户态 CPU-mask helper、ratelimit 弃用警告、文档、sparse 注解。
遍历代码
这封 GIT PULL 本身不包含逐 patch 的 diff,但 commit message 列出了所有修复项。按类别逐步展开:
1. 子调度器生命周期修复
-
use-after-free #1 & #2:子调度器在卸载或切换时,其内部数据结构(如 task context 或 DSQ 引用)被释放后,仍有代码路径通过残留指针访问它们。
修复方向:在子调度器 teardown 流程中,确保先断链、再释放,或引入 RCU / refcount 保护。 -
enable 失败路径半初始化:当
ops.enable()失败时,子调度器数据已部分初始化(比如已挂入全局链表),但后续 cleanup 代码未完全清理,导致一个"半死不活"的子调度器留在系统中。
修复方向:在 enable 失败分支中做完整的 rollback,包括断链和资源释放。
2. dispatch 路径锁缺陷
-
迁移竞争 → 虚假 abort:当一个任务正在从一个 CPU 迁移到另一个 CPU 的过程中,dispatch 路径中的锁序或状态检查会误判为异常,触发 scheduler abort。
修复方向:在 dispatch 路径中,对 migration 中间态做宽容处理或加适当的 seqlock 保护。 -
stale rq-lock tracking → lockdep splat:内核 lockdep 机制依赖 runqueue lock 的正确跟踪记录;sched_ext 的 dispatch 代码在 local DSQ dispatch 场景下,没有正确维持 rq-lock 的持有/释放状态记录,导致 lockdep 报告虚假的锁序违规。
修复方向:在 local DSQ dispatch 中 preserve rq tracking(Andrea Righi 的补丁之一)。
3. 回调与任务状态缺陷
-
任务离开 SCX 残留状态:当任务从 SCX 调度类退出回到 CFS 时,其
dsq_vtime和slice仍保留着 SCX 调度器写入的值,这些值在 CFS 语境下无意义,可能干扰后续调度决策。
修复:resetdsq_vtime和slice(Andrea Righi 的补丁之一)。 -
weight 回调在 disable 后执行:SCX disable 之后,
ops.set_weight()回调仍然会被调用,但此时子调度器已不再活跃,回调行为没有意义甚至可能出错。
修复:对 disabled 任务 skipops.set_weight()(这是 pull 的 tip commit0e2f4ab68a89)。 -
core-scheduling forced idle 虚假 warning:在 core-scheduling 的 forced idle 场景下,一个本应正常的代码路径触发了 warning,属于条件判断过于严格。
修复:放宽或修正判断条件。
4. nohz_full tick 缺陷
- 在
nohz_full(自适应 tickless)模式下,拥有 finite slice 的 SCX 任务被 pick 后,系统应该为其启用 tick 以保证 slice 到期时能得到调度器处理。
但之前遗漏了这一逻辑,导致这类任务的 slice 可能过期而不被处理。
修复:pick finite-slice 任务时启用 tick,并附带 selftest 验证。
5. 小修复
- 用户态 CPU-mask helpers 的修正
- 弃用警告改为 ratelimited(避免日志洪泛)
- 文档更新
- sparse 注解修正
ASCII 流程图
sched_ext Fixes for v7.2-rc3
============================
+----------------------+ +----------------------+
| Sub-scheduler | | Dispatch-path |
| lifecycle | | locking |
| | | |
| * UAF #1, #2 | | * Migration race |
| * Half-init on | | -> spurious abort |
| enable failure | | * Stale rq-lock |
+----------+-----------+ | -> lockdep splat |
| +----------+-----------+
v v
[teardown: unlink then free] [tolerate migration midstate]
[enable fail: full rollback] [preserve rq tracking on
local DSQ dispatch]
+----------------------+ +----------------------+
| Callback & task | | nohz_full tick |
| state | | |
| | | |
| * stale dsq_vtime | | * finite-slice task |
| & slice on exit | | misses expiry tick |
| * set_weight after | | |
| disable | +----------+-----------+
| * bogus forced-idle | |
| warning | v
+----------+-----------+ [enable tick when
| finite-slice task
v is picked + selftest]
[reset dsq_vtime/slice
on leaving SCX]
[skip set_weight for
disabled tasks]
[fix forced-idle check]
+-----------------------------------+
| Smaller fixes |
| * CPU-mask helpers |
| * ratelimited deprecation warns |
| * docs + sparse annotation |
+-----------------------------------+
Git branch: tj/sched_ext -> tags/sched_ext-for-7.2-rc3-fixes
Tip commit: 0e2f4ab68a89 "sched_ext: Skip ops.set_weight()
for disabled tasks"
Merge commit: f7574d3f906a (torvalds/linux)
概念类比
想象一个大型医院的科室轮转系统:
- 子调度器生命周期就好比一个新科室刚挂牌(enable),但挂牌过程中发现资质不合格(enable failure),这时如果不把已经挂上的牌子摘掉、把已搬进的设备退回,就会出现一个"有名无实"的科室挂在那里,病人还在往里走(use-after-free)。
- dispatch 路径锁缺陷就像病人在转运途中(migration),挂号系统还没更新完地址,护士就按旧地址去发药,结果系统判定"这个病人不存在"而中止流程(spurious abort)。或者药房交接班的记录没及时更新(stale rq-lock tracking),内控系统以为有人违规操作(lockdep splat)。
- 任务离开 SCX 残留状态相当于一个医生从急诊科调回普通门诊,但他的排班系统里还留着急诊科的特殊权限参数(dsq_vtime、slice),在门诊场景下这些参数完全无用甚至会产生误导。
- set_weight 在 disable 后执行好比科室已经关停,但人事系统还在给这个科室的岗位发"调整权重"通知——通知发到了一个不存在的接收端。
- nohz_full tick就像一个定时吃药的病人,在"自助管理"模式下(nohz_full),系统应该在病人该吃药时派护士提醒(tick),但之前忘了设置这个提醒,导致病人错过服药时间(slice 过期不被处理)。
Highlight 突出问题
-
子调度器 enable 失败路径是高风险区:任何涉及"部分初始化后失败需要 rollback"的逻辑,都是最容易遗漏清理步骤的地方。这次修复了半初始化挂链的问题,但类似的 rollback 不完整风险在其他 enable/callback 路径中仍需持续关注。
-
migration 竞态与 dispatch 交互是持续痛点:sched_ext 的 dispatch 路径与 CPU migration 之间的竞态条件不是一次性问题,而是架构层面需要长期维护的交互面。每次修改 dispatch 逻辑时,都要重新审视 migration 中间态是否被正确处理。
-
nohz_full 与 sched_ext 的组合是新兴测试盲区:finite-slice 任务在 nohz_full 下错过 tick 的问题说明,sched_ext 的 tick 管理逻辑与 nohz_full 的 tickless 模式之间的交互尚未被充分测试。附带 selftest 是正确做法,但其他 tick 相关场景(如 infinite-slice + nohz_full)也需要验证。
-
lockdep splat 不等于真正的锁序违规:stale rq-lock tracking 导致的 lockdep splat 是"记录不准确"而非"真正的锁序死锁",这类 splat 容易引起不必要的恐慌,也容易在后续修改中被误判为真实 bug。
-
Andrea Righi 的 4 个补丁涉及 dispatch 和状态清理两个核心路径,这些是高频执行代码,修复的 correctness 优先级极高,但性能副作用也需要在合入后观察。
版本演进
这是 v7.2-rc3 的单次 fix pull,没有多版本迭代。补丁在 rc 窗口内一次性提交并合入。
与其他相关 patch 系列的关联
- 本 pull 中的子调度器生命周期修复,直接服务于 v7.2 开发周期中早先合入的 sub-scheduler support 新特性。新特性合入后暴露了 use-after-free 和 rollback 不完整的问题,这是典型的"新特性落地后的首轮 fix round"。
- nohz_full tick 修复与内核 NOHZ 子系统长期存在的 tick 管理重构有关。
- Andrea Righi 的 rq tracking 修复与之前的
sched_ext: Preserve rq tracking系列逻辑相关。
一句话总结
sched_ext 向 Linus 提交 v7.2-rc3 集中 bugfix pull,涵盖子调度器生命周期、dispatch 锁、回调状态、nohz_full tick 及杂项修复,已合入主线。