一台 PVE 虚拟机突然无法启动,QEMU 报 “Image is corrupt”。快照回滚失败,专用修复工具未授权。最终发现是 qcow2 镜像头部的 corrupt 保护标记残留,一条命令即可修复。本文完整记录排查过程、根因分析和标准 SOP。
结论前置#
| 项目 | 内容 |
|---|---|
| 故障类型 | qcow2 镜像头部残留 corrupt: true 标记 |
| 恢复用时 | 约 25 分钟 |
| 修复命令 | qemu-img check -r all <disk.qcow2> |
| 数据损失 | 无 |
三个关键结论:(1)
corrupt: true 不等于数据已损坏,check 通过说明结构完好;(2) 修复只需 check -r all,无需数据恢复或镜像重建;(3) 快照不能替代完整备份,底层镜像异常时快照回滚同样失败。故障现象#
执行 qm start <vmid> 后,PVE 控制台输出:
qcow2: Image is corrupt; cannot be opened read/write
start failed: QEMU exited with code 1
受影响磁盘为关键数据盘(虚拟 1 TiB,实占 329 GiB),不可废弃,必须原地修复。
排查时间线#
flowchart TD
START["VM 启动失败"]
START --> ERR["报错:qcow2 Image is corrupt
QEMU exited with code 1"]
ERR --> CHECK1["qemu-img check
一致性检查"]
CHECK1 --> R1{"检查结果?"}
R1 -->|"No errors found"| CONFLICT["矛盾:check 通过
但 QEMU 仍报错"]
CONFLICT --> CONFIG["qm config
确认目标磁盘为关键盘"]
CONFIG --> ROLLBACK["尝试快照回滚"]
ROLLBACK --> R2{"回滚结果?"}
R2 -->|失败| SNAP_FAIL["镜像无法打开
快照回滚被阻断"]
SNAP_FAIL --> INFO["qemu-img info
确认 corrupt: true"]
INFO --> FIX1["qemu-img check -r leaks
低风险修复"]
FIX1 --> FIX2["qemu-img check -r all
清除 corrupt 标记"]
FIX2 --> VERIFY["qemu-img info
确认 corrupt: false"]
VERIFY --> END["VM 启动成功"]
style START fill:#e55,color:#fff
style CONFLICT fill:#f90,color:#fff
style SNAP_FAIL fill:#f90,color:#fff
style END fill:#4a4,color:#fff
一致性检查通过,但启动仍失败#
qemu-img check /path/to/vm-disk.qcow2
# 输出:No errors were found on the image.
关键矛盾:
qemu-img check 通过说明镜像内部逻辑结构完整(refcount、cluster、L1/L2 表均无异常),但 QEMU 启动仍报错。问题来自镜像头部的状态标记,而非数据本身。快照回滚全部失败#
三个自动快照均无法恢复:
qm rollback <vmid> <snapshot-name>
# 结果:失败,错误仍指向 qcow2 镜像无法打开
快照回滚流程需要先以读写方式打开底层镜像。corrupt 标记导致 QEMU 在第一步就拒绝打开,回滚被阻断。
方案评估#
| 方案 | 风险 | 结论 |
|---|---|---|
qemu-img check -r | 低 | 优先采用 |
qcow2-dump 专项工具 | 低 | 环境未授权,不可用 |
| 快照回滚 | 低 | 已确认失效 |
qemu-img convert 重建 | 中 | 耗时长,空间需求大,留作后手 |
qemu-nbd + ddrescue | 高 | 适合严重损坏,本次非首选 |
确认根因并修复#
# Step 1:查看镜像状态
qemu-img info /path/to/vm-disk.qcow2
# 输出:corrupt: true <-- 损坏标记存在
# Step 2:执行修复
qemu-img check -r all /path/to/vm-disk.qcow2
# Step 3:验证修复
qemu-img info /path/to/vm-disk.qcow2
# 输出:corrupt: false <-- 标记已清除
# Step 4:启动虚拟机
qm start <vmid>
# 成功
根因分析#
corrupt 标记的触发机制#
flowchart TD
A1["宿主机异常重启 / 强制断电"] --> F
A2["存储设备瞬断 I/O 中断"] --> F
A3["QEMU 进程被强制 kill"] --> F
A4["存储空间不足导致写入失败"] --> F
F["QEMU 检测到写入异常"] --> G["标记 corrupt: true"]
G --> H["拒绝后续读写打开"]
H --> I["异常结束后标记未自动清理"]
I --> J["虚拟机下次启动失败"]
qcow2 镜像头部有一个 corrupt 字段,是 QEMU 的保护机制。写入异常时置为 true,防止后续写入造成更严重损坏。但异常结束后标记不会自动清理。
qemu-img check vs QEMU 启动的检查差异#
| 检查维度 | qemu-img check | QEMU 启动 |
|---|---|---|
| cluster 分配 | 检查 | 不独立检查 |
| refcount 信息 | 检查 | 不独立检查 |
| L1/L2 table | 检查 | 不独立检查 |
corrupt 标记 | 不清除 | 直接拒绝 |
这是最容易误判的点:check 通过不代表能启动,必须用 check -r 才能清除标记。
快照回滚失败的原理#
flowchart TD
A["qm rollback"] --> B["需要打开底层镜像"]
B --> C["镜像头部 corrupt: true"]
C --> D["QEMU 拒绝读写打开"]
D --> E["快照回滚被阻断"]
style C fill:#f66,color:#fff
style E fill:#f66,color:#fff
快照不等于完整灾备。快照适合短期版本回退,但底层镜像异常时快照回滚同样失败。关键业务必须建立"快照 + 独立完整备份"双层保护。
标准 SOP:三阶段修复#
遇到 PVE / qcow2 虚拟机启动失败,按以下三阶段顺序处理,不跳步。
阶段一:诊断(只读,零风险)#
# 停止虚拟机
qm stop <vmid> || true
# 查看镜像状态,确认 corrupt 字段
qemu-img info <disk.qcow2>
# 一致性检查(不执行修复)
qemu-img check <disk.qcow2>
flowchart TD
A["qemu-img info + check"] --> B{"corrupt 标记?"}
B -->|"false"| C["check 通过? → 镜像正常,检查其他原因"]
B -->|"true"| E{"check 结果?"}
E -->|无错误| F["阶段二:清除 corrupt 标记"]
E -->|有错误| G["阶段二:修复错误 + 清除标记"]
E -->|严重错误| H["阶段三:数据级恢复"]
style F fill:#6a6,color:#fff
style G fill:#fa0,color:#fff
style H fill:#f66,color:#fff
阶段二:标记修复(低风险)#
# Step 1:仅修复 leaks(最保守)
qemu-img check -r leaks <disk.qcow2>
# Step 2:修复所有可修复问题,含 corrupt 标记
qemu-img check -r all <disk.qcow2>
# Step 3:验证 corrupt: false
qemu-img info <disk.qcow2>
# Step 4:启动虚拟机
qm start <vmid>
阶段三:高级恢复(高风险,阶段二无效时)#
# 检查宿主机内核日志
dmesg -T | grep -iE "I/O error|corrupt|EXT4-fs error|nvme|scsi"
# 镜像转换重建
qemu-img convert --salvage -O qcow2 <damaged.qcow2> <recovered.qcow2>
# 数据级恢复(最后手段)
modprobe nbd max_part=8
qemu-nbd --connect=/dev/nbd0 <disk.qcow2>
ddrescue /dev/nbd0 /dev/nbd1 rescue.log
qemu-nbd --disconnect /dev/nbd0
阶段三风险提示:执行前确认磁盘空间充足,强烈建议先拷贝镜像文件。宿主机存在 I/O 错误时优先排查底层存储硬件。
预防措施#
1. 存储健康巡检#
# 内核错误日志
dmesg -T | grep -iE "I/O error|blk|buffer|EXT4-fs error|nvme|scsi|corrupt|ENOSPC"
# 系统级错误
journalctl -b -p err..alert
2. 存储空间监控#
建议告警阈值:
- 文件系统使用率 > 80%
- inode 使用率 > 70%
- LVM thin pool > 75%
3. 有序停机#
# 正确方式:等待 QEMU 完成写入后退出
qm shutdown <vmid>
qm wait <vmid>
强制 kill -9 QEMU、宿主机掉电、存储瞬断均可能触发 corrupt 标记。
4. 双层备份保护#
flowchart LR
VM["关键虚拟机"]
VM -->|短期| SNAP["快照:每日自动"]
VM -->|长期| BAK["完整备份:每周全量"]
SNAP --> SA["用途:版本回退"]
SNAP --> SB["限制:依赖底层镜像"]
BAK --> BA["用途:灾难恢复"]
BAK --> BB["存储:独立备份介质"]
核心经验#
corrupt: true不等于数据已损坏。须结合qemu-img check判断,check 通过说明是标记残留qemu-img check不清除 corrupt 标记。只有check -r leaks或check -r all才能清除- 快照回滚依赖底层镜像正常打开。镜像有 corrupt 标记时快照回滚同样失败
- 分阶段修复,低风险优先。顺序:
info→check→check -r leaks→check -r all,不跳步 - 关键磁盘高风险操作前必须先备份。即使时间紧迫,也应至少新建快照
