在 Debian bullseye 中,我通过命令行使用 QEMU / KVM 启动虚拟机(即,没有virsh
或其他帮助器 / 包装器)。其中一个虚拟机从声明如下的块设备启动:
-blockdev driver=file,node-name=q1,filename=/dev/loop0 \
就在今天,我无意中注意到 QEMU 在启动该 VM 时发出以下警告:
Opening a block device as a file using the 'file' driver is deprecated
一些研究表明这个警告是已知的,并且有解决方案,例如@Stephen Kitt在这里接受的答案提出了以下blockdev
声明:
-blockdev node-name=q1,driver=raw,file.driver=host_device,file.filename=/dev/loop0 \
这个解决方案无疑是有效的,但我找不到任何有关file.driver=host_device
. 因此,我测试了一些其他选项,并得出了以下似乎也有效的解决方案:
-blockdev driver=host_device,node-name=q1,filename=/dev/loop0 \
有人可以简单解释一下这两个声明之间的区别吗?值得注意的是,其中一个在延迟或吞吐量方面是否会优于另一个?
作为一个额外的问题,有人知道文档在哪里吗host_device
?在上面链接的其他问题/答案中,有一个指向可能实现该驱动程序的提交的链接。但是,我也找不到该链接背后的任何文档。
根据QEMU 变更日志,在 QEMU 版本 3.0 中,访问主机块设备时驱动程序被弃用
file
并引入了驱动程序。host_device
您提到的 Stephen Kitt 的答案中的 PDF 演示文稿(请参阅第 20...24 页)表明,定义 QEMU 存储的最详尽的方法意味着首先使用 a 设置数据位置(
file
或host_device
)node_name=
,然后使用另一个--blockdev
选项file=<previously_defined_node_name>
在第一层之上添加另一层以指定数据格式(例如raw
或qcow2
例如)。这为用户提供了极好的控制,但对于大多数基本情况来说就太过分了。在 QEMU 源代码存储库中,该
qemu-options.hx
文件似乎具有-blockdev
迄今为止我所见过的选项的最佳描述。有一段话或许可以为我们解开这个
file.<something>=<something>
谜团提供一些启示:因此,
file.<something>=
语法本质上是指定另一个-blockdev
声明的简写方式,同时也避免了“中间节点”名称使命名空间变得混乱node_name
。所以,史蒂芬·基特的
blockdev
声明:似乎相当于扩展形式:
这和你的声明之间的区别
这是一个比较棘手的问题,需要深入研究 QEMU 源代码才能弄清楚。
QEMU的
-blockdev
驱动程序file
,host_device
并且host_cdrom
针对不同的主机架构有多个版本。对于 Linux,适用的位于block/file-posix.c
. 搜索字符串的实例BlockDriver bdrv_
,您将找到每一个。(您还会发现,host_cdrom
出于某种原因,FreeBSD 有一个完全独立的定义。)每个
BlockDriver
似乎都是由(大部分)函数指针的结构定义的。这些指针可能指向特定于驱动程序的函数,或者引用与另一个驱动程序共享的公共实现。驱动
file
程序定义如下:所以它本质上是驱动程序的克隆
raw
,几乎所有功能都引用它。定义
host_device
稍微复杂一点:它还引用
raw
驱动程序的大部分功能,但有自己的专用功能,例如:其中一些
host_device
特定函数只是执行额外的错误检查,然后调用驱动程序的等效函数raw
。但它可能是最后一个提供了驱动程序的大部分价值host_device
:它允许虚拟机显式地查看主机设备的实际块大小和几何结构(如果适用)。通过通用 SCSI 命令,VM 可以被授予访问磁带库机器人、大容量磁带驱动器和 DVD 刻录机等内容的权限......以及许多其他内容。您的较短声明有效,因为在大多数情况下
host_device
声明本质上都会回落到驱动程序的功能raw
。请注意,上述内容仅适用于 POSIX 风格的操作系统:如果您在 Windows 上运行 QEMU,设备访问可能必须与常规文件访问完全不同,并且您的较短声明可能根本不起作用。
file
和之间的区别可能host_device
主要是为了将 QEMU 移植到其他系统架构,其中设备访问与常规文件有很大不同。您担心性能,但我希望性能基本相同,因为所有三个驱动程序最终都会调用完全相同的代码段来实现核心功能、
bdrv_co_preadv
和bdrv_co_pwritev
函数。当将驱动程序彼此分层时,可以非常简单地检测给定驱动程序是否使用与将在其之上分层的驱动程序完全相同的功能,并优化消除重复。我的第一个猜测是,这样的优化实际上是非常必要的,以避免各种愚蠢的行为。因此,如果配置最终执行完全相同的操作,我希望它执行相同的操作,无论它是如何声明的。