热插拔:资源上线、客户机协作与安全回收
一、热插拔的资源范围与协作过程
热插拔允许虚拟机运行期间增加或移除设备、CPU 与内存。管理程序表达变更目标,QEMU 修改虚拟硬件,客户机驱动完成发现、上线或停用。资源是否已经可用或可以回收,取决于这些阶段是否全部完成。
客户机操作系统维护着自己的设备清单、驱动绑定与资源分配。在线变更需要通过它能识别的硬件协议通知变化:增加时发现并配置新资源,移除时先停止使用并交还资源。由此,热插拔同时改变虚拟硬件和客户机的软件状态,需要双方完成交接。
下面以 Q35 虚拟机在线添加、移除网卡为主线,再比较 vCPU 与内存调整。热添加先准备资源,再交给客户机使用;热移除先让客户机停止使用,再回收资源。两条流程都需要管理程序、虚拟硬件和客户机协调,通知协议与完成条件随资源类型而变。
源码版本:QEMU 10.2.0、Linux 6.18。
二、配置变更、硬件通知与客户机资源状态
冷启动时,客户机可以从头枚举所有硬件。运行中增加网卡,操作系统却不会因管理程序改了一个配置字段就自动发现它。QEMU 要模拟插槽状态变化并发出通知,客户机的总线驱动重新枚举设备,分配地址与中断,再把设备交给具体驱动。
移除更困难:网卡可能仍持有发送缓冲区,内存可能还装着进程页或内核对象。先删掉宿主资源,会让后续访问落到无效对象上。因此热移除要先发出请求,等客户机停止使用资源,再解除后端引用。这是增加与移除不能简单互为反向操作的原因。
| 状态所在位置 | 增加网卡时发生的变化 | 完成条件 |
|---|---|---|
| 管理层:宿主用户态 | Libvirt 等管理程序记录目标配置,准备网络后端 | 目标配置已记录,运行变更已发起;仍需跟踪下面两层 |
| 机器模型:QEMU 进程 | 在可热插拔端口下创建 PCIe 设备 | 设备已实例化并发布插槽变化;客户机仍需完成资源分配 |
| 客户机内核与驱动 | 枚举、绑定驱动并启用接口 | 驱动和网络配置生效,业务能够使用 |
三份视图有传播顺序,短时间不一致并不罕见。持久配置中的网卡也可能只在下次启动时出现;一次在线添加成功,不代表重启后仍会保留。管理工具需要分别说明变更范围和当前进度。
三、增加与移除的交接顺序
Mermaid 源码
flowchart TB
accTitle: 资源热增与热移除的完成边界
accDescr: 增加资源先准备后端与虚拟设备,再通知客户机识别使用;移除资源先通知客户机停止访问,再确认移除并回收资源。
subgraph ADD["增加资源"]
A["管理程序:准备后端与容量"] --> B["QEMU:提供设备或内存块"]
B --> C["客户机:识别、上线并使用"]
end
subgraph REMOVE["移除资源"]
D["管理程序:请求移除或缩容"] --> E["客户机:停止访问或迁移页面"]
E --> F["确认完成:移除设备或内存块"]
F --> G["回收已无使用者的宿主资源"]
end
C -. "后续调整" .-> D
classDef management fill:#eaf0f6,stroke:#8198ac,color:#263c4c;
classDef handoff fill:#e4f1ec,stroke:#438575,color:#173e34;
classDef guest fill:#fff4db,stroke:#b89a55,color:#59491e;
class A,D,G management;
class B,F handoff;
class C,E guest;
1. 热增:准备空间,再通知客户机
本例先为网卡预留可热插拔的 PCIe 端口、总线号与 BAR 窗口。运行中,管理程序创建宿主网络后端,再由 QEMU 创建并连接网卡 net1;端口报告插槽变化,客户机重新枚举设备、分配资源并绑定驱动。至此虚拟硬件与驱动已经建立,客户机还需配置接口和业务通路,才能真正使用新增网卡。
2. 热移除:先停止使用,再归还资源
移除同一块 net1 时,管理程序发起请求,QEMU 通过插槽通知客户机。客户机停止网卡队列和驱动访问,交还设备后,QEMU 才完成虚拟网卡的拆除。独立创建的网络后端还要等网卡不再引用它时清理。客户机可能延迟响应或无法完成,因此从请求受理到资源回收之间需要保留待处理状态。
四、移除 net1,缩减一段内存
向 QMP 发送 {"execute":"device_del","arguments":{"id":"net1"}} 后,成功响应只表示删除请求已受理。对于需要客户机配合的设备,管理程序继续等待对应 DEVICE_DELETED,再清理已无引用的网络后端。未收到完成事件时,要查看客户机驱动、插槽状态与错误事件,不能直接复用设备 ID。
DEVICE_DELETED 标识 QEMU 设备已移除;它并不证明应用已把流量切换到另一块网卡。若 net1 承载管理连接,应先让业务转用另一条通路,再发起移除,否则热插拔协议即使正确完成,业务仍会断连。
内存缩容沿用“先停止使用,再交还资源”的原则,交还对象变成了内存块。以 virtio-mem 为例,目标容量 requested-size 从 4 GiB 改为 2 GiB 后,实际已提供的 size 可能暂时仍为 4 GiB。客户机需要迁走被回收块中的页面,再发送 UNPLUG 请求;长期固定的页面可能阻止回收。这里等待的是内存块交还,前面网卡例子等待的是设备删除,不能用同一种完成事件判断两者。
下表把网卡、vCPU 与内存放回相同的交接顺序。各类资源都先通知客户机,但客户机的停用工作和管理层应核对的结果不同;内存还应分别观察设备提供容量、客户机在线容量和宿主 RSS。
| 资源 | 通知与交接机制 | 移除前客户机的工作 | 需要分别确认的结果 |
|---|---|---|---|
| PCIe 网卡 | 端口原生热插拔或 ACPI 通知,取决于机器配置 | 停用驱动、停止队列和设备访问 | QEMU 设备删除、独立后端清理、业务通路切换 |
| x86 vCPU | ACPI CPU 通知与 eject | 迁移任务、中断和定时器,再下线处理器 | 客户机 offline、QEMU 对象移除;仅 offline 不等于拔出 |
| virtio-mem 容量 | 配置通知与队列中的 PLUG/UNPLUG 请求 | 迁走页面并停止使用选定块 | requested-size、实际 size 和客户机在线容量逐步收敛 |
五、从整设备增删到细粒度资源调整
设备与内存沿着各自的协议发展。前者侧重插槽发现、地址空间与驱动生命周期,后者侧重可调整容量、页面迁移与回收粒度。
传统 PCI 热插拔可以借助 ACPI 事件通知操作系统;PCIe 原生热插拔使用 Root Port 等端口的插槽寄存器与事件机制,客户机在获得相应控制权后由 PCIe 热插拔驱动处理。两者对应不同的机器配置与控制方式,不能假定所有虚拟机都走相同通知路径。资源预留帮助新增设备获得地址空间,但端口、总线号和 BAR 窗口仍有边界。
virtio-mem 用较小粒度的块调整容量,减少反复添加大块 DIMM 的需要,同时引入块状态与回收协议。更细粒度不保证任意页面都可迁移。评价热插拔要记录操作完成时间、客户机停顿与失败原因,而非只看管理命令是否成功返回。
| 内存调整方式 | 宿主资源回收方式 | 主要限制 |
|---|---|---|
| DIMM 热插拔 | 按内存设备增删,由客户机上线或下线相应区域 | 插槽、地址空间、移除范围及可迁移页面 |
| 传统 virtio-balloon | 驱动占用客户机页面并通知宿主回收后备存储 | 改变可用资源,不等同于移除一条 DIMM;需要客户机合作 |
| virtio-mem | 在设备区域内按块提供或收回内存 | 目标容量与已提供容量可能暂时不同,页面固定仍会阻碍缩容 |
六、用完成状态和业务影响判断操作结果
热插拔的收益是避免为资源调整重启客户机,代价是引入拓扑预留、驱动协作和异步失败处理。增加设备时分别检查命令、枚举、驱动与业务;移除设备时分别检查请求、客户机停用、设备删除与资源回收。超时后先查询实际状态,避免重复创建或删除已经变化的对象。
内存缩容还应观察页面迁移耗时、不可迁移页和客户机延迟。更细的回收粒度能避开部分忙页,代价是维护更多块状态;更大的地址空间预留方便后续扩容,也会占用有限的桥窗口或拓扑资源。方案选择应结合实际扩容上限和可接受的回收等待。
七、按资源类型继续阅读
- PCIe 热插拔与异步设备移除:端口、插槽事件和 DEVICE_DELETED。
- x86 vCPU 热插拔:最大拓扑、ACPI 通知、客户机上线与异步移除。
- virtio-mem 容量调整与内存回收:目标容量、块位图及客户机协作。
- QEMU 对象模型与设备初始化:设备创建和 realize 的失败边界。
- VFIO 地址转换与隔离:直通设备涉及的 DMA 映射与宿主资源。