目录
0. 文档用途与口径
1. 现网拓扑(可定死)
1.1 槽位 ↔ Root Port ↔ Endpoint ↔ 控制器实例
1.2 双口为何被排除
2. 失败链(建议按此顺序对外讲述)
3. pciehp 在干什么(物理层入口)
3.1 典型片段(Slot 40 / 32 / 42 形态相同)
3.2 与 -ENODEV 的关系
3.3 现场需一并核对
4. 两类 I/O:必须拆开,禁止写成「盘坏了」
4.1 僵尸 gendisk 被 udev / blkid 戳(容量已废)
4.2 活着或半活路径上的介质 / PI 完成错
4.3 最危险的时序:新实例已活,旧 n1 无人释放
5. 与 CLR / CSTS=0x1 如何衔接(改口径,不推翻旧事实)
6. 证据分级(对外时不要把推断写成事实)
7. 立即处置(只读 + 止血)
7.1 止血
7.2 链路 / 槽位 / AER(只读)
7.3 盘侧只读(禁止 reset / NSSR / FLR)
8. 对外话术(可直接转发)
8.1 平台 / 现场
8.2 盘厂 / 固件
9. 后续决策树(避免现场即兴)
10. 一句话结论
0. 文档用途与口径
本文把现网日志、PCI 拓扑、Identify 信息和块层错误压成一条可对外、可复盘的因果链。结论用于:
- 现场止血(停旧节点、禁 reset、禁槽位 power cycle)
- 平台侧查 U.2 / 背板 / 供电 / 带外
- 盘厂侧查 CC 状态机、未开 PI 时报 Guard Check、残留 NS 完成路径
口径必须同时写两头,缺一不可:
| 责任面 | 已坐实的现象 | 不能单独解释的部分 |
|---|---|---|
| 平台 / 物理链路 | pciehpSurprise:Card present + No link,约 30s 后再 Link Up;槽位反复重新枚举 | 掉链之前盘已对 4K Read 回0x281;CLR 后CSTS.RDY不落 |
| 盘固件 / NVMe 状态机 | Controller Reset 后 RDY 卡在0x1→-ENODEV;IdentifyCMIC=0 | 槽位 Presence 仍在、链路自己掉;pciehp风暴先于多数-19 |
只骂固件或只骂槽位,都会漏掉一半证据。
明确排除:
- 不是「双端口对端」故事。全机 NVMe 均为
xx:00.0单功能,无.1第二 PF。 - 不只是「
CC.EN清不掉RDY」单点。那是失败链中段,入口在链路 Surprise,出口在残留 gendisk 仍被 udev / 巡检打 I/O。
硬禁令(已在现网验证会恶化):
nvme reset/ FLR / 写 NSSRecho 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 | 同一 BDFe1: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在这条链上有两种充分条件,不必互斥:
- PCI 设备已从总线消失(Surprise remove)→ 任何后续 admin/io 都是
-ENODEV。 - 设备还在,但 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| 字段 | 规格含义 | 现场解读 |
|---|---|---|
Opcode0x2 | Read | 读路径 |
| 8 blocks | 典型 512B×8 =4KB | 对齐一次页面/一次 scrub 单元 |
| LBA 散落 + 间隔 ~2s | — | scrub / 巡检 / 用户态扫盘,不是随机业务 |
| SCT=2 SC=81 | 0x281End-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.EN0→1 或 Controller Reset | CSTS.RDY在 CAP.TO 内置 1 | 保持0x1或不可读 |
| 设备从 PCI 消失 | 驱动应 teardown 并释放旧 NS | 旧n1残留 |
| Identify CMIC | 双口应有多控制器/多口标志 | CMIC=0 |
6. 证据分级(对外时不要把推断写成事实)
| 级别 | 内容 |
|---|---|
| 已坐实 | 三槽pciehpSurprise;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/*/power7.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.1Slot(32)、e0:03.1Slot(40)、e0:03.3Slot(42) 发生 PCIe 热插拔 Surprise:Presence 仍在(Card present),链路未训练(No link),约 30s 后再 Link Up。Slot(40)/(42) 伴随 NVMe Endpoint 反复重新枚举;Slot(40) 在两日内多次enabling device。请检查:
- U.2 连接器、背板、线序、槽位供电;
- 带外/BMC 是否对上述 slot 做 power 操作(日志中有
Already disabled/Already in powering on state); - 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):IdentifyCMIC=0。同样出现过 CLR 后 RDY 不落;再枚举后能建 128 队列并 rescan NS,但旧nvme5n1仍报0x281。
请书面回复:
- 链路 Surprise(PD 仍在、LTSSM 掉)后
CC.EN/CSTS.RDY的状态机与超时; - Namespace未启用 PI时为何完成
0x281Guard Check(或确认内部是否误用该 status); - 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 完成路径共同承担。
你在现网遇到过类似的pciehpSurprise 掉链 + 旧 gendisk 残留的组合吗?当时是怎么定位和止血的?欢迎在评论区分享你的排查思路,一起把这条失败链补得更完整。