0/5 已展开

LLM 分析

sched_ext:将 arena-pointer 接口迁移到 __arena 参数

系列概况

  • 标题: [PATCHSET sched_ext/for-7.3-arena-args] sched_ext: Convert arena-pointer interfaces to __arena arguments
  • 作者: Tejun Heo <tj@kernel.org>
  • 版本: PATCHSET v1(0/3 + 1/3 + 2/3 + 3/3),单轮无 v2/v3
  • 规模: 11 个文件,+148 / -148 行(整体保持行数中性)
  • 修改文件:
    • kernel/sched/ext/arena.c
    • kernel/sched/ext/cid.c
    • kernel/sched/ext/ext.c
    • kernel/sched/ext/internal.h
    • kernel/sched/ext/sub.c
    • kernel/sched/ext/types.h
    • tools/sched_ext/include/scx/common.bpf.h
    • tools/sched_ext/include/scx/compat.bpf.h
    • tools/sched_ext/scx_qmap.bpf.c
    • tools/sched_ext/scx_qmap.c
    • tools/sched_ext/scx_qmap.h
  • 代码统计: 11 files changed, 148 insertions(+), 148 deletions(-)(cover letter diffstat);patch 1/3单独 4 files, 13 insertions(+), 27 deletions(-)
  • Message-ID: cover 20260812211609.2495583-1-tj@kernel.org,patch …-2/3/4-tj@kernel.org,应用回执 c7abeaf94f09d45703fd91d1dbb440d4@kernel.org
  • 完整性: 完整 PATCHSET;作者于次日(2026-08-13)亲自 Applied 1-3 到 sched_ext/for-7.3-arena-args,无后续讨论回复

补丁目的

cid-form scheduler 把数据放在 BPF arena 中,但 kernel ↔ BPF 之间传递 arena 对象的接口(ops_cid 回调、sub-cap kfunc、scx_bpf_cid_override())定义在 __arena 参数支持之前,kfunc 只能用 __ign 标量或 verifier 检查 buffer 收指针,两边各自手工 rebase。

bpf-next 刚刚合入 kfunc 与 struct_ops 的 __arena 参数支持(merge commit d114bb989367)。本系列趁此把所有相关接口统一迁到 __arena 参数,移除手工 scx_kaddr_to_arena(),让 trampoline 自动完成地址翻译,BPF 端不再需要丑陋的 (void *)(long) cast。

旧流程的问题

  • kernel 在 arena 构造 cmask 后调用 scx_kaddr_to_arena(sch, kern_va) 减去 arena_kern_base 转成 BPF 形式交给 BPF;BPF 收到后又用 scx_arena_to_kaddr() 加回 kernel 侧 ——双重手工 rebase。
  • sub-cap kfunc 的 cmask 参数被声明为 __ign,verifier 不能识别 arena 指针语义,scx_qmap 调用侧只能写 (void *)(long)&qa.held_excl.mask 这种 cast 绕开类型系统。
  • cid_override_cpu_to_cid[] / cid_override_shard_start[] 必须放在 bss,因为旧签名里 len-paired 指针被 verifier 当 read/write 处理,rodata 会触发 "write into map forbidden"。
  • 每加一个跨边界接口都要复制粘贴 rebase 帮助函数,容易漏改。

新流程

   kernel builds cmask in arena (kern_va)
                       |
                       |  pass kernel address directly (no manual rebase)
                       v
   +------------------+   struct_ops trampoline    kfunc trampoline
   |  set_cmask()     |  -------------------------+------------------+
   |  sub_caps_updated| rebases __arena arg | |
   +------------------+                          v                   v
                                          BPF-side arena pointer
                                          (naturally typed, no cast)
  • ops_cid.set_cmask()sub_caps_updated() 直接收 kernel 地址,由 struct_ops trampoline 完成 rebase。
  • sub-cap kfunc 的 cmask 输入改 __arenaout__arenadenied_out__nullable
  • scx_bpf_cid_override() 两个数组参数改 __arena__sz 拆为显式 cnt,kernel 端做范围校验并限制单次 snapshot ≤ 32 KiB,落在 arena fault recovery guard region 内。
  • BPF 端声明加 __arena 修饰,scx_qmap 直接传 &qa.xxx.mask

Patch 概览

  • 1/3 ops_cid callbacks —— 删除手工 scx_kaddr_to_arena(),trampoline 翻译;CFi stub 与 sched_ext_ops_cid 成员类型加 __arena 后缀。
  • 2/3 sub-cap kfuncs —— scx_bpf_sub_grant/revoke/caps 三处 cmask/out 参数改 __arenadenied_out__nullablescx_cmask_ref_init() 不再 rebase 入参;BPF 头与 qmap 调用清理 cast。
  • 3/3 scx_bpf_cid_override() —— 数组参数加 __arena__sz 拆为 cnt 并加强校验;qmap 的 cid_override 数组从 bss 迁移到 arena,在 attach 前由用户态填充。

关键实现

Patch 1/3:ops_cid 直接收 kernel 地址

SCX_CALL_CID_OP_TASK(sch, set_cmask, rq, task, kern_va);

internal.h 中回调签名改为:

void (*set_cmask)(struct task_struct *p, const struct scx_cmask *cmask__arena);
void (*sub_caps_updated)(const struct scx_cmask *cmask__arena, u64 caps);

