0/2 已展开

LLM 分析

sched_ext:修复 scx_bpf_dsq_reenq___compat kfunc extern 声明

系列概况

  • Title: [PATCH sched_ext/for-7.2-fixes] sched_ext: Fix scx_bpf_dsq_reenq___compat kfunc extern prototype
  • Author: Tejun Heo tj@kernel.org
  • Version: 单封 patch(无 v 编号)
  • Scale: 1 个文件,3 +/−
  • 修改文件: tools/sched_ext/include/scx/compat.bpf.h
  • 代码统计: 1 file changed, 3 insertions(+), 3 deletions(-)
  • Message-ID: 20260814205955.3490381-1-tj@kernel.org
  • 完整性: 含 patch 正文 + maintainer 应用回执,完整

补丁目的

修正 compat.bpf.h 中 scx_bpf_dsq_reenq___compat weak extern 的参数签名,让它与 KF_IMPLICIT_ARGS 注册的内核 BTF 原型一致;libbpf 才能在真正支持该 kfunc 的内核上成功 resolve,通用 reenq 路径不再被静默关掉。

旧流程的问题

旧 extern 显式多写一个 const struct bpf_prog_aux *aux__prog 参数;而 scx_bpf_dsq_reenq() 在内核用 KF_IMPLICIT_ARGS 注册,BTF 原型把 aux 隐式省略。libbpf 一比对就对不上。

后果:

  • weak extern 在所有内核上都 unresolved,bpf_ksym_exists(...) 永远 false;
  • __COMPAT_has_generic_reenq() 始终返 false,包装函数恒走 scx_bpf_reenqueue_local() 老分支;
  • scx_qmap 的 lowpri 等通用 reenq 用户被禁用;
  • 跨本地 DSQ 的 reenq 反而以 "kernel too old" 失败,即便内核已经支持;
  • 用户完全无感——没有编译告警,也没有运行时报错,特性"静默死亡"。

新流程

去掉 extern 与调用点的 aux 参数,使声明与 BTF 原型一致;libbpf 在支持该 kfunc 的内核上能正确 resolve,__COMPAT_has_generic_reenq() 恢复返回 true,调用者重新走真正的 reenq 路径。同时把注释里过时的 "v6.20" 订正为 "v7.1",并加 Fixes:Cc: stable 标签。

Patch 概览

  • tools/sched_ext/include/scx/compat.bpf.h
    • 注释:v6.20 -> v7.1
    • extern:去掉 aux__prog 参数。
    • 包装函数调用点:去掉第三参数 NULL

关键实现

/* 旧 extern */
void scx_bpf_dsq_reenq___compat(
    u64 dsq_id, u64 reenq_flags,
    const struct bpf_prog_aux *aux__prog) __ksym __weak;

/* 新 extern */
void scx_bpf_dsq_reenq___compat(
    u64 dsq_id, u64 reenq_flags) __ksym __weak;
/* 旧调用点 */
scx_bpf_dsq_reenq___compat(dsq_id, reenq_flags, NULL);
/* 新调用点 */
scx_bpf_dsq_reenq___compat(dsq_id, reenq_flags);

类比

KF_IMPLICIT_ARGS 像酒店 VIP "自动签房卡" 通道:客人签合同时合同里看不到那张附加卡,前台会自己塞一张进去。旧 extern 偏要合同上写"我拿两张卡",前台一对不上号就把客人拒之门外。修好之后合同只写一张卡,前台实际发的也是一张,匹配成功,VIP 通道重新打开。

    compat extern (OLD)                BTF (KF_IMPLICIT_ARGS)
    =====================              ========================
    u64 dsq_id                          u64 dsq_id
    u64 reenq_flags                     u64 reenq_flags
    bpf_prog_aux *aux__prog             (aux dropped)
              |                                |
              +----- libbpf resolve ----> signature mismatch
                          |
                          v
               weak extern never resolves
                          |
                          v
            __COMPAT_has_generic_reenq() = false
                          |
                          v
      fallback to reenq_local, non-local = "kernel too old"

    AFTER FIX:
              |
              v
    extern matches BTF -> libbpf resolves
                          |
                          v
            __COMPAT_has_generic_reenq() = true on supported kernels
                          |
                          v
      calls scx_bpf_dsq_reenq() directly, no fallback

Highlight:风险与注意点

  1. 凡用 KF_IMPLICIT_ARGS 注册的 kfunc,compat 层 weak extern 都必须省略被隐式吃掉的辅助参数;否则 libbpf resolve 永远失败,特性"静默死亡"——这是这类问题最容易踩的坑。
  2. compat.bpf.h 是 user-space skeleton 与内核 BTF 的隐式契约,BTF 一旦变动都要回头检查 extern 是否仍对齐;这类签名错位不会编译报错,也不会写 dmesg。
  3. patch 本意发往 for-7.2-fixes,但因为 7.2 已经定型被挪到 sched_ext/for-7.3;需要单独走 stable@vger.kernel.org # v7.1+ 后向移植通道。
  4. 注释里把该 kfunc 误写成 v6.20(实际 v7.1 引入),文档或 CHANGELOG 还可能存在同源描述,应一并订正以免误导。
  5. compat.bpf.h 同时包含了 __COMPAT_has_generic_reenqscx_bpf_dsq_reenq 两个包装器,它们的判断逻辑都依赖 bpf_ksym_exists(...);只要 weak extern resolve 不对,整条 generic reenq 兼容层就被锁死。

版本变化

仅一版 patch,无 vN -> vN+1 演进;关键差异在落点分支从 sched_ext/for-7.2-fixes 改为 sched_ext/for-7.3,意味着它会随 7.3 发布并 stable 后向移植到 7.1+。

一句话总结

让 compat 层声明与 KF_IMPLICIT_ARGS 注册的 BTF 原型对齐,修复 scx_bpf_dsq_reenq 在所有内核上被静默判定为"不存在"的 bug,恢复 scx_qmap 等使用者的跨 DSQ reenq 路径。