render / rpms / libvirt

Forked from rpms/libvirt 10 months ago
Clone
127bba
From fa914e6aea49d5cdc063b366a793d4d76a3a4030 Mon Sep 17 00:00:00 2001
127bba
Message-Id: <fa914e6aea49d5cdc063b366a793d4d76a3a4030@dist-git>
127bba
From: Martin Kletzander <mkletzan@redhat.com>
127bba
Date: Fri, 4 Nov 2016 10:29:54 +0100
127bba
Subject: [PATCH] qemu: Add support for hot/cold-(un)plug of shmem devices
127bba
127bba
This is needed in order to migrate a domain with shmem devices as that
127bba
is not allowed to migrate.
127bba
127bba
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
127bba
(cherry picked from commit fb2d0cc6332ed2d5546aad623792231d619a4707)
127bba
127bba
 Conflicts:
127bba
	tests/qemuhotplugtest.c -- ccw hotplug tests
127bba
	tests/qemuhotplugtestdata -- directories refactor
127bba
127bba
https://bugzilla.redhat.com/show_bug.cgi?id=1392031
127bba
127bba
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
127bba
---
127bba
 src/qemu/qemu_driver.c                             |  39 +++-
127bba
 src/qemu/qemu_hotplug.c                            | 239 ++++++++++++++++++++-
127bba
 src/qemu/qemu_hotplug.h                            |   6 +
127bba
 tests/qemuhotplugtest.c                            |  21 ++
127bba
 ...uhotplug-hotplug-base-live+ivshmem-doorbell.xml |  65 ++++++
127bba
 ...plug-hotplug-base-live+ivshmem-plain-detach.xml |   1 +
127bba
 ...qemuhotplug-hotplug-base-live+ivshmem-plain.xml |   1 +
127bba
 .../qemuhotplug-ivshmem-doorbell-detach.xml        |   7 +
127bba
 .../qemuhotplug-ivshmem-doorbell.xml               |   4 +
127bba
 .../qemuhotplug-ivshmem-plain-detach.xml           |   6 +
127bba
 .../qemuhotplug-ivshmem-plain.xml                  |   3 +
127bba
 ...emuxml2argv-hotplug-base-live+ivshmem-plain.xml |  58 +++++
127bba
 12 files changed, 445 insertions(+), 5 deletions(-)
127bba
 create mode 100644 tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-doorbell.xml
127bba
 create mode 120000 tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-plain-detach.xml
127bba
 create mode 120000 tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-plain.xml
127bba
 create mode 100644 tests/qemuhotplugtestdata/qemuhotplug-ivshmem-doorbell-detach.xml
127bba
 create mode 100644 tests/qemuhotplugtestdata/qemuhotplug-ivshmem-doorbell.xml
127bba
 create mode 100644 tests/qemuhotplugtestdata/qemuhotplug-ivshmem-plain-detach.xml
127bba
 create mode 100644 tests/qemuhotplugtestdata/qemuhotplug-ivshmem-plain.xml
127bba
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hotplug-base-live+ivshmem-plain.xml
127bba
127bba
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
127bba
index 6775327..9b4d54b 100644
127bba
--- a/src/qemu/qemu_driver.c
127bba
+++ b/src/qemu/qemu_driver.c
127bba
@@ -7519,6 +7519,15 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
127bba
         dev->data.memory = NULL;
127bba
         break;
127bba
 
127bba
+    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
+        ret = qemuDomainAttachShmemDevice(driver, vm,
127bba
+                                          dev->data.shmem);
127bba
+        if (ret < 0) {
127bba
+            alias = dev->data.shmem->info.alias;
127bba
+            dev->data.shmem = NULL;
127bba
+        }
127bba
+        break;
127bba
+
127bba
     case VIR_DOMAIN_DEVICE_NONE:
127bba
     case VIR_DOMAIN_DEVICE_FS:
127bba
     case VIR_DOMAIN_DEVICE_INPUT:
127bba
@@ -7530,7 +7539,6 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
127bba
     case VIR_DOMAIN_DEVICE_SMARTCARD:
127bba
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
127bba
     case VIR_DOMAIN_DEVICE_NVRAM:
127bba
-    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
     case VIR_DOMAIN_DEVICE_TPM:
127bba
     case VIR_DOMAIN_DEVICE_PANIC:
