ext_*.c 平铺在 kernel/sched/ 下用前缀代替子目录,Linus 称其 disgusting。Tejun 承诺下个 cycle 重组,周末提交把源码移到 kernel/sched/ext/ 并去掉 ext_ 前缀的补丁。原文[2]7eab73b18630e)后写操作 defer 到 nbcon 线程,主线已无此问题,仅剩 -stable。Petr Mladek 说明根因是 legacy console 运行在 semaphore(console_lock)下、console_unlock() 中 wake_up_process()。Peter Zijlstra 重申反对 printk_deferred。原文[3]sched_class == &fair_sched_class 判断,只剩一条 !busiest->curr->on_rq 跳过 active balance。18 核 300 秒测试里 1839 次 fair && !on_rq 触发失败 1791 次(97.4%)。原文[4]need_freq_update 在 adjust_perf 路径泄漏——Zhongqiu Han(高通)发现 sugov_update_single_perf() 不走 sugov_update_next_freq(),标志位永不清。自 commit 75da043d8f88 后该标志使 sugov_should_update_freq() 永远返回 true,intel_pstate/amd-pstate passive 模式下 cpufreq_driver_adjust_perf() 在持 rq->lock 时每次利用率更新都被调用,限流失效。一行修复,已作为 7.2-rc 材料合入。原文[5]原文[1]
Tejun Heo 6 月 15 日发出 v7.2 pull request,本周三(6/17)被 Linus 合入。共 29 个文件、+4090/-704,围绕一个方向:把 dispatch 路径在 7.1 打下的 sub-scheduler 基础设施继续推进,目标是让一个 root BPF 调度器能把工作委托给嵌套的子调度器。本周期补上绝大部分基础设施。
四部分:
(start, length) 切片。原始 CPU 编号稀疏又不反映拓扑邻近,拿来给 sub-scheduler 分片、在 BPF 里用都很别扭。新增 kernel/sched/ext_cid.c(707 行)和 ext_cid.h(271 行)。NR_CPUS cpumask。bpf_sched_ext_ops_cid struct_ops 变体和配套的 cid-form kfunc,cid-form 调度器注册它;cpu-form kfunc 被禁止用于 cid-form 调度器。kernel/sched/ext_arena.c(131 行)和 arena 子分配器。scx_qmap 大改(890 行)来实际跑这套 arena + cid 接口:globals 和 cpu_ctx 挪进 BPF arena map,task_ctx 进 arena slab,FIFO queue map 换成 arena-backed 链表,加上 cmask-based idle tracking 和 cid-based idle pick。exit-dump 也改进了——先 dump 触发退出的 CPU、把 exit_cpu 暴露给 BPF 和用户态、规范化 dump header。
原文[2]
Linus 合入 v7.2 的回复只盯着一处:diff 末尾那串新建的 ext_arena.c、ext_cid.c、ext_types.h。他的态度很直接——用文件名前缀代替子目录是错误的,子目录存在的意义就是把相关文件归到一起、把不相关的分开。尽管如此他还是把这批改动拉进了树,只是明说 under protest,并提醒分层文件系统 1965 年就有了。
Tejun 当场认账,承诺下个 cycle 重组。周末(6/21)他就提交了 Move sources under kernel/sched/ext/[6],把十个平铺的 ext_* 文件挪进新建的 kernel/sched/ext/ 子目录,去掉冗余的 ext_ 前缀(ext.c/ext.h 保留原名)。sashiko-bot 顺手挑出几处注释里残留的旧文件名引用(ext_cid.c → cid.c)。
原文[7]
Shrikanth Hegde(IBM)的 20 补丁系列推到 v4。场景是虚拟化下的 steal time:客机被 hypervisor 偷走的 CPU 时间占比高时,继续往这些 vCPU 上塞任务就是浪费。他的思路是用一个 cpu_preferred_mask 维护"当前可用"的 CPU 子集,周期性采样 steal time,按阈值增减 preferred CPU,wakeup 与 load balance 都只在 preferred CPU 间进行,被标为 non-preferred 的 CPU 上跑的任务尽量 push 走,并在任务清完前保持 tick。
v4 相对 v3 的几个收口动作:preferred 集合改为 active(在线且可调度)的子集而非 online 的子集(K Prateek Nayak、Peter Zijlstra 的意见);砍掉 RT 补丁;认定通用的 sched_ext 改动没意义,相关 select_cpu/enqueue/dequeue 留给自定义 BPF 调度器以后做;is_cpu_allowed/select_fallback_rq 的改动重构成避免 O(N²)(编码进两个 bit)。作者称已无重大 TODO,性能数据预期与 v2 持平。base 是 tip/sched/core。
原文[8]
上周 Vlad Poenaru 的 netpoll 补丁(在 netpoll_poll_dev() 外包 local_bh_disable() 阻止 raise_softirq_irqoff() 唤醒 ksoftirqd)本周引发一场跨子系统讨论。起因是 Jakub Kicinski 上周向 RT 维护者提问:用 _local_bh_enable() 阻止 softirq 唤醒 ksoftirqd 是否可靠。
Sebastian Siewior 给出结论(原文[3]):netconsole 转 NBCON(commit 7eab73b18630e)之后写操作已经 defer 到 nbcon 线程,所以主线没这个问题了,纯是 -stable 的事。他指出原补丁几处问题:PREEMPT_RT 的 ifdef 多余(RT 下 legacy console 含转 NBCON 前的 netconsole 已被 force_legacy_kthread() 包进专用线程),问题只限 !PREEMPT_RT;补丁也不够,NIC 驱动要是调 schedule_work() 就原地复现,驱动拿的锁还会让 lockdep 报 rq↔driver-lock 的 ABBA。他给出两个方向:给所有 rq_lock() 变体加 printk_deferred_enter/exit();或新开一组 WARN_ON_DEFERRED 宏替换 kernel/sched/ 下所有 WARN。
Peter Zijlstra(原文[9])照旧坚决反对 deferred,称其为该痛苦死去的可憎之物。他坚持的方向没变:printk 应删掉 console sem、自身变为 atomic safe——消息进 buffer(无锁)→ 打到 atomic console(无锁)→ 用 irq_work 唤醒 console kthreads(无锁)→ 每个 kthread 在非原子上下文 flush 自己的非 atomic console。
Petr Mladek(原文[10])说明根因:legacy console 的问题在于它们运行在 console_lock()(一个 semaphore)下,console_unlock() 在有其他等待者时会调用 wake_up_process()——这才是 rq->lock 下 printk 死锁的源头。一旦 legacy 驱动清退、NBCON 成为默认,printk_deferred() 就可以去除。
Peter 顺势问(原文[11]):能不能把所有 legacy console 一起塞进单个 legacy kthread,别一个个等转换?Petr 的回答点破了僵局——逐个 console 转 NBCON 是当年和 Linus 立的约,只能在多数转完之后把最后几个没转的挪进 kthread,现在还早。
netconsole 能否摘掉 CON_NBCON_ATOMIC_UNSAFE 是另一条支线。Breno Leitao(原文[12])指出 NIC TX 本质依赖共享 DMA ring 和 doorbell 寄存器,做不到真正 lockless,netconsole 大概要长期带着这个标志。John Ogness(原文[13])给了 UART 的参照方案:UART 用 port lock 配合 nbcon 包装器,write_atomic() 只抢 nbcon 硬件不抢 port lock;netconsole 若能找到一个统管所有发包的锁,可以照搬。
【影响范围】主线(netconsole 已转 NBCON)不受影响,仅 -stable:旧 LTS 上持 rq->lock 时触发 printk 且输出经 netconsole 的路径。本周讨论把病根锁定在 legacy console 的 semaphore + wake_up_process(),并明确了收口前提是 NBCON 转换进度。
原文[14]
上周 Cloudflare 的 Matt Fleming 抓到的 ABBA:CPU#1 持 rq->lock 进入 call_rcu_tasks_generic() 要抢 cbs_gbl_lock;CPU#2 持 cbs_gbl_lock 时 pr_info 经 console_unlock 唤醒任务又去抢 rq->lock。本周 Paul McKenney 上周给的方向——让 call_rcu_tasks*() 在中断关闭时 defer 到 irq_work——Matt 给出了具体补丁。
做法是把 call_rcu_tasks_generic() 里那段 needadjust 时抢 cbs_gbl_lock 调整 per-CPU 队列的代码挪出去:新增 cbs_adjust_irq_work(IRQ_WORK_INIT_HARD),needadjust 时只 irq_work_queue(),由 irq_work 上下文去抢 cbs_gbl_lock 做 expand,从而避开 rq-locked 调用者直接抢这把锁。Paul 评价不错,并指出很快还要更进一步——直接 bypass call_rcu_tasks_generic() 本身(仅当调用时中断已关),但那需要和 rcu_barrier_tasks_generic() 配合(用 raw_spin_trylock_rcu_node(rtpcp) 做串行化),Matt 已答应去挖。(原文[15])
【影响范围】6.18.x LTS + sched_ext + bpf task storage 的组合,主线 v7.0+ 已由 RCU Tasks Trace 重写为基于 SRCU 而不受影响。本周的 irq_work 方案对 backport 友好,比重写整组 SRCU 改动轻得多。
原文[16]
Kuba Piecuch(Google)修了一个会让 BPF 调度器被错误 scx_error() 终止的竞态。task_can_run_on_remote_rq() 假设 p->migration_disabled 是稳定的——内核看到 is_migration_disabled(p)==true,就认定 BPF 调度器 dispatch 时也一定看得到,是 BPF 调度器的责任。这个假设不成立。关键在 CONFIG_PREEMPT_RCU:任务执行 BPF 程序期间 migration 是 disabled 的。于是可能出现 BPF 调度器检查时任务没在跑 BPF 程序、内核检查时任务正在跑 BPF 程序的窗口,BPF 调度器没有任何过错却被终止。
CPU A (任务 @p 在跑) CPU B (ops.dispatch())===== =====被高优先级类抢占,进入 __schedule() p->migration_disabled == 0put_prev_task_scx(): @p 放回 BPF 调度器内部数据结构 pop @p, 查 is_migration_disabled() = false dispatch @p 到 CPU B 本地 DSQtrace_sched_switch() 进入 BPF 程序 ← 进入 BPF 程序, @p migration_disabled finish_dispatch()→dispatch_to_local_dsq() task_can_run_on_remote_rq() is_migration_disabled(@p) == true → scx_error() ← 错误终止 BPF 调度器修复是把 task_can_run_on_remote_rq() 的调用挪到 dispatch_to_local_dsq() 拿到 @p 的 rq lock 之后。@p 一直持有自己的 rq lock 直到被切出,这样 put_prev_task_scx() 到 context switch 结束之间触发的所有 BPF 程序都保证已跑完、无法再改 p->migration_disabled。另在 task_can_run_on_remote_rq() 加了 lockdep_assert_rq_held(task_rq(p))(enforce==true 时)。Andrea Righi 给了 Reviewed-by 并顺手更新了 ext_internal.h 里 Cross-CPU Task Migration 的文档注释。(原文[17])
【影响范围】开启 CONFIG_PREEMPT_RCU + sched_ext + BPF 调度器 hook sched_switch tracepoint 的组合(多数生产 scx 调度器都用 tracepoint 探测 idle→fair 转换)。修复消除一类 BPF 调度器被错误终止的虚假故障。
原文[5]
need_freq_update 让 sugov_should_update_freq() 无视 rate_limit_us 限流,正常在 sugov_update_next_freq() 里清掉。sugov_update_single_freq() 和 sugov_update_shared() 都走这个 helper,没事。但 sugov_update_single_perf()(给实现了 ->adjust_perf() 的驱动用,如 intel_pstate、amd-pstate passive 模式)直接调 cpufreq_driver_adjust_perf(),从不走 sugov_update_next_freq(),标志位在这条路径上永不清。
commit 75da043d8f88 之前这无所谓——那时即便标志位置上,sugov_should_update_freq() 仍尊重 rate limit。该 commit 之后标志位强行让 sugov_should_update_freq() 永远返回 true,于是在 adjust_perf 路径上一旦置上就永久生效:每次调度器利用率更新(持 rq->lock)都调一次 cpufreq_driver_adjust_perf(),限流形同虚设,哪怕驱动自己会跳过冗余的硬件更新。修复就一行——在 adjust_perf 路径末尾置 sg_policy->need_freq_update = false。Hongyan Xia、Christian Loehle Reviewed-by,Rafael Wysocki 已作为 7.2-rc 材料合入。Fixes: 75da043d8f88,Cc: stable。
原文[18]
Aaron Tomlin 的 v3。MIPS 的 mipsmt_sys_sched_setaffinity() 在 CONFIG_CPUMASK_OFFSTACK 下 cpumask_var_t 是指针,sizeof(new_mask) 退化成指针大小,copy_from_user(&new_mask, ...) 把用户数据直接写到指针变量上、破坏指针;而且原逻辑是先 copy_from_user 再分配 mask。修复是先 alloc_cpumask_var(),用 cpumask_size() 截断过长或零填充过短的用户 mask,再 copy_from_user 进分配好的 buffer。Fixes: 295cbf6d63165(2007 年 MIPS FPU affinity 代码独立),Cc: stable。Thomas Bogendoerfer 已 applied 到 mips-next。(原文[19])
【影响范围】MIPS + CONFIG_CPUMASK_OFFSTACK(典型大 NR_CPUS 配置)下的 sched_setaffinity,一个能被用户态稳定触发的内存破坏。Bug 龄近 20 年,只是 offstack 配置不常见。
原文[20]
Jing Wu 报的:sched_tick_start()/stop() 在 CPU hotplug 时给不在 HK_TYPE_KERNEL_NOISE 集合里的 CPU 调用,解引用 tick_work_cpu。这个 per-CPU 指针只在 sched_tick_offload_init()(__init、仅在 boot 时 nohz_full= 存在时由 housekeeping_init() 调用)里分配。DHM 子系统运行时首次启用 HK_TYPE_KERNEL_NOISE 时 tick_work_cpu 还是 NULL——再对 isolated CPU 做一次 offline/online 就触发 WARN_ON_ONCE(!tick_work_cpu) 后 NULL 解引用 panic。修复给两个 helper 加 || !tick_work_cpu 提前返回。
Thomas Gleixner 的 review 很不客气(原文[21]):他直接把这套称作和 tick 本身一样的 fake functionality,并指出加 NULL 检查后还留着那条彻底没意义的 WARN_ON_ONCE(!tick_work_cpu) 等于白加。换句话说 tglx 认为这个补丁在掩盖 DHM 运行时启用 nohz_full 的功能缺陷,修复方向没对。
原文[4]
Xin Zhao 的系列从上周 v2 一路推到本周 v5。核心数据没变:18 核平台 300 秒 fillback 场景,fair && !on_rq 的 active balance 触发 1839 次失败 1791 次(97.4%)。根因也和上周一致——__schedule() 在 pick_next_task() 里调 sched_balance_rq(),unlock 再 re-lock rq 产生一个窗口;try_to_block_task() 在这个窗口里把 curr->on_rq 置 0,而 rq->curr 还没指向 next,别的 CPU 在这个窗口看到 rq->curr->on_rq==0。
v5 最大的变化是按 Valentin Schneider 的建议删掉了 busiest->curr->sched_class == &fair_sched_class 这条判断,补丁大幅简化成一条:active balance 触发条件里,只要 !busiest->curr->on_rq 就跳过。理由是 src 上 curr 不在 rq 上意味着它正被切出、前面 detach 阶段大概率已扫过其他 CFS 任务,硬上 active balance(靠 migration 线程中断 src 当前任务)几乎必然失败、纯属浪费 migration IPI。!fair 的情况仍保留原亲和性检查。
本周 sched_ext 的核心演进就是上文的 v7.2 pull request 整批合入——cid、cmask、BPF arena、cid-form struct_ops 一次性落地,dispatch 路径的 sub-scheduler 支持基本成型,scx_qmap 重写为参照实现。(原文[1])配套的源码重组(Move sources under kernel/sched/ext/[6])是同一脉络的整理动作。
此外 scx_bpf_cpu_rq() 标记 nullable(Nuoqi Gui,清华)修了一个 verifier 漏洞:这个 kfunc 能因非法 CPU 或无 SCX 调度器激活而返回 NULL,但注册只声明了 KF_IMPLICIT_ARGS,verifier 不把返回值标成可能为 NULL,BPF 程序可能直接解引用空指针。补丁补上 KF_RET_NULL(与相邻的 scx_bpf_locked_rq()、scx_bpf_cpu_curr() 一致),并加 selftest 拒绝未检查的 rq->nr_running 读取。Fixes: 6203ef73fa5c。(原文[22])同作者配套提交了 Remove deprecated scx_bpf_cpu_rq(),Andrea Righi Reviewed-by。
remote rq 资格检查的 migration_disabled 竞态(Kuba Piecuch,Google)是本周一项稳定性修复——把 task_can_run_on_remote_rq() 挪到持任务 rq lock 之后,消除 BPF 调度器因 PREEMPT_RCU 下 BPF 程序执行期间 migration_disabled 翻转而被 scx_error() 错误终止的窗口。详见"重要 Bug 修复"一章。(原文[16])v2 同周跟上,纳入 Andrea Righi 的文档更新。(原文[17])
上周的 exit_cpu 准确性(Cheng-Yang Chou,for-7.2)本周随 v7.2 pull 一并合入;scx_flatcg cvtime_delta 双重计费(Wanwu Li)和任务离开 SCX 后 dsq_vtime 残留(Andrea Righi)这两个上周在 review 的修复也已在本周期消化。
生态侧的头条就是 源码重组到 kernel/sched/ext/(Tejun Heo)——直接响应 Linus 对 v7.2 文件命名的反对,把 ext_cid.c 改成 ext/cid.c、ext_arena.c 改成 ext/arena.c,去掉前缀。这本身不改逻辑。(原文[6])同期 scx_qmap 已被重写为 arena + cid 的参照实现,文档也补了 arena-backed 双链表、连续多次 ops.enqueue() 等说明。
perf sched 的哨兵指针清理(Arnaldo Carvalho de Melo)延续上周,acme 继续把 perf sched 内部那几个 (void *)1 魔法值哨兵换成运行时分配,避免把伪指针当真指针用的脆弱性。这组清理由 sashiko-bot 发现、AI 辅助编写,bot 在 perf 工具维护里已常态化参与。(原文[23])
need-resched 定时等待接口(Ankur Arora,Oracle)的 v12 系列本周在收尾,tif_need_resched_relaxed_wait(timeout_ns) 这块 cpuidle/poll 基础设施继续推进,同期还伴生 sched_tick 守卫补丁(见 Bug 修复章,被 tglx 判为 fake functionality)。(原文[20])
rq->lock 下的 printk 死锁,收口取决于 NBCON 转换进度,而非调度器侧改动。 上周三个独立事件(SCHED_WARN_ON 提案、scx_lavd lockup、252 核 netconsole 自死锁)是同一根因的不同表现。本周讨论把根因讲清:Petr Mladek 指出 legacy console 在 semaphore(console_lock)下运行、console_unlock() 中的 wake_up_process() 才是 rq->lock 下死锁的源头。Peter Zijlstra 坚持 printk 自身应变为 atomic safe、删除 console sem 的同步唤醒;Sebastian Siewior 建议 rq_lock 加 deferred 或引入 WARN_DEFERRED。Petr Mladek 说明逐个 console 转 NBCON 是与 Linus 的约定,没法整体移入 legacy kthread。这意味着 printk_deferred 作为临时手段还得保留较长时间,尤其对 -stable。短期看 scx_lavd 那条 irq_work 方案(needadjust 不在 rq-locked 上下文抢 cbs_gbl_lock)是目前可见的一条具体修复路径。
sched_ext 把层级调度做进了核心,三条同源路线里推进最快。 把本周 scx sub-scheduler(cid/cmask/arena)、上周 CFS sched/flat(压平 cgroup 层级)、RT rt_rq 解耦放一起:三者都在回应"单一全局调度模型在容器化/多租户/异构负载下不够用",但 scx 用 BPF arena + cid 切片把可组合子调度做成了本周期 4000 行级别的实际基础设施,enqueue 路径层级支持已是明确的下一步。CFS 在简化层级遍历,RT 在解耦队列,scx 在搭框架——scx 这条线推进最快,且有 BPF 的可试错性降低风险。Linus 的 disgusting 虽是针对文件命名,也侧面说明 sched_ext 源码规模已达主线基础设施级别。
虚拟化 steal time 开始被核心调度器正面处理。 cpu_preferred_mask v4 不是 scx_lavd 那种 BPF 方案,而是把"高 steal 时缩减可用 vCPU 集合、wakeup 与 balance 仅在 preferred CPU 间进行"做进 CFS 核心。如果合入,云上客机调度会多一个不依赖 BPF 的 steal 感知机制。20 补丁要碰 wakeup 和 load-balance 热路径,review 会长,但方向已获 Peter 阶段性认可(preferred 改为 active 子集)。
schedule_work() 即复现)、PREEMPT_RT ifdef 多余;这条 stable 补丁最终长什么样、是否换成 Petr 建议的把 ksoftirq 唤醒 offload 到 irq_work,值得跟。!on_rq 检查,Valentin 已深度参与,合入条件成熟。is_cpu_allowed 改动的最终态度决定这组能否进。sched_tick_offload_init() 可运行时重新调用。[1] 原文: https://lore.kernel.org/all/6a0da8f90fd3890f734555f1632a3a0f@kernel.org/[2] 原文: https://lore.kernel.org/all/CAHk-=wghMm2c+AYEcwYY7drSVXB27DYqc-ZXpFiq=XFs-w59wA@mail.gmail.com/[3] 原文: https://lore.kernel.org/all/20260616103529.Yh9Dxsjp@linutronix.de/[4] 原文: https://lore.kernel.org/all/20260617072151.1173416-2-jackzxcui1989@163.com/[5] 原文: https://lore.kernel.org/all/20260616154733.2405236-1-zhongqiu.han@oss.qualcomm.com/[6] Move sources under kernel/sched/ext/: https://lore.kernel.org/all/20260621163026.434856-1-tj@kernel.org/[7] 原文: https://lore.kernel.org/all/20260617174139.155540-1-sshegde@linux.ibm.com/[8] 原文: https://lore.kernel.org/all/20260610183621.3915271-1-vlad.wing@gmail.com/[9] 原文: https://lore.kernel.org/all/20260616170257.GH49951@noisy.programming.kicks-ass.net/[10] 原文: https://lore.kernel.org/all/ajJy92ES-Q8ro97A@pathway.suse.cz/[11] 原文: https://lore.kernel.org/all/20260617111504.GK49951@noisy.programming.kicks-ass.net/[12] 原文: https://lore.kernel.org/all/ajKi4wtA8U1iZkMD@gmail.com/[13] 原文: https://lore.kernel.org/all/87tsr1m6y5.fsf@jogness.linutronix.de/[14] 原文: https://lore.kernel.org/all/ajErr_GEejCD7n47@matt-Precision-5490/[15] 原文: https://lore.kernel.org/all/120adbd6-08f6-4eec-83cd-523e25489707@paulmck-laptop/[16] 原文: https://lore.kernel.org/all/20260618170047.283701-1-jpiecuch@google.com/[17] 原文: https://lore.kernel.org/all/ajTwP6tQxR_6UGsQ@gpd4/[18] 原文: https://lore.kernel.org/all/20260526141651.773306-1-atomlin@atomlin.com/[19] 原文: https://lore.kernel.org/all/ai_T_uRkojOsTE-Z@alpha.franken.de/[20] 原文: https://lore.kernel.org/all/20260618-wujing-dhm-v3-10-28f1a4d83b68@gmail.com/[21] 原文: https://lore.kernel.org/all/87a4srefok.ffs@fw13/[22] 原文: https://lore.kernel.org/all/20260619-f01-14-scx-cpu-rq-ret-null-v1-0-3b4281cdf0da@mails.tsinghua.edu.cn/[23] 原文: https://lore.kernel.org/all/20260612003444.50723-10-acme@kernel.org/