[libvirt PATCH v2 6/6] qemu: implement vhost-user-blk support

Pavel Hrdina phrdina at redhat.com
Wed Feb 3 15:25:59 UTC 2021


Implements QEMU support for vhost-user-blk together with live
hotplug/unplug.

Signed-off-by: Pavel Hrdina <phrdina at redhat.com>
Reviewed-by: Ján Tomko <jtomko at redhat.com>
---

Changes in v2:
    - moved check for vhostuser in qemuDomainPrepareDiskSource
    - added hot-unplug support
    - disable blockjobs in qemuDomainDiskBlockJobIsSupported
    - error out in qemuDomainSetBlockIoTune and qemuDomainGetBlockIoTune
    - print proper error in qemuDomainBlockPeek,
      qemuDomainSetBlockThreshold, qemuDomainGetBlockInfo,
      qemuDomainBlockResize
    - correctly handle qemuDomainBlockStats(Flags) and
      qemuDomainGetStatsBlockExportDisk

 src/qemu/qemu_block.c                         | 42 +++++++++
 src/qemu/qemu_block.h                         |  7 ++
 src/qemu/qemu_command.c                       | 91 +++++++++++++++++--
 src/qemu/qemu_command.h                       |  8 ++
 src/qemu/qemu_domain.c                        | 12 +++
 src/qemu/qemu_driver.c                        | 72 +++++++++++++++
 src/qemu/qemu_hotplug.c                       | 14 ++-
 src/qemu/qemu_validate.c                      | 13 +++
 .../disk-vhostuser.x86_64-latest.args         | 41 +++++++++
 tests/qemuxml2argvtest.c                      |  1 +
 10 files changed, 290 insertions(+), 11 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 4ae736d553..0b8ca2a3f5 100644
--- a/src/qemu/qemu_block.c
+++ b/src/qemu/qemu_block.c
@@ -1642,6 +1642,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);
 }
 
@@ -1815,6 +1817,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;
 }
 
@@ -1837,6 +1846,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 "
@@ -2004,6 +2020,32 @@ qemuBlockStorageSourceChainDetachPrepareDrive(virStorageSourcePtr src,
 }
 
 
+/**
+ * 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:
  * @mon: monitor object
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
index 8f2a05f46a..7f97e913b3 100644
--- a/src/qemu/qemu_block.h
+++ b/src/qemu/qemu_block.h
@@ -99,6 +99,11 @@ struct qemuBlockStorageSourceAttachData {
     char *driveAlias;
     bool driveAdded;
 
+    virDomainChrSourceDefPtr chardevDef;
+    char *chardevAlias;
+    char *chardevCmd;
+    bool chardevAdded;
+
     virJSONValuePtr authsecretProps;
     char *authsecretAlias;
 
@@ -160,6 +165,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 5501f90221..c24929571e 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1714,9 +1714,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)
@@ -1775,11 +1782,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)
@@ -1989,6 +2002,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;
@@ -2027,7 +2043,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) &&
         !qemuDiskBusIsSD(disk->bus)) {
         if (virStorageSourceIsEmpty(disk->src))
             return 0;
@@ -10296,6 +10315,38 @@ qemuBuildStorageSourceAttachPrepareDrive(virDomainDiskDefPtr disk,
 }
 
 
+/**
+ * qemuBuildStorageSourceAttachPrepareChardev:
+ * @src: disk source to prepare
+ *
+ * Prepare qemuBlockStorageSourceAttachDataPtr for use 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
@@ -10378,6 +10429,30 @@ qemuBuildStorageSourceChainAttachPrepareDrive(virDomainDiskDefPtr disk,
 }
 
 
+/**
+ * qemuBuildStorageSourceChainAttachPrepareChardev:
+ * @src: disk definition
+ *
+ * Prepares qemuBlockStorageSourceChainDataPtr for attaching @disk via -drive.
+ */
+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 3cfe6ff3e9..a33fbf6f4e 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -115,6 +115,10 @@ bool qemuDiskBusIsSD(int bus);
 qemuBlockStorageSourceAttachDataPtr
 qemuBuildStorageSourceAttachPrepareDrive(virDomainDiskDefPtr disk,
                                          virQEMUCapsPtr qemuCaps);