127bba
     case VIR_DOMAIN_DEVICE_IOMMU:
127bba
@@ -7609,6 +7617,9 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
127bba
     case VIR_DOMAIN_DEVICE_MEMORY:
127bba
         ret = qemuDomainDetachMemoryDevice(driver, vm, dev->data.memory);
127bba
         break;
127bba
+    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
+        ret = qemuDomainDetachShmemDevice(driver, vm, dev->data.shmem);
127bba
+        break;
127bba
 
127bba
     case VIR_DOMAIN_DEVICE_FS:
127bba
     case VIR_DOMAIN_DEVICE_INPUT:
127bba
@@ -7620,7 +7631,6 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
127bba
     case VIR_DOMAIN_DEVICE_SMARTCARD:
127bba
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
127bba
     case VIR_DOMAIN_DEVICE_NVRAM:
127bba
-    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
     case VIR_DOMAIN_DEVICE_REDIRDEV:
127bba
     case VIR_DOMAIN_DEVICE_NONE:
127bba
     case VIR_DOMAIN_DEVICE_TPM:
127bba
@@ -7767,6 +7777,7 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
127bba
     virDomainControllerDefPtr controller;
127bba
     virDomainFSDefPtr fs;
127bba
     virDomainRedirdevDefPtr redirdev;
127bba
+    virDomainShmemDefPtr shmem;
127bba
 
127bba
     switch ((virDomainDeviceType) dev->type) {
127bba
     case VIR_DOMAIN_DEVICE_DISK:
127bba
@@ -7891,6 +7902,18 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
127bba
         dev->data.redirdev = NULL;
127bba
         break;
127bba
 
127bba
+    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
+        shmem = dev->data.shmem;
127bba
+        if (virDomainShmemDefFind(vmdef, shmem) >= 0) {
127bba
+            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
127bba
+                           _("device is already in the domain configuration"));
127bba
+            return -1;
127bba
+        }
127bba
+        if (virDomainShmemDefInsert(vmdef, shmem) < 0)
127bba
+            return -1;
127bba
+        dev->data.shmem = NULL;
127bba
+        break;
127bba
+
127bba
     case VIR_DOMAIN_DEVICE_INPUT:
127bba
     case VIR_DOMAIN_DEVICE_SOUND:
127bba
     case VIR_DOMAIN_DEVICE_VIDEO:
127bba
@@ -7900,7 +7923,6 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
127bba
     case VIR_DOMAIN_DEVICE_SMARTCARD:
127bba
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
127bba
     case VIR_DOMAIN_DEVICE_NVRAM:
127bba
-    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
     case VIR_DOMAIN_DEVICE_NONE:
127bba
     case VIR_DOMAIN_DEVICE_TPM:
127bba
     case VIR_DOMAIN_DEVICE_PANIC:
127bba
@@ -8047,6 +8069,16 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
127bba
         virDomainRedirdevDefFree(virDomainRedirdevDefRemove(vmdef, idx));
127bba
         break;
127bba
 
127bba
+    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
+        if ((idx = virDomainShmemDefFind(vmdef, dev->data.shmem)) < 0) {
127bba
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
127bba
+                           _("matching shmem device was not found"));
127bba
+            return -1;
127bba
+        }
127bba
+
127bba
+        virDomainShmemDefFree(virDomainShmemDefRemove(vmdef, idx));
127bba
+        break;
127bba
+
127bba
 
127bba
     case VIR_DOMAIN_DEVICE_INPUT:
127bba
     case VIR_DOMAIN_DEVICE_SOUND:
127bba
@@ -8057,7 +8089,6 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
127bba
     case VIR_DOMAIN_DEVICE_SMARTCARD:
127bba
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
127bba
     case VIR_DOMAIN_DEVICE_NVRAM:
127bba
-    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
     case VIR_DOMAIN_DEVICE_NONE:
127bba
     case VIR_DOMAIN_DEVICE_TPM:
127bba
     case VIR_DOMAIN_DEVICE_PANIC:
127bba
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
127bba
index f038be5..df3764f 100644
127bba
--- a/src/qemu/qemu_hotplug.c
127bba
+++ b/src/qemu/qemu_hotplug.c
127bba
@@ -2134,6 +2134,131 @@ qemuDomainAttachHostDevice(virConnectPtr conn,
127bba
     return -1;
127bba
 }
