0%

qemu scsi 磁盘直通

概述

virtio-scsi 提供了直接连接 SCSI LUN 的能力,并且也提供了继承目标设备特性的能力:
通过 virtio-scsi 控制器连接的虚拟硬盘或 CD,可以从 host 主机通过 QEMU scsi-block 设备实现物理 SCSI 设备的直通 (pass-through),这样就可以实现每个 guest 使用上百个设备,也提供了极高的存储性能。

guest 与 host 链路:
guest: app -> 文件系统-> Block Layer -> SCSI Layer -> scsi_mod
host: SCSI Layer -> Block Device Driver -> Hardware

前端 后端
virtio-scsi—qemu virtio-scsi
virtio-scsi—kernel vhost-scsi

直通方式

kernel vhost-scsi

QEMU负责对该PCI设备的模拟,只是把来自virtqueue的数据处理逻辑拿到内核空间了。QEMU需要告知内核vhost-scsi模块关于virtqueue的内存信息及Guest的内存映射,这样其实省去了Guest到QEMU用户态空间,再到宿主机内核空间多次数据复制; 但是,将queue的ID写到PCI配置空间的这步操作还是存在。

image-20240416111040666

通过vfio-pci直接进行SATA控制器直通

所有PC上的SATA控制器都在PCI总线上运行。您可以插入备用SATA控制器并通过它。所有连接的磁盘将直接传递给客户机。该解决方案几乎没有延迟或开销,并提供了最高的吞吐量。该解决方案的缺点是您将需要专门用于VM的第二个SATA控制器。来宾运行时,主机上的磁盘也将不可用。

image-20240416111048252

通过vfio-pci直接NVMe驱动器直通

与SATA控制器直通相似,通过NVMe驱动器也有助于提高性能。实际上,由于NVMe驱动器的疯狂吞吐量,性能提升甚至更高。开销也很低。
后端qemu直接对接宿主机上的块设备,不经过文件系统。但是这样的性能和中间有文件系统来对比,差别不会很大。

virtio-scsi

virtio-scsi功能是一个新的准虚拟化的SCSI控制器设备。它是KVM Virtualization的另一种存储实现的基础,它取代了virtio-blk,并改进了它的能力。它提供了与virtio-blk相同的性能,并增加了以下直接的好处。

  • 提高可扩展性–虚拟机可以连接到更多的存储设备(virtio-scsi可以处理每个虚拟SCSI适配器的多个块设备)。
  • 标准命令集virtio-scsi使用标准SCSI命令集,简化了新特征的添加。
  • 命名为virtio-scsi磁盘的标准设备使用与裸机系统相同的路径。这简化了物理到虚拟和虚拟到虚拟的迁移。
  • SCSI设备直通式virtio-scsi可以直接向guest 提供物理存储设备。
    Virtio-SCSI提供了直接连接到SCSI LUN的能力,与virtio-blk相比,显著提高了可扩展性。virtio-SCSI的优点是它能够处理数百个设备,而virtio-blk只能处理大约30个设备并耗尽PCI插槽。旨在取代virtio-blk,virtio-scsi保留了virtio-blk的性能优势,同时提高了存储的可扩展性,允许通过一个控制器访问多个存储设备,并使客户操作系统的重用成为可能。

pass-through the SCSI messages from the virtual machine kernel directly to the real device (virtio-scsi back end)
The virtio-scsi back end allows the guest to directly send SCSI requests back to the real device.
image-20240416111054089
All SCSI commands responses are sent by the real device, passing through QEMU. This mechanism allows the guest device to use all the features that the real device implements. Read and write requests from the guest are also sent directly to the real device.

1
2
3
-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x2 \
-device scsi-block,bus=scsi0.0,channel=0,scsi-id=0,lun=2,drive=drive-scsi0-0-0-2,id=scsi0-0-0-2 \
-drive file=/dev/disk/by-id/scsi-3600605b000a2c110ff0004053d84a61b,format=raw,if=none,id=drive-scsi0-0-0-2,cache=none

当fd有信号之后会唤醒eventfd等待队列上的对象,这里会执行vhost_poll_wakeup函数,该函数把work挂到vhost_dev的work_list中,然后唤醒vhost_dev的work线程,也就是在绑定用户态进程时创建的线程,vhost_scsi_handle_kick

1
2
3
4
5
6
vs->vqs[VHOST_SCSI_VQ_CTL].vq.handle_kick = vhost_scsi_ctl_handle_kick;
vs->vqs[VHOST_SCSI_VQ_EVT].vq.handle_kick = vhost_scsi_evt_handle_kick;
for (i = VHOST_SCSI_VQ_IO; i < VHOST_SCSI_MAX_VQ; i++) {
vqs[i] = &vs->vqs[i].vq;
vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick;
}

qemu 通过 vhost_dev_enable_notifiers -> virtio_bus_set_host_notifier 对几个vq绑定了ioeventfd,

guest os觉得有必要通知host对virtqueue上的请求进行处理,就会执行vp_notify(),相当于执行一次port I/O(或者mmio),虚拟机则会退出guest mode, 由kvm 处理guest store execption, kvm先判断自己能不能处理, 即查对应的mmio 区间是否注册了对应的处理函数, 这个地方由于ioeventfd的注册过程中注册了对应mmio的处理函数为 ioeventfd_write, 该函数给对应的fd发信号, 而vq上的poll返回后调用响应的handle_kick, 此处vhost-scsi 内核模块最终响应 vhost_scsi_handle_kick 函数处理vq, vq中封装的是scsi message. host 将scsi message 下发给hardware.

qemu virtio-scsi方案的演进,块设备模拟仍然是由qemu来做,只是把virtio backend放到了host kernel中,由kernel去处理virtqueue。 host kernel要处理virtqueue需要知道地址,因此qemu会把virtqueue的内存信息和guest的GPA-HVA的映射告知内核vhost-scsi模块,host kernel直接接收virtqueue中的请求并下发到后端,缩短了io路径,省去了host上用户态到内核态的拷贝

存储栈:
guest os: 文件系统层 -> 块设备层(block layer) -> scsi层(virtio-scsi 后端)
host os: scsi层 (vhost-scsi) -> hardware驱动 -> hardware

这里的直通是 通过 virtio-scsi – vhost-scsi 模拟了传统存储栈中的scsi layer, 替代了 scsi upper midi layer的功能, 创建出了 lun, lun是接收scsi cmd的实体, 每个lun需要有一个实体的hardware的驱动, 如对应sata设备会加载sd公版驱动.
上述scsi cmd最终转发到sd驱动中.

总结

非PCI方式的完整块设备映射,还是借助了virtio半虚拟化;
走PCI方式的直通, 通过vfio-pci实现的直接sata控制器直通和直接NVMe驱动器直通,这两种是真正意义上的passthrough,宿主机需要开启IOMMU;另外,需要对磁盘做vfio相关的配置,才能最终提供给虚机使用。

综上,

从virtio半虚拟化出发,为提高本地盘性能,可以将后端qemu virtio-scsi,替换为kernel vhost-scsi. 这种方式并未真正的直通, guest os的设备中断和数据请求都需要经过kvm, 这里所谓的直通只是将数据封装形式从之前的文件系统的消息转变为了scsi message, 该message 需要借助virtio 的vq在前后端(virtio-scsi – vhost-scsi)之间传递, 由这两个脚手架模拟了传统存储栈中的scsi layer.
存储栈参考 https://blog.csdn.net/Wang20122013/article/details/122090135

从直通方式提升性能,可以使用通过vfio-pci实现的直接sata控制器直通和直接NVMe驱动器直通这两种。