0/1 已展开

LLM 分析

sched/core: 让 core-sched 翻转等待 in-flight 选择完成

系列概况

  • 标题: [PATCH] sched/core: Make core-sched flips wait for in-flight selections
  • 作者: Tejun Heo tj@kernel.org(本邮件由 stable 机器人 gregkh 代发回执)
  • 版本: 单封 patch,无 v2/v3 系列号
  • 规模: 修改 2 个文件 — kernel/sched/core.ckernel/sched/sched.h;新增 1 个 unsigned int 字段,若干自增/自减与轮询等待逻辑
  • Message-ID: 2026090311-expediter-squire-a01e@gregkh;原 commit f3629c63a4af3e491381780bc6c123cb498c4c40
  • 完整性: Greg KH 报告该 patch 在 linux-6.1.y 上无法干净 cherry-pick,需要手工回填冲突后重新投递到 stable@vger.kernel.org

补丁目的

Core scheduling 的 pick_next_task() 会在一次共享 core 锁内挑选 SMT sibling 上的下一个 task。如果某个 sched_class 的 ->pick_task() 临时 drop 了 rq 锁,其它 sibling 的 __lock 瞬间处于"无主"状态。这时 __sched_core_flip(false) 可以在选型中途完成,把 rq_lockp() 偷偷换绑。

随后选型在分裂后的两把锁上继续运行,访问不再归它保护的 sibling 状态;__schedule() 退出时释放一把根本没拿到的锁,并泄漏原来持有的那把 — 这是真实存在的锁状态错乱。本补丁让 __sched_core_flip() 等待所有 in-flight 选型归零,避免在选型进行中换锁。

旧流程的问题

  • __sched_core_flip() 不感知 core 选型是否正在进行,能在 ->pick_task() drop 锁的窗口里把 rq_lockp() 换掉。
  • 选型继续在分裂后的锁上跑,sibling 状态一致性被破坏。
  • sched_core_cpu_deactivate()copy 把 counter 搬到新 leader,旧 leader 再次上线时会保留 stale 计数,永远 bias。
  • sched_init() 没有为新字段显式清零。

新流程

  • 在 leader 的 rq 上挂一个 unsigned int core_pick_in_flight,只在共享 core 锁下变化。
  • pick_next_task() 进入选型前 ++,退出前 --
  • __sched_core_flip() 在翻转前自旋轮询该计数,归零后再换 rq_lockp()
  • sched_core_cpu_deactivate()move(不是 copy)把计数搬到新 leader,旧 leader 清零。
  • sched_init() 显式初始化为 0。

关键实现

锁变化只在共享锁下进行,所以等待侧只需采样同一把锁下的字段,不需要额外 smp_mb:

static void __sched_core_flip(bool enabled)
{
    /*
     * A core-wide selection may have the shared rq lock temporarily
     * released by a lock-dropping ->pick_task(). Flipping would
     * rebind rq_lockp() under it. Wait it out.
     */
    while (cpu_rq(cpu)->core->core_pick_in_flight) {
        sched_core_unlock(cpu, &flags);
        cpu_relax();
        sched_core_lock(cpu, &flags);
    }
    /* ...翻转 rq_lockp 与 core_enabled... */
}

进入选型时增加计数,退出时减小计数:

static struct task_struct *pick_next_task(struct rq *rq, struct rq_flags *rf)
{
    /* 进入:标记一次 core-wide selection 正在进行 */
    rq->core->core_pick_in_flight++;

    /* ...原有选型逻辑... */

    /* 退出:扣减一次 */
    rq->core->core_pick_in_flight--;
    return next;
}

CPU切换 leader 时搬移计数:

static void sched_core_cpu_deactivate(unsigned int cpu)
{
    /*
     * A stale leftover would bias the count forever if this CPU later
     * returns as its own leader. Move, don't copy.
     */
    core_rq->core_pick_in_flight = rq->core->core_pick_in_flight;
    rq->core->core_pick_in_flight = 0;
}

新增 struct 字段:

struct rq {
    /* ... existing fields ... */
    unsigned int core_pick_in_flight;
};

整体状态机(flip 侧的等待循环):

          +----------------------+
          |  __sched_core_flip() |
          +----------+-----------+
                     |
                     v
          +----------+----------+
          | core_pick_in_flight  |
          | == 0 ?               |
          +----------+----------+
              yes |          | no
 v          v
          +-------+----+   +-------------------+
          | rebind      |   | unlock + relax |
          | rq_lockp() |   | re-lock + retry   |
          | flip done |   +-------------------+
          +------------+

Patch 概览

本邮件本体并非"讨论"或"RFC",而是 stable 回填失败的告警;真正的 patch 内容在原 commit f3629c63a4af 中:

kernel/sched/core.c __sched_core_flip():        新增 while 等待 core_pick_in_flight
                  pick_next_task():          进入 ++ / 退出 --
                  sched_core_cpu_deactivate: move 而不是 copy
                  sched_init():              初始化 0
kernel/sched/sched.h
                  struct rq: 新增 core_pick_in_flight 字段

类比

把 SMT 兄弟核想象成会议桌旁的两组人,桌上原本只有一把大门钥匙(共享 core 锁)。如果发言环节有人临时把钥匙放在桌上(drop rq lock),另一组人趁机换锁,原发言的人再回来时已经进错了房间。本补丁在大门口装一个计数器 — 凡是进会议的人都要在登记表上 +1,离场时 -1;只有登记表归零才允许换锁,相当于会议中间不许换。CPU 下线迁移相当于把"今日签到表"转交给新 leader,而不是复印一份,否则下次开会旧 leader 桌上会多出一张永远没人认领的签到表。

Highlight:风险与注意点

  • 自旋等待是 active polling,但 __sched_core_flip() 是 cookie 生命周期事件,频率极低,热路径不受影响。
  • 计数只在共享锁下变化,无需 barrier;前提是后续不能有人绕过这把锁读写它。
  • 6.1-stable 直接 cherry-pick 失败:sched.h 在该分支结构与上下文略有差异,需要手工解决冲突再投递。
  • 任何持有共享 core 锁却不再走 pick_next_task() 的新代码路径,必须记得对称 ++/--,否则 flip 会永久卡住。
  • 字段是 unsigned int,极端嵌套退出会导致 wrap;理论上必须先验证 core_pick_in_flight 在重负载下不会溢出。

版本变化

没有 v2/v3,原 commit 即终版;本邮件仅是一次 stable backport 失败通知。

与其他相关 patch 系列的关联

  • 根因 patch:539f65125d20 ("sched: Add core wide task selection and scheduling"),本补丁 Fixes 标签即指该提交。
  • 配套 lockdown/cookie 路径:sched_core_lock() / sched_core_unlock(),本补丁等待循环正是依赖它们的对称 unlock/lock。
  • stable 范围标注:v5.14+,意味着所有受支持的 stable/longterm 都需要回填。

一句话总结

Greg KH 自动通知:sched/core: Make core-sched flips wait for in-flight selectionslinux-6.1.y 上 cherry-pick 失败,需要手工解决冲突后用 git send-email 重投 stable@vger.kernel.org