跳到正文
Hacker News· wicket·· 9 天前AI 评分36

Boro:面向 Linux 内核补丁的多阶段智能体审查与测试 CLI

Boro – Linux patch review and testing CLI with a multi-stage agentic workflow

AI 导读

Boro 是一款 AI 辅助的 Linux 内核开发 CLI,在开发者本地 git 树中运行,用于补丁系列公开前的交互式审查与修复,以及 backport、发行版内核维护等下游工作。

正文 · AI 翻译

Boro 的用途

Boro 是一款 AI 辅助的内核开发 CLI,面向在自己的 git 树中工作的开发者。它适用于补丁系列公开发布之前的阶段,也适用于可能永远不会走常规邮件列表评审流程的下游工作:backport、发行版内核维护、安全修复集成,以及其他本地补丁栈的迭代。

该项目受 Sashiko 启发。 两个工具共享相同的底层评审提示词,但面向补丁生命周期的不同时刻。Sashiko 针对补丁系列出现在公共邮件列表之后的评审进行了优化;Boro 则针对开发者仍在塑造补丁系列或将其向下游携带时的交互式本地评审与修复进行了优化。

TL;DR

从此检出安装 boro:

cargo install --force --path .

将其指向任意 OpenAI 兼容的 chat/completions 端点:

export BORO_URL=https://api.example.com/v1
export BORO_KEY=<api-key>
export BORO_MODEL=<model-name>

在 Linux 内核 git 树中运行评审:

cd /path/to/linux
boro review origin/master..HEAD

传入单个提交 ID 会被解释为 abc123^..abc123。

应用发布到 lore 的补丁系列,然后评审本地创建的提交:

boro --source /path/to/linux apply \
  --message-id 20260620192214.923500-1-oliver@liuxiaozhen.dev
boro --source /path/to/linux review BASE..HEAD

这需要 b4。Boro 会在一个一次性 worktree 中导入已发布的补丁系列,通过常规的 boro apply 工作流应用每个提交,移除该 worktree,并打印出用于 boro review 的精确 BASE..HEAD 范围。b4 会在 boro 将其应用到选定的源 HEAD 之前,按补丁系列声明或推断的基线重建该系列。

演示

boro-demo.mp4

设计与工作流

同步执行

整个流水线在一个进程中同步运行。实时多行状态会在工作过程中显示每个 worker 的状态以及每个阶段的 token 计数。

模型角色与 token 核算

Boro 将承担大部分工作的模型与强验证模型分开。

BORO_MODEL 驱动常规的广泛发现与专项发现。在常规评审中,BORO_VALIDATION_MODEL 驱动初始的完整上下文快速评审,仅验证新的常规阶段候选,并渲染报告。使用 --fast 时,快速评审改用 BORO_MODEL。

预期的工作流是让广泛阶段和专项阶段保持低成本,同时对受保护的基线、验证和报告使用更强的模型。

例如,在广泛阶段和专项阶段运行本地模型,并将验证阶段指向更强的远程模型。运行摘要中会按阶段细分 token 使用量,因此你可以确切看到预算花在了哪里。

评审、构建与测试

Boro 支持可选的构建与测试验证:它可以构建每个提交,并在需要时在 virtme-ng 下启动生成的内核,以运行由 AI 选择的针对性测试。

子命令:

  • boro review COMMIT_RANGE:使用面向内核的提示词(子系统说明、模式、检查清单)进行多阶段 agent 代码评审,最后给出 LKML 风格的叙述式摘要。
  • boro build COMMIT_RANGE - 在各自的 worktree 中检出每个提交,用 vng -b 构建它,然后让模型对构建日志进行分诊。
  • boro test COMMIT_RANGE - 与 build 相同,然后在 virtme-ng 下启动内核,并在 VM 内运行由模型挑选的快速测试(匹配的 kselftest、对受影响代码路径的用户空间探测,或作为兜底的 dmesg)。模型会对捕获的输出进行分诊,并生成摘要以及任何发现。
  • boro test --config CONFIG_FOO - 构建 HEAD,并将 CONFIG_FOO=y 合并到 virtme-ng 的默认配置中,要求模型从 Kconfig/源码上下文中为该选项选择一个快速测试,然后启动并运行它。也接受显式值,例如 CONFIG_FOO=m、CONFIG_NR_CPUS=512 或 CONFIG_CMDLINE="console=ttyS0 root=/dev/vda"。 添加 --plan 可生成详细的、不执行的测试计划。计划模式可以描述多步骤、长时间运行或依赖硬件的测试,因为 boro 在该模式下不会构建或启动内核。当 --plan 与多提交范围一起使用时,boro 会为整个范围生成一个集成测试计划,而不是为每个提交生成一个计划。

