0/2 已展开

LLM 分析

系列基线信息

字段
标题[PATCH sched_ext/for-7.2-fixes] selftests/sched_ext: Handle sleeping task affinity changes in numa test
作者Kuba Piecuch
版本单 patch,无版本号
规模1 file changed, 12 insertions, 1 deletion
Message-ID20260723095955.1415621-1-jpiecuch@google.com
来源sched-ext

明确目的

修复 sched_ext NUMA 自测调度器中的一个崩溃性 bug:当睡眠任务的 CPU affinity 在其睡眠期间被修改后,task_cpu(p) 可能指向一个已不在 p->cpus_ptr 中的 CPU。由此确定的 NUMA node 完全落在任务 cpumask 之外,导致 scx_pick_idle_cpu_node() / scx_pick_any_cpu_node() 找不到合法 CPU 并返回 -EBUSY(即 -16)。sched_ext 框架将 -16 当作非法 CPU 编号处理,触发 scx_bpf_error("invalid CPU -16") 并使调度器异常退出。

补丁在 numa_select_cpu() 中增加防护逻辑:如果选定 NUMA node 内找不到可用 CPU,且检测到 task_cpu 已不在 p->cpus_ptr 中(说明 affinity 在睡眠中被改过),就回退到 prev_cpu 作为安全兜底。


遍历代码

改动集中在 tools/testing/selftests/sched_ext/numa.bpf.c,分两部分:

1. 提取 task_cpu 为局部变量(小重构)

// 之前:内联调用
int node = __COMPAT_scx_bpf_cpu_node(scx_bpf_task_cpu(p));

// 之后:先取出 task_cpu
s32 task_cpu = scx_bpf_task_cpu(p);
int node = __COMPAT_scx_bpf_cpu_node(task_cpu);

scx_bpf_task_cpu(p) 的返回值存到 task_cpu,后续 numa_select_cpu 也要用到这个值做 cpumask 检查,避免重复调用。

2. numa_select_cpu 中新增兜底检查

if (cpu < 0 && !bpf_cpumask_test_cpu(task_cpu, p->cpus_ptr))
    return prev_cpu;

逻辑链:

  • cpu < 0:在选定 NUMA node 内没找到可用的 CPU(scx_pick_*_cpu_node 返回负值)。
  • !bpf_cpumask_test_cpu(task_cpu, p->cpus_ptr)task_cpu 不在任务当前 cpumask 中 → 说明 affinity 在睡眠期间被改过,task_cpu 是过时的。
  • 满足两个条件就返回 prev_cpu:wakeup 之前任务实际所在的 CPU,作为安全回退值。

概念类比

想象一个人在酒店睡觉时,酒店前台把他的房间号改了(相当于修改了 CPU affinity)。当他醒来问"我在哪个楼层?"(NUMA node),前台按旧房间号查楼层,结果发现那个楼层已经不属于他了。前台说"本楼层没空房"(cpu < 0),而且他的旧房间号在新房卡上找不到(task_cpu 不在 cpus_ptr 中),于是前台只好说"回到你睡觉前的那个房间吧"(return prev_cpu)。


ASCII 流程图

  Task sleeping on CPU X (task_cpu = X)
       |
       |  affinity changed while sleeping
       |  cpus_ptr now = {A, B, C}  (X removed!)
       |
  wakeup → numa_select_cpu()
       |
       |-- node = scx_bpf_cpu_node(X)  ← X may be outside cpus_ptr!
       |
       |-- scx_pick_idle_cpu_node(cpus_ptr, node)
       |       |
       |       |-- found CPU?  → YES → return that CPU
       |       |
       |       |-- NO (cpu < 0) ──────────────────┐
       |                                          |
       |-- bpf_cpumask_test_cpu(X, cpus_ptr)      |
       |       |                                  |
       |       |-- X in cpus_ptr → other fallback  |
       |       |                                  |
       |       |-- X NOT in cpus_ptr ──────────────┘
       |                         (affinity changed)
       |                              |
       +-- return prev_cpu ───────────┘  ← safe fallback

Highlight 突出问题

  1. 只修了 selftest,没修 sched_ext 框架本身task_cpu 可能超出 cpus_ptr 是一个更普遍的 wakeup 语义问题。其他 sched_ext BPF 调度器如果也依赖 task_cpu/scx_bpf_cpu_node(task_cpu) 做 NUMA 决策,同样会踩坑。本补丁只让 selftest 变得健壮,框架层是否需要统一兜底值得后续跟进。

  2. prev_cpu 也可能不在新 cpus_ptr 中:如果 affinity 改动同时也把 prev_cpu 移出了 cpus_ptr,返回 prev_cpu 同样不合法。当前场景中 prev_cpu 通常仍属合法范围,但极端情况下需验证框架是否会二次拦截。

  3. 竞态窗口短暂但真实:从 affinity 变更到 select_task_rq() 完成选队之间,task_cpucpus_ptr 不一致。窗口虽短,但在 migration/cpu hotplug 等路径下可触发。


版本演进

本补丁为单一版本(无 v1/v2 迭代),Tejun Heo 已直接 apply 到 sched_ext/for-7.2-fixes 分支。


与其他相关 patch 系列的关联

  • Fixes tag 指向 5ae5161820e5("selftests/sched_ext: Add NUMA-aware scheduler test"),即引入 numa.bpf.c 自测的原始提交。
  • 与 sched_ext 框架的 select_task_rq_scx()task_cpu 语义相关,后续若框架层增加对"sleeping task affinity change"的统一处理,本 selftest 补丁中的防护逻辑可能变得冗余。

一句话总结

修复 NUMA 自测调度器在睡眠任务 affinity 被改后因 task_cpu 越界导致 "invalid CPU -16" 崩溃的问题,通过检测 cpumask 不一致时回退 prev_cpu 兜底。