sub.ccaps_updated_deliver() 去掉 scx_kaddr_to_arena(sch, cu->cmask_arena_out),原样把 kernel 地址传出去。internal.hscx_kaddr_to_arena() 帮助函数被删除,注释更新为指向 trampoline 自动翻译。

Patch 2/3:sub-cap kfunc 参数重写

__bpf_kfunc s32 scx_bpf_sub_grant(u64 cgroup_id, u64 caps,
    const struct scx_cmask *cmask__arena,
    struct scx_cmask *denied_out__arena__nullable,
    const struct bpf_prog_aux *aux);

__bpf_kfunc void scx_bpf_sub_revoke(u64 cgroup_id, u64 caps,
    const struct scx_cmask *cmask__arena, const struct bpf_prog_aux *aux);

__bpf_kfunc s32 scx_bpf_sub_caps(u64 cgroup_id, u64 caps,
    struct scx_cmask *out__arena, const struct bpf_prog_aux *aux);

实现里 scx_cmask_ref_init() 直接读 src->base 等字段,不需要再把 src 重新 rebase 回 kernel 地址。types.hscx_cmask_ref_init() 的注释相应改为 "snapshots @base/@nr_cids"。common.bpf.h__ksym 声明加上 __arena 修饰;scx_qmap.bpf.c(void *)(long)&qa.xxx.mask 全部简化为 &qa.xxx.mask

Patch 3/3:scx_bpf_cid_override()__arena 数组

__bpf_kfunc void scx_bpf_cid_override(const s32 *cpu_to_cid__arena, u32 cpu_to_cid_cnt,
                                      const s32 *shard_start__arena, u32 shard_start_cnt,
                                      const struct bpf_prog_aux *aux);

变化点:

  • cpu_to_cid__szshard_start__sz 拆为显式 cnt,kernel 端做范围校验:cpu_to_cid_cnt == nr_cpu_idsnr_shards 非0 且 <= npossible
  • snapshot 用 kmemdup(... cnt * sizeof(s32), ...),单次最多 32 KiB,落在 arena fault recovery guard region 内。
  • compat.bpf.h 的兼容符号和 inline wrapper 都补上 __arena 标注。

scx_qmap.bpf.c 删除 bss 中的 cid_override_cpu_to_cid[] / cid_override_shard_start[],改用 arena 内的 qa.cid_override_*scx_qmap.c 把原本在 load 后写 skel->bss 的初始化逻辑迁移到 attach 前对 qa 的初始化(注释明确写 "live in the arena ... populated before qmap_init_cids() consumes them at attach"),新增 cid_override_shard_sz 本地变量并删除 bad-mode 处理循环。

类比

把 BPF arena 想象成双门公寓:kernel 和 BPF 各自有独立的门牌号体系,旧 rebase 模式下寄信必须把"门牌号 − 楼层偏移"翻译一次再发。新的 __arena 参数等于装了统一信箱:kernel 把信投入自家信箱即可,电梯(trampoline)按收件人自动换成对方看得懂的地址。从此寄信人不用关心偏移,verifier 也能直接读懂"这是 arena 邮件"。

scx_bpf_cid_override()__sz 改成 cnt,类似餐厅点餐:以前要写"我要 1024 字节的宫保鸡丁",后厨自己猜份数;现在写"我要 256 份宫保鸡丁",后厨按份数备菜并当场校验合理性。

Highlight:风险与注意点

  • 架构限制:arena 参数地址翻译目前只在 x86-64 上实现。cid-form scheduler 在其他架构上 load 会失败,使用者需注意运行平台。
  • bss → arena 迁移时序cid_override_* 从 bss 迁到 arena 后,用户态必须在 attach前的初始化路径里写好;旧 bss 写法会被 attach 流程覆盖,调试时容易踩坑。
  • count 校验行为变更:kernel 现在显式拒绝 cpu_to_cid_cnt != nr_cpu_ids、空 shard 或过多 shard 的输入。qmap 的 BAD_* mode 因此改为在 attach 前写 arena 而不是触发 kfunc 错误路径 —— 这是行为差异,要跟进 selftest 输出。
  • ABI 表面:kernel C 结构体成员类型仍是裸指针,__arena 仅出现在 BPF 端声明和 CFi stub 上,翻译由 trampoline 完成。后续新增跨边界接口应沿用同一约定,避免再次出现"两边各自 rebase"的隐患。
  • 32 KiB guard region:snapshot 上限是否随 nr_cpu_ids 增长而触顶,需要后续在大系统上回归验证;其他架构支持何时合并也应跟进 bpf-next 主线。

版本变化

仅一个 PATCHSET,无 v2/v3 演进记录。本系列在发出第二天(2026-08-13)由作者本人 Applied 1-3 到 sched_ext/for-7.3-arena-args,无后续讨论回复,干净落地。

一句话总结

借 bpf-next 刚落地的 __arena 参数支持,把 sched_ext cid-form 的 ops_cid 回调、sub-cap kfunc 和 scx_bpf_cid_override() 全部迁到 __arena 参数,删除手工 rebase 与 BPF 端丑陋 cast,由 trampoline 统一完成地址翻译,目前仅限 x86-64。