build 和 test 模式会将真实的编译器输出和真实的内核运行时输出反馈给模型,而不仅仅是 diff 文本。这正是值得在本地机器上运行而不是把任务提交到某处的原因。

AI 辅助 cherry-pick

Boro 还支持对无法干净应用的提交进行 AI 辅助 cherry-pick,自动尝试解决冲突。

子命令:

  • boro apply COMMIT_RANGE - 应用单个提交或某个范围内的每个提交,例如 BASE..TIP,从最旧的开始。Boro 在第一次失败时停止,并保留之前已应用的提交。每个提交都会经过下面现有的 git cherry-pick -x -s 工作流;--dry-run 仅列出该系列。 如果 Git 报告 cherry-pick 失败或为空,boro 首先检查提交主题是否已存在于路径受限的历史中,若存在则跳过它。 否则,boro 会在目标提交消息中查找显式的提交引用;任何尚未在 HEAD 中的被引用提交会先用 git cherry-pick -x -s 尝试,然后重试目标提交。

  • boro apply --message-id MESSAGE_ID - 使用 b4 获取已发布的系列,并通过相同的从最旧开始的工作流应用它。成功后,boro 会打印生成的本地提交范围以及可复制的 boro review 命令。

    对于剩余的 diff3 冲突,BORO_MODEL 会为每个冲突提出解决方案,并由 BORO_VALIDATION_MODEL 进行把关。验证器的拒绝会被发送回主模型以再次尝试解决,每个 hunk 最多 10 轮。如果每个 hunk 都通过验证,boro 会重写冲突文件、暂存它们、继续 cherry-pick、将 git 的 -x 尾注更新为 (backported from commit ...),并打印 agent 所做的更改。

    在应用后审查阶段之后,boro 会对新添加的结构体字段访问运行仅源码检查,并标记明显的 backport 缺口。如果该检查失败,验证模型会收到确切问题以及 edit_file,在能够修复缺口时修正提交,然后 boro 重新运行仅源码检查。

要求

  • 对于 apply --message-id:安装 b4 并确保它在 $PATH 上。
  • 对于 build / test:安装 virtme-ng(vng)并确保它在你的 PATH 上。
  • 可选:在 $PATH 上安装 lei(来自 public-inbox 包),用于 upstream-followup 阶段。没有 lei 时,boro 仍会运行其他所有阶段并生成完整审查——只是跳过 lore.kernel.org 检索。Linux-master Fixes: 查找仍然可用。即使已安装 lei,也要显式禁用 lore 部分,请设置 BORO_LORE_ENABLED=0。

构建 & 安装

cargo build --release
# binary: target/release/boro

可选,通过运行以下命令安装二进制文件:

cargo install --force --path .

凭据

上述成本感知、多模型方案由这些环境变量驱动。验证器槽位独立于主模型,因此你可以自由混合端点(廉价的本地主模型、强大的远程验证器,或任何其他组合)。

使用 API Key

对于真实的 API 运行,请设置以下 OpenAI 兼容环境变量:

变量 含义
BORO_URL OpenAI 兼容的 API 基础 URL
BORO_KEY API key
BORO_MODEL 模型名称

可选地,初始的快速审查、常规补充验证阶段、报告渲染器以及boro apply冲突验证器可以指向另一个(通常更强的)模型:

变量 含义
BORO_VALIDATION_URL 验证模型的基础 URL(默认为BORO_URL)
BORO_VALIDATION_KEY 验证模型的 API 密钥(默认为BORO_KEY)
BORO_VALIDATION_MODEL 验证模型的名称(默认为BORO_MODEL)