127bba
 
127bba
+
127bba
+int
127bba
+qemuDomainAttachShmemDevice(virQEMUDriverPtr driver,
127bba
+                            virDomainObjPtr vm,
127bba
+                            virDomainShmemDefPtr shmem)
127bba
+{
127bba
+    int ret = -1;
127bba
+    char *shmstr = NULL;
127bba
+    char *charAlias = NULL;
127bba
+    char *memAlias = NULL;
127bba
+    bool release_backing = false;
127bba
+    bool release_address = true;
127bba
+    virErrorPtr orig_err = NULL;
127bba
+    virJSONValuePtr props = NULL;
127bba
+    qemuDomainObjPrivatePtr priv = vm->privateData;
127bba
+
127bba
+    switch ((virDomainShmemModel)shmem->model) {
127bba
+    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_PLAIN:
127bba
+    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL:
127bba
+        break;
127bba
+
127bba
+    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
127bba
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
127bba
+                       _("live attach of shmem model '%s' is not supported"),
127bba
+                       virDomainShmemModelTypeToString(shmem->model));
127bba
+        /* fall-through */
127bba
+    case VIR_DOMAIN_SHMEM_MODEL_LAST:
127bba
+        return -1;
127bba
+    }
127bba
+
127bba
+    if (qemuAssignDeviceShmemAlias(vm->def, shmem, -1) < 0)
127bba
+        return -1;
127bba
+
127bba
+    if (qemuDomainPrepareShmemChardev(shmem) < 0)
127bba
+        return -1;
127bba
+
127bba
+    if (VIR_REALLOC_N(vm->def->shmems, vm->def->nshmems + 1) < 0)
127bba
+        return -1;
127bba
+
127bba
+    if ((shmem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
127bba
+         shmem->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) &&
127bba
+         (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &shmem->info) < 0))
127bba
+        return -1;
127bba
+
127bba
+    if (!(shmstr = qemuBuildShmemDevStr(vm->def, shmem, priv->qemuCaps)))
127bba
+        goto cleanup;
127bba
+
127bba
+    if (shmem->server.enabled) {
127bba
+        if (virAsprintf(&charAlias, "char%s", shmem->info.alias) < 0)
127bba
+            goto cleanup;
127bba
+    } else {
127bba
+        if (!(props = qemuBuildShmemBackendMemProps(shmem)))
127bba
+            goto cleanup;
127bba
+
127bba
+        if (virAsprintf(&memAlias, "shmmem-%s", shmem->info.alias) < 0)
127bba
+            goto cleanup;
127bba
+    }
127bba
+
127bba
+    qemuDomainObjEnterMonitor(driver, vm);
127bba
+
127bba
+    if (shmem->server.enabled) {
127bba
+        if (qemuMonitorAttachCharDev(priv->mon, charAlias,
127bba
+                                     &shmem->server.chr) < 0)
127bba
+            goto exit_monitor;
127bba
+    } else {
127bba
+        if (qemuMonitorAddObject(priv->mon, "memory-backend-file",
127bba
+                                 memAlias, props) < 0) {
127bba
+            props = NULL;
127bba
+            goto exit_monitor;
127bba
+        }
127bba
+        props = NULL;
127bba
+    }
127bba
+
127bba
+    release_backing = true;
127bba
+
127bba
+    if (qemuMonitorAddDevice(priv->mon, shmstr) < 0)
127bba
+        goto exit_monitor;
127bba
+
127bba
+    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
127bba
+        release_address = false;
127bba
+        goto cleanup;
127bba
+    }
127bba
+
127bba
+    /* Doing a copy here just so the pointer doesn't get nullified
127bba
+     * because we need it in the audit function */
127bba
+    VIR_APPEND_ELEMENT_COPY_INPLACE(vm->def->shmems, vm->def->nshmems, shmem);
127bba
+
127bba
+    ret = 0;
127bba
+    release_address = false;
127bba
+
127bba
+ audit:
127bba
+    virDomainAuditShmem(vm, shmem, "attach", ret == 0);
127bba
+
127bba
+ cleanup:
127bba
+    if (release_address)
127bba
+        qemuDomainReleaseDeviceAddress(vm, &shmem->info, NULL);
127bba
+
127bba
+    virJSONValueFree(props);
127bba
+    VIR_FREE(memAlias);
127bba
+    VIR_FREE(charAlias);
127bba
+    VIR_FREE(shmstr);
127bba
+
127bba
+    return ret;
127bba
+
127bba
+ exit_monitor:
127bba
+    orig_err = virSaveLastError();
127bba
+    if (release_backing) {
127bba
+        if (shmem->server.enabled)
127bba
+            ignore_value(qemuMonitorDetachCharDev(priv->mon, charAlias));
127bba
+        else
127bba
+            ignore_value(qemuMonitorDelObject(priv->mon, memAlias));
127bba
+    }
127bba
+
127bba
+    if (orig_err) {
127bba
+        virSetError(orig_err);
127bba
+        virFreeError(orig_err);
127bba
+    }
127bba
+
127bba
+    if (qemuDomainObjExitMonitor(driver, vm) < 0)
127bba
+        release_address = false;
127bba
+
127bba
+    goto audit;
127bba
+}
127bba
+
127bba
+
127bba
 static int
