0/5 已展开

LLM 分析

sched_ext:当 cpu.max 配置但 BPF 调度器未实现带宽控制时的告警

系列概况

  • 标题:[PATCH RFC] sched_ext: warn when cpu.max is set but the BPF scheduler doesn't implement bandwidth control
  • 作者:Tao Cui cuitao@kylinos.cn
  • 版本:v1(RFC,单 patch)
  • 规模:1 个文件,+6 行
  • 修改文件kernel/sched/ext/ext.cscx_group_set_bandwidth() 函数内)
  • 代码统计:1 file changed, 6 insertions(+)
  • Message-ID20260818135328.174152-1-cui.tao@linux.dev
  • 完整性:完整可读,含 diff 与 commit message

补丁目的

cgroup v2 的 cpu.max 接口在内核中被 sched_ext(scx)记录到 task_group,并通过 ops.cgroup_set_bandwidth() 回调和 scx_cgroup_init_args 推送给 BPF 调度器。

但内核本身并不强制执行该配额——它依赖 BPF 调度器去兑现。

实际问题是:树内几乎所有示例调度器(如 scx_simple)都没有实现 cgroup_set_bandwidth(),只有 scx_qmap 实现了(但只是 bpf_printk() 参数)。这意味着当用户给 cgroup 写 cpu.max = "50000 100000" 时,他们以为限制了 50% CPU,但实际却不受约束。

作者实测:单 busy任务 10 秒用掉 9946ms CPU,nr_throttled 仍为 0。

补丁目的:在 quota 为有限值、scx 已启用、但当前 BPF 调度器未实现该回调时,打印一次告警,提醒用户/编排器配额未被强制执行。

旧流程的问题

  • 用户/编排器配置 cpu.max → 内核存储到 task_group → 调用 BPF 回调- 如果 BPF 调度器未实现 ops.cgroup_set_bandwidth() → 内核 SCX_CALL_OP 什么也不做
  • 用户看到的是「我已经设置了50% 配额」,但实际上 cgroup 仍能跑满 CPU——静默失败
user writes cpu.max=50000 100000
        |
        v
 task_group stores period/quota/burst
        |
        v
  SCX_CALL_OP(cgroup_set_bandwidth) --+--> if scheduler implements: printk only (scx_qmap)
 |
                                       +--> if missing: silently NO-OP <-- silent failure

新流程

补丁在原有 if 分支之外加了一条 else if

else if (scx_cgroup_enabled && sch &&
 !SCX_HAS_OP(sch, cgroup_set_bandwidth) &&
         quota_us != RUNTIME_INF)
    pr_warn_once("sched_ext: BPF scheduler \"%s\" does not implement "
                 "ops.cgroup_set_bandwidth(); cpu.max will not be enforced\n",
                 sch->ops.name);
  • scx_cgroup_enabled:scx 的 cgroup 路径已打开
  • sch:当前有加载的 BPF 调度器
  • !SCX_HAS_OP(...):该调度器没有实现 cgroup_set_bandwidth
  • quota_us != RUNTIME_INF:用户实际配置了有限配额(不是 max
  • pr_warn_once:避免每次带宽变更都刷屏

Patch 概览

单 patch,单文件,定位明确:在 scx_group_set_bandwidth() 中已有 SCX_CALL_OP 调用旁加一个 else if 警告分支,不影响现有调用路径与状态更新。

关键实现

void scx_group_set_bandwidth(struct task_group *tg,
                             u64 period_us, u64 quota_us, u64 burst_us)
{
    ...
    if (period_us != tg->scx.bw_period_us ||
        quota_us != tg->scx.bw_quota_us ||
        burst_us != tg->scx.bw_burst_us)
        SCX_CALL_OP(sch, cgroup_set_bandwidth, NULL,
                    tg_cgrp(tg), period_us, quota_us, burst_us);
    else if (scx_cgroup_enabled && sch &&
             !SCX_HAS_OP(sch, cgroup_set_bandwidth) &&
             quota_us != RUNTIME_INF)
        pr_warn_once(...);
    ...
}

设计要点:

  • 放在 else if 而不是独立路径,避免在「真正实现了回调」的调度器上误报。
  • pr_warn_once 保证只打一次,不污染 dmesg
  • 不修改 quota 在 task_group 上的存储,仍由未来 BPF 调度器按需读取——零行为破坏。

类比

想象你去银行设置「每月 ATM 取款上限 5000 元」:

  • 银行把你的限额登记到账户系统里 ✓(内核写入 task_group
  • 但真正去 ATM 取钱时,机器要不要遵守这个限额,要看你刷卡时银行选择走哪个出纳模块(BPF 调度器)
  • 大多数出纳模块压根没接「限额检查」逻辑,于是限额登记了,但没人去执行——钱照样能取出来
  • 补丁相当于:出纳模块没接限额检查时,大堂喇叭播报一次「本窗口暂不执行 ATM限额,请注意」
  • Tejun 的反馈相当于说:大堂喇叭太吵,应该在门口贴一张「本行部分窗口不执行限额」的告示(文档)

Highlight:风险与注意点

  • 告警粒度过粗:Sashiko AI 指出,启动 BPF 调度器时已存在的 cgroup 配额不会触发新警告——警告只在用户运行时修改 cpu.max 时出现。这会让「启动即生效」的容器配额在重启后静默。
  • 维护者态度保留:Tejun 引用 cpu.weight 的前例——之前的类似警告「制造的麻烦多于帮助」。他倾向于通过文档说明每个 BPF 调度器实现了哪些 cgroup 接口,而不是运行时打 warning。
  • 告警覆盖范围有限:BPF 调度器还可以忽略 nicecpu.idle、内存节流等,这些都不会有警告;如果走「运行时告警」路线,未来类似的告警会越加越多,可能刷屏。
  • 可执行或可观测?:作者只打了 warning,但用户多半期望 cgroup 真的被节流。这条 patch 解决了「发现问题」,但没有解决「解决问题」(谁来节流)。
  • 是否需要 caps 化:可以扩展成 sched_ext 暴露一个 sysfs/ops 位图,声明「我实现了哪些 cgroup 接口」,让用户/编排器主动查询,而不是被动听警告。
         +-----------------------+
         |  user sets cpu.max    |
         +----------+------------+
                    |
                    v
         +----------+------------+
         |  does sch implement |
         |  cgroup_set_bandwidth?|
         +----+-------------+----+
              |yes |no
              v v
       SCX_CALL_OP       pr_warn_once<-- new |              |
              v              v silently printk     user notified
      (qmap only)        but quota still
                         NOT enforced

版本变化

仅 v1(RFC),无 v2。

评审脉络

邮件作者关键观点
#1Tao Cui提交 RFC,描述问题 + 测得9946ms/10s,提议 warning
#2Tao Cui自我转发/补发,主体内容一致
#3sashiko-botAI 评审:警告不覆盖启动时已存在的 cgroup 配额(中风险)
#4Tejun Heo反对运行时 warning;类比 cpu.weight 旧案,建议文档化
#5Tao Cui接受 Tejun 反馈,表示理解(信息被截断)

一句话总结

Tao Cui 想给「BPF 调度器忽略 cpu.max」的场景加运行时告警,但 Tejun 倾向文档化,二者尚未达成一致——这条 RFC 的下一步取决于作者是否改成文档 patch,或扩展为「cgroup 能力位图」机制。