任何未设置的值都会回退到其BORO_*对应项,因此当替代模型位于同一端点时,只需设置BORO_VALIDATION_MODEL即可。

Agent 后端

作为 API 密钥的替代方案,你可以通过--backend claude|opencode|codex使用 Claude、OpenCode 或 Codex 后端。

在此模式下,boro 依赖 agent CLI 来提供凭据、工具和权限。

与本地 Ollama 配合使用

使用 Ollama 拉取 qwen3-coder:30b 模型:

$ ollama pull qwen3-coder:30b
$ ollama serve

审查 Linux 内核 git 树中从 origin/master 到 HEAD 的提交:

$ cd /path/to/linux
$ BORO_URL=http://127.0.0.1:11434 \
  BORO_MODEL=qwen3-coder:30b \
  boro review origin/master..HEAD

审查流水线

对于范围内的每个提交,Boro 首先在本地收集补丁元数据和源代码上下文,然后运行以下有序阶段。

步骤 阶段 简要描述
0 识别内核子系统 为共享参考包选择子系统指南提示
1 上游跟进 查询 lore.kernel.org 并总结相关跟进
2 快速完整上下文审查 建立受保护的只读基线发现
3 广泛关注点 对参考上下文 + 补丁进行独立的常规检查
4 执行流验证 控制流、逻辑、错误、分支、宏、链接器/LTO 风险
5 资源管理 生命周期、泄漏、UAF、引用计数、拆除与异步交接
6 锁与并发 睡眠/原子规则、顺序、竞态、RCU、屏障、IRQ 上下文
7 安全 边界、溢出、提权、TOCTOU、用户/内核数据边界
8 硬件与可移植性 驱动/硬件:DMA、IRQ、屏障、字节序
9 注释/代码一致性 根据实际代码审计补丁触及的注释
10 整合阶段 将常规关注点转化为候选补充
11 强裁定与补充验证 独立裁定每个基线发现并过滤常规补充
12 增量合并与 LKML 报告 将幸存项合并到基线中并渲染报告

BORO_MODEL用于常规发现和整合。在常规审查中,BORO_VALIDATION_MODEL用于步骤 2、11 和 12,未设置时回退到BORO_MODEL。

初始快速审查使用与 --fast 相同的提示词和输入: 常规审查者系统提示词、 fast-review.md 指令、参考及预取的源上下文、 由步骤 0 选择的子系统指南、上游跟进摘要、提交 信息以及 diff。在常规审查中它使用 BORO_VALIDATION_MODEL; 在 --fast 下它使用 BORO_MODEL。常规发现是独立的, 只能贡献新发现;它不能改写或替换基线 发现或其 lore 来源。专家可以单独质疑某个 快速发现,但这只是可选证据,基线在所有专家运行期间保持 只读。随后强验证模型会针对仓库独立裁决每一条基线发现, 包括没有任何专家质疑的发现。它只有在经过仓库工具检查后返回 完整精确的发现并附上无保留的结构化矛盾证明时, 才能 DROP 某条发现。宿主只应用精确的、经工具验证的 DROP 决策;验证失败、歧义、缺少工具检查、 输出格式错误或 --validation-mode=off 都会保留该发现。 确定性的上游修复发现必须获得 KEEP,且不能被丢弃。 验证器还会丢弃明显报告同一底层问题的常规候选。 本地合并仅移除完全相同的身份,因此同一 位置的不同发现会被保留。

--validation-mode 仅改变发现后的阶段:

  • filter(默认):裁决每一条基线发现,验证常规 新增项,合并幸存项,然后渲染 LKML 文本。
  • findings:执行相同的基线裁决和增量合并,同时跳过 LKML 渲染。
  • off:保留每一条快速发现,并添加未经 验证的原始常规候选。

boro review --upstream-repo URI --upstream-branch BRANCH COMMIT_RANGE 选择用于检查后续修复的 Git 仓库和分支。它默认为 git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git;使用 本地路径或 file:// URI 来改为检查本地 Linux 仓库。 --upstream-branch 默认为 master。