127bba
 qemuDomainChangeNetBridge(virDomainObjPtr vm,
127bba
                           virDomainNetDefPtr olddev,
127bba
@@ -3398,6 +3523,62 @@ qemuDomainRemoveRNGDevice(virQEMUDriverPtr driver,
127bba
 }
127bba
 
127bba
 
127bba
+static int
127bba
+qemuDomainRemoveShmemDevice(virQEMUDriverPtr driver,
127bba
+                            virDomainObjPtr vm,
127bba
+                            virDomainShmemDefPtr shmem)
127bba
+{
127bba
+    int rc;
127bba
+    int ret = -1;
127bba
+    ssize_t idx = -1;
127bba
+    char *charAlias = NULL;
127bba
+    char *memAlias = NULL;
127bba
+    qemuDomainObjPrivatePtr priv = vm->privateData;
127bba
+    virObjectEventPtr event = NULL;
127bba
+
127bba
+    VIR_DEBUG("Removing shmem device %s from domain %p %s",
127bba
+              shmem->info.alias, vm, vm->def->name);
127bba
+
127bba
+    if (shmem->server.enabled) {
127bba
+        if (virAsprintf(&charAlias, "char%s", shmem->info.alias) < 0)
127bba
+            return -1;
127bba
+    } else {
127bba
+        if (virAsprintf(&memAlias, "shmmem-%s", shmem->info.alias) < 0)
127bba
+            return -1;
127bba
+    }
127bba
+
127bba
+    qemuDomainObjEnterMonitor(driver, vm);
127bba
+
127bba
+    if (shmem->server.enabled)
127bba
+        rc = qemuMonitorDetachCharDev(priv->mon, charAlias);
127bba
+    else
127bba
+        rc = qemuMonitorDelObject(priv->mon, memAlias);
127bba
+
127bba
+    if (qemuDomainObjExitMonitor(driver, vm) < 0)
127bba
+        goto cleanup;
127bba
+
127bba
+    virDomainAuditShmem(vm, shmem, "detach", rc == 0);
127bba
+
127bba
+    if (rc < 0)
127bba
+        goto cleanup;
127bba
+
127bba
+    event = virDomainEventDeviceRemovedNewFromObj(vm, shmem->info.alias);
127bba
+    qemuDomainEventQueue(driver, event);
127bba
+
127bba
+    if ((idx = virDomainShmemDefFind(vm->def, shmem)) >= 0)
127bba
+        virDomainShmemDefRemove(vm->def, idx);
127bba
+    qemuDomainReleaseDeviceAddress(vm, &shmem->info, NULL);
127bba
+    virDomainShmemDefFree(shmem);
127bba
+
127bba
+    ret = 0;
127bba
+ cleanup:
127bba
+    VIR_FREE(charAlias);
127bba
+    VIR_FREE(memAlias);
127bba
+
127bba
+    return ret;
127bba
+}
127bba
+
127bba
+
127bba
 int
127bba
 qemuDomainRemoveDevice(virQEMUDriverPtr driver,
127bba
                        virDomainObjPtr vm,
127bba
@@ -3429,6 +3610,10 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
127bba
         ret = qemuDomainRemoveMemoryDevice(driver, vm, dev->data.memory);
127bba
         break;
127bba
 
127bba
+    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
+        ret = qemuDomainRemoveShmemDevice(driver, vm, dev->data.shmem);
127bba
+        break;
127bba
+
127bba
     case VIR_DOMAIN_DEVICE_NONE:
127bba
     case VIR_DOMAIN_DEVICE_LEASE:
127bba
     case VIR_DOMAIN_DEVICE_FS:
127bba
@@ -3442,7 +3627,6 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
127bba
     case VIR_DOMAIN_DEVICE_SMARTCARD:
127bba
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
127bba
     case VIR_DOMAIN_DEVICE_NVRAM:
127bba
-    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
     case VIR_DOMAIN_DEVICE_TPM:
127bba
     case VIR_DOMAIN_DEVICE_PANIC:
127bba
     case VIR_DOMAIN_DEVICE_IOMMU:
127bba
@@ -4017,6 +4201,59 @@ int qemuDomainDetachHostDevice(virQEMUDriverPtr driver,
127bba
         return qemuDomainDetachThisHostDevice(driver, vm, detach);
127bba
 }
127bba
 
127bba
+
127bba
+int
127bba
+qemuDomainDetachShmemDevice(virQEMUDriverPtr driver,
127bba
+                            virDomainObjPtr vm,
127bba
+                            virDomainShmemDefPtr dev)
127bba
+{
127bba
+    int ret = -1;
127bba
+    ssize_t idx = -1;
127bba
+    virDomainShmemDefPtr shmem = NULL;
127bba
+    qemuDomainObjPrivatePtr priv = vm->privateData;
127bba
+
127bba
+    if ((idx = virDomainShmemDefFind(vm->def, dev)) < 0) {
127bba
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
127bba
+                       _("device not present in domain configuration"));
127bba
+        return -1;
127bba
+    }
127bba
+
127bba
+    shmem = vm->def->shmems[idx];
127bba
+
127bba
+    switch ((virDomainShmemModel)shmem->model) {
127bba
+    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_PLAIN:
127bba
+    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM_DOORBELL:
127bba
+        break;
127bba
+
127bba
+    case VIR_DOMAIN_SHMEM_MODEL_IVSHMEM:
127bba
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
127bba
+                       _("live detach of shmem model '%s' is not supported"),
127bba
+                       virDomainShmemModelTypeToString(shmem->model));
127bba
+        /* fall-through */
127bba
+    case VIR_DOMAIN_SHMEM_MODEL_LAST:
127bba
+        return -1;
127bba
+    }
127bba
+
127bba
+    qemuDomainMarkDeviceForRemoval(vm, &shmem->info);
127bba
+    qemuDomainObjEnterMonitor(driver, vm);
127bba
+
127bba
+    ret = qemuMonitorDelDevice(priv->mon, shmem->info.alias);
127bba
+
127bba
+    if (qemuDomainObjExitMonitor(driver, vm) < 0)
127bba
+        ret = -1;
127bba
+
127bba
+    if (ret == 0) {
127bba
+        if ((ret = qemuDomainWaitForDeviceRemoval(vm)) == 1) {
127bba
+            qemuDomainReleaseDeviceAddress(vm, &shmem->info, NULL);
127bba
+            ret = qemuDomainRemoveShmemDevice(driver, vm, shmem);
127bba
+        }
127bba
+    }
127bba
+    qemuDomainResetDeviceRemoval(vm);
127bba
+
127bba
+    return ret;
127bba
+}
127bba
+
127bba
+
127bba
 int
