sched-ext discussion
[PATCH] sched_ext: Fix stale errno in scx_sub_enable_workfn()
LLM 分析
sched_ext: Fix stale errno in scx_sub_enable_workfn()
系列基线信息
- 标题:
[PATCH] sched_ext: Fix stale errno in scx_sub_enable_workfn()→ v2 保持同一标题 - 作者: Cui Jian (
cjian720@163.com) - 版本: v1 → v2
- 规模: v1 改 1 文件 5 行 (+4/-1);v2 改 1 文件 2 行 (+2)
- Message-ID:
20260718201713.17890-1-cjian720@163.com(v1),20260722100352.36627-1-cjian720@163.com(v2) - 来源: sched-ext 频道
- 审核者: Andrea Righi(review)、Tejun Heo(maintainer,已合入)
明确目的
scx_sub_enable_workfn() 中有两处错误路径在跳转到 err_disable 时没有设置 ret,导致 ret 仍为 0。这使得 commit db4e9defd2e8 引入的 fallback 错误信息打印出 scx_sub_enable() failed (0) —— 一个 errno=0 的"成功式失败"日志。
当前无害,因为这两处路径在跳转前已经调用了 scx_error() 记录具体错误信息,而 scx_error() 的"first error wins"机制保证了有意义的信息已被记录。但 fallback 路径本身是坏的,未来如果"first error wins"逻辑改变或 fallback 被其他场景依赖,就会暴露问题。
本 patch 的目标:在嵌套深度检查处设 ret = -EINVAL,在 cgroup online 检查处设 ret = -ENODEV,使 fallback 始终报告真实 errno。
遍历代码
scx_sub_enable_workfn() 是 sched_ext 子调度器启用的工作函数,负责在 cgroup 层级下启用嵌套的 sched_ext 调度器。
关键路径:
-
嵌套深度检查:
if (sch->level >= SCX_SUB_MAX_DEPTH)→ 调用scx_error()报错 →goto err_disable,但未设 ret。补丁加入ret = -EINVAL。 -
cgroup online 检查:
if (!(cgrp->self.flags & CSS_ONLINE))→ 调用scx_error()→goto err_unlock_and_disable,未设 ret。补丁加入ret = -ENODEV。 -
err_disable标签处的 fallback:db4e9defd2e8在此处添加了 fallback 日志scx_sub_enable() failed (ret),期望 ret 总是非零,但上述两条路径跳转过来时 ret=0。
v1 还修复了 validate_ops() 调用路径(if (validate_ops(sch, ops)) 改为 ret = validate_ops(sch, ops); if (ret)),但 v2 发现该路径已在 for-7.3 分支中被修复,所以 v2 只保留两处仍需修复的路径。
ASCII 流程图
scx_sub_enable_workfn() 错误路径
=================================
sch->level >= SCX_SUB_MAX_DEPTH?
│
YES --> scx_error("max nesting depth")
│
ret = 0 <-- 原代码(BUG)
ret = -EINVAL <-- 补丁修复
│
goto err_disable --> fallback: "failed (ret)"
原来打印 "(0)"
修复打印 "(-EINVAL)"
!(cgrp->self.flags & CSS_ONLINE)?
│
YES --> scx_error("cgroup not online")
│
ret = 0 <-- 原代码(BUG)
ret = -ENODEV <-- 补丁修复
│
goto err_unlock_and_disable --> 同上 fallback
概念类比
想象医院急诊分诊系统:病人被拒收时,护士手写详细拒收原因贴在病历上(scx_error()),然后到出口登记台把拒收代码录入电脑(fallback 日志的 ret)。问题是——护士写了详细原因后,忘了在电脑输入对应拒收代码,电脑默认填"0"(正常),打印出"拒收原因:0"。手写记录写着真实原因,但电脑记录是错误的。补丁让护士在写手写记录的同时,也把正确拒收代码输入电脑。
Highlight 突出问题
-
"first error wins"掩盖了 fallback 的缺陷:当前无害是因为
scx_error()先记录了具体信息,fallback 只是冗余补充。但如果未来 scx_error 的"first wins"规则被修改,或 fallback 被其他代码路径依赖,ret=0 就会成为真正的问题。这种"当前无害但机制不健壮"的 bug 最容易被忽视。 -
v1→v2 范围缩减说明分支间代码已变动:
validate_ops()路径在 for-7.3 分支已被独立修复(移到sub.c并改为ret = scx_validate_ops())。提交 patch 前应检查目标分支最新状态,避免重复修复。 -
两个 goto 目标不同:嵌套深度检查跳
err_disable,cgroup 检查跳err_unlock_and_disable(需要先解锁),补丁只加了ret赋值没改变 goto 目标,逻辑正确,但读者需注意两个错误出口的清理步骤不同。
版本演进
| 版本 | 关键改动 |
|---|---|
| v1 | 修复 3 条路径:嵌套深度(ret = -EINVAL)、validate_ops(ret = validate_ops(); if (ret))、cgroup online(ret = -ENODEV);改 ext.c |
| v2 | 只修复 2 条路径(嵌套深度 + cgroup online);validate_ops 已在 for-7.3 的 sub.c 中独立修复;文件从 ext.c 变为 sub.c |
与其他相关 patch 系列的关联
- commit
db4e9defd2e8("sched_ext: Record an error on errno-only sub-enable failure"):引入 fallback 错误日志机制,是本 bug 的根源——它假设所有路径跳到err_disable时 ret 已设为非零,但遗漏了两条路径。 scx_root_enable_workfn():v1 commit message 提到 root enable 函数已正确保存validate_ops()返回值到ret,是本修复的参照实现。
一句话总结
修复 scx_sub_enable_workfn() 中两条错误路径未设置 ret 导致 fallback 日志打印 errno=0 的缺陷,确保所有失败路径都报告真实错误码。