使用 --fast 时,每个提交只获得快速完整上下文审查, 使用 BORO_MODEL。该响应会经过常规的 逐提交 LKML 渲染器以生成最终报告。上游跟进 阶段在子系统识别之后运行,两个阶段都为参考 包提供输入。专家轮次、验证以及运行范围的模型摘要都会被 跳过。将 --fast 与 --no-tools 结合使用,可在快速审查和 LKML 渲染轮次中 都禁用仓库工具。

上游跟进阶段(lore.kernel.org + 上游分支)

在发现开始之前,boro 会针对 lore.kernel.org 运行一次确定性的、无状态的查询, 以呈现围绕该补丁的现有邮件列表活动——v-bumps、稍后发送的 Fixes: 补丁, 以及实质性的维护者审查。它还会将选定的上游分支直接 获取到 Git 的临时 FETCH_HEAD 中,并检查其 提交信息中是否有 Fixes: <12-char-reviewed-sha> 尾注。这能捕获 已到达所配置上游分支但在所配置 lore 窗口内无法发现的 后续修复。lore 结果作为参考包的一部分为每个 下游发现阶段提供输入,因此上游社区已经提出的关切可以被后续审查阶段 使用。这些评论是证据而非强制发现:当下游审查确认被审查的新代码或完整系列 已明确解决该关切时,必须丢弃它们,并且仅对仍然适用的关切保留 lore URL。来自所配置上游分支的 Git Fixes: 命中也会作为高严重性发现添加,因此即使模型原本会忽略仅作参考的上下文, 它们也能通过验证并出现在最终报告中。 查询为:

lei q -I https://lore.kernel.org/all/ -f mboxo --threads -d mid --no-save \
    -- '"<patch-subject>" AND rt:<window>'

配置(全部可选):

变量 默认值 作用
BORO_LORE_ENABLED 1 设为 0 可完全跳过该阶段
BORO_LORE_WINDOW 1.year.ago.. Public-inbox rt: 窗口。
BORO_LORE_MAX_BYTES 65536 从 lei 结果中保留的最大字节数
BORO_LORE_INBOX_URL https://lore.kernel.org/all 远程收件箱

lore 部分需要 lei(来自 public-inbox 包)在 $PATH 上;上游分支查找仅使用 git,并且在未安装 lei 时仍会运行。它独立于 lore 查找运行,包括在 lei 可用时。上游分支每次内核审查获取一次到 FETCH_HEAD;boro 不会添加或修改已配置的远程。获取失败、lei 查询或模型调用失败会被记录;审查会继续使用仍然可用的任一后续来源。

注释 / 代码一致性阶段

第六个专家阶段(上文第 8 步)审查补丁所触及的注释是否准确描述了它们所指的代码。与其他专注于查找缺陷的专家阶段不同,此阶段也会标记措辞层面的偏差——例如 kernel-doc 声称两个标志“一起清除”,而代码用两条顺序语句清除它们,即使正确性不受影响也会被报告,因为过时或不精确的注释是后续回归的已知来源。

该阶段按流程运行:枚举 diff 中注释(块注释、行注释、尾随注释、kernel-doc)提出的每一项不同的事实性声明,定位支持每项声明的代码(当引用的代码位于另一个函数或文件时,提示词强制要求使用工具),对照定位到的代码验证每项声明,并对每一处矛盾发出发现——同时引用注释文本和与之矛盾的代码行。

明确标记的模式包括代码未实现的原子性 / 顺序声明(互斥锁串行化并非原子)、与实际调用者矛盾的锁定或调用者上下文声明、补丁触及的注释中过时或已重命名的符号引用、kernel-doc @param / Return: / Context: 不匹配,以及代码未确立的前置 / 后置条件声明。

在 --fast 上跳过(单遍折叠)。

额外选项

选项 --fast 标识子系统,运行上游后续阶段,以每个提交一个 BORO_MODEL 步骤执行完整上下文快速审查,然后对该结果运行常规 LKML 报告流程。它跳过专家、验证和运行范围摘要。