127bba
 qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
127bba
                           virDomainObjPtr vm,
127bba
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
127bba
index b048cf4..ca54bbd 100644
127bba
--- a/src/qemu/qemu_hotplug.h
127bba
+++ b/src/qemu/qemu_hotplug.h
127bba
@@ -50,6 +50,9 @@ int qemuDomainAttachHostDevice(virConnectPtr conn,
127bba
                                virQEMUDriverPtr driver,
127bba
                                virDomainObjPtr vm,
127bba
                                virDomainHostdevDefPtr hostdev);
127bba
+int qemuDomainAttachShmemDevice(virQEMUDriverPtr driver,
127bba
+                                virDomainObjPtr vm,
127bba
+                                virDomainShmemDefPtr shmem);
127bba
 int qemuDomainFindGraphicsIndex(virDomainDefPtr def,
127bba
                                 virDomainGraphicsDefPtr dev);
127bba
 int qemuDomainAttachMemory(virQEMUDriverPtr driver,
127bba
@@ -86,6 +89,9 @@ int qemuDomainDetachNetDevice(virQEMUDriverPtr driver,
127bba
 int qemuDomainDetachHostDevice(virQEMUDriverPtr driver,
127bba
                                virDomainObjPtr vm,
127bba
                                virDomainDeviceDefPtr dev);
127bba
+int qemuDomainDetachShmemDevice(virQEMUDriverPtr driver,
127bba
+                                virDomainObjPtr vm,
127bba
+                                virDomainShmemDefPtr dev);
127bba
 int qemuDomainAttachLease(virQEMUDriverPtr driver,
127bba
                           virDomainObjPtr vm,
127bba
                           virDomainLeaseDefPtr lease);
127bba
diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c
127bba
index 07b8091..9a92855 100644
127bba
--- a/tests/qemuhotplugtest.c
127bba
+++ b/tests/qemuhotplugtest.c
127bba
@@ -73,6 +73,8 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt,
127bba
 
127bba
     virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_VIRTIO_SCSI);
127bba
     virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE);
