sched-ext discussion
[PATCH sched_ext/for-7.3] sched_ext: skip ops.set_weight() for disabled tasks
LLM 分析
sched_ext:禁止向已禁用任务回调 set_weight
系列概况
- 标题:
[PATCH sched_ext/for-7.3] sched_ext: skip ops.set_weight() for disabled tasks - 作者:Kuba Piecuch
<jpiecuch@google.com> - 版本:初始投稿(无显式 vN)
- 规模:1 个实际 patch
- 修改文件:
kernel/sched/ext/ext.c(1 个文件) - 代码统计:
+11/-0 - Message-ID:
20260710144342.3802587-1-jpiecuch@google.com - 完整性:
b4找到 3 封邮件和 1/1 个 patch,无缺失警告、无 tip-bot2 污染;含 Sashiko 自动审查和 Tejun Heo 的应用回复
一句话总结:任务离开 SCX 后不再收到
ops.set_weight(),避免 BPF 调度器访问已经在ops.disable()中清理的任务状态。
补丁目的
任务从 sched_ext 切换到其他 sched_class 时,调度类切换框架先执行
switched_from_scx(),其中 scx_disable_task() 调用 ops.disable();随后更新
调度参数又进入 reweight_task_scx(),反而调用 ops.set_weight()。
这破坏了 SCX 生命周期约定:ops.disable() 表示 BPF 调度器可以忘掉该任务,
其后应当只可能退出任务或重新启用,而不应继续更新权重。补丁在权重回调前检查
任务状态,只处理 SCX_TASK_ENABLED 任务。
旧流程的问题
回归来源是 637b0682821b(sched: Fold sched_class::switch{ing,ed}_{to,from}() into the change pattern)。
该提交把 switched_from() 提前到调度参数更新之前;对 SCX 而言,这等价于把
ops.disable() 移到了 reweight_task_scx() 之前。
旧路径的关键顺序是:
sched_change_begin()调用switched_from_scx();scx_disable_task()调用 BPFops.disable(p),随后状态转为SCX_TASK_READY;__setscheduler_params()经set_load_weight()调用旧调度类的reweight_task_scx();- 后者仍更新
p->scx.weight并调用ops.set_weight(p); - 最后才把
p->sched_class改为新调度类。
若 BPF 调度器在 ops.disable() 中删除哈希表、队列或其他 bookkeeping,第 4 步
可能访问已不存在的状态;即使具体调度器碰巧容忍,也违反回调接口语义。
新流程
任务离开 SCX
|
v
scx_disable_task() --> ops.disable() --> state = SCX_TASK_READY
|
v
set_load_weight() --> reweight_task_scx()
|
v
state == SCX_TASK_ENABLED ?
/
是 否
| |
v v
更新 scx.weight 并回调 直接返回
ops.set_weight()
旧:只排除已死亡且完成清理的任务,禁用后的 READY 任务仍会收到权重回调。
新:在计算 p->scx.weight 前要求状态为 SCX_TASK_ENABLED;离开 SCX 的任务
直接返回。如果以后重新加入,__scx_enable_task() 会依据当前优先级重算权重,
并在启用路径通知 ops.set_weight(),因此不会永久丢失更新。
关键实现
1. 状态检查同时保护数据和回调
if (scx_get_task_state(p) != SCX_TASK_ENABLED)
return;
检查位于 p->scx.weight 赋值之前,所以既不改写已禁用任务的 SCX 权重,也不
进入 BPF 回调。这里依赖调用者已持有 rq lock;函数原有的
lockdep_assert_rq_held() 保留不变。
2. 状态转换提供判定依据
scx_disable_task() 在调用 ops.disable() 后把状态从 ENABLED 改成 READY。
所以后续 reweight_task_scx() 能稳定识别任务已离开 SCX。整个切换路径持有任务
和 runqueue 所需锁,补丁没有增加新锁、RCU 操作或睡眠点。
3. 重入 SCX 时恢复最新权重
__scx_enable_task() 根据 static_prio(idle 策略另行处理)重新计算
p->scx.weight,再调用 ops.enable() 与 ops.set_weight();外层随后设置
SCX_TASK_ENABLED。所以本补丁跳过的是错误生命周期阶段的通知,而不是取消权重语义。
4. 投稿与应用版本需区分
原始投稿目标写作 sched_ext/for-7.3。Tejun Heo 回复称实际应用到
sched_ext/for-7.2-fixes,并补充:
Fixes: 637b0682821b (...)Cc: stable@vger.kernel.org # v6.19+
b4 am 生成的补丁包含经 DKIM 验证的 Fixes trailer,代码 diff 未变化。当前
本地 master 能找到回归提交,但尚未出现这 11 行保护,不能据维护者回复推断当前
检出已合入修复。
类比
把 BPF 调度器想成会员系统:ops.disable() 是注销会员并删除档案,
ops.set_weight() 是修改会员等级。旧流程先注销、再要求修改等级;补丁让前台先
检查会员仍有效。若用户以后重新注册,系统会按最新信息重新建立等级。
Highlight:风险与注意点
- 修复只改变非
SCX_TASK_ENABLED路径;正常启用任务的权重更新不变,热路径仅多一次状态判断。 - 提前返回也跳过
p->scx.weight更新,但重新启用路径会重算,因此生命周期闭合。 - Sashiko 提出
reweight_task_scx()未同步p->se.load,可能令转回 CFS 的 load weight 陈旧;其明确标为既有问题,不是本补丁引入,也没有人工评审结论支持或否定。 - Tejun 明确认定这是 v6.19 起的回归并应用到 fixes 分支;线程没有其他人工 review。自动审查回复不能等同于维护者对旁支问题的认可。
- stable 回传需核对各分支的文件迁移和调用顺序;当前主线文件为
kernel/sched/ext/ext.c,较早基线使用kernel/sched/ext.c。
版本变化
线程没有 v2/v3。唯一重要变化发生在维护者处理阶段:投稿标注面向 7.3,最终被
视为 7.2 fixes 和 v6.19+ stable 回归修复,并追加 Fixes 与 stable Cc;补丁逻辑
本身没有修订。
一句话总结
该补丁用一个 SCX 状态门禁恢复任务生命周期顺序:禁用后不再回调权重更新,重新
启用时再按最新优先级重建权重,以极小改动消除 BPF 调度器的失效状态访问窗口。