选项 --validation-mode 选择是否(以及如何)验证常规阶段候选新增项:

  • filter(默认):验证常规新增项,对每个受保护基线发现用一项结构化、由仓库工具支持的 KEEP 或 DROP 证明独立裁定,将幸存项与已验证的常规新增项合并,然后渲染每个提交的 LKML 文本。不完整、顺序错误或不精确的基线裁定会被拒绝并重试;只有当 DROP 的精确证明通过主机验证时才会被应用。查看器 / 人类报告的 Findings 部分显示 validated_findings;LKML 部分显示由这些幸存项构建的文本。没有幸存项的提交没有 LKML 报告正文;渲染器不会独立添加或移除发现。
  • findings:执行相同的基线裁定、增量验证和合并,跳过每个提交的 LKML 流程(每个提交节省一次 LLM 调用;此模式下人类报告的 LKML 部分为空)。scripts/boro-json-view 自动检测此模式(以及 filter),并将 validated_findings 内联锚定在每个发现的 location.file:line 处、紧邻 diff——使用 --use-validated=auto|always|never 可覆盖。
  • off:完全跳过验证。原始常规候选在按提交进行 LKML 渲染之前被添加到快速基线中。

全局标志 --json 会在 stdout 上输出一份格式化良好的 JSON 文档,而不是人类可读的报告——其结构与内部使用的相同,包含每个提交的 findings[]、lkml_report(仅限 filter/off 模式)、validated_findings[](验证成功时的 filter/findings 模式),以及一个 usage_summary。在 filter/findings 模式下,findings[] 是在强验证器做出精确的、经工具验证的 DROP 决策后受保护的快速基线,而 validated_findings[] 是基线加上已接受的常规新增内容。每个 finding 可以携带可选的 location 和 references 字段:

{"file": "path/in/diff", "line": 42, "line_end": 45, "side": "RIGHT"}

references 记录来源信息,例如 lore 讨论:

{"kind": "lore", "url": "https://lore.kernel.org/all/<message-id>/", "claim": "What the thread supports"}

合并、验证和 LKML 渲染会原样保留引用 URL。

缺失时 side 默认为 RIGHT(post-image / additions / context);LEFT 锚定到 pre-image(deletions)。line_end 对范围而言是可选的。模型被指示在无法将 finding 定位到某个 hunk 时省略 location,而不是编造一个——并且作为兜底,boro 会解析每个提交的 unified diff 一次,并丢弃任何在给定侧无法锚定到真实 hunk 行(或其文件不在该提交的变更路径中)的 location。finding 的文字内容会被保留;只移除错误的锚点,因此查看器会回退为将其渲染为提交级评论。

结构化审查高亮

审查 JSON 保留 summary.text 和 summary.counts,并新增 summary.highlights。该附加字段是可选的,因为较旧的生产者会省略它,但当前 Boro 会输出一个数组,该数组可能为空。因此 schema_version 仍为 1,现有消费者可以继续只读取 text 和 counts。

每个 finding_ref 都是 <full-commit-sha>:<zero-based-effective-finding-index>。有效数组在存在时(包括为空时)为 validated_findings,否则为 findings。Boro 从该 finding 复制权威的 commit、severity 以及可选的 location;title 和 question 是编辑性字符串。未知、重复或格式错误的引用会被省略,并且最多输出三个高亮。未知的响应对象键会被忽略,而不会被复制到公开高亮中。

将 summary.text、title 和 question 视为不受信任的纯文本。在空白规范化之后,Boro 会拒绝剩余的 Unicode 控制字符和双向格式控制字符。类似 URL 的编辑性文本仍不受信任,且永远不会成为权威链接目标;Boro 不接受任何由模型编写的权威 URL 字段。此解析器检查不是输出上下文转义:每个 GitHub、GitLab、HTML 或聊天消费者仍必须针对其输出上下文集中转义或清理这些字符串,包括链接、HTML 和提及。仅从权威的 commit 和 location 字段构建源链接。

{
  "schema_version": 1,
  "summary": {
    "text": "One medium-risk issue needs attention.",
    "counts": {"Critical": 0, "High": 0, "Medium": 1, "Low": 0},
    "highlights": [{
      "finding_ref": "a64709a4a613d3008b63c1c7d20c295bdd1cad49:0",
      "commit": "a64709a4a613d3008b63c1c7d20c295bdd1cad49",
      "severity": "Medium",
      "title": "Notifier callbacks can self-deadlock",
      "question": "Can callbacks re-enter notifier registration while dpll_lock is held?",
      "location": {"file": "drivers/dpll/dpll_core.c", "line": 51, "line_end": 54, "side": "RIGHT"}
    }]
  }
}

