sched discussion
[PATCH 5.15 001/843] nvmet-tcp: fix race between ICReq handling and queue teardown
LLM 分析
Linux 5.15 stable:5.15.212-rc1 超大规模修复审查
系列概况
- 标题:
[PATCH 5.15 000/843] 5.15.212-rc1 review - 作者:稳定版系列由 Greg Kroah-Hartman 发布;补丁来自多个上游作者,并由稳定版维护者回移。
- 版本:Linux 5.15.212-rc1。
- 规模:843 个正式补丁,加 1 封封面邮件和 5 封回复,共 849 封邮件。
- 修改文件:跨越 NVMe、NFS、F2FS、网络、调度器、KVM、BPF、USB、PCI、perf、ALSA、IIO、加密、文件系统及大量设备驱动。输入未提供完整汇总文件清单。
- 代码统计:封面邮件称提供了 diffstat,但输入中的封面正文在 shortlog 中途截断,无法可靠给出全系列增删行总数。部分补丁各自带有局部统计。
- Message-ID:
20260721152405.946368001@linuxfoundation.org - 完整性:补丁编号
000/843至843/843均出现,编号层面完整;但大量邮件正文为空,若只依赖本次输入,不能逐项核验这些补丁的 commit message、diff 和依赖关系。
尽管来源频道标为 sched,这不是单独的 scheduler 系列,而是一次覆盖整个 Linux 5.15 稳定树的发布候选审查。
补丁目的
该系列准备 Linux 5.15.212 稳定版,目标是把已经进入上游或其他稳定树的修复安全地回移到 5.15.y,并在正式发布前收集构建、启动和运行回归报告。
整体重点包括:
- 修复 use-after-free、越界访问、整数溢出、空指针和信息泄漏。
- 修复锁顺序、引用计数、资源释放及设备移除竞态。
- 加强文件系统、网络协议、固件和设备返回数据的边界检查。
- 修正 scheduler、RT mutex、CPU hotplug、cpufreq 和 perf 等核心路径。
- 为 5.15 的旧 API 和旧数据结构进行上下文适配。
旧流程的问题
多个补丁反映了相似的旧流程缺陷:
- 外部长度、索引或状态值未经验证便参与数组访问、位移或长度计算。
- 对象已经进入销毁阶段,异步工作、socket 回调或错误路径仍可能再次操作它。
- 数据结构被移动或拆分时,配套的所有权位图、引用计数或状态位没有同步移动。
- 错误路径直接释放已发布对象,没有先从 IDR、RCU 列表或注册表中摘除。
- 旧稳定树直接接受较新内核 API 的调用,可能缺少函数、类型或结构成员。
- 部分调度决策统计了任务不允许运行的 CPU,或者为非 PREEMPT_RT 配置启用了代价较高的 RT push IPI。
新流程
新流程普遍采用“先验证、再变更;先阻止新使用者、再释放”的顺序:
Upstream fixes
|
v
5.15 backport and context adaptation
|
v
843-patch stable review ---> build and runtime testers
| |
| v
+---------------------- regression reports
|
v
fix, dependency, or drop
典型防护逻辑可以概括为:
if (!entry_is_valid(entry))
return -EINVAL;
lock_object_state();
if (object_is_tearing_down())
return -ESHUTDOWN;
update_state_and_ownership_together();
对于无锁页表重检,则只在条目确实为 present PTE 时解释写权限位,避免把 swap 或 migration entry 的 offset 位误当成权限位。
Patch 概览
| 范围或补丁 | 作用 |
|---|---|
| 001 | 串行化 NVMe/TCP ICReq 完成与 queue teardown,防止重复释放 |
| 003–015 | 修复 NFSD stateid 生命周期并整理 recovery 数据所有权 |
| 005 | userfaultfd 只对 present PTE 检查 write bit |
| 016 | KVM ioeventfd 使用 get_unaligned(),移除 guest 可触发的 BUG_ON() |
| 018 | 修复 nftables 删除 set 失败后的事务回滚 |
| 019–020 | 把 sk_msg.sg.copy 攓为位图,并在 SG 变换中保持同步 |
| 021–023 | 修复 AppArmor 引用竞态、netns 权限检查和 Fast Open connect 绕过 |
| 024–033 | F2FS 元 inode、损坏镜像、zone capacity、xattr 与 GC 死锁修复 |
| 044–045 | 修正 rtmutex waiter 删除对象及未入队 waiter 处理 |
| 117 | 非 PREEMPT_RT 配置默认关闭 RT_PUSH_IPI |
| 199 | fair scheduler 选择目标组时只统计任务允许的 CPU |
| 405–440 | 集中修复 perf 工具的空文件、长度、格式化和边界问题 |
| 620 | 修复 MIPS scheduler 在 CPUMASK_OFFSTACK 下的内存破坏 |
| 765–770 | PCI Resizable BAR 失败回滚、资源树恢复及代码整理 |
| 843 | 修复 ALSA sequencer 事件复制中的未初始化堆数据泄漏 |
关键实现
1. NVMe/TCP queue teardown 状态机
nvmet_tcp_handle_icreq() 原来可能在 teardown 已把队列设为 DISCONNECTING 后,又写回 LIVE 或失败状态,导致后续 socket 状态变化再次进入释放路径并执行第二次 kref_put()。
补丁在发送 ICResp 后使用 state_lock 检查状态;若 teardown 已开始,返回内部哨兵 -ESHUTDOWN。接收状态仍保持 NVMET_TCP_RECV_ERR,防止旧 ICReq 被再次解析。
ICReq consumed socket closes
| |
v v
io_work DISCONNECTING
| |
+------ state_lock --------+
|
already tearing down?
/ \
yes no
| |
-ESHUTDOWN set LIVE
2. F2FS 的边界与死锁修复
F2FS 补丁形成一个相对完整的防护组:
- 拒绝损坏目录项把普通 inode 指向内部 meta inode。
- 只在
compress_cache启用时把压缩缓存 inode 视为内部 inode。 - 校验 orphan block 的
entry_count,防止越过ino[]。 - 无论 inode 是否带 inline-xattr 标志,都限制磁盘提供的最大 inline xattr size。
- 使用 zone capacity 而不是物理 section 大小计算有效块。
- pinned file 的 fallocate 起点向 section 边界下取整。
- foreground GC 前提交缓存的 OPU/IPU DATA bio,避免 GC 与 writeback 围绕同一 folio 互相等待。
3. sk_msg.sg.copy 所有权同步
sg.copy 表示对应 scatterlist entry 是否来自不能向 BPF 暴露为可写内存的外部页。
旧代码移动 sg.data[] 时没有移动该位,可能把 page-cache 页移动到一个 copy 位为 0 的槽中,使 BPF 获得错误的可写视图。019 先把单个 unsigned long 改为可扩展位图,020 再覆盖 pull、push、pop、shift、xfer 和 TLS split 等变换路径。
4. scheduler 与锁路径
sched/fair选择 destination group 时只更新任务 cpumask 允许 CPU 的统计,避免不可达 CPU 扭曲负载均衡结果。sched/rt对普通非 PREEMPT_RT 内核默认关闭RT_PUSH_IPI,减少不必要的跨 CPU push 中断行为。- rtmutex 补丁使用
waiter->task而不是假定current,且 waiter 未实际入队时不再调用删除逻辑。 - MIPS scheduler 修复动态 cpumask 存储使用错误导致的内存破坏。
5. 审查中发现的 perf 构建回归
Florian Fainelli 报告 5.15.212-rc1 的 perf 构建失败,错误指向:
perf_env__get_cpu_topology()在 5.15 工具代码中没有声明;(struct perf_cpu){ al->cpu }与该树的数据结构不匹配。
这与补丁 406 perf tools: Use perf_env__get_cpu_topology() in machine__resolve() 高度相关,说明回移时可能遗漏前置 API 或结构体转换。它是本线程中最明确的 RC 阻塞项,不能仅凭内核本体构建成功而忽略。
类比
这次 stable review 像一次大型旧楼翻修:843 个补丁分别加固电线、消防门、电梯和水管。很多修复本身来自新楼的成熟方案,但 5.15 是旧楼,接口尺寸和管线位置不同,不能把新零件原样塞进去。
sk_msg.sg.copy 类似货箱上的“不可拆封”标签:搬动货箱时必须连标签一起搬。只移动箱子、不移动标签,就可能让下一位工人误把外部所有的货物当成可修改物品。
perf 回归则像消防系统改造完成后,发现维护人员的检测仪插头与旧楼插座不兼容:修复意图正确,但回移缺少配套接口,发布前仍必须修正。
Highlight:风险与注意点
- 明确构建阻塞:perf 的
perf_env__get_cpu_topology()缺失或 API 不匹配需要在发布前解决。 - 系列过大:843 个补丁横跨全树,单一 RC 中的交互风险和二分成本都很高。
- 输入内容不完整:大量邮件正文为空,无法从本次材料审计每个补丁的实际 diff、签名链和依赖。
- 回移语义风险:多个补丁明确进行了 5.15 专用改写,不能仅依据上游测试结果确认正确性。
- 调度语义变化:
RT_PUSH_IPI默认值和 allowed-CPU 统计会改变特定负载下的迁移行为,需要 RT、cpuset、CPU hotplug 和 NUMA 场景测试。 - 安全修复密集:系列包含大量 UAF、OOB、权限绕过和信息泄漏修复,应避免因普通硬件测试通过而低估其重要性。
- 依赖顺序重要:019→020、026→027、031→032、765→770 等补丁需要按系列顺序应用。
版本变化
本线程只提供 5.15.212-rc1,没有 v2 或 rc2。
不过可见多处上游到 5.15 的适配:
- NVMe/TCP 删除了 5.15 尚不存在的
NVMET_TCP_Q_FAILED相关 hunk。 - userfaultfd 将新树的 marker/return 风格改写为 5.15 原有函数结构。
- KVM 使用旧树的
<asm/unaligned.h>。 - AppArmor 展开了 5.15 中不存在的
sk_is_tcp()。 - NFSD 因 5.15 没有
ls_fence_work,删除了对应初始化 hunk。
一句话总结
5.15.212-rc1 是一组以安全性、并发正确性和边界校验为主的超大稳定版回移,但当前已出现明确的 perf 旧树 API 构建回归,修复并完成跨架构验证后才适合发布。