Skip to the content.

为什么 QEMU 中不支持

2026-07-27 询问 codex 关于,简单看了,基本都是对的。

为什么 NVMe 迁移困难

NVMe 运行状态不仅是几个 PCI 寄存器,还包括:

其中 BlockAIOCB *、QEMUSGList、BH、host 指针不能直接序列化。更严重的是,如果把一条已经落盘、但 CQE 尚未送给 guest 的 WRITE 在目标端重新执行,会产生重复写; COPY、DSM、Zone Append 的重复执行风险更大

所以迁移点必须建立下面的边界:

停止获取新 SQE ↓ 排空所有已提交的后端 AIO ↓ 把能写入的 CQE 写入 guest RAM ↓ 保存仍因 CQ 满而无法投递的 CQE ↓ 迁移设备状态 ↓ 目标端重建队列/BH/ioeventfd ↓ 继续投递 CQE、继续处理未消费的 SQE

当前代码是怎么支持的

2026 年 7 月合入的核心提交是:

迁移前,hw/nvme/ctrl.c:nvme_ctrl_pre_save 做了这些工作:

  1. 在 BQL 保护下取消所有 SQ BH,停止获取新命令
  2. 对 namespace 调用 blk_drain(),等待所有在途后端 I/O 完成
  3. 尽量把完成请求写入 guest CQ
  4. CQ 已满时,把还不能投递的 NvmeRequest 保存到迁移流
  5. 单独检查和保存 outstanding AER
  6. 验证不存在不可序列化的 aiocb、SGL 映射、opaque context

VMState 在 static const VMStateDescription nvme_vmstate = { 中保存:

目标端的 hw/nvme/ctrl.c:nvme_ctrl_post_load 会:

这套设计的重点是:不迁移后端 AIO,也不重放已经完成的 I/O;所有在途 I/O都在源端排空

当前能迁移什么

目前实际支持的是最基础的这种配置:

-device nvme,drive=drv0,serial=…

也就是:

尤其要注意,hw/nvme/ctrl.c:10271 要求 namespace 必须是 n->namespace。因此即使只有一个独立的 nvme-ns 设备,也可能在迁移最后阶段失败,不仅仅是“数量不能超过一个”

当前 blocker 明确禁止以下配置,见 hw/nvme/ctrl.c:9366:

另外 SMART 的 I/O 统计来自 BlockAcctStats,当前不会完整保留;温度和 critical warning 等部分状态会迁移

如果要把支持做完整

建议按下面顺序扩展

1. 多 namespace

这是最适合首先完成的部分:

配置拓扑仍应由目标端命令行预先创建,迁移流只恢复运行状态

2. Zoned Namespace

需要迁移的不只是当前 nvme_vmstate_ns 中的几个 ZRWA 参数,还包括:

必须保持当前“源端 drain 后再保存”策略,不能在目标端重新执行 Zone Append

3. FDP

应在 NvmeSubsystem 层保存:

4. CMB/PMR

BAR 寄存器已经在 VMState 中,但实际内存内容没有迁移。需要:

5. SR-IOV 和 SPDM

这两项最复杂:

关联代码

当前已有两个很有价值的测试:

测试结果

QEMU emulator version 11.0.91 (v11.1.0-rc1-48-g05e27e70df42-dirty)

是支持的 nvme 热迁移的,和我再次调查这个问题也就是几周时间。

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。