对于终端查看,scripts/boro-json-view 会消费该 JSON 并渲染出 GitHub 风格的“Files changed”视图:每个文件的 diff 带有旧/新行号栏、ANSI 着色的 diff 正文,以及锚定在每个 finding 位置的按严重程度着色的行内评论框。

boro review HEAD~3..HEAD --json | scripts/boro-json-view | less -R

对于 boro test,--timeout SECONDS 标志限制 VM 内命令(默认 300 秒)。运行长时间 kselftest 时请调高它。

对于 boro review,--timeout SECONDS 设置每个模型阶段的超时时间(默认 600 秒),包括重试、工具循环和子进程后端。

使用 boro test --plan COMMIT_RANGE 或 boro test --plan --config CONFIG_FOO 来请求详细的测试计划,而无需调用 vng -b 或启动内核。对于多提交范围,boro 会请求一个覆盖整个系列的单一计划。与普通的 test 选择器不同,计划模式不限于在最小 virtme-ng VM 内执行一条快速命令:它可以指定所需硬件、内核配置、设置步骤、命令以及预期的成功或失败信号。

提示缓存默认开启:boro 会在系统提示和初始用户块上发送 Anthropic 风格的 cache_control 标记,以便提供商能够在各阶段的工具循环迭代中(以及跨阶段,因为系统提示相同)从提示缓存中提供固定前缀。子进程 CLI(--backend claude / opencode / codex)自行管理缓存并忽略此设置。如果提供商拒绝这些标记(使用不同缓存机制的模型系列,例如 Gemini),boro 会在不带标记的情况下重试同一请求一次,并在本次运行的剩余时间内静默保持缓存关闭。当针对你已知不支持该功能的端点运行时,传入 --no-prompt-caching 以跳过标记形式(以及一次性的回退探测)。

在审查一系列多个提交时,该工具会并行运行多个工作进程,按顺序处理审查流水线。最后,所有工作进程的发现会被合并在一起,生成 LKML 风格的报告(第 10 步)。

该工具的目标是即使个别步骤或 API 调用失败也能完成整个范围:你可能会在报告中看到部分结果或每个提交的错误说明,而不是整个运行中止。

示例输出

  • boro review:
 LKML-style report