127bba
+    virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_PLAIN);
127bba
+    virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_DOORBELL);
127bba
     if (event)
127bba
         virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT);
127bba
 
127bba
@@ -118,6 +120,9 @@ testQemuHotplugAttach(virDomainObjPtr vm,
127bba
     case VIR_DOMAIN_DEVICE_CHR:
127bba
         ret = qemuDomainAttachChrDevice(&driver, vm, dev->data.chr);
127bba
         break;
127bba
+    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
+        ret = qemuDomainAttachShmemDevice(&driver, vm, dev->data.shmem);
127bba
+        break;
127bba
     default:
127bba
         VIR_TEST_VERBOSE("device type '%s' cannot be attached\n",
127bba
                 virDomainDeviceTypeToString(dev->type));
127bba
@@ -140,6 +145,9 @@ testQemuHotplugDetach(virDomainObjPtr vm,
127bba
     case VIR_DOMAIN_DEVICE_CHR:
127bba
         ret = qemuDomainDetachChrDevice(&driver, vm, dev->data.chr);
127bba
         break;
127bba
+    case VIR_DOMAIN_DEVICE_SHMEM:
127bba
+        ret = qemuDomainDetachShmemDevice(&driver, vm, dev->data.shmem);
127bba
+        break;
127bba
     default:
127bba
         VIR_TEST_VERBOSE("device type '%s' cannot be detached\n",
127bba
                 virDomainDeviceTypeToString(dev->type));
127bba
@@ -602,6 +610,19 @@ mymain(void)
127bba
                    "device_del", QMP_OK,
127bba
                    "chardev-remove", QMP_OK);
127bba
 
127bba
+    DO_TEST_ATTACH("hotplug-base-live", "ivshmem-plain", false, true,
127bba
+                   "object-add", QMP_OK,
127bba
+                   "device_add", QMP_OK);
127bba
+    DO_TEST_ATTACH("hotplug-base-live", "ivshmem-doorbell", false, true,
127bba
+                   "chardev-add", QMP_OK,
127bba
+                   "device_add", QMP_OK);
127bba
+    DO_TEST_DETACH("hotplug-base-live+ivshmem-plain", "ivshmem-doorbell-detach", false, true,
127bba
+                   "device_del", QMP_OK,
127bba
+                   "chardev-remove", QMP_OK);
127bba
+    DO_TEST_DETACH("hotplug-base-live", "ivshmem-plain-detach", false, false,
127bba
+                   "device_del", QMP_OK,
127bba
+                   "object-del", QMP_OK);
127bba
+
127bba
     qemuTestDriverFree(&driver);
127bba
     return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
127bba
 }
