sched-ext discussion
[PATCH] tools/sched_ext: Extend the prolog migration probe to cid-form schedulers
LLM 分析
sched_ext:扩展 prolog 迁移探测以覆盖 cid-form 调度器
系列概况
- 标题:[PATCH] tools/sched_ext: Extend the prolog migration probe to cid-form schedulers
- 作者:David Carlier devnexen@gmail.com
- 版本:单封 PATCH(无 v 编号),由 maintainer 转为走 scx 仓库流程
- 规模:2 文件变更,+32 / -24
- 修改文件:
tools/sched_ext/include/scx/common.bpf.h、tools/sched_ext/include/scx/compat.h - 代码统计:
common.bpf.h53 行变更;compat.h3 行新增(一个__SCX_OPS_OPEN宏片段) - Message-ID:
20260829122035.58018-1-devnexen@gmail.com(回复:d6cfdbdd795ef5b4c546fa8eddc6ad23@kernel.org) - 完整性:单封 PATCH + 一封 Tejun Heo 回复(建议转到 scx 仓库,并指出默认值的翻转已在 888a907d84b5 合入)
补丁目的
sched_ext 的 tools 侧头文件里有一个静态标志 __scx_prolog_disables_migration,用来告诉 is_migration_disabled() 当前 task 在非睡眠 BPF prolog (__bpf_prog_enter) 之后是否真的处于禁止迁移状态。原来这个标志只通过一个 fentry probe 挂在 bpf_scx_reg() 上。
但自从 v7.2 之后,kernel 新增了 cid-form 调度器,对应 bpf_sched_ext_ops_cid,它的 .reg 回调指向另一个函数 bpf_scx_reg_cid(),于是原 probe 永远不会触发——标志位就只能保留编译期默认值。这会让 is_migration_disabled(current) 给出错误答案,进而导致本应可以跨 CPU 分派的任务被错误地限制在本地队列上。
补丁要做两件事:
- 给
bpf_scx_reg_cid()同样挂一个 probe; - 把
__scx_prolog_disables_migration的默认值从true(保守)改为false,让未挂 probe 的 loader 行为与注释描述的 safe 方向一致。
旧流程的问题
struct_ops link created |
v
+-------------------+
| bpf_scx_reg() | <----- cpu-form: enters here
+-------------------+
|
fentry probe fires
|
v
__scx_prolog_disables_migration = true
(default = true, kept forever)
cid-form path:
bpf_sched_ext_ops_cid.reg -> bpf_scx_reg_cid()
(a SEPARATE function, no probe attached)
-> flag stays at compile-time default
-> is_migration_disabled(current) returns stale value
旧代码假设所有调度器都从 bpf_scx_reg() 入口经过。cid-form 调度器走的是 bpf_scx_reg_cid(),所以 probe 不触发;默认值 true 让所有未触发 probe 的路径都"看起来"已经禁迁移,与注释里说的 safe 方向(over-reporting)刚好相反——准确地说,原作者用 true 兜底是为了避免 under-reporting 引发的崩溃,但代价是把 cid-form 路径悄悄错误地标记成"已禁迁移"。
新流程
struct_ops link created
|
+-------+-------+
| |
v v
bpf_scx_reg() bpf_scx_reg_cid() (cid-form, since v7.2)
| |
fentry probe ?fentry probe
| |
+-------+-------+
|
v
__scx_record_prolog_migration()
|
v
__scx_prolog_disables_migration = (md > 0)
Loader that never attaches any probe:
default flag = false
-> is_migration_disabled(current) returns false
-> over-reporting side -> safe (matches comment)
新代码把两个 probe 共用同一个 body __scx_record_prolog_migration(),避免逻辑漂移。cid-form probe 用 ?fentry/... 形式,让 libbpf 在找不到符号时跳过 attach;__SCX_OPS_OPEN() 通过 __COMPAT_has_ksym("bpf_scx_reg_cid") 决定是否启用该 program 的 autoload。
关键实现
common.bpf.h 的核心变化:
/* body shared by both probes */
static __always_inline void __scx_record_prolog_migration(void)
{
if (bpf_core_field_exists(
((struct task_struct *)0)->migration_disabled)) {
const struct task_struct *p = bpf_get_current_task_btf();
__scx_prolog_disables_migration = md > 0;
}
}
SEC("fentry/bpf_scx_reg") __weak
int scx_lib_init_probe(void *ctx)
{
__scx_record_prolog_migration();
return 0;
}
SEC("?fentry/bpf_scx_reg_cid") __weak
int scx_lib_init_probe_cid(void *ctx)
{
__scx_record_prolog_migration();
return 0;
}
注意 __weak:fentry program 自身不能内联,必须保留符号;但即便如此,编译器仍允许该函数被复制到多个翻译单元里(这里是 common.bpf.h,被多个 BPF skeleton 共享),所以通过 __weak 避免链接冲突。__scx_prolog_disables_migration 同样声明为 __weak。
compat.h 里通过 __SCX_OPS_OPEN 宏启用 cid probe 的 autoload:
if (__COMPAT_has_ksym("bpf_scx_reg_cid"))
bpf_program__set_autoload(
(__oskel)->progs.scx_lib_init_probe_cid, true);
默认值翻转:
- bool __scx_prolog_disables_migration __weak = true;
+ bool __scx_prolog_disables_migration __weak;
注释里特意强调:prolog 至多给 migration_disabled 加 1;如果读到 >1,说明上游 bpf_struct_ops_link_create -> bpf_scx_reg{,_cid} 路径里有人在 prolog 之前禁了迁移,结果不可信——这条警告留给上游路径审计。
类比
把 bpf_scx_reg() 和 bpf_scx_reg_cid() 想象成两扇不同的大门:
bpf_scx_reg()是 cpu-form 顾客进商场走的那扇正门,门口保安(probe)会在每位顾客胸口贴一张"本层禁换"标签;bpf_scx_reg_cid()是 cid-form 顾客走的后门,原来根本没有保安,所以这些顾客出来时都没有标签;is_migration_disabled()就是商场广播:看到标签就广播"请勿换层",没标签就广播"可换层"。
旧实现里后门顾客默认被贴了"本层禁换"标签(保守,但与注释里说的 safe 方向相反),其实是不准确的。新补丁在后门也安了保安,并要求后门没保安时统一贴"未贴标签"——这样广播才能正确决定该不该让顾客换层,避免把后门顾客错误地限制在本层。
Highlight:风险与注意点
- probe attach 失败的 fallback:把默认值改为
false后,任何不挂 probe 的 loader 都会走 over-reporting 安全路径;如果未来 cid-form probe 在某些 libbpf 版本上?fentry解析失败,需要在 loader 端验证 autoload 实际成功。 migration_disabled累积问题:注释提到 "adds at most 1",但代码判断是md > 0。如果在bpf_struct_ops_link_create -> bpf_scx_reg{,_cid}路径里有人先migrate_disable(),会出现md > 1,此时整个标志不可信——这条警告需要后续真的有人踩到再决定是否需要 abort 而不是继续用。- Tejun 已经把默认值翻转提到 scx 仓库:commit
888a907d84b5已经处理默认值变更,作者应当把整个 patch 重新基于 scx 仓库发送,避免在 kernel 镜像上重复提交。 SEC("?fentry/...")行为依赖 libbpf 版本:旧版 libbpf 可能忽略前缀?而直接尝试 attach 失败,需要确认仓库 CI 用的是较新版本。
一句话总结
为 sched_ext 工具头文件中的 prolog 迁移探测补上 cid-form 调度器的入口 bpf_scx_reg_cid(),并将默认标志翻为 false 使其在未挂 probe 时落到注释声明的 safe 方向;maintainer 要求改走 scx 仓库提交。