567 lines
21 KiB
Diff
567 lines
21 KiB
Diff
|
|
From e07709c7275349eac376660c08bacc6d18f28ff8 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Luo Yifan <luoyifan_yewu@cmss.chinamobile.com>
|
||
|
|
Date: Wed, 30 Nov 2022 18:13:37 +0800
|
||
|
|
Subject: [PATCH 17/24] qemu: implement vhost-user-blk support
|
||
|
|
MIME-Version: 1.0
|
||
|
|
Content-Type: text/plain; charset=UTF-8
|
||
|
|
Content-Transfer-Encoding: 8bit
|
||
|
|
|
||
|
|
Implements QEMU support for vhost-user-blk together with live
|
||
|
|
hotplug/unplug.
|
||
|
|
|
||
|
|
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
|
||
|
|
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
||
|
|
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
|
||
|
|
(cherry picked from commit d763466edc6e8d4965fb42092c6e8f4296acf6c6)
|
||
|
|
Signed-off-by: Luo Yifan <luoyifan_yewu@cmss.chinamobile.com>
|
||
|
|
---
|
||
|
|
src/qemu/qemu_block.c | 40 ++++++++
|
||
|
|
src/qemu/qemu_block.h | 7 ++
|
||
|
|
src/qemu/qemu_command.c | 93 +++++++++++++++++--
|
||
|
|
src/qemu/qemu_command.h | 6 ++
|
||
|
|
src/qemu/qemu_domain.c | 13 +++
|
||
|
|
src/qemu/qemu_driver.c | 66 +++++++++++++
|
||
|
|
src/qemu/qemu_hotplug.c | 12 ++-
|
||
|
|
.../disk-vhostuser.x86_64-latest.args | 40 ++++++++
|
||
|
|
tests/qemuxml2argvtest.c | 1 +
|
||
|
|
9 files changed, 268 insertions(+), 10 deletions(-)
|
||
|
|
create mode 100644 tests/qemuxml2argvdata/disk-vhostuser.x86_64-latest.args
|
||
|
|
|
||
|
|
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
|
||
|
|
index 8bd6238238..0b7f2f6874 100644
|
||
|
|
--- a/src/qemu/qemu_block.c
|
||
|
|
+++ b/src/qemu/qemu_block.c
|
||
|
|
@@ -1553,6 +1553,8 @@ qemuBlockStorageSourceAttachDataFree(qemuBlockStorageSourceAttachDataPtr data)
|
||
|
|
VIR_FREE(data->httpcookiesecretAlias);
|
||
|
|
VIR_FREE(data->driveCmd);
|
||
|
|
VIR_FREE(data->driveAlias);
|
||
|
|
+ VIR_FREE(data->chardevAlias);
|
||
|
|
+ VIR_FREE(data->chardevCmd);
|
||
|
|
VIR_FREE(data);
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -1719,6 +1721,13 @@ qemuBlockStorageSourceAttachApply(qemuMonitorPtr mon,
|
||
|
|
data->driveAdded = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (data->chardevDef) {
|
||
|
|
+ if (qemuMonitorAttachCharDev(mon, data->chardevAlias, data->chardevDef) < 0)
|
||
|
|
+ return -1;
|
||
|
|
+
|
||
|
|
+ data->chardevAdded = true;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -1741,6 +1750,13 @@ qemuBlockStorageSourceAttachRollback(qemuMonitorPtr mon,
|
||
|
|
|
||
|
|
virErrorPreserveLast(&orig_err);
|
||
|
|
|
||
|
|
+ if (data->chardevAdded) {
|
||
|
|
+ if (qemuMonitorDetachCharDev(mon, data->chardevAlias) < 0) {
|
||
|
|
+ VIR_WARN("Unable to remove chardev %s after failed " "qemuMonitorAddDevice",
|
||
|
|
+ data->chardevAlias);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
if (data->driveAdded) {
|
||
|
|
if (qemuMonitorDriveDel(mon, data->driveAlias) < 0)
|
||
|
|
VIR_WARN("Unable to remove drive %s (%s) after failed "
|
||
|
|
@@ -1904,6 +1920,30 @@ qemuBlockStorageSourceChainDetachPrepareDrive(virStorageSourcePtr src,
|
||
|
|
return g_steal_pointer(&data);
|
||
|
|
}
|
||
|
|
|
||
|
|
+/**
|
||
|
|
+ * qemuBlockStorageSourceChainDetachPrepareChardev
|
||
|
|
+ * @src: storage source chain to remove
|
||
|
|
+ *
|
||
|
|
+ * Prepares qemuBlockStorageSourceChainDataPtr for detaching @src and its
|
||
|
|
+ * backingStore if -chardev was used.
|
||
|
|
+ */
|
||
|
|
+qemuBlockStorageSourceChainDataPtr
|
||
|
|
+qemuBlockStorageSourceChainDetachPrepareChardev(char *chardevAlias)
|
||
|
|
+{
|
||
|
|
+ g_autoptr(qemuBlockStorageSourceAttachData) backend = NULL;
|
||
|
|
+ g_autoptr(qemuBlockStorageSourceChainData) data = NULL;
|
||
|
|
+
|
||
|
|
+ data = g_new0(qemuBlockStorageSourceChainData, 1);
|
||
|
|
+ backend = g_new0(qemuBlockStorageSourceAttachData, 1);
|
||
|
|
+
|
||
|
|
+ backend->chardevAlias = chardevAlias;
|
||
|
|
+ backend->chardevAdded = true;
|
||
|
|
+
|
||
|
|
+ if (VIR_APPEND_ELEMENT(data->srcdata, data->nsrcdata, backend) < 0)
|
||
|
|
+ return NULL;
|
||
|
|
+
|
||
|
|
+ return g_steal_pointer(&data);
|
||
|
|
+}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* qemuBlockStorageSourceChainAttach:
|
||
|
|
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
|
||
|
|
index 2ad2ce1a1f..862572e028 100644
|
||
|
|
--- a/src/qemu/qemu_block.h
|
||
|
|
+++ b/src/qemu/qemu_block.h
|
||
|
|
@@ -94,6 +94,11 @@ struct qemuBlockStorageSourceAttachData {
|
||
|
|
char *driveAlias;
|
||
|
|
bool driveAdded;
|
||
|
|
|
||
|
|
+ virDomainChrSourceDefPtr chardevDef;
|
||
|
|
+ char *chardevAlias;
|
||
|
|
+ char *chardevCmd;
|
||
|
|
+ bool chardevAdded;
|
||
|
|
+
|
||
|
|
virJSONValuePtr authsecretProps;
|
||
|
|
char *authsecretAlias;
|
||
|
|
|
||
|
|
@@ -153,6 +158,8 @@ qemuBlockStorageSourceChainDetachPrepareBlockdev(virStorageSourcePtr src);
|
||
|
|
qemuBlockStorageSourceChainDataPtr
|
||
|
|
qemuBlockStorageSourceChainDetachPrepareDrive(virStorageSourcePtr src,
|
||
|
|
char *driveAlias);
|
||
|
|
+qemuBlockStorageSourceChainDataPtr
|
||
|
|
+qemuBlockStorageSourceChainDetachPrepareChardev(char *chardevAlias);
|
||
|
|
|
||
|
|
int
|
||
|
|
qemuBlockStorageSourceChainAttach(qemuMonitorPtr mon,
|
||
|
|
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
|
||
|
|
index bc62843783..4b12be6ede 100644
|
||
|
|
--- a/src/qemu/qemu_command.c
|
||
|
|
+++ b/src/qemu/qemu_command.c
|
||
|
|
@@ -2152,9 +2152,16 @@ qemuBuildDiskDeviceStr(const virDomainDef *def,
|
||
|
|
break;
|
||
|
|
|
||
|
|
case VIR_DOMAIN_DISK_BUS_VIRTIO:
|
||
|
|
- if (qemuBuildVirtioDevStr(&opt, "virtio-blk", qemuCaps,
|
||
|
|
- VIR_DOMAIN_DEVICE_DISK, disk) < 0) {
|
||
|
|
- return NULL;
|
||
|
|
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ if (qemuBuildVirtioDevStr(&opt, "vhost-user-blk", qemuCaps,
|
||
|
|
+ VIR_DOMAIN_DEVICE_DISK, disk) < 0) {
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ } else {
|
||
|
|
+ if (qemuBuildVirtioDevStr(&opt, "virtio-blk", qemuCaps,
|
||
|
|
+ VIR_DOMAIN_DEVICE_DISK, disk) < 0) {
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
|
||
|
|
if (disk->iothread)
|
||
|
|
@@ -2231,11 +2238,17 @@ qemuBuildDiskDeviceStr(const virDomainDef *def,
|
||
|
|
virQEMUCapsGet(qemuCaps, QEMU_CAPS_DISK_SHARE_RW))
|
||
|
|
virBufferAddLit(&opt, ",share-rw=on");
|
||
|
|
|
||
|
|
- if (qemuDomainDiskGetBackendAlias(disk, qemuCaps, &backendAlias) < 0)
|
||
|
|
- return NULL;
|
||
|
|
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ backendAlias = qemuDomainGetVhostUserChrAlias(disk->info.alias);
|
||
|
|
|
||
|
|
- if (backendAlias)
|
||
|
|
- virBufferAsprintf(&opt, ",drive=%s", backendAlias);
|
||
|
|
+ virBufferAsprintf(&opt, ",chardev=%s", backendAlias);
|
||
|
|
+ } else {
|
||
|
|
+ if (qemuDomainDiskGetBackendAlias(disk, qemuCaps, &backendAlias) < 0)
|
||
|
|
+ return NULL;
|
||
|
|
+
|
||
|
|
+ if (backendAlias)
|
||
|
|
+ virBufferAsprintf(&opt, ",drive=%s", backendAlias);
|
||
|
|
+ }
|
||
|
|
|
||
|
|
virBufferAsprintf(&opt, ",id=%s", disk->info.alias);
|
||
|
|
if (bootindex)
|
||
|
|
@@ -2453,6 +2466,9 @@ qemuBuildBlockStorageSourceAttachDataCommandline(virCommandPtr cmd,
|
||
|
|
if (data->driveCmd)
|
||
|
|
virCommandAddArgList(cmd, "-drive", data->driveCmd, NULL);
|
||
|
|
|
||
|
|
+ if (data->chardevCmd)
|
||
|
|
+ virCommandAddArgList(cmd, "-chardev", data->chardevCmd, NULL);
|
||
|
|
+
|
||
|
|
if (data->storageProps) {
|
||
|
|
if (!(tmp = virJSONValueToString(data->storageProps, false)))
|
||
|
|
return -1;
|
||
|
|
@@ -2492,7 +2508,10 @@ qemuBuildDiskSourceCommandLine(virCommandPtr cmd,
|
||
|
|
g_autofree char *copyOnReadPropsStr = NULL;
|
||
|
|
size_t i;
|
||
|
|
|
||
|
|
- if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV)) {
|
||
|
|
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ if (!(data = qemuBuildStorageSourceChainAttachPrepareChardev(disk)))
|
||
|
|
+ return -1;
|
||
|
|
+ } else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV)) {
|
||
|
|
if (virStorageSourceIsEmpty(disk->src))
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
@@ -10437,6 +10456,39 @@ qemuBuildStorageSourceAttachPrepareDrive(virDomainDiskDefPtr disk,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
+/**
|
||
|
|
+ * qemuBuildStorageSourceAttachPrepareChardev:
|
||
|
|
+ * @src: disk source to prepare
|
||
|
|
+ *
|
||
|
|
+ * Prepare qemuBlockStorageSourceAttachDataPtr for vhost-user disk
|
||
|
|
+ * to be used with -chardev.
|
||
|
|
+ */
|
||
|
|
+qemuBlockStorageSourceAttachDataPtr
|
||
|
|
+qemuBuildStorageSourceAttachPrepareChardev(virDomainDiskDefPtr disk)
|
||
|
|
+{
|
||
|
|
+ g_autoptr(qemuBlockStorageSourceAttachData) data = NULL;
|
||
|
|
+ g_auto(virBuffer) chardev = VIR_BUFFER_INITIALIZER;
|
||
|
|
+
|
||
|
|
+ data = g_new0(qemuBlockStorageSourceAttachData, 1);
|
||
|
|
+
|
||
|
|
+ data->chardevDef = disk->src->vhostuser;
|
||
|
|
+ data->chardevAlias = qemuDomainGetVhostUserChrAlias(disk->info.alias);
|
||
|
|
+
|
||
|
|
+ virBufferAddLit(&chardev, "socket");
|
||
|
|
+ virBufferAsprintf(&chardev, ",id=%s", data->chardevAlias);
|
||
|
|
+ virBufferAddLit(&chardev, ",path=");
|
||
|
|
+ virQEMUBuildBufferEscapeComma(&chardev, disk->src->vhostuser->data.nix.path);
|
||
|
|
+
|
||
|
|
+ qemuBuildChrChardevReconnectStr(&chardev,
|
||
|
|
+ &disk->src->vhostuser->data.nix.reconnect);
|
||
|
|
+
|
||
|
|
+ if (!(data->chardevCmd = virBufferContentAndReset(&chardev)))
|
||
|
|
+ return NULL;
|
||
|
|
+
|
||
|
|
+ return g_steal_pointer(&data);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
/**
|
||
|
|
* qemuBuildStorageSourceAttachPrepareCommon:
|
||
|
|
* @src: storage source
|
||
|
|
@@ -10513,6 +10565,31 @@ qemuBuildStorageSourceChainAttachPrepareDrive(virDomainDiskDefPtr disk,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
+/**
|
||
|
|
+ * qemuBuildStorageSourceChainAttachPrepareChardev:
|
||
|
|
+ * @src: disk definition
|
||
|
|
+ *
|
||
|
|
+ * Prepares qemuBlockStorageSourceChainDataPtr for attaching a vhost-user
|
||
|
|
+ * disk's backend via -chardev.
|
||
|
|
+ */
|
||
|
|
+qemuBlockStorageSourceChainDataPtr
|
||
|
|
+qemuBuildStorageSourceChainAttachPrepareChardev(virDomainDiskDefPtr disk)
|
||
|
|
+{
|
||
|
|
+ g_autoptr(qemuBlockStorageSourceAttachData) elem = NULL;
|
||
|
|
+ g_autoptr(qemuBlockStorageSourceChainData) data = NULL;
|
||
|
|
+
|
||
|
|
+ data = g_new0(qemuBlockStorageSourceChainData, 1);
|
||
|
|
+
|
||
|
|
+ if (!(elem = qemuBuildStorageSourceAttachPrepareChardev(disk)))
|
||
|
|
+ return NULL;
|
||
|
|
+
|
||
|
|
+ if (VIR_APPEND_ELEMENT(data->srcdata, data->nsrcdata, elem) < 0)
|
||
|
|
+ return NULL;
|
||
|
|
+
|
||
|
|
+ return g_steal_pointer(&data);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
static int
|
||
|
|
qemuBuildStorageSourceChainAttachPrepareBlockdevOne(qemuBlockStorageSourceChainData *data,
|
||
|
|
virStorageSourcePtr src,
|
||
|
|
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
|
||
|
|
index 4b1c2103c5..283aaf358c 100644
|
||
|
|
--- a/src/qemu/qemu_command.h
|
||
|
|
+++ b/src/qemu/qemu_command.h
|
||
|
|
@@ -115,6 +115,10 @@ qemuBlockStorageSourceAttachDataPtr
|
||
|
|
qemuBuildStorageSourceAttachPrepareDrive(virDomainDiskDefPtr disk,
|
||
|
|
const virDomainDef *def,
|
||
|
|
virQEMUCapsPtr qemuCaps);
|
||
|
|
+
|
||
|
|
+qemuBlockStorageSourceAttachDataPtr
|
||
|
|
+qemuBuildStorageSourceAttachPrepareChardev(virDomainDiskDefPtr disk);
|
||
|
|
+
|
||
|
|
int
|
||
|
|
qemuBuildStorageSourceAttachPrepareCommon(virStorageSourcePtr src,
|
||
|
|
qemuBlockStorageSourceAttachDataPtr data,
|
||
|
|
@@ -126,6 +130,8 @@ qemuBuildStorageSourceChainAttachPrepareDrive(virDomainDiskDefPtr disk,
|
||
|
|
const virDomainDef *def,
|
||
|
|
virQEMUCapsPtr qemuCaps);
|
||
|
|
|
||
|
|
+qemuBlockStorageSourceChainDataPtr
|
||
|
|
+qemuBuildStorageSourceChainAttachPrepareChardev(virDomainDiskDefPtr disk);
|
||
|
|
|
||
|
|
qemuBlockStorageSourceChainDataPtr
|
||
|
|
qemuBuildStorageSourceChainAttachPrepareBlockdev(virStorageSourcePtr top,
|
||
|
|
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
|
||
|
|
index c315717c8a..b2ac1d37cc 100644
|
||
|
|
--- a/src/qemu/qemu_domain.c
|
||
|
|
+++ b/src/qemu/qemu_domain.c
|
||
|
|
@@ -7250,6 +7250,14 @@ qemuDomainDeviceDefValidateDisk(const virDomainDiskDef *disk,
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (disk->src->type == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VHOST_USER_BLK)) {
|
||
|
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||
|
|
+ _("vhostuser disk is not supported with this QEMU binary"));
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
for (n = disk->src; virStorageSourceIsBacking(n); n = n->backingStore) {
|
||
|
|
if (qemuDomainValidateStorageSource(n, qemuCaps) < 0)
|
||
|
|
return -1;
|
||
|
|
@@ -16767,6 +16775,11 @@ qemuDomainPrepareDiskSource(virDomainDiskDefPtr disk,
|
||
|
|
qemuDomainObjPrivatePtr priv,
|
||
|
|
virQEMUDriverConfigPtr cfg)
|
||
|
|
{
|
||
|
|
+ /* Nothing to prepare as it will use -chardev instead
|
||
|
|
+ * of -blockdev/-drive option. */
|
||
|
|
+ if (disk->src->type == VIR_STORAGE_TYPE_VHOST_USER)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
qemuDomainPrepareDiskCachemode(disk);
|
||
|
|
|
||
|
|
/* set default format for storage pool based disks */
|
||
|
|
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
||
|
|
index b2ad021e4d..1791e3c902 100644
|
||
|
|
--- a/src/qemu/qemu_driver.c
|
||
|
|
+++ b/src/qemu/qemu_driver.c
|
||
|
|
@@ -10707,6 +10707,12 @@ qemuDomainBlockResize(virDomainPtr dom,
|
||
|
|
goto endjob;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
||
|
|
+ _("block resize is not supported for vhostuser disk"));
|
||
|
|
+ goto endjob;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
/* qcow2 and qed must be sized on 512 byte blocks/sectors,
|
||
|
|
* so adjust size if necessary to round up.
|
||
|
|
*/
|
||
|
|
@@ -10798,6 +10804,12 @@ qemuDomainBlocksStatsGather(virQEMUDriverPtr driver,
|
||
|
|
goto cleanup;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
||
|
|
+ _("block stats are not supported for vhostuser disk"));
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
if (blockdev) {
|
||
|
|
entryname = QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName;
|
||
|
|
} else {
|
||
|
|
@@ -10854,6 +10866,10 @@ qemuDomainBlocksStatsGather(virQEMUDriverPtr driver,
|
||
|
|
disk = vm->def->disks[i];
|
||
|
|
entryname = disk->info.alias;
|
||
|
|
|
||
|
|
+ /* No stats to report for vhost-user disk */
|
||
|
|
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER)
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
if (blockdev)
|
||
|
|
entryname = QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName;
|
||
|
|
|
||
|
|
@@ -11483,6 +11499,12 @@ qemuDomainBlockPeek(virDomainPtr dom,
|
||
|
|
if (!(disk = qemuDomainDiskByName(vm->def, path)))
|
||
|
|
goto cleanup;
|
||
|
|
|
||
|
|
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
||
|
|
+ _("peeking is not supported for vhostuser disk"));
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
if (disk->src->format != VIR_STORAGE_FILE_RAW) {
|
||
|
|
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
|
||
|
|
_("peeking is only supported for disk with 'raw' format not '%s'"),
|
||
|
|
@@ -11840,6 +11862,12 @@ qemuDomainGetBlockInfo(virDomainPtr dom,
|
||
|
|
goto endjob;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
||
|
|
+ _("block info is not supported for vhostuser disk"));
|
||
|
|
+ goto endjob;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
if (virStorageSourceIsEmpty(disk->src)) {
|
||
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
||
|
|
_("disk '%s' does not currently have a source assigned"),
|
||
|
|
@@ -18882,6 +18910,19 @@ typedef enum {
|
||
|
|
} qemuBlockIoTuneSetFlags;
|
||
|
|
|
||
|
|
|
||
|
|
+static bool
|
||
|
|
+qemuDomainDiskBlockIoTuneIsSupported(virStorageSourcePtr src)
|
||
|
|
+{
|
||
|
|
+ if (virStorageSourceGetActualType(src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||
|
|
+ _("a block I/O throttling is not supported for vhostuser disk"));
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
/* If the user didn't specify bytes limits, inherit previous values;
|
||
|
|
* likewise if the user didn't specify iops limits. */
|
||
|
|
static int
|
||
|
|
@@ -19250,6 +19291,9 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
|
||
|
|
if (!(disk = qemuDomainDiskByName(def, path)))
|
||
|
|
goto endjob;
|
||
|
|
|
||
|
|
+ if (!qemuDomainDiskBlockIoTuneIsSupported(disk->src))
|
||
|
|
+ goto endjob;
|
||
|
|
+
|
||
|
|
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV)) {
|
||
|
|
qdevid = QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName;
|
||
|
|
} else {
|
||
|
|
@@ -19257,6 +19301,9 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
|
||
|
|
goto endjob;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (!qemuDomainDiskBlockIoTuneIsSupported(conf_disk->src))
|
||
|
|
+ goto endjob;
|
||
|
|
+
|
||
|
|
cur_info = qemuDomainFindGroupBlockIoTune(def, disk, &info);
|
||
|
|
|
||
|
|
if (qemuDomainSetBlockIoTuneDefaults(&info, cur_info,
|
||
|
|
@@ -19440,6 +19487,9 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
|
||
|
|
if (!(disk = qemuDomainDiskByName(def, path)))
|
||
|
|
goto endjob;
|
||
|
|
|
||
|
|
+ if (!qemuDomainDiskBlockIoTuneIsSupported(disk->src))
|
||
|
|
+ goto endjob;
|
||
|
|
+
|
||
|
|
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV)) {
|
||
|
|
qdevid = QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName;
|
||
|
|
} else {
|
||
|
|
@@ -19461,6 +19511,10 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
|
||
|
|
path);
|
||
|
|
goto endjob;
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+ if (!qemuDomainDiskBlockIoTuneIsSupported(disk->src))
|
||
|
|
+ goto endjob;
|
||
|
|
+
|
||
|
|
reply = disk->blkdeviotune;
|
||
|
|
|
||
|
|
/* Group name needs to be copied since qemuMonitorGetBlockIoThrottle
|
||
|
|
@@ -21389,6 +21443,12 @@ qemuDomainGetStatsBlockExportDisk(virDomainDiskDefPtr disk,
|
||
|
|
VIR_INFO("optional disk '%s' source file is missing, "
|
||
|
|
"skip getting stats", disk->dst);
|
||
|
|
|
||
|
|
+ return qemuDomainGetStatsBlockExportHeader(disk, disk->src, *recordnr,
|
||
|
|
+ params);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* vhost-user disk doesn't support getting block stats */
|
||
|
|
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
if (qemuDomainGetStatsBlockExportHeader(disk, disk->src, *recordnr,
|
||
|
|
params) < 0) {
|
||
|
|
return -1;
|
||
|
|
@@ -22638,6 +22698,12 @@ qemuDomainSetBlockThreshold(virDomainPtr dom,
|
||
|
|
if (!(src = qemuDomainGetStorageSourceByDevstr(dev, vm->def)))
|
||
|
|
goto endjob;
|
||
|
|
|
||
|
|
+ if (virStorageSourceGetActualType(src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
||
|
|
+ _("setting device threshold is not supported for vhostuser disk"));
|
||
|
|
+ goto endjob;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
if (!src->nodestorage &&
|
||
|
|
qemuBlockNodeNamesDetect(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
|
||
|
|
goto endjob;
|
||
|
|
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
|
||
|
|
index c9347bac04..cb571c3161 100644
|
||
|
|
--- a/src/qemu/qemu_hotplug.c
|
||
|
|
+++ b/src/qemu/qemu_hotplug.c
|
||
|
|
@@ -702,7 +702,10 @@ qemuDomainAttachDiskGeneric(virQEMUDriverPtr driver,
|
||
|
|
if (qemuDomainPrepareDiskSource(disk, priv, cfg) < 0)
|
||
|
|
goto cleanup;
|
||
|
|
|
||
|
|
- if (blockdev) {
|
||
|
|
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ if (!(data = qemuBuildStorageSourceChainAttachPrepareChardev(disk)))
|
||
|
|
+ goto cleanup;
|
||
|
|
+ } else if (blockdev) {
|
||
|
|
if (disk->copy_on_read == VIR_TRISTATE_SWITCH_ON) {
|
||
|
|
if (!(corProps = qemuBlockStorageGetCopyOnReadProps(disk)))
|
||
|
|
goto cleanup;
|
||
|
|
@@ -4280,7 +4283,12 @@ qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
|
||
|
|
disk->info.alias, vm, vm->def->name);
|
||
|
|
|
||
|
|
|
||
|
|
- if (blockdev) {
|
||
|
|
+ if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
|
||
|
|
+ char *chardevAlias = qemuDomainGetVhostUserChrAlias(disk->info.alias);
|
||
|
|
+
|
||
|
|
+ if (!(diskBackend = qemuBlockStorageSourceChainDetachPrepareChardev(chardevAlias)))
|
||
|
|
+ goto cleanup;
|
||
|
|
+ } else if (blockdev) {
|
||
|
|
corAlias = g_strdup(diskPriv->nodeCopyOnRead);
|
||
|
|
|
||
|
|
if (diskPriv->blockjob) {
|
||
|
|
diff --git a/tests/qemuxml2argvdata/disk-vhostuser.x86_64-latest.args b/tests/qemuxml2argvdata/disk-vhostuser.x86_64-latest.args
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000000..0a2b579e21
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/tests/qemuxml2argvdata/disk-vhostuser.x86_64-latest.args
|
||
|
|
@@ -0,0 +1,40 @@
|
||
|
|
+LC_ALL=C \
|
||
|
|
+PATH=/bin \
|
||
|
|
+HOME=/tmp/lib/domain--1-QEMUGuest1 \
|
||
|
|
+USER=test \
|
||
|
|
+LOGNAME=test \
|
||
|
|
+XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \
|
||
|
|
+XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \
|
||
|
|
+XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \
|
||
|
|
+QEMU_AUDIO_DRV=none \
|
||
|
|
+/usr/bin/qemu-system-x86_64 \
|
||
|
|
+-name guest=QEMUGuest1,debug-threads=on \
|
||
|
|
+-S \
|
||
|
|
+-object secret,id=masterKey0,format=raw,\
|
||
|
|
+file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
|
||
|
|
+-machine pc,accel=tcg,usb=off,dump-guest-core=off \
|
||
|
|
+-cpu qemu64 \
|
||
|
|
+-m 214 \
|
||
|
|
+-overcommit mem-lock=off \
|
||
|
|
+-smp 1,sockets=1,cores=1,threads=1 \
|
||
|
|
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
|
||
|
|
+-display none \
|
||
|
|
+-no-user-config \
|
||
|
|
+-nodefaults \
|
||
|
|
+-chardev socket,id=charmonitor,fd=1729,server,nowait \
|
||
|
|
+-mon chardev=charmonitor,id=monitor,mode=control \
|
||
|
|
+-rtc base=utc \
|
||
|
|
+-no-shutdown \
|
||
|
|
+-no-acpi \
|
||
|
|
+-boot strict=on \
|
||
|
|
+-device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 \
|
||
|
|
+-chardev socket,id=chr-vu-virtio-disk0,path=/tmp/vhost1.sock \
|
||
|
|
+-device vhost-user-blk-pci,bus=pci.0,addr=0x2,chardev=chr-vu-virtio-disk0,\
|
||
|
|
+id=virtio-disk0,bootindex=1 \
|
||
|
|
+-chardev socket,id=chr-vu-virtio-disk1,path=/tmp/vhost1.sock,reconnect=10 \
|
||
|
|
+-device vhost-user-blk-pci,bus=pci.0,addr=0x3,chardev=chr-vu-virtio-disk1,\
|
||
|
|
+id=virtio-disk1 \
|
||
|
|
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 \
|
||
|
|
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\
|
||
|
|
+resourcecontrol=deny \
|
||
|
|
+-msg timestamp=on
|
||
|
|
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
|
||
|
|
index e07d6cf398..7b117f5984 100644
|
||
|
|
--- a/tests/qemuxml2argvtest.c
|
||
|
|
+++ b/tests/qemuxml2argvtest.c
|
||
|
|
@@ -1209,6 +1209,7 @@ mymain(void)
|
||
|
|
VIR_FREE(driver.config->vxhsTLSx509certdir);
|
||
|
|
DO_TEST("disk-no-boot", NONE);
|
||
|
|
DO_TEST_CAPS_LATEST("disk-nvme");
|
||
|
|
+ DO_TEST_CAPS_LATEST("disk-vhostuser");
|
||
|
|
DO_TEST_PARSE_ERROR("disk-device-lun-type-invalid",
|
||
|
|
QEMU_CAPS_VIRTIO_SCSI);
|
||
|
|
DO_TEST_CAPS_LATEST_PARSE_ERROR("disk-attaching-partition-nosupport");
|
||
|
|
--
|
||
|
|
2.27.0
|
||
|
|
|