────────────────────────────────────────────────────────────────────────
  Commit 56930b7600b9...
  ····························································
  commit 56930b7600b9d512e73e7c9468c0f362481546d5
  Author: Andrea Righi <arighi@nvidia.com>

  sched/core: Skip put_prev_task/set_next_task re-entry for sched_ext donors

  This commit avoids re-entering the sched_ext class during proxy-execution
  donor stabilization to prevent potential BPF vtable corruption or NULL
  pointer dereferences. It checks the donor's scheduling class before
  calling put_prev_task and set_next_task.

  > diff --git a/kernel/sched/core.c b/kernel/sched/core.c
  > index 75541e5bb66d1..1c161dd9d7440 100644
  > --- a/kernel/sched/core.c
  > +++ b/kernel/sched/core.c
  > @@ -7147,9 +7147,14 @@ static void __sched notrace __schedule(int sched_mode)
  [ ... ]
  > -			donor->sched_class->put_prev_task(rq, donor, donor);
  > -			donor->sched_class->set_next_task(rq, donor, true);
  > +			if (donor->sched_class != &ext_sched_class) {
  > +				donor->sched_class->put_prev_task(rq, donor, donor);
  > +				donor->sched_class->set_next_task(rq, donor, true);
  > +			}

  Does this direct reference to ext_sched_class cause a build regression when
  CONFIG_SCHED_CLASS_EXT is disabled?

  It appears that ext_sched_class is used here in __schedule() without a check
  for whether the sched_ext class is actually defined or enabled in the
  kernel configuration.

  Commit d430a73a84b4...
  ····························································
  commit d430a73a84b470169a8f10f15bb0d486b8fbcdae
  Author: Andrea Righi <arighi@nvidia.com>

  sched_ext: Fix migration-disabled tasks with proxy execution

  This patch addresses two races on the SCX_DSQ_LOCAL_ON deferred dispatch
  path under proxy execution: (1) mutex-blocked donors being fed through
  ops.enqueue() producing stale deferred LOCAL_ON entries, and (2) those
  deferred entries becoming stale by drain time. It short-circuits
  put_prev_task_scx() for blocked donors and skips stale entries in
  process_ddsp_deferred_locals().

  I have a couple of questions about potential regressions:

  > diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
  > index 1f9ae082811f0..859e2bf4cf808 100644
  > --- a/kernel/sched/ext.c
  > +++ b/kernel/sched/ext.c

  [ ... ]

  > @@ -4078,6 +4102,25 @@ static void process_ddsp_deferred_locals(struct rq *rq)
  >  		list_del_init(&p->scx.dsq_list.node);
  >  		clear_direct_dispatch(p);
  >
  > +		/*
  > +		 * Skip stale entries. The deferred LOCAL_ON entry was queued
  > +		 * by BPF's ops.enqueue() at wakeup time; by the time we drain,
  > +		 * @p's state may have moved on:
  > +		 *
  > +		 *   - task_on_cpu: @p is already running. The dispatch is moot
  > +		 *     and reading remote @p->migration_disabled here races
  > +		 *     with BPF trampoline prologs that flip it transiently.
  > +		 *
  > +		 *   - task_is_blocked: @p became a proxy-exec donor and is
  > +		 *     pinned to its current rq as part of the proxy chain.
  > +		 *     Cross-CPU dispatch would tear it out of the chain.
  > +		 *
  > +		 * In both cases the next ttwu / put_prev cycle re-fires
  > +		 * ops.enqueue() with fresh state.
  > +		 */
  > +		if (task_on_cpu(task_rq(p), p) || task_is_blocked(p))
  > +			continue;

  Could there be a TOCTOU race here? Both task_on_cpu(task_rq(p), p) and
  task_is_blocked(p) are read without holding the remote rq lock. If a
  concurrent put_prev_task or context switch on another CPU changes the
  task's state between this check and the subsequent
  dispatch_to_local_dsq() call, could the task transition into the blocked
  state right after the check passes?

  That would lead to the exact cross-CPU dispatch of a proxy-exec donor
  that this patch is trying to prevent.

  Additionally, when this check causes a deferred entry to be skipped, the
  task has already been removed from the deferred list via list_del_init()
  and had clear_direct_dispatch() called on it. The comment says "the next
  ttwu / put_prev cycle re-fires ops.enqueue() with fresh state."

  Is that guaranteed? If the task is a blocked donor stuck in a mutex
  chain that never resolves (e.g., a priority inversion deadlock), would
  it ever receive a ttwu? The first hunk handles blocked donors in
  put_prev_task_scx(), but that only fires if put_prev runs for that task
  on its current rq.

  Could a task end up on no dispatch queue and no deferred list after
  being skipped here, with no future event to re-enqueue it?

  >  		dsq = find_dsq_for_dispatch(sch, rq, dsq_id, task_cpu(p));
  >  		if (!WARN_ON_ONCE(dsq->id != SCX_DSQ_LOCAL))
  >  			dispatch_to_local_dsq(sch, rq, dsq, p, enq_flags);
  • boro test:
Findings
────────────────────────────────────────────────────────────────────────
  8b9be1c3f479...  (0 findings)
    test: make -C tools/testing/selftests run_tests TARGETS="sched_ext" SKIP_TARGETS=""
    The kselftest for the sched_ext scheduler was executed successfully, running
    all 26 test cases without any failures or timeouts. The tests exercised
    various aspects of the scheduler's task lifecycle callbacks, including
    running and stopping operations, dispatch behaviors, and proxy-exec donor
    handling. While some tests intentionally triggered error conditions (like
    loading invalid BPF programs), these were handled gracefully as expected.
    The kernel appeared to be functioning correctly throughout the test
    execution.

另请参阅

boro --help

许可证

  • Boro 依据 Apache License 2.0 许可 - 参见 LICENSE。

  • resources/prompts/kernel/ 是来自 Sashiko 的第三方材料,同样依据 Apache License 2.0 许可。

来源:Hacker News · github.com