sched-ext discussion
[PATCHSET sched_ext/for-7.3-fixes] sched_ext: Sync tools headers from the scx repo
LLM 分析
sched_ext:把 scx 仓库里的 tools 头文件同步回内核树
系列概况
- 标题:[PATCHSET sched_ext/for-7.3-fixes] sched_ext: Sync tools headers from the scx repo
- 作者:Tejun Heo tj@kernel.org
- 版本:无版本号(单轮 patchset),目标分支
sched_ext/for-7.3-fixes,基于5f01293930d1 - 规模:2 个 patch,5 个文件改动,+501/-32 行
- 修改文件:
tools/sched_ext/include/scx/common.bpf.h(+140/-)tools/sched_ext/include/scx/compat.bpf.h(+68/-)tools/sched_ext/include/scx/compat.h(+97,新文件)tools/sched_ext/include/scx/enum_defs.autogen.h(+5/-1)tools/sched_ext/include/scx/enums_abi.autogen.h(+223,新文件)
- Message-ID:
20260818205711.3175265-1-tj@kernel.org(cover),...-2-(1/2),...-3-(2/2) - 完整性:完整;含完整 diff、git 分支指针、最终被 maintainer 标记为 Applied
补丁目的
sched_ext 的 BPF 用户态工具头在 tools/sched_ext/include/scx/ 下与 scx 仓库各自维护了一份。
时间一长,两边已经漂移:scx 仓库里积累了若干 fix 与改进,但内核树拷贝没跟上。
本系列把这些修复反向同步回内核树,让 make -C tools/sched_ext 编译出的 BPF skeleton 直接吃到最新逻辑。
它一并解决四类问题:
- 64 位 scx enum 在老 BTF(无
BTF_KIND_ENUM64)上读取截断; - v6.18+ 不开
CONFIG_PREEMPT_RCU时,is_migration_disabled()对当前任务 under-report; scx_bpf_dsq_peek()的版本门控以及 Gavin/Changwoo 提出的scx_bpf_reenqueue_local_from_anywhere();- 兼容老内核用的
__COMPAT_scx_bpf_cpu_curr()被恢复;同时文档化 rq clock helper 在 idle CPU 上的 stale-read 行为。
旧流程的问题
旧 is_migration_disabled() 只有单一公式:
if (p->migration_disabled == 1)
return bpf_get_current_task_btf() != p;
else
return p->migration_disabled;
这公式的前提是「BPF trampoline prolog 一定 migrate_disable()」。
但 8e4f0b1ebcf2 之后,prolog 只在 CONFIG_PREEMPT_RCU 下才 migrate_disable()。
所以 v6.18+、不开 PREEMPT_RCU 的内核上跑这条老逻辑,对 p == current 的 task 会返回 false —— 即错误地认为 current 没被禁迁移,下游可能去别的 CPU 上 dispatch 它,调度器就 crash。
__COMPAT_read_enum() 在老 BTF 上读 64-bit enum 会被截断;__COMPAT_scx_bpf_cpu_curr() 之前没保留,旧调度器无法在 pre-v6.18 内核上跑。
新流程
新流程加入运行时探测 + 多分支快速判定:
is_migration_disabled(p)
|
p->migration_disabled == 1 ?
/ \
no yes
| |
return migration_disabled CONFIG_PREEMPT_RCU ?
/ \
yes no
| |
current == p ? LINUX_KERNEL_VERSION >= 6.18 ?
/ \ / \
return return return return
false true true __scx_prolog_disables
_migration ? cmp: return true
__scx_prolog_disables_migration 默认 true,由 scx_lib_init_probe(一个挂在 bpf_scx_reg 上的 fentry)写入。失败时按保守值(pre-v6.18 prolog 行为)兜底。
Patch 概览
Patch 1/2 — Sync autogen enum headers
enum_defs.autogen.h:补HAVE_SCX_DSP_NONE/LOCAL/PREV/RETRY,删HAVE_SCX_RQ_IN_BALANCE。- 新增
enums_abi.autogen.h:以__attribute__((unused))表形式存放编译期已知的 scx 枚举值,作为老 BTF 上读 64-bit enum 的回查表。
Patch 2/2 — Sync common and compat headers
- 新增
__scx_prolog_disables_migration与scx_lib_init_probe。 - 重写
is_migration_disabled():CONFIG_PREEMPT_RCU 快速路径、>=6.18 快速路径、pre-v6.18 慢路径。 - 恢复
__COMPAT_scx_bpf_cpu_curr(),先尝试scx_bpf_cpu_currksym,否则退回scx_bpf_cpu_rq。 - 文档化
scx_clock_task/scx_clock_pelt在 NO_HZ_IDLE idle CPU 上的 stale-read。
关键实现
新 is_migration_disabled() 的 C 形态:
if (p->migration_disabled == 1) {
if (CONFIG_PREEMPT_RCU)
return bpf_get_current_task_btf() != p;
if (LINUX_KERNEL_VERSION >= KERNEL_VERSION(6, 18, 0))
return true;
return __scx_prolog_disables_migration
? bpf_get_current_task_btf() != p
: true;
}
return p->migration_disabled;
新 probe 通过 fentry 钩进 bpf_scx_reg:
SEC("fentry/bpf_scx_reg") __weak
int scx_lib_init_probe(void *ctx)
{
if (bpf_core_field_exists(...)) {
const struct task_struct *p = bpf_get_current_task_btf();
unsigned int md = p->migration_disabled;
if (md > 1)
bpf_printk("...probe result unreliable");
__scx_prolog_disables_migration = md > 0;
}
return 0;
}
类比
把 is_migration_disabled(p) 想成「问快递员:你手头的包裹是不是被锁在自家车上了?」。
旧版本只问一句「包裹上有没有锁?」,但 BPF trampoline 在你出发前自动给 current 也加了把锁,结果你对所有 current 都以为没锁,把包裹送去了别处 —— 收件人找不到。
新版本先看清三条规则:PREEMPT_RCU 默认会加锁、6.18 之后默认不加锁、介于两者之间还要看仓库当年到底有没有 cherry-pick prolog 改动;同时有一个「上岗第一天的小测试员」—— scx_lib_init_probe —— 在调度器装载那一刻亲自跑一遍 trampoline,把结果记下来给后面用。规则不清晰就用「默认假设 prolog 加了锁」(保守高估,最多本地派送,不会跨 CPU),避免炸调度器。
Highlight:风险与注意点
- 默认值的语义翻转:sashiko-bot 与 Changwoo 都指出
__scx_prolog_disables_migration默认true,但在慢路径里,true会走bpf_get_current_task_btf() != p,对p == current返回false(under-report)。注释说「under-report 会炸调度器」,但代码路径恰恰相反。Tejun 解释true是「对齐 stock pre-v6.18 行为」,但下游 cherry-pick 后 probe 失败就会爆。需明确:默认false才让 fallback 真的返回true。 - sleepable kfunc 不适用:注释明确
SEC("fentry.s/...")、BPF_STRUCT_OPS_SLEEPABLE、SEC("syscall")不走 prolog 改写路径,误用会在p == current处假阴性。 - rq clock stale-read:
scx_clock_task/pelt文档化了 idle CPU 上的 stale 行为,调用方不能在远端 idle CPU 上做时间差估算,否则窗口接近 0。 __COMPAT_scx_bpf_cpu_curr顺序:先bpf_ksym_exists(scx_bpf_cpu_curr),回退到scx_bpf_cpu_rq,意味着调度器要能在 v6.18 之前/之后都跑。
版本变化
- 这是同步性 patchset,没有 vN→vN+1 的演进;改动来源是 scx 仓库的累积差异。
- 评审回复指出 1/2 系列的
enum_defs.autogen.h同步本身没有 review 反馈记录(无人直接评论 patch 1)。
一句话总结
把 scx 仓库里关于 64-bit enum 回查、v6.18+ prolog 探测、scx_bpf_cpu_curr 兼容、rq clock stale-read 文档化的修复反向同步进 tools/sched_ext/include/scx/,但默认值的语义与 fallback 行为仍需在后续版本里对齐注释。