127bba
diff --git a/tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-doorbell.xml b/tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-doorbell.xml
127bba
new file mode 100644
127bba
index 0000000..8d09fee
127bba
--- /dev/null
127bba
+++ b/tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-doorbell.xml
127bba
@@ -0,0 +1,65 @@
127bba
+<domain type='kvm' id='7'>
127bba
+  <name>hotplug</name>
127bba
+  <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid>
127bba
+  <memory unit='KiB'>4194304</memory>
127bba
+  <currentMemory unit='KiB'>4194304</currentMemory>
127bba
+  <vcpu placement='static'>4</vcpu>
127bba
+  <os>
127bba
+    <type arch='x86_64' machine='pc'>hvm</type>
127bba
+    <boot dev='hd'/>
127bba
+  </os>
127bba
+  <features>
127bba
+    <acpi/>
127bba
+    <apic/>
127bba
+    <pae/>
127bba
+  </features>
127bba
+  <clock offset='utc'/>
127bba
+  <on_poweroff>destroy</on_poweroff>
127bba
+  <on_reboot>restart</on_reboot>
127bba
+  <on_crash>restart</on_crash>
127bba
+  <devices>
127bba
+    <emulator>/usr/libexec/qemu-kvm</emulator>
127bba
+    <controller type='usb' index='0'>
127bba
+      <alias name='usb'/>
127bba
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
127bba
+    </controller>
127bba
+    <controller type='ide' index='0'>
127bba
+      <alias name='ide'/>
127bba
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
127bba
+    </controller>
127bba
+    <controller type='scsi' index='0' model='virtio-scsi'>
127bba
+      <alias name='scsi0'/>
127bba
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
127bba
+    </controller>
127bba
+    <controller type='pci' index='0' model='pci-root'>
127bba
+      <alias name='pci'/>
127bba
+    </controller>
127bba
+    <controller type='virtio-serial' index='0'>
127bba
+      <alias name='virtio-serial0'/>
127bba
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
127bba
+    </controller>
127bba
+    <input type='mouse' bus='ps2'>
127bba
+      <alias name='input0'/>
127bba
+    </input>
127bba
+    <input type='keyboard' bus='ps2'>
127bba
+      <alias name='input1'/>
127bba
+    </input>
127bba
+    <memballoon model='none'>
127bba
+      <alias name='balloon0'/>
127bba
+    </memballoon>
127bba
+    <shmem name='shmem0'>
127bba
+      <model type='ivshmem-plain'/>
127bba
+      <size unit='M'>4</size>
127bba
+      <alias name='shmem0'/>
127bba
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
127bba
+    </shmem>
127bba
+    <shmem name='shmem1'>
127bba
+      <model type='ivshmem-doorbell'/>
127bba
+      <server path='/var/lib/libvirt/shmem-shmem1-sock'/>
127bba
+      <msi ioeventfd='on'/>
127bba
+      <alias name='shmem1'/>
127bba
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
127bba
+    </shmem>
127bba
+  </devices>
127bba
+  <seclabel type='none' model='none'/>
127bba
+</domain>
127bba
diff --git a/tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-plain-detach.xml b/tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-plain-detach.xml
127bba
new file mode 120000
127bba
index 0000000..d5e2051
127bba
--- /dev/null
127bba
+++ b/tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-plain-detach.xml
127bba
@@ -0,0 +1 @@
127bba
+../qemuxml2argvdata/qemuxml2argv-hotplug-base-live.xml
127bba
\ No newline at end of file
127bba
diff --git a/tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-plain.xml b/tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-plain.xml
127bba
new file mode 120000
127bba
index 0000000..cf27c10
127bba
--- /dev/null
127bba
+++ b/tests/qemuhotplugtestdata/qemuhotplug-hotplug-base-live+ivshmem-plain.xml
127bba
@@ -0,0 +1 @@
127bba
+../qemuxml2argvdata/qemuxml2argv-hotplug-base-live+ivshmem-plain.xml
127bba
\ No newline at end of file
127bba
diff --git a/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-doorbell-detach.xml b/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-doorbell-detach.xml
127bba
new file mode 100644
127bba
index 0000000..7c06696
127bba
--- /dev/null
127bba
+++ b/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-doorbell-detach.xml
127bba
@@ -0,0 +1,7 @@
127bba
+<shmem name='shmem1'>
127bba
+  <model type='ivshmem-doorbell'/>
127bba
+  <server path='/var/lib/libvirt/shmem-shmem1-sock'/>
127bba
+  <msi ioeventfd='on'/>
127bba
+  <alias name='shmem1'/>
127bba
+  <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
127bba
+</shmem>
127bba
diff --git a/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-doorbell.xml b/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-doorbell.xml
127bba
new file mode 100644
127bba
index 0000000..06cb0c9
127bba
--- /dev/null
127bba
+++ b/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-doorbell.xml
127bba
@@ -0,0 +1,4 @@
127bba
+<shmem name='shmem1'>
127bba
+  <model type='ivshmem-doorbell'/>
127bba
+  <server/>
127bba
+</shmem>
127bba
diff --git a/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-plain-detach.xml b/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-plain-detach.xml
127bba
new file mode 100644
127bba
index 0000000..68f592f
127bba
--- /dev/null
127bba
+++ b/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-plain-detach.xml
127bba
@@ -0,0 +1,6 @@
127bba
+<shmem name='shmem0'>
127bba
+  <model type='ivshmem-plain'/>
127bba
+  <size unit='M'>4</size>
127bba
+  <alias name='shmem0'/>
127bba
+  <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
127bba
+</shmem>
127bba
diff --git a/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-plain.xml b/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-plain.xml
127bba
new file mode 100644
127bba
index 0000000..6bd96ff
127bba
--- /dev/null
127bba
+++ b/tests/qemuhotplugtestdata/qemuhotplug-ivshmem-plain.xml
127bba
@@ -0,0 +1,3 @@
127bba
+<shmem name='shmem0'>
127bba
+  <model type='ivshmem-plain'/>
127bba
+</shmem>
127bba
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hotplug-base-live+ivshmem-plain.xml b/tests/qemuxml2argvdata/qemuxml2argv-hotplug-base-live+ivshmem-plain.xml
127bba
new file mode 100644
127bba
index 0000000..ac3fa4f
127bba
--- /dev/null
127bba
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hotplug-base-live+ivshmem-plain.xml
127bba
@@ -0,0 +1,58 @@
127bba
+<domain type='kvm' id='7'>
127bba
+  <name>hotplug</name>
127bba
+  <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid>
127bba
+  <memory unit='KiB'>4194304</memory>
127bba
+  <currentMemory unit='KiB'>4194304</currentMemory>
127bba
+  <vcpu placement='static'>4</vcpu>
127bba
+  <os>
127bba
+    <type arch='x86_64' machine='pc'>hvm</type>
127bba
+    <boot dev='hd'/>
127bba
+  </os>
127bba
+  <features>
127bba
+    <acpi/>
127bba
+    <apic/>
127bba
+    <pae/>
127bba
+  </features>
127bba
+  <clock offset='utc'/>
127bba
+  <on_poweroff>destroy</on_poweroff>
127bba
+  <on_reboot>restart</on_reboot>
127bba
+  <on_crash>restart</on_crash>
127bba
+  <devices>
127bba
+    <emulator>/usr/libexec/qemu-kvm</emulator>
127bba
+    <controller type='usb' index='0'>
127bba
+      <alias name='usb'/>
127bba
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
127bba
+    </controller>
127bba
+    <controller type='ide' index='0'>
127bba
+      <alias name='ide'/>
127bba
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
127bba
+    </controller>
127bba
+    <controller type='scsi' index='0' model='virtio-scsi'>
127bba
+      <alias name='scsi0'/>
127bba
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
127bba
+    </controller>
127bba
+    <controller type='pci' index='0' model='pci-root'>
127bba
+      <alias name='pci'/>
127bba
+    </controller>
127bba
+    <controller type='virtio-serial' index='0'>
127bba
+      <alias name='virtio-serial0'/>
127bba
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
127bba
+    </controller>
127bba
+    <input type='mouse' bus='ps2'>
127bba
+      <alias name='input0'/>
127bba
+    </input>
127bba
+    <input type='keyboard' bus='ps2'>
127bba
+      <alias name='input1'/>
127bba
+    </input>
127bba
+    <memballoon model='none'>
127bba
+      <alias name='balloon0'/>
127bba
+    </memballoon>
127bba
+    <shmem name='shmem0'>
127bba
+      <model type='ivshmem-plain'/>
127bba
+      <size unit='M'>4</size>
127bba
+      <alias name='shmem0'/>
127bba
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
127bba
+    </shmem>
127bba
+  </devices>
127bba
+  <seclabel type='none' model='none'/>
127bba
+</domain>
127bba
-- 
127bba
2.10.2
127bba