sched-ext discussion
[PATCHSET v7 sched_ext/for-7.3] sched: Make proxy execution compatible with sched_ext
LLM 分析
sched: Make proxy execution compatible with sched_ext
系列概况
- 标题: [PATCHSET v7 sched_ext/for-7.3] sched: Make proxy execution compatible with sched_ext
- 作者: Andrea Righi arighi@nvidia.com(基于 John Stultz jstultz@google.com 早期工作)
- 版本: v7(cover letter 含 v1-v6 全部前序链接)
- 规模: 11 patch + cover letter + 21 回复 = 33 邮件
- 修改文件: kernel/sched/{core.c,sched.h,syscalls.c}, kernel/sched/ext/{ext.c,ext.h,internal.h,sub.c,sub.h}, include/linux/sched/ext.h, init/Kconfig, tools/sched_ext/{scx_qmap.bpf.c,scx_qmap.c,scx_qmap.h}, tools/testing/selftests/sched_ext/{enq_blocked.bpf.c,enq_blocked.c,Makefile,.gitignore,config}
- 代码统计: core.c ±27;ext.c 累计 ~±200;scx_qmap +45/-21;selftest ~900;init/Kconfig -2
- Message-ID: 20260716132229.61603-1-arighi@nvidia.com
- 完整性: 完整——cover + 11 patch + 多轮 maintainer/作者/Sashiko-bot 交互
补丁目的
让 CONFIG_SCHED_PROXY_EXEC=y 与 CONFIG_SCHED_CLASS_EXT=y 不再构建期互斥,让发行版可发一份镜像按需启用。
proxy-exec 让 mutex waiter(donor)把自身调度上下文让给 owner,让 owner 以 donor 的优先级/时间片跑临界区。sched_ext 由 BPF 自己调度(vtime/DSQ/who-is-running),core 突然把 BPF 未 dispatch 的 owner 跑在 rq 上,会让 kfunc/helper 看到与 BPF 视角不一致的 current。任务以错误 IRQ/preempt 状态 resume,触发 sleeping-while-atomic 与 lockdep 损坏。
旧流程的问题
- NOHZ CFS bandwidth tick 仍检
rq->curr且要求nr_running==1;retained FAIR donor 不在路径上 → tick 错停,runtime 未 enforce。 consume_remote_task()在 DSQ lockless scan → 源 rq lock 的 handoff 窗口里,task 可能因 proxy-exec 在源 rq 上 on-CPU(task_on_cpu/migration_disabled已变)但holding_cpu仍指旧 CPU。set_next_task_scx()在 donor 被选中时调ops.running(),随后put_prev_task_scx()又调ops.stopping(),但 donor 自己不实际执行 → callback 配对虚假。- 两特性构建期互斥。
新流程
- 新 ops flag
SCX_OPS_ENQ_BLOCKED:BPF 显式声明接管 blocked donor,需实现ops.enqueue()。 scx_allow_proxy_exec(p):非 EXT 一律允许;EXT 看sch->ops.flags & SCX_OPS_ENQ_BLOCKED。__schedule()中task_is_blocked(prev)不再强制 block。sched_can_stop_tick()改检rq->donor,去掉nr_running==1限制。consume_remote_task()在拿到源 rq 锁后用task_can_move_from_locked_rq()再验;失败时 fall back 到 global DSQ(非 BPF 错误)。- 新
SCX_TASK_RUN_TRACKED标志:donor 走 proxy 时不调 running/stopping;真跑时设上、离开时清掉。 - 调度类切换(
sched_setscheduler/ PI de-boost /scx_root_enable)调sched_proxy_block_task()把 retained donor 退回普通 block 路径。 - core 簿记口径统一:
rq->donor是"被调度器看到的 current scheduling context";rq->curr是"正在执行 instruction 的 task"。BPF kfunc 全读rq->donor。 - scx_qmap
-B:blocked donor 拿 fresh slice 插所在 cid 的 local DSQ 头,立即 preempt。 - init/Kconfig 去掉
depends on !SCHED_CLASS_EXT。
Patch 概览
| # | 主题 | 关键改动 |
|---|---|---|
| 01/11 | NOHZ CFS bandwidth 跟 donor | __need_bw_check 用 rq->donor,去 nr_running==1 |
| 02/11 | 加 sched_proxy_block_task() | helper 把 retained donor 从 rq dequeue |
| 03/11 | 调度类切换 block donor | scx_allow_proxy_exec / scx_prepare_setscheduler |
| 04/11 | 修 running/stopping 配对 | SCX_TASK_RUN_TRACKED |
| 05/11 | 修 TOCTOU | 拆 task_can_move_from_locked_rq |
| 06/11 | curr|donor 拆分 | update_curr/task_tick/kfunc 读 donor |
| 07/11 | blocked donor 迁移 | 锁源 rq 时再判;put_prev 放 local DSQ |
| 08/11 | admission 交 BPF | SCX_OPS_ENQ_BLOCKED / SCX_ENQ_BLOCKED |
| 09/11 | selftest enq_blocked | 新 BPF+userspace 测试 |
| 10/11 | scx_qmap -B | demo 策略 |
| 11/11 | Kconfig 解互斥 | 删 depends on !SCHED_CLASS_EXT |
关键实现
/* Patch 03: 默认拒绝 retained EXT donor */
bool scx_allow_proxy_exec(const struct task_struct *p)
{
return p->sched_class != &ext_sched_class;
}
/* Patch 04: SCX_TASK_RUN_TRACKED 单独配对 running/stopping */
if ((p->scx.flags & SCX_TASK_QUEUED) && !p->is_blocked) {
if (SCX_HAS_OP(sch, running))
SCX_CALL_OP_TASK(sch, running, rq, p);
p->scx.flags |= SCX_TASK_RUN_TRACKED;
}
/* Patch 05: 锁源 rq 后再验能否迁移 */
if (unlikely(!task_can_move_from_locked_rq(sch, p, this_rq, false))) {
p->scx.dsq = NULL;
p->scx.holding_cpu = -1;
scx_dispatch_enqueue(sch, src_rq, find_global_dsq(sch, task_cpu(p)),
p, enq_flags | SCX_ENQ_CLEAR_OPSS | SCX_ENQ_GDSQ_FALLBACK);
switch_rq_lock(src_rq, this_rq);
return false;
}
/* Patch 08: BPF 接管 donor admission */
enq_blocked = (sch->ops.flags & SCX_OPS_ENQ_BLOCKED)
&& p->is_blocked && !(enq_flags & SCX_ENQ_WAKEUP);
if (enq_blocked)
enq_flags |= SCX_ENQ_BLOCKED;
+------------------+ blocking on mutex +------------------+
| Donor (D) | <----------------------- | Mutex (M) |
| prio: high | +------------------+
+------------------+ ^
| proxy execution: | held by
| donor's slice/class |
v drives the CPU |
+------------------+ +------------------+
| rq->donor = D | scheduler sees D | Owner (O) |
| rq->curr = O |<-- BPF view: D | prio: low |
+------------------+ +------------------+
^ |
| preempted by | runnable
| v
+------------------+
| Task T |
+------------------+
D's slice / class / priority drive scheduling;
O's instructions execute on the CPU.
类比
proxy-exec 像"借身份办事"。Donor 把银行账户(优先级/时间片)借给 Owner,让 Owner 拿 Donor 的额度去柜台办业务。sched_ext 是柜台经理,原本只认"自己叫号派发的人"。如果没看见 Donor 就看到 Owner 来取钱,会怀疑账户对不上。
SCX_OPS_ENQ_BLOCKED 是经理说:"我现在接受账户借出,请把 Donor 的号也通知我,我来决定要不要现在插队、插哪个柜台。"
rq->donor 是"柜台账面上的客户";rq->curr 是"真站在窗口的人"。经理只信 donor 这本账——Owner 借走期间 BPF 簿记仍按 donor 更新。
Highlight:风险与注意点
- Tejun 关注 TOCTOU 检查语义:未开 proxy-exec 时 DSQ lock + holding_cpu handshake 已能阻止状态变化;新增迁移检查应仅在 proxy-exec 启用时启用并显式说明,避免误导——v8 已按此收窄。
- Sashiko 标"潜在无限 livelock"(Patch 05):fallback 到 global DSQ 后下个 idle CPU 再次 pick 该 task,可能反复重演。需观察 idle CPU 命中率。
- Sashiko 标"缺 TICK_DEP_BIT_SCHED 保护"(Patch 06):跨类 proxy-exec 时远端 NOHZ tick 状态可能错乱。
- John Stultz 提 scx_pair 不设 SCX_OPS_ENQ_BLOCKED 时 donor 仍被走 wakeup 路径(Patch 08):
activate_blocked_waiters()在 owner 醒来后无条件 enqueue donor,触发 WARN_ON。修复方向是在do_activate_blocked_waiter()检scx_allow_proxy_exec()。 - John Stultz 报 scx_qmap BPF 加载 -EACCES:clang 19.1.7 + BPF arena 生成错,迁到 clang 22/23 后正常——环境问题,非代码 bug。
- 调度类切换漏点:retained EXT donor 必须先 dequeue;漏一处(如只走 root enable、不走 sched_setscheduler)会让 donor 带旧 EXT 状态进新 EXT scheduler。
- scx_qmap -B 刻意不公平:demo 时好看但生产部署不能照抄。
版本变化
- v1→v7:v1 起步自 John Stultz 早期工作;Andrea 接手后逐步加入 donor/curr 拆分、
SCX_TASK_RUN_TRACKED、TOCTOU 修复、selftest、scx_qmap -B。 - v7→v8 走向(讨论中浮现):Tejun 要求 TOCTOU 修复合围在 proxy-exec 条件内;John Stultz 的 "distinguish proxy activations from wakeups" 补丁会并入其 sleeping-owner 系列,本系列独立推进。
一句话总结
让 BPF 调度器通过 SCX_OPS_ENQ_BLOCKED 显式接管 mutex-blocked donor 的调度决策,统一 rq->donor/rq->curr 簿记口径,并修补 NOHZ tick、TOCTOU 迁移、running/stopping 配对三处回归,从而把 proxy-exec 与 sched_ext 从互斥改成可同开的两个特性。