本文主要介绍通过 virsh detach-
device 命令发起卸载虚机磁盘设备操作时 qemu 的处理流程(x86_ 64架构+KVM),分别以 virtio- blk 盘和 virtio- scsi 盘为例进行分析,并简要说明这两类磁盘热拔时的区别。此外,也顺带介绍下虚机内部移除磁盘时 qemu 侧的处理流程。 如有不对之处,烦请指正,感谢。
环境信息
- ARCH:x86_
64 - Host OS:Linux 6.6.0-
98.0.0.103.oe2403sp2.x86_ 64 | open Euler 24.03 (LTS- SP2) - Guest OS:Linux guest 6.6.0-
102.0.0.8.oe2509.x86_ 64 | open Euler 25.09 - QEMU:QEMU emulator version 10.2.0 (v10.2.0) | stable-
10.2 - Libvirt:libvirtd (libvirt) 9.10.0
其中 QEMU 为社区 stable-
1、虚机创建命令和测试磁盘创建命令如下:
# guest
virt-install --name test --vcpus 2 --ram 2048 --import --disk path=/var/lib/libvirt/images/openEuler-25.09-x86_64.qcow2,format=qcow2 --network network=default --graphics vnc,listen=0.0.0.0 --noautoconsole --osinfo openeuler22.03
# disk
qemu-img create -f qcow2 /var/lib/libvirt/images/test-disk.qcow2 1G
2、virtio-
# disk.xml
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' />
<source file='/var/lib/libvirt/images/test-disk.qcow2'/>
<target dev='vdb' bus='virtio'/>"
</disk>
3、virtio-
# disk-scsi.xml
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' />
<source file='/var/lib/libvirt/images/test-disk.qcow2'/>
<target dev='sdb' bus='scsi'/>"
</disk>
注:
1、通过 virsh attach-device test disk.xml 命令挂载后,再使用 virsh detach-device test disk.xml 命令卸载,默认为 –live 即热插拔模式。
2、libvirt 通过调用 qmp device_
3、如果通过 virsh attach-device 命令挂载 virtio-<controller type='scsi' model='virtio-scsi'/>。
virtio-blk 盘热拔流程
先看热拔 virtio-
1、IO 线程处理
qemu 进程 io 线程(mon_handle_ 处理,将对应请求加入协程队列(g_)并唤醒(aio_co_wake(qmp_)。

2、主线程处理
1、主线程中完成协程处理,流程为monitor_,组装好 bh 后调用 aio_ 将 do_ 加入 aio 队列(aio_);

2、主线程轮询到 aio 事件,调用 do_ 处理,对应回调函数为 qmp_,实际处理函数为qmp_device_del;


3、 qdev_unplug 会调用hotplug_ 进行处理,对应hdc->unplug_request 为piix4_;

4、piix4_ 中会调用acpi_,然后调用acpi_send_event向虚机发送卸载设备 ACPI 中断事件,对应 adevc->send_event 为piix4_send_gpe;


5、piix4_send_gpe中经过一系列处理,最终调用 kvm_set_irq 把中断注入虚机(kvm_vm_ioctl(s, s->irq_set_ioctl, &event))。


3、虚机系统处理
中断注入虚机后,虚机操作系统调用相应的驱动程序进行处理,处理完成后通过 ACPI BIOS _
4、KVM 线程处理
虚机内部处理完成后发起的移除设备请求由 kvm 线程处理,最终调用 qdev_unrealize 完成 qemu 侧磁盘设备移除。
注意,此时虚机内部发起设备移除请求对应的处理函数是 hotplug_,而前面 qmp 命令对应的处理函数是hotplug_。


virtio-scsi 盘热拔流程
再看下热拔 virtio-
1、IO 线程处理
与 virtio-handle_ 处理。

2、主线程处理
1、与 virtio-qmp_device_del 进行处理;

2、与 virtio-qdev_unplug 中,由于 hdc->unplug_request 为空,所以是调用 hotplug_,而不是hotplug_,相当于已经走到了热拔 virtio-

3、在 hotplug_ 中,对应的 hdc->unplug 是 virtio_;

4、virtio_ 会调用 qdev_,而 qdev_ 则直接调用 qdev_unrealize 完成 qemu 侧磁盘设备移除。

5、virtio_ 中再调用 virtio_ 通知虚机磁盘设备已移除。


virtio-blk 盘和 virtio-scsi 盘热拔区别
综上,virtio-
此外,QEMU 官方博客中也提到 virtio-
- Prefer virtio-
blk in performance- critical use cases. - Prefer virtio-
scsi for attaching more than 28 disks or for full SCSI support.
虚机内部移除磁盘
现在看下在虚机内部热拔磁盘时 qemu 侧的处理,还是分别以 virtio-qdev_unrealize 处打上断点。
注:虚机内部通过执行echo 0 > /sys/bus/pci/slots/xx/power 命令移除设备。
virtio-blk 盘移除
gdb 结果如下所示,可以发现,虚机内直接通过 ACPI BIOS _pci_write -> acpi_。这和通过 qmp 命令热拔 virtio-


virtio-scsi 盘移除
gdb 结果如下所示,可以发现,依然是虚机内直接通过 ACPI BIOS _



最后调用 qapi_ 通知 libvirt 设备已移除。

注:
1、virtio-
2、虚机内移除 virtio-/machine/peripheral/scsi0-0-0-1、/machine/peripheral/scsi0/virtio-backend和/machine/peripheral/scsi0 都移除了,通过 qmp 命令热拔 virtio-

总结
1、通过 qmp 命令热拔磁盘时,virtio-
2、从虚机内部移除磁盘时,virtio-
3、Windows 虚机里“安全删除硬件”(非设备管理器中卸载设备)相当于 Linux 虚机中执行 echo 0 > /sys/bus/pci/slots/xx/power 命令移除设备,都是通过 ACPI BIOS _
以下为 Chat

参考资料
1、QEMU<->ACPI BIOS PCI hotplug interface
2、Configuring virtio-
3、QEMU-
4、block中断 virtio_
5、virtio-