+
+qemuBlockStorageSourceAttachDataPtr
+qemuBuildStorageSourceAttachPrepareChardev(virDomainDiskDefPtr disk);
+
 int
 qemuBuildStorageSourceAttachPrepareCommon(virStorageSourcePtr src,
                                           qemuBlockStorageSourceAttachDataPtr data,
@@ -126,6 +130,10 @@ qemuBuildStorageSourceChainAttachPrepareDrive(virDomainDiskDefPtr disk,
                                               virQEMUCapsPtr qemuCaps);
 
 
+qemuBlockStorageSourceChainDataPtr
+qemuBuildStorageSourceChainAttachPrepareChardev(virDomainDiskDefPtr disk);
+
+
 qemuBlockStorageSourceChainDataPtr
 qemuBuildStorageSourceChainAttachPrepareBlockdev(virStorageSourcePtr top,
                                                  virQEMUCapsPtr qemuCaps);
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index e60f814e36..f1beb22d06 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -10572,6 +10572,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 */
@@ -11062,6 +11067,13 @@ qemuDomainDiskBlockJobIsSupported(virDomainObjPtr vm,
         return false;
     }
 
+    if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
+                       _("block jobs are not supported on vhostuser disk '%s'"),
+                       disk->dst);
+        return false;
+    }
+
     return true;
 }
 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ed840a5c8d..69fcd28666 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -9821,6 +9821,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.
      */
@@ -9913,6 +9919,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 && QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName) {
             entryname = QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName;
         } else {
@@ -9968,6 +9980,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 && QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName)
                 entryname = QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName;
 
@@ -10616,6 +10632,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'"),
@@ -10973,6 +10995,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"),
@@ -15851,6 +15879,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
@@ -16219,6 +16260,9 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
         if (!(disk = qemuDomainDiskByName(def, path)))
             goto endjob;
 
+        if (!qemuDomainDiskBlockIoTuneIsSupported(disk->src))
+            goto endjob;
+
         if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV) &&
             QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName) {
             qdevid = QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName;
@@ -16312,6 +16356,9 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
             goto endjob;
         }
 
+        if (!qemuDomainDiskBlockIoTuneIsSupported(conf_disk->src))
+            goto endjob;
+
         conf_cur_info = qemuDomainFindGroupBlockIoTune(persistentDef, conf_disk, &info);
 
         if (qemuDomainSetBlockIoTuneDefaults(&conf_info, conf_cur_info,
@@ -16412,6 +16459,9 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
         if (!(disk = qemuDomainDiskByName(def, path)))
             goto endjob;
 
+        if (!qemuDomainDiskBlockIoTuneIsSupported(disk->src))
+            goto endjob;
+
         if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV) &&
             QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName) {
             qdevid = QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName;
@@ -16434,6 +16484,10 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
                            path);
             goto endjob;
         }
+
+        if (!qemuDomainDiskBlockIoTuneIsSupported(disk->src))
+            goto endjob;
+
         reply = disk->blkdeviotune;
 
         /* Group name needs to be copied since qemuMonitorGetBlockIoThrottle
@@ -18364,6 +18418,18 @@ qemuDomainGetStatsBlockExportDisk(virDomainDiskDefPtr disk,
                                                    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;
+        }
+
+        (*recordnr)++;
+
+        return 0;
+    }
+
     for (n = disk->src; virStorageSourceIsBacking(n); n = n->backingStore) {
         g_autofree char *alias = NULL;
 
@@ -19571,6 +19637,12 @@ qemuDomainSetBlockThreshold(virDomainPtr dom,
     if (!(src = qemuDomainGetStorageSourceByDevstr(dev, vm->def, priv->backup)))
         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 (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV) &&
         !src->nodestorage &&
         qemuBlockNodeNamesDetect(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 882e5d2384..213be41553 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -714,7 +714,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;
@@ -4314,8 +4317,13 @@ qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver,
               disk->info.alias, vm, vm->def->name);
 
 
-    if (blockdev &&
-        !qemuDiskBusIsSD(disk->bus)) {
+    if (virStorageSourceGetActualType(disk->src) == VIR_STORAGE_TYPE_VHOST_USER) {
+        char *chardevAlias = qemuDomainGetVhostUserChrAlias(disk->info.alias);
+
+        if (!(diskBackend = qemuBlockStorageSourceChainDetachPrepareChardev(chardevAlias)))
+            goto cleanup;
+    } else if (blockdev &&
+               !qemuDiskBusIsSD(disk->bus)) {
         corAlias = g_strdup(diskPriv->nodeCopyOnRead);
 
         if (diskPriv->blockjob) {
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index f5016e4d0c..78e80b7919 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -2957,6 +2957,19 @@ qemuValidateDomainDeviceDefDisk(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;
+        }
+
+        if (qemuValidateDomainDefVhostUserRequireSharedMemory(def, "vhostuser",
+                                                              qemuCaps) < 0) {
+            return -1;
+        }
+    }
+
     return 0;
 }
 
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..b24b2c0b4f
--- /dev/null
+++ b/tests/qemuxml2argvdata/disk-vhostuser.x86_64-latest.args
@@ -0,0 +1,41 @@
+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,memory-backend=pc.ram \
+-cpu qemu64 \
+-m 214 \
+-object memory-backend-memfd,id=pc.ram,share=yes,size=224395264 \
+-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 0f4ec4533c..faa71a7a16 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1268,6 +1268,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.29.2




More information about the libvir-list mailing list