Linux 内核调度子系统周报(2026-07-20 ~ 2026-07-26)
本期重点
- 1. proxy execution 与 sched_ext 共存一周迭代 v8→v9——Andrea Righi 在上期 v7 基础上连发两版,v9 引入 incoming-class
prepare_switch() callback 阻断 retained donor 进入 sched_ext、per-rq reject DSQ 泛化用于 proxy-raced remote transfer(取代弹到 global DSQ)、ops.tick() 记账限定在 tracked session 内。 - 2. sched_ext exit 处理改为 NMI-safe——Tejun Heo 的 5 补丁系列让 exit claiming 改 lock-free、bstr exit 顺序反转成 claim-first,使
scx_bpf_error()/scx_bpf_exit() 能从 NMI 安全调用,hardlockup handler 改为直接从 NMI abort 调度器。 - 3. cap rejection 的 reenqueue 循环被加上限——故障调度器反复把任务 reenqueue 到缺 cap 的 cid 会自激 reenqueue irq_work、阻塞 stall 检测直到 NMI hardlockup。Tejun Heo 加 per-task
reenq_cnt,超限 eject owning scheduler。 - 4. cluster scheduling 在 big/small 非对称拓扑下修复到 v6——Ricardo Neri 的 6 补丁系列修复负载均衡在 big core + small core cluster 拓扑下无法跨 small cluster 均衡的五个问题,已拿 Vincent Guittot Reviewed-by。
- 5. sub-scheduler 与 cid 进入密集收尾——本周 Tejun Heo 发出 follow-up + cap enforcement(新增
SCX_CAP_PERF)、sub-scheduler/cid fixes(stall 归责 DSQ owner、bypass 跳过默认 CPU selection、cid 表未分配保护)、sparse 标注清理三个系列,stale errno 补丁 v2 apply 到 for-7.3。
一、核心进展
proxy execution 与 sched_ext 共存:一周 v8→v9
[1]
上期 v7 把 scheduler-facing kfuncs 统一报告 donor、NOHZ bandwidth 跟 rq->donor、kselftest 加 cross-CPU topology(设计见上期周报一、)。本周 v8(7 月 21 日)、v9(7 月 25 日)连发两版,改动集中在 donor 生命周期与迁移路径的边界。(Andrea Righi,v9 系列)
v8 的关键变更:remote-DSQ migration check 重做,locked re-check 只处理 proxy-exec 状态变化;处理无 SCX_OPS_ENQ_BLOCKED 的 scx 调度器下 blocked-donor 的 reactivation(John Stultz);补 proxy-exec 下 sched_ext callback 行为文档(sashiko);加 prep fix 避免 proxy-exec 移动 migration-disabled donor 时的误告警;scx_qmap 避免把 rejected blocked donor redispatch 回同一 local DSQ。
v9 的关键变更:新增 incoming-class prepare_switch() callback,用它阻断 retained donor 在转入 sched_ext 的过渡(Tejun Heo);把 per-rq reject DSQ 泛化,用于 proxy-raced remote transfer,取代之前把任务弹到 global DSQ 的做法(Tejun Heo);migration-disabled warning 例外只限于调度上下文确实被 proxy 迁移的 blocked donor(sashiko);ops.tick() 和其他 donor 记账限定在 tracked ops.running()/ops.stopping() session 内(sashiko);阻止 BPF 定向迁移 active proxy donor,restore 时用 donor 作 current 调度上下文(sashiko);sched_fair_update_stop_tick() 改用 queued FAIR 任务数(sashiko)。[1]
系列内含的 consume_remote_task TOCTOU 修复(上期报告的 patch 05/11)在 v8/v9 持续细化——remote CPU 检查从 lockless 扫描移出,只在锁源 rq 后做,locked migration recheck 紧贴任务移动前。
sched_ext:exit 处理改为 NMI-safe
[2]
exit 路径此前不是 NMI-safe:exit claiming 在 scx_sched_lock 下遍历子调度器层级,bstr exit kfuncs 在 raw spinlock 下把消息格式化进共享 buffer。"any" 类别的 kfuncs 可被 tracing 程序调用,而 tracing 程序能 attach 到 NMI 中运行的函数,其中很多在输入非法时 raise scx_error()——这样一个不慎的坏参数就可能死锁整机。hardlockup handler 有同样问题,此前把 abort 推迟到 irq_work,而 irq_work 无法在检测到 lockup 的 CPU 上运行。(Tejun Heo,5 补丁系列)
系列让 exit 处理端到端 NMI-safe:
patch 0001 让 exit claiming lock-free。->aborting 用同步 lockless sweep 断言(RCU 下扫节点存 ->aborting 再读 children,与 scx_link_sched() 的 insert-then-check-parent-->aborting 配 full barrier 配对,一侧总能看到另一侧),locked 的 SCX_EXIT_PARENT 传播推到新 irq_work,两者都 NMI-safe。因 undo 的 list_del_rcu() 留下非空 ->sibling,teardown 不能再用 list_empty() 识别从未 link 的 sched,改用 sch->linked。NMI exit 时跳过 exit backtrace(stack_trace_save() 的 NMI 安全性 arch 依赖且无文档)。
patch 0002 反转 bstr exit 顺序为 claim-first,消息直接格式化进 winner 拥有的 exit_info buffer。这两条合起来让 scx_bpf_error() 和 scx_bpf_exit() 从任何上下文(含 NMI)安全。
patch 0003-0005 应用新可能的直接错误上报:NMI kick 改为 abort 调度器而非静默丢弃;hardlockup handler 直接从 NMI abort,使自检 lockup 可恢复;scx_link_sched() 内联报告失败。[2]
sched_ext:cap rejection reenqueue 循环加上限并 eject owning scheduler
[3]
与 local reenqueue 不同,cap rejection 没有重复上限。故障调度器可持续把任务 re-insert 到它缺 cap 的 cid,让任务在 reject 和 reenqueue 间循环。此前认为这安全——从不运行的任务会触发 stall watchdog。但 reenqueue irq_work 自重装且优先级高于 timer vector,会阻塞 CPU 上其他一切(含 stall 检测和恢复),直到 NMI hardlockup detector 触发。
local reenqueue 此前已有重复上限 SCX_REENQ_LOCAL_MAX_REPEAT,但 per-cpu 在 root 计数,子调度器拥有的 bounce 会拆掉整个层级。补丁把每个 reenqueue 用一个 per-task 计数器统一约束:reenq_cnt 在 scx_do_enqueue_task()(所有 reenqueue 生产者经过的唯一漏斗)里对每个 SCX_ENQ_REENQ 递增,任务被 pick 运行时在 clr_task_runnable() 清零。超 SCX_REENQ_MAX_REPEAT 后任务的 owning scheduler 以新 SCX_EXIT_ERROR_REENQ eject,任务滞留待 sched exit 时收尾。事件 SCX_EV_REENQ_LOCAL_REPEAT 改为 SCX_EV_REENQ_REPEAT,统计所有来源的 reenqueue。(Tejun Heo,v3 系列)[3]
cluster scheduling:非对称容量拓扑下修复跨 cluster 均衡
[4]
cluster scheduling 旨在把负载分散到共享中间级资源的 CPU cluster,在均匀系统上工作正常,但在 big/small cluster 拓扑上失效。典型拓扑:两个 big core(各带 L2)+ 两组 small core cluster(每组四个 small core 共享 L2,全体共享 L3)。部分忙碌系统上,非对称容量调度确保 misfit 任务落到 big core,剩余任务(misfit 与否)应在 small CPU cluster 间均衡,但 CONFIG_SCHED_CLUSTER 启用时实际不发生。
负载均衡器有几个问题阻止一个 cluster 的 small CPU 从另一个 cluster 拉任务:update_sd_pick_busiest() 可能选 per-CPU 容量更高的 fully_busy 组为 busiest,挡住等容量 fully_busy 组;misfit-load 统计用于识别该迁到大核的任务,但目标 CPU 同样小时毫无意义且阻断 cluster 间均衡;真正的 has_spare/fully_busy 组被误判为 misfit_task 而被跳过;sched_balance_find_src_rq() 拒绝向等容量 CPU 迁移;非对称容量域缺 SD_PREFER_SIBLING flag。
系列逐个解决并恢复预期行为。v6 的主要变化:把 SD_PREFER_SIBLING flag 恢复给所有非对称容量的调度域(不止有 cluster 子域的,Vincent 建议);patch 5 用 get_actual_cpu_capacity() 取代 arch_scale_cpu_capacity() 识别等容量 cluster,以计入硬件和 cpufreq 压力(Vincent 建议)。作者在 Alder Lake(SMT Pcore + Ecore cluster,SMT 开关都测)、Lunar Lake、Panther Lake(Ecore cluster 不连 L3)上测试,Christian 在合成 arm64 qemu 拓扑、Andrea 在 Vera Rubin(arm64)上验证无回归。已拿 Vincent Guittot Reviewed-by。(Ricardo Neri / Intel,v6 系列)[4]
sched_ext:sub-scheduler 与 cid 的 follow-up 收尾
capability v5 之后(上期转入 follow-up 阶段),本周 Tejun Heo 发出三个收尾系列。
Follow-up fixes and missing cap enforcement(5 补丁):patch 0001 修工具的 restart 循环覆盖 pending exit——工具在内核以 SCX_ECODE_ACT_RESTART 退出调度器时重启,重启决策不查 exit_req,restart 条件持续时到达的 exit 请求被忽略、工具紧循环 reload;patch 0002 给 local DSQ reenq 加 baseline cid 访问检查并计数;patch 0003 计数因缺 baseline cid 被拒的 kick;patch 0004 抽出 scx_cpuperf_set();patch 0005 新增 SCX_CAP_PERF(默认只 root 持有),scx_bpf_cidperf_set() 经新版本化接口同步报告结果(其检查在目标 rq 锁下是权威的)。这些检查 lockless——cap rotation 的瞬态 false positive 无害、false negative 按可见性不会发生。[5]
Sub-scheduler and cid fixes(3 补丁):runnable stall 归责 DSQ owner 而非任务 owner(子调度器层级下任务可能卡在别的调度器负责排空的 DSQ 上,如祖先的 bypass DSQ);bypass 时跳过默认 CPU selection(pick 反正被 bypass enqueue 丢弃,且会查对做自己的 idle tracking 的调度器而言已冻结的 idle mask);cid kfuncs 防 cid 表未分配(程序可在首个调度器 enable 的竞争中撞上)。[6]
Sparse annotation cleanups:sparse 扫 kernel/sched/ext 标出用 plain load 读的 __rcu 指针,读都受调用上下文保护但没说明如何。加 accessor 编码保护方式(如 scx_cgroup_sched() 声明稳定关联的锁)并转换 reader。[7]
二、重要 Bug 修复
sched_ext:WAKE_SYNC 选到 waker CPU 时不标 busy
[8]
【问题】sched_ext 内建 idle CPU 跟踪不完美,可能与实际 idle 状态失同步(启用 SCX 后立即尤为明显,因 scx_idle_enable() 把所有在线 CPU 标 idle)。scx_select_cpu_dfl() 在 SCX_WAKE_SYNC 情况下若选中的 CPU 是 waker CPU,就跳过标 busy。若 waker CPU 被 SCX 标为 idle,CPU selection 后、甚至切到 wakee 后它仍被标 idle。allowed_cpus selftest 因此报 "CPU 0 should be marked as busy"。
【修复方案】显式标 waker CPU 为 busy。补丁后该测试失败不再复现。仍存在一些较不可能的竞态(如 pick_task_idle() 在 selection 和 validation 间把选中 CPU 标 idle)。
【影响范围】for-7.2-fixes。(Kuba Piecuch)
sched_ext:selftest allowed_cpus 的 idle 校验改 race-free
[9]
【问题】远程选中的 CPU 可在 BPF 程序校验 selection 前被 idle-to-idle re-pick 重新广播为 idle,检查"选中 CPU 仍不在 idle mask 中"本身有竞态。
【修复方案】改校验稳定的本地不变量:ops.select_cpu() 中运行非 idle 调度上下文的 CPU 不得被广播为 idle。同时校验选中 CPU 的请求域和任务亲和。启动阶段在每个 active CPU 跑任务、ops.running() 刷新初始 idle 状态,确保严格校验前 idle mask 已正确初始化。(Andrea Righi)与上条 waker CPU busy 修复配合,共同解决 allowed_cpus 测试的 idle 跟踪失同步。
CPU freeze 在 isolcpus=domain 下崩溃(RFC)
[10]
【问题】suspend 时 freeze_secondary_cpus() 把除 primary 外每个 CPU 置 offline。配合 domain 隔离(isolcpus=domain,0,3-31,primary 是 CPU0,HK_TYPE_DOMAIN 只剩 CPU1/CPU2),offline 掉最后一个 domain housekeeping CPU 后冻结的热插拔路径在该 mask 内无 active CPU。
【根因】三个相关问题:frozen cpuset 回调请求一个 fallback scheduler domain,即便其 span 为空;受限于被冻结 CPU 的用户任务会耗尽 select_fallback_rq()(正常 fallback mask 无 active CPU);强制这类任务到临时 CPU 会清掉 user_cpus_ptr,使临时亲和在 CPU 恢复后仍存活。复现:CPU2 offline 后为 CPU1 重建 sched domain 产生空 span warning,随后 build_perf_domains() 通用保护错误。
【修复方案】系列在冻结 CPU fallback 期间保留并恢复用户亲和;允许一个 isolated 但具备任务能力的 active CPU 作临时最后手段;无 active HK_TYPE_DOMAIN CPU 时显式拆除 scheduler domain。作者标 RFC,征求对任务跟踪/恢复方案、task_cpu_possible_mask() 作临时 fallback、显式零域请求 partition_sched_domains() 的意见。(Guopeng Zhang / 麒麟)
sched_ext:sub-enable 路径 stale errno v2 apply 到 for-7.3
[11]
上期 w29 报告的 stale errno 补丁(scx_sub_enable_workfn() 的 validate_ops() 等路径 ret 未赋值)本周 v2 被 Tejun Heo apply 到 sched_ext/for-7.3。v1 的 validate_ops() 路径 for-7.3 已修(sub.c 已有 ret = scx_validate_ops()),v2 只处理剩余两条:nesting depth 检查设 -EINVAL、cgroup online 检查设 -ENODEV。(Cui Jian)
三、sched_ext 进展
核心功能演进
本周核心演进的主线是上面三节展开的 proxy execution v8→v9、NMI-safe exit、cap rejection reenqueue 上限。承接上期判断——sched_ext 在朝"层级化、可在子调度器间按 capability 划分 CPU、并能与 proxy execution 共存"走——本周的改动集中在让这套模型在错误路径(NMI、故障 reenqueue、cap enforcement 缺口)下保持健壮。
proxy execution v8→v9 补的是 donor 与 owner 并存时更多核心路径的边界:incoming-class prepare_switch() 阻断过渡、per-rq reject DSQ 取代把任务改道到 global DSQ、ops.tick() 记账限定 tracked session。这些是把上期 v7 确定的"函数调用"抽象在 tick、迁移、class 转换这些路径上对齐。
NMI-safe exit 和 cap rejection reenqueue 上限属于"调度器自身出错时的安全网":前者让任意上下文(含 NMI、hardlockup)能安全 abort 调度器,后者防止故障调度器的 reenqueue 自激阻塞 stall 检测。两者都是 capability/proxy-exec 模型落地后暴露的失败模式处理。
稳定性修复
本周稳定性修复分三块:for-7.2-fixes 候选(WAKE_SYNC waker CPU busy、allowed_cpus race-free selftest、numa test affinity),见二、;exit 与 reenqueue 的安全网(见一、);sub-scheduler/cid 的边界修复(stall 归责、bypass 跳过 CPU selection、cid 表未分配保护,见一、)。
生态与工具改进
scx_pair: Convert to sched_switch TP(Cheng-Yang Chou)——上期已报告,本周延续。ops.cpu_acquire/release() 已废弃,改用 tp_btf/sched_switch 程序边沿检测同样转换,消除加载时的废弃告警。[12]
selftests/sched_ext: build BPF schedulers via shared lib.bpf.mk(v2 4/4)——selftest 的 BPF 调度器改用共享的 lib.bpf.mk 构建。[1]
sched_ext: repair kernel-doc comments(Randy Dunlap)——补 finish_dispatch、scx_rcu_cpu_stall、scx_hardlockup 缺失的参数描述,修函数名,消 kernel-doc warning。[13]
Fix incorrect SCX_PICK_IDLE_CPU_ flag prefix in kernel-doc*(Liang Luo,KylinOS)——pick-idle kfuncs 的 flag 来自 scx_pick_idle_cpu_flags 枚举(前缀 SCX_PICK_IDLE_),kernel-doc 误标为 SCX_PICK_IDLE_CPU_*。[14]
tools/sched_ext/include: Regenerate enum_defs.autogen.h——cap rejection reenqueue 补丁把 SCX_REENQ_LOCAL_MAX_REPEAT 改为 SCX_REENQ_MAX_REPEAT 后,工具头重新生成。[15]
四、工具链与调试
perf sched: Suppress latency table output when trace samples are missing(Aaron Tomlin,v1→v2→v3)——perf sched latency 在不含 tracepoint sample 的 perf.data 上,perf_session__has_traces() 正确报错,但 perf_sched__read_events() 随后 fall through 返回 0,调用方 perf_sched__lat() 误以为成功并渲染空的 latency 表头。补丁在缺 trace sample 时抑制表输出。[16]
cpufreq: schedutil: Publish util hooks only after all sg_cpu initialized(Zhongqiu Han,高通)——上期 w29 已报告,本周延续。shared cpufreq policy 上 sugov_start() 合并初始化循环引入 sugov_update_shared() 与兄弟 CPU memset 的数据竞争。Fixes: 16a03c71bba0,Cc: stable。[17]
cpufreq: schedutil: Replace sprintf() with sysfs_emit() in sysfs show(Zhongqiu Han,高通)——rate_limit_us_show() 的 sprintf() 换 sysfs_emit(),提供 PAGE_SIZE 边界检查。无功能改动。[18]
sched: Update the THREAD_INFO_IN_TASK description(Huacai Chen,龙芯,v2)——THREAD_INFO_IN_TASK 在 4.9 引入时只支持 x86 且 thread_info 只有 flags 字段,Kconfig 描述说 thread_info 只该有 flags 字段但未解释原因。arm64 后续 split thread_info,描述需更新以反映 thread_info 可含更多字段。[19]
sched: fix two misspellings(Jiangong.Han,Wind River)——include/linux/sched.h 一个拼错单词和一个函数名 typo。[20]
五、下周关注点
- 1. proxy execution + sched_ext v9 之后——v9 把
prepare_switch()、per-rq reject DSQ、ops.tick() tracked session 对齐后,Peter Zijlstra 是否接受函数调用模型;consume_remote_task TOCTOU 在 v8/v9 的细化是否解决上期 sashiko AI 标出的 lost wakeup 和 fallback 链表腐败两个 High 风险。 - 2. NMI-safe exit 与 cap rejection reenqueue 的合入——两个系列都是 capability/proxy-exec 模型落地后的安全网,关注是否进
for-7.3,以及 hardlockup handler 直接从 NMI abort 在实机上的表现。 - 3. cluster scheduling v6 的合入——已拿 Vincent Reviewed-by 且多平台验证,关注是否进 tip 树,以及
SD_PREFER_SIBLING 恢复给所有非对称容量域对其他拓扑的影响。 - 4. CPU freeze RFC 的反馈——
isolcpus=domain 下 suspend 崩溃的修复涉及 task 跟踪/恢复和零域请求,作者明确征求方案意见,关注 cgroup/cpuset maintainer 的回应。 - 5. sub-scheduler 收尾系列的合入路径——follow-up + cap enforcement、sub-scheduler/cid fixes、sparse cleanup 三个系列本周齐发,关注哪些进
for-7.3、哪些回填 for-7.2-fixes。
引用链接
[1] 原文: https://lore.kernel.org/all/20260725160513.57477-1-arighi@nvidia.com/
[2] 原文: https://lore.kernel.org/all/20260725005019.1297049-1-tj@kernel.org/
[3] 原文: https://lore.kernel.org/all/7f80005b54904a9a037822c2df5bcbc2@kernel.org/
[4] 原文: https://lore.kernel.org/all/20260720-rneri-fix-cas-clusters-v6-0-bb500bf4afd4@linux.intel.com/
[5] 原文: https://lore.kernel.org/all/20260724182125.985061-1-tj@kernel.org/
[6] 原文: https://lore.kernel.org/all/20260720082605.1451945-1-tj@kernel.org/
[7] 原文: https://lore.kernel.org/all/20260724012914.107823-1-tj@kernel.org/
[8] 原文: https://lore.kernel.org/all/20260722143307.2772632-1-jpiecuch@google.com/
[9] 原文: https://lore.kernel.org/all/20260726064754.378671-1-arighi@nvidia.com/
[10] 原文: https://lore.kernel.org/all/20260722115238.351821-1-guopeng.zhang@linux.dev/
[11] 原文: https://lore.kernel.org/all/2434032013e3edae6ea0548db08006fc@kernel.org/
[12] 原文: https://lore.kernel.org/all/20260719142917.34238-1-yphbchou0911@gmail.com/
[13] 原文: https://lore.kernel.org/all/20260723173118.327466-1-rdunlap@infradead.org/
[14] 原文: https://lore.kernel.org/all/20260724080824.2483100-1-luoliang@kylinos.cn/
[15] 原文: https://lore.kernel.org/all/20260726220016.D958B1F000E9@smtp.kernel.org/
[16] 原文: https://lore.kernel.org/all/20260724142901.634761-1-atomlin@atomlin.com/
[17] 原文: https://lore.kernel.org/all/20260716115159.848403-1-zhongqiu.han@oss.qualcomm.com/
[18] 原文: https://lore.kernel.org/all/20260716131546.1159644-1-zhongqiu.han@oss.qualcomm.com/
[19] 原文: https://lore.kernel.org/all/20260609031924.97092-1-chenhuacai@loongson.cn/
[20] 原文: https://lore.kernel.org/all/20260720010027.4020911-1-jiangong.han@windriver.com/