NVMe Surprise 掉链、控制器实例漂移与残留 I/O

目录

[0. 文档用途与口径](#0. 文档用途与口径)

[1. 现网拓扑(可定死)](#1. 现网拓扑(可定死))

[1.1 槽位 ↔ Root Port ↔ Endpoint ↔ 控制器实例](#1.1 槽位 ↔ Root Port ↔ Endpoint ↔ 控制器实例)

[1.2 双口为何被排除](#1.2 双口为何被排除)

[2. 失败链(建议按此顺序对外讲述)](#2. 失败链(建议按此顺序对外讲述))

[3. pciehp 在干什么(物理层入口)](#3. pciehp 在干什么(物理层入口))

[3.1 典型片段(Slot 40 / 32 / 42 形态相同)](#3.1 典型片段(Slot 40 / 32 / 42 形态相同))

[3.2 与 -ENODEV 的关系](#3.2 与 -ENODEV 的关系)

[3.3 现场需一并核对](#3.3 现场需一并核对)

[4. 两类 I/O:必须拆开,禁止写成「盘坏了」](#4. 两类 I/O:必须拆开,禁止写成「盘坏了」)

[4.1 僵尸 gendisk 被 udev / blkid 戳(容量已废)](#4.1 僵尸 gendisk 被 udev / blkid 戳(容量已废))

[4.2 活着或半活路径上的介质 / PI 完成错](#4.2 活着或半活路径上的介质 / PI 完成错)

[4.3 最危险的时序:新实例已活,旧 n1 无人释放](#4.3 最危险的时序:新实例已活,旧 n1 无人释放)

[5. 与 CLR / CSTS=0x1 如何衔接(改口径,不推翻旧事实)](#5. 与 CLR / CSTS=0x1 如何衔接(改口径,不推翻旧事实))

[6. 证据分级(对外时不要把推断写成事实)](#6. 证据分级(对外时不要把推断写成事实))

[7. 立即处置(只读 + 止血)](#7. 立即处置(只读 + 止血))

[7.1 止血](#7.1 止血)

[7.2 链路 / 槽位 / AER(只读)](#7.2 链路 / 槽位 / AER(只读))

[7.3 盘侧只读(禁止 reset / NSSR / FLR)](#7.3 盘侧只读(禁止 reset / NSSR / FLR))

[8. 对外话术(可直接转发)](#8. 对外话术(可直接转发))

[8.1 平台 / 现场](#8.1 平台 / 现场)

[8.2 盘厂 / 固件](#8.2 盘厂 / 固件)

[9. 后续决策树(避免现场即兴)](#9. 后续决策树(避免现场即兴))

[10. 一句话结论](#10. 一句话结论)


0. 文档用途与口径

本文把现网日志、PCI 拓扑、Identify 信息和块层错误压成一条可对外、可复盘的因果链。结论用于:

  • 现场止血(停旧节点、禁 reset、禁槽位 power cycle)
  • 平台侧查 U.2 / 背板 / 供电 / 带外
  • 盘厂侧查 CC 状态机、未开 PI 时报 Guard Check、残留 NS 完成路径

口径必须同时写两头,缺一不可:

责任面 已坐实的现象 不能单独解释的部分
平台 / 物理链路 pciehp Surprise:Card present + No link,约 30s 后再 Link Up;槽位反复重新枚举 掉链之前 盘已对 4K Read 回 0x281;CLR 后 CSTS.RDY 不落
盘固件 / NVMe 状态机 Controller Reset 后 RDY 卡在 0x1 → -ENODEV;Identify CMIC=0 槽位 Presence 仍在、链路自己掉;pciehp 风暴先于多数 -19

只骂固件或只骂槽位,都会漏掉一半证据。

明确排除:

  • 不是「双端口对端」故事。全机 NVMe 均为 xx:00.0 单功能,无 .1 第二 PF。
  • 不只是「CC.EN 清不掉 RDY」单点。那是失败链中段,入口在链路 Surprise,出口在残留 gendisk 仍被 udev / 巡检打 I/O。

硬禁令(已在现网验证会恶化):

  • nvme reset / FLR / 写 NSSR
  • echo 0 > /sys/bus/pci/slots/*/power

Slot(40)/(42) 已在断电级循环。在循环上再 reset,会把「链路不稳」升级为「CLR 卡死、CSTS=0x1、最终 -ENODEV」。


1. 现网拓扑(可定死)

1.1 槽位 ↔ Root Port ↔ Endpoint ↔ 控制器实例

热插拔槽 Root Port Endpoint 现 ctrl 旧 ctrl 本次是否进 surprise 风暴
Slot(40) e0:03.1 e1:00.0 nvme0 nvme3 是,反复 enabling device
Slot(42) e0:03.3 e3:00.0 nvme8 nvme5 是,至少两次完整回来并建队列
Slot(32) 80:01.1 很大概率 81:00.0 nvme7 --- 抖动最密;本段 grep 未见 配套 81:00.0 增删
其他槽 --- 含另一厂商一块、以及同系列另外两颗 若干 --- 未进入同一套风暴

readlink 即使未贴全也不影响:内核已把 Slot(40)→e1:00.0→nvme0、Slot(42)→e3:00.0→nvme8 打进 dmesg。

1.2 双口为何被排除

  • lspci -d ::0108(NVM Express 类代码)全部是 xx:00.0,无第二功能。
  • 对 0000:e1:00.0/0000:e1:00.* 的列举路径本身错误:那是找「该设备下的子设备」,不是找同槽第二 PF。
  • 故障后再枚举的 ctrl Identify:CMIC=0、CNTLID=0,与单控制器一致。

实例号从 nvme3→nvme0、nvme5→nvme8,是 PCI remove/add 后 nvme 核心按空闲最小号重分配,不是对端口换身份。


2. 失败链(建议按此顺序对外讲述)

复制代码
U.2 / 背板 / 供电 / 线序 / 带外 power
        │
        ▼
pciehp: Card present, No link  (~3s PD 断言, LTSSM 未起来)
        │  ~30s 等链路
        ▼
Card present + Link Up → pci enabling device
        │  上电过程中再次 Surprise
        ▼
Endpoint 从 PCI 消失 / 再出现
        │
        ├─ 用户可见:ctrl 号漂移(nvme3→0, nvme5→8)
        ├─ 驱动可见:旧 gendisk 未释放(nvme3n1 / nvme5n1 仍在)
        └─ 若此时再 nvme reset / FLR
                │
                ▼
           CC.EN 置位或 CLR,CSTS.RDY 不落(保持 0x1)
                │
                ▼
           超时 → -ENODEV (-19)   ← 链路已没设备时也会直接 -19

并行、独立的一条盘侧错误(发生在部分 Link Down 之前):

复制代码
周期性 4K Read(opcode 0x2, 8 blocks, ~2s, LBA 散落)
        │
        ▼
完成状态 SCT=2 SC=81 (0x281 Guard Check) + MORE + DNR
        │
        ▼  (随后才)
Slot Link Down → 未完成命令被 host abort → SCT=3 SC=71 (0x371)

因此:0x281 不是掉链的结果 ,是掉链前 盘已经在报 PI/介质类错误;0x371 才是掉链瞬间的 host 侧取消。


3. pciehp 在干什么(物理层入口)

3.1 典型片段(Slot 40 / 32 / 42 形态相同)

复制代码
Card present
No link                          ← Presence Detect 仍断言,链路未训练
... ~30s(热插拔驱动等 Link Up)...
Card present + Link Up
pci ... enabling device
Already in powering on state     ← 上电未完成又来一次 surprise

叠加:

日志 含义
Already disabled 槽位已被软件关掉(pciehp 自己,或有人写了 slots/*/power)
Slot(40) 反复 enabling device 同一 BDF e1:00.0 被拆掉再枚举成同一个名字 nvme0,是循环不是一次 hang
Slot(42) 建队列成功 Shutdown timeout 15s、128/0/0 default/read/poll queues、rescanning namespaces → 新实例曾经 Ready 且有 NS
Slot(32) 最密但缺 81:00.0 增删 更像 LTSSM 抖、尚未完整 remove,或 remove/add 打在别的 BDF。必须单独确认下游

3.2 与 -ENODEV 的关系

-19 / -ENODEV 在这条链上有两种充分条件,不必互斥:

  1. PCI 设备已从总线消失(Surprise remove)→ 任何后续 admin/io 都是 -ENODEV。
  2. 设备还在,但 CLR 后 CSTS.RDY 不置位,驱动放弃 → 同样 -ENODEV。

现网两种都出现过。实例号空洞大量可用 Surprise 直接解释,不必先假设双口。

3.3 现场需一并核对

  • MPS 被抬到 512:是否符合 Root Port / 交换机 / 盘的协商设计,避免当成「无关配置」。
  • BMC / 带外是否对 slot 做 power cycle(会与 pciehp 抢状态,出现 Already disabled / Already in powering on state)。

4. 两类 I/O:必须拆开,禁止写成「盘坏了」

4.1 僵尸 gendisk 被 udev / blkid 戳(容量已废)

复制代码
I/O error, dev nvme3n1, sector 0
unable to read RDB block 0
unable to read partition table
partition table beyond EOD, truncated
项 说明
谁在打 systemd-udevd / blkid / 监控扫残节点
打什么 sector 0、RDB、分区表
块层状态 gendisk 还在,容量已是 EOD 或队列已死
是不是业务 不是

4.2 活着或半活路径上的介质 / PI 完成错

复制代码
nvmeXn1: I/O Cmd(0x2) @ LBA ..., 8 blocks, I/O Error (sct 0x2 / sc 0x81) MORE DNR
critical medium error
字段 规格含义 现场解读
Opcode 0x2 Read 读路径
8 blocks 典型 512B×8 = 4KB 对齐一次页面/一次 scrub 单元
LBA 散落 + 间隔 ~2s --- scrub / 巡检 / 用户态扫盘,不是随机业务
SCT=2 SC=81 0x281 End-to-end Guard Check(PI/DIF CRC) 厂商也可能把 0x81 当通用 media error;必须以 Identify 的 dps/ms 核对是否真开了 PI
MORE 后续还有错 不要当单点 ECC
DNR Do Not Retry 固件禁止 host 重试;再打也是同一条错

对照样本:

复制代码
Slot(40): Link Down
nvme3n1: ... (sct 0x3 / sc 0x71)     ← 0x371 HOST_ABORTED_CMD

时序:先 0x281 完成,后 Link Down,再 0x371。

掉链不能用来「洗掉」掉链前的 Guard Check。

4.3 最危险的时序:新实例已活,旧 n1 无人释放

Endpoint 新绑定 旧节点仍在 completion
e1:00.0 已是 nvme0 nvme3n1 仍出 I/O 完成
e3:00.0 已是 nvme8,128 队列 nvme5n1 仍报 0x281

内核 nvme 驱动在 Surprise remove 时:

  • PCI 功能没了 → 分配新的 nvmeX 次序号;
  • 若用户态 / udev / multipath 仍持有旧 /dev/nvmeXn1 的打开文件或 gendisk 引用 ,旧节点不会消失,I/O 会继续下到已经无效或半死的请求队列。

谁还握着 /dev/nvme3n1、/dev/nvme5n1(OSD、qemu、multipath、监控、厂商工具),谁就在给死路径喂 I/O,并把固件从「偶发 PI 错」推向「再 reset / 再掉链」。

数据面只认现实例: nvme0n1 / nvme8n1(且 list-ns 非空)。

旧节点只许停、不许修、不许再 blkid。


5. 与 CLR / CSTS=0x1 如何衔接(改口径,不推翻旧事实)

仍成立:

  • 两颗问题盘都经历过 Controller Reset 后 RDY 不落 → -ENODEV。
  • 现网没有第二 PF。
  • nvme8 是故障后再枚举、「看起来 Ready」的实例(曾建 128 队列并 rescan NS)。

必须改的口径:

  • -19 与实例空洞,优先用 Slot(40)/Slot(42) Surprise 解释,CLR 卡死是叠加动作的结果。
  • Slot(40) 两日内反复 enabling device = 链路/热插拔循环,不是单次固件 hang。
  • 在循环上打 nvme reset:链路窗口内 admin 超时 → 驱动见 CSTS 停在 0x1 → 放弃设备。

规格对照(便于盘厂对接,无需厂商名):

寄存器/状态 期望 现网
CC.EN 0→1 或 Controller Reset CSTS.RDY 在 CAP.TO 内置 1 保持 0x1 或不可读
设备从 PCI 消失 驱动应 teardown 并释放旧 NS 旧 n1 残留
Identify CMIC 双口应有多控制器/多口标志 CMIC=0

6. 证据分级(对外时不要把推断写成事实)

级别 内容
已坐实 三槽 pciehp Surprise;e1:00.0↔nvme0↔旧 nvme3;e3:00.0↔nvme8↔旧 nvme5;无第二 PF;0x281 出现在部分 Link Down 之前;旧 n1 在新 ctrl 存活后仍 completion;CLR 后 RDY 不落曾导致 -ENODEV
高置信推断 Slot(32) 下游为 81:00.0;4K/~2s 为 scrub/巡检;僵尸 sector 0 为 udev/blkid
待取证 Slot(32) 下游 BDF 实锤;AER/Uncorrectable 是否伴随;BMC 是否 cycle power;id-ns 的 dps/ms(PI 是否真开);谁持有旧 fd;数据现在在 nvme0n1/nvme8n1 还是空 ctrl

7. 立即处置(只读 + 止血)

原则:先切断旧节点 I/O,再采集只读信息,全程禁止 reset 与槽位下电。

7.1 止血

复制代码
lsof /dev/nvme3n1 /dev/nvme5n1 /dev/nvme3 /dev/nvme5 2>/dev/null
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,PKNAME | grep -E 'nvme[0358]'
multipath -ll 2>/dev/null | grep -A2 -E 'nvme[0358]'
# 若 OSD/文件系统/qemu 仍挂在 nvme3n1、nvme5n1 → 先停业务再卸设备
ls -l /dev/nvme{0,3,5,8}* 2>/dev/null
nvme list
nvme list-ns /dev/nvme0
nvme list-ns /dev/nvme8

判定:

  • list-ns 对 nvme0/nvme8 有 NS 且存在 nvme0n1/nvme8n1 → 数据面在新节点,旧节点一律停。
  • 只有空 ctrl、无 n1 → 不要对旧 n1 做任何「修复」;先固定链路再谈数据。

7.2 链路 / 槽位 / AER(只读)

复制代码
ls -l /sys/bus/pci/devices/0000:80:01.1/
find /sys/bus/pci/devices/0000:80:01.1 -name address -o -name devicetype 2>/dev/null | head
ls /sys/bus/pci/slots
for s in /sys/bus/pci/slots/*; do echo "== $s"; cat $s/address $s/power 2>/dev/null; done
for d in 0000:e1:00.0 0000:e3:00.0; do
echo "== $d"
cat /sys/bus/pci/devices/$d/current_link_speed
cat /sys/bus/pci/devices/$d/current_link_width
done
dmesg -T | grep -iE 'AER|PCIe Bus Error|Uncorrectable|e1:00|e3:00|81:00'
核对待外/BMC 是否对上述 slot 做 cycle;不要在此时手动写 slots/*/power

7.3 盘侧只读(禁止 reset / NSSR / FLR)

复制代码
nvme smart-log /dev/nvme0
nvme smart-log /dev/nvme8
nvme error-log /dev/nvme0 -e 16
nvme error-log /dev/nvme8 -e 16
nvme id-ns /dev/nvme0n1 2>/dev/null | egrep 'nsze|ncap|dps|lbaf|ms '
nvme id-ns /dev/nvme8n1 2>/dev/null | egrep 'nsze|ncap|dps|lbaf|ms '

若 dps/ms 显示 PI 未开 却大量 0x281:固件乱报或内部映射/RAID 损坏,直接作为盘厂缺陷单,而不是「开 PI 后的 CRC」。

禁止: nvme reset、FLR、写 NSSR、echo 0 > slots/*/power。

建议回收给分析侧:nvme list、旧 n1 的 lsof、nvme0/8 的 list-ns、Slot(32) 下游 BDF、id-ns 的 PI 字段、当前 link speed/width。


8. 对外话术(可直接转发)

8.1 平台 / 现场

80:01.1 Slot(32)、e0:03.1 Slot(40)、e0:03.3 Slot(42) 发生 PCIe 热插拔 Surprise:Presence 仍在(Card present),链路未训练(No link),约 30s 后再 Link Up。Slot(40)/(42) 伴随 NVMe Endpoint 反复重新枚举;Slot(40) 在两日内多次 enabling device。请检查:

  1. U.2 连接器、背板、线序、槽位供电;
  2. 带外/BMC 是否对上述 slot 做 power 操作(日志中有 Already disabled / Already in powering on state);
  3. MPS 被协商到 512,是否符合该槽位设计。

在链路未稳定前,不要 对槽位软件下电,不要对盘做 Controller Reset / FLR。

8.2 盘厂 / 固件

  • 盘 A (现 nvme0@e1:00.0,Slot 40;内核旧名 nvme3):掉链前 Read 返回 SCT=2 SC=81(Guard Check)DNR ,随后 Link Down,host 侧 SCT=3 SC=71(HOST_ABORTED_CMD) 。历史 CLR 时 CSTS 保持 0x1,随后 -ENODEV。
  • 盘 B (现 nvme8@e3:00.0,Slot 42;内核旧名 nvme5):Identify CMIC=0。同样出现过 CLR 后 RDY 不落;再枚举后能建 128 队列并 rescan NS,但旧 nvme5n1 仍报 0x281。

请书面回复:

  1. 链路 Surprise(PD 仍在、LTSSM 掉)后 CC.EN / CSTS.RDY 的状态机与超时;
  2. Namespace 未启用 PI 时为何完成 0x281 Guard Check(或确认内部是否误用该 status);
  3. PCI remove 后残留 NS / 旧块设备上 I/O 的完成与 abort 路径,以及为何 DNR。

9. 后续决策树(避免现场即兴)

复制代码
链路是否仍在 Surprise 循环?
  ├─ 是 → 只做物理排查;禁 reset / 禁 slot power;停旧 n1 I/O
  └─ 否 → nvme0 / nvme8 是否仍在且 list-ns 非空?
            ├─ 有 n1 → 业务切到新节点;销毁旧 udev 规则/残留 dm;再观察 smart/error-log
            └─ 无 n1 → 不要扫描旧 n1;保留现场,提交盘厂(RDY/NS 残留)+ 平台(槽位)
PI 未开却 0x281?
  └─ 是 → 固件缺陷单,不要用「开 PI」去圆
谁还在打开 nvme3n1/nvme5n1?
  └─ 有 → 先杀/停该进程,再谈任何「修复」

10. 一句话结论

三条线同时成立:槽位 Surprise 掉链、PCI 重枚举导致 ctrl 号漂移、旧 gendisk 被 udev/巡检继续打 4K 读。

掉链前已有 0x281,CLR 后曾 RDY 不落;双口不成立。

止血是停旧节点、禁 reset、禁槽位下电;根因由平台链路与盘侧 CC/PI 完成路径共同承担。

你在现网遇到过类似的 pciehp Surprise 掉链 + 旧 gendisk 残留的组合吗?当时是怎么定位和止血的?欢迎在评论区分享你的排查思路,一起把这条失败链补得更完整。

相关推荐
工作10年+,存储芯片行业2 天前
SSD 端到端数据保护:PI 三件套深度解析
ssd·nvme·芯片·存储·pcie·保护·nand
工作10年+,存储芯片行业3 天前
Linux NVMe 中断排查与性能优化:CPU 亲和性
linux·运维·服务器·windows·性能优化·ssd·pcie
gwf2164 天前
NAND闪存晶圆级测试与表征技术深度解析(从CP测试到可靠性认证全流程)
晶圆测试·3d nand·nand·失效分析·可靠性测试·nand闪存·cp测试
工作10年+,存储芯片行业4 天前
存储芯片行业全景:从嵌入式存储到车规级认证的技术演进
人工智能·ssd·nvme·半导体·ufs·emmc·存储芯片
工作10年+,存储芯片行业4 天前
存储芯片产业全景:从产品矩阵到技术优势与质量体系
ai·nvme·芯片·数据中心·存储·pcie·半导体
gwf2165 天前
Completion Queue(CQ)与中断处理:轮询、中断聚合与错误码 —— 面向AI集群的驱动级深度剖析
驱动开发·性能调优·pcie·rdma·ai集群·中断聚合·cq
工作10年+,存储芯片行业5 天前
长鑫存储深度分析:国产 DRAM 的崛起、挑战与未来
人工智能·ssd·芯片·存储·pcie·dram·ddr
工作10年+,存储芯片行业5 天前
武汉新芯发展历程与产品体系全览
ssd·集成电路·芯片·存储·半导体·flash·nor
gwf2165 天前
SSD固件测试与验证方法论深度解析(从单元测试到系统级一致性验证)
ssd·nvme·固件测试·掉电恢复·性能回归·协议一致性·企业级存储