sched discussion
FAILED: patch "[PATCH] sched_ext: Skip ops.set_weight() for disabled tasks" failed to apply to 7.1-stable tree
LLM 分析
sched_ext:回退稳定版时跳过对已禁用任务的 ops.set_weight() 调用
系列概况
- 标题:
[PATCH] sched_ext: Skip ops.set_weight() for disabled tasks(稳定线回退相关) - 作者:Kuba Piecuch(Google),Tejun Heo Ack;Greg KH(stable 维护者);Sasha Levin(stable 机器人)
- 版本:上游主分支为单个
[PATCH];随后作为[PATCH 7.1.y]单独回退到 7.1 稳定线 - 规模:仅
kernel/sched/ext.c(7.1.y 路径,主线为kernel/sched/ext/ext.c),+11/-0,单 hunk - 修改文件:
kernel/sched/ext.c(stable)或kernel/sched/ext/ext.c(主线) - 代码统计:1 file changed, 11 insertions(+)
- Message-ID:
2026072131-citation-reshape-587c@gregkh(失败通知);DK4AN7P1B5KK.15R8G3B5L5E85@google.com(作者回应);2026072141-spotless-tarantula-5421@gregkh、2026072139-phrasing-scroll-e4fa@gregkh(Greg KH 跟进,被截断);20260721150403.3680077-1-jpiecuch@google.com(正式 7.1.y 回退 patch);20260721201114.0009-stable-reply@kernel.org(Sasha 接收) - 完整性:主线 patch 已存在(commit
0e2f4ab68a89fad42e0f5a9ff4b740738e7aa1d6),回退路径经过 Greg KH 拒收 → 作者手工 cherry-pick → Sasha 入队 7.1 完整闭环
补丁目的
主线 commit 0e2f4ab68a89fad42e0f5a9ff4b740738e7aa1d6 已经合并了同一改动,本线程关注的是把这一改动同步到 7.1 稳定线。
触发的根本 bug 如下:
__sched_setscheduler() sequence when leaving SCX
+------------------------+
| sched_change_begin() |
| switched_from_scx() |
| scx_disable_task(p) | <- task enters SCX_TASK_DISABLED
| ops.disable(p) | <- BPF scheduler may "forget" the task
| __setscheduler_params()
| set_load_weight()
| reweight_task_scx(p) |
| ops.set_weight(p) | <- called AFTER ops.disable(); breaks contract
| p->sched_class = next_class
| sched_change_end() |
+------------------------+
按照 BPF SCX ops 约定,ops.disable() 之后只能跟 ops.exit_task() 或 ops.enable(),再调用 ops.set_weight() 等通用 ops 会让 BPF 端对一个已经"忘记"的对象做写操作。修复方法是在 reweight_task_scx() 顶部判断状态,若已不是 SCX_TASK_ENABLED 就直接 return。
旧流程的问题
[scx task] -- __sched_setscheduler() --> [next class]
|
|-- scx_disable_task(p) -- SCX_TASK_DISABLED
|-- ops.disable(p) -- BPF may have freed/cleaned p's BPF ctx
|-- reweight_task_scx(p)
| +-- ops.set_weight(p, w) -- writing to a "forgotten" object
v may: stale ctx / negative ref / BPF writes out of band
风险点不是一定崩,而是违反 enable/disable 之间的对称约束。BPF 调度器实现可能假设 disable 之后不会再收到针对该任务的 ops,从而出现内部 map 负引用、release 后再 use,或在 exit_task/enable 之外发生状态写。
新流程
reweight_task_scx(rq, p, lw):
if (task_dead_and_done(p)) return;
+ if (scx_get_task_state(p) != SCX_TASK_ENABLED)
+ return;
p->scx.weight = sched_weight_to_cgroup(scale_load_down(lw->weight));
if (SCX_HAS_OP(sch, set_weight))
SCX_CALL_OP_TASK(sch, set_weight, rq, p, p->scx.weight);
任务如果以后重新回到 SCX,权重会在 scx_enable_task() 时被重新计算并下发,因此这里 return 是无损的。
Patch 概览
- 主线:commit
0e2f4ab68a89fad42e0f5a9ff4b740738e7aa1d6,文件kernel/sched/ext/ext.c:3967,作者 Kuba Piecuch。 - 稳定线 7.1.y:commit
adc748e669cc1564255430299abf086b9ecd9b45(cherry-pick 自0e2f4ab68),文件kernel/sched/ext.c:3904,同样是 +11/-0。
仅一处 hunk,新增 11 行(含 5 行注释和 6 行实际判断 + 提前返回)。
关键实现
/*
* When switching sched_class away from SCX, reweight_task_scx()
* is called _after_ scx_disable_task(). Skip calling ops.set_weight()
* since the BPF scheduler may have already forgotten the task in
* ops.disable().
*
* p->scx.weight will be recalculated in scx_enable_task() if the task
* ever returns to SCX class.
*/
if (scx_get_task_state(p) != SCX_TASK_ENABLED)
return;
判断位置选在 reweight_task_scx() 顶部,避开了 p->scx.weight = ... 赋值与后续 SCX_CALL_OP_TASK(...),所以即使跳过也不会让 p->scx.weight 残留错值;下一次进入 SCX 走 scx_enable_task() 时会重新算。
Fixes: 637b0682821b 指向 fold switch_{to,from} 的 commit,正是这次回调序变化的源头。Cc: stable 注明 v6.19+,所以同步给 7.1 稳定线。
##旧版 vs 新版对比图
OLD (buggy) NEW (fixed)
+-----------------+--------------------+ +--------------------+----------+
| scx_disable(p) | task=DISABLED | | scx_disable(p) | DISABLED |
| ops.disable(p) | BPF forgets p | | ops.disable(p) | BPF forgets |
| reweight_task_scx(p) | | reweight_task_scx(p) |
| set_weight(p, w) <-- BAD: late op | | state != ENABLED -> return |
+-----------------+--------------------+ +--------------------+----------+
|
v
scx_enable_task() recalcs weight
类比
把 SCX 任务想成酒店住客的房卡:退房(ops.disable)时前台已经把这张房卡注销;之后房间清扫时如果系统按旧卡号去记录清洁工时(ops.set_weight),就会把工时记到一张"已经销毁"的卡上,账单系统要么报错要么记错。
新版做法是:扫房时先确认房卡仍有效(scx_get_task_state(p) == SCX_TASK_ENABLED),无效就直接跳过;下一次入住办新卡时(scx_enable_task)会按新卡号重新计算工时,不会丢失。
Highlight:风险与注意点
- 路径差异:
7.1.y中kernel/sched/ext.c是单文件,主线已拆成kernel/sched/ext/ext.c。stable 机器人按上游 SHA 自动回退时只比对 blob 内容,不感知目录重命名,因此 cherry-pick 会失败,这是线程里 Greg KH 报告失败的真正源头,不是逻辑冲突。 - 截断回复:第 3、4 封 Greg KH 的邮件在 lore 上看起来是空或被截断的回执,依赖 stable 机器人的反压机制(第 5、6 封才闭环);下游不能据此判断 Greg 是否真的认可改动。
- 上游 commit
Fixes: 637b0682821b暗示只要内核还携带该 fold 改动,就都需要这一修复;任何在 6.19 之后手工定制的 backport 都应补这一 hunk。 - 状态机局限:
scx_get_task_state(p)只能反映 SCX 自身状态机;如果未来其他 BPF 调度器引入更细的 ops 状态,需要重新评估这一短路是否会漏掉合法调用。
版本变化
仅主线 commit → 7.1.y 回退这一段:
- 主线:以
0e2f4ab68a89fad42e0f5a9ff4b740738e7aa1d6入 master,文件路径kernel/sched/ext/ext.c,偏移 3967。 - 7.1.y 回退:以
adc748e669cc1564255430299abf086b9ecd9b45重新打包,文件路径kernel/sched/ext.c,偏移 3904(行号偏移来自缺少-4行@段头),差异仅是文件路径与 hunk 上下文,本体逻辑不变。
一句话总结
主线 sched_ext 修复让 reweight_task_scx 在任务已经 disable 后跳过 ops.set_weight();本线程用 [PATCH 7.1.y] 把同一短路逻辑同步进 7.1 稳定线,Sasha 已入队。