[libvirt] [PATCH 2/3] conf: add memdev device in <devices> XML

Chen Fan chen.fan.fnst at cn.fujitsu.com
Wed Jun 25 06:42:31 UTC 2014


Since qemu has supported memory-backend-ram and memory-backend-file object,
so we should add a new 'memdev' device type in <devices> XML to introduce the
memory element, Its definition like the following:

  <memdev type='ram' merge='yes' dump='yes' prealloc='yes'>
    <name>ram0</name>
    <capacity unit='MiB'>1000</capacity>
    <source host-nodes='0-1' policy='bind' />
  </memdev>

then we enable to support -numa memdev=ram0 command line for binding guest
numa nodes to host numa nodes.

Signed-off-by: Chen Fan <chen.fan.fnst at cn.fujitsu.com>
---
 src/conf/domain_conf.c       | 203 ++++++++++++++++++++++++++++++++++++++++++-
 src/conf/domain_conf.h       |  42 +++++++++
 src/libvirt_private.syms     |   4 +
 src/qemu/qemu_capabilities.c |   4 +
 src/qemu/qemu_capabilities.h |   2 +
 src/qemu/qemu_command.c      |  74 ++++++++++++++++
 src/qemu/qemu_command.h      |   4 +
 src/qemu/qemu_hotplug.c      |   1 +
 8 files changed, 333 insertions(+), 1 deletion(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index be81dbe..c55bf47 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -204,7 +204,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
               "chr",
               "memballoon",
               "nvram",
-              "rng")
+              "rng",
+              "memdev")
 
 VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
               "none",
@@ -454,6 +455,16 @@ VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
               "xen",
               "none")
 
+VIR_ENUM_IMPL(virDomainMemDev, VIR_DOMAIN_MEMDEV_LAST,
+              "ram",
+              "file")
+
+VIR_ENUM_IMPL(virDomainHostNodePolicy, VIR_DOMAIN_HOST_NODE_POLICY_LAST,
+              "default",
+              "preferred",
+              "bind",
+              "interleave")
+
 VIR_ENUM_IMPL(virDomainSmbiosMode, VIR_DOMAIN_SMBIOS_LAST,
               "none",
               "emulate",
@@ -770,6 +781,10 @@ static void virDomainObjDispose(void *obj);
 static void virDomainObjListDispose(void *obj);
 static void virDomainXMLOptionClassDispose(void *obj);
 
+static int
+virDomainParseMemory(const char *xpath, xmlXPathContextPtr ctxt,
+                     unsigned long long *mem, bool required);
+
 static int virDomainObjOnceInit(void)
 {
     if (!(virDomainObjClass = virClassNew(virClassForObjectLockable(),
@@ -1661,6 +1676,18 @@ void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
     VIR_FREE(def);
 }
 
+void virDomainMemDevDefFree(virDomainMemDevDefPtr def)
+{
+    if (!def)
+        return;
+
+    VIR_FREE(def->name);
+    VIR_FREE(def->mempath);
+    VIR_FREE(def->hostnodes);
+    VIR_FREE(def);
+}
+
+
 void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def)
 {
     if (!def)
@@ -1864,6 +1891,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
     case VIR_DOMAIN_DEVICE_NVRAM:
         virDomainNVRAMDefFree(def->data.nvram);
         break;
+    case VIR_DOMAIN_DEVICE_MEMDEV:
+        virDomainMemDevDefFree(def->data.memdev);
+        break;
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_NONE:
         break;
@@ -2543,6 +2573,7 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
     /* The following devices do not contain virDomainDeviceInfo */
     case VIR_DOMAIN_DEVICE_LEASE:
     case VIR_DOMAIN_DEVICE_GRAPHICS:
+    case VIR_DOMAIN_DEVICE_MEMDEV:
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_NONE:
         break;
@@ -2780,6 +2811,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
     case VIR_DOMAIN_DEVICE_NVRAM:
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_RNG:
+    case VIR_DOMAIN_DEVICE_MEMDEV:
         break;
     }
 
@@ -9192,6 +9224,104 @@ virDomainMemballoonDefParseXML(xmlNodePtr node,
     goto cleanup;
 }
 
+static virDomainMemDevDefPtr
+virDomainMemDevDefParseXML(xmlNodePtr node,
+                           xmlXPathContextPtr ctxt)
+{
+    char *type;
+    virDomainMemDevDefPtr def;
+    xmlNodePtr save = ctxt->node;
+    char *tmp = NULL;
+    char *policy = NULL;
+
+    if (VIR_ALLOC(def) < 0)
+        return NULL;
+
+    type = virXMLPropString(node, "type");
+    if (type == NULL) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("memory device must contain a type name"));
+        goto error;
+    }
+
+    if ((def->type = virDomainMemDevTypeFromString(type)) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("unknown memory device type '%s'"), type);
+        goto error;
+    }
+
+    if ((tmp = virXMLPropString(node, "merge")) != NULL) {
+        if (STREQ(tmp, "yes"))
+            def->merge = true;
+        VIR_FREE(tmp);
+    }
+
+    if ((tmp = virXMLPropString(node, "dump")) != NULL) {
+        if (STREQ(tmp, "yes"))
+            def->dump = true;
+        VIR_FREE(tmp);
+    }
+
+    if ((tmp = virXMLPropString(node, "prealloc")) != NULL) {
+        if (STREQ(tmp, "yes"))
+            def->prealloc = true;
+        VIR_FREE(tmp);
+    }
+
+    ctxt->node = node;
+
+    def->name = virXPathString("string(./name)", ctxt);
+    if (!def->name) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("Missing memory device name element"));
+        goto error;
+    }
+
+    /* Extract memory capacity */
+    if (virDomainParseMemory("./capacity", ctxt,
+                             &def->capacity, true) < 0)
+        goto error;
+
+    def->mempath = virXPathString("string(./source/@mem-path)", ctxt);
+    if (def->type == VIR_DOMAIN_MEMDEV_FILE && !def->mempath) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("The mem-path element must be specified when "
+                         "memory device type is 'file'"));
+        goto error;
+    }
+
+    if (def->type == VIR_DOMAIN_MEMDEV_RAM && def->mempath) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("The mem-path element should be not specified when "
+                         "memory device type is 'ram'"));
+        goto error;
+    }
+
+    def->hostnodes = virXPathString("string(./source/@host-nodes)", ctxt);
+
+    policy = virXPathString("string(./source/@policy)", ctxt);
+    if (policy != NULL) {
+        if ((def->policy = virDomainHostNodePolicyTypeFromString(policy)) < 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("unknown host node policy: '%s'"), policy);
+            goto error;
+        }
+    }
+
+cleanup:
+    VIR_FREE(type);
+    VIR_FREE(policy);
+    ctxt->node = save;
+
+    return def;
+
+ error:
+    virDomainMemDevDefFree(def);
+    def = NULL;
+    goto cleanup;
+}
+
+
 static virDomainNVRAMDefPtr
 virDomainNVRAMDefParseXML(xmlNodePtr node,
                           unsigned int flags)
@@ -10067,6 +10197,10 @@ virDomainDeviceDefParse(const char *xmlStr,
         if (!(dev->data.nvram = virDomainNVRAMDefParseXML(node, flags)))
             goto error;
         break;
+    case VIR_DOMAIN_DEVICE_MEMDEV:
+        if (!(dev->data.memdev = virDomainMemDevDefParseXML(node, ctxt)))
+            goto error;
+        break;
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_LAST:
         break;
@@ -12752,6 +12886,24 @@ virDomainDefParseXML(xmlDocPtr xml,
     }
     VIR_FREE(nodes);
 
+    /* analysis of the memory devices */
+    if ((n = virXPathNodeSet("./devices/memdev", ctxt, &nodes)) < 0) {
+        goto error;
+    }
+
+    if (n && VIR_ALLOC_N(def->memdevs, n) < 0)
+        goto error;
+
+     for (i = 0; i < n; i++) {
+         virDomainMemDevDefPtr memdev = virDomainMemDevDefParseXML(nodes[i], ctxt);
+         if (!memdev)
+             goto error;
+
+         def->memdevs[def->nmemdevs++] = memdev;
+     }
+     VIR_FREE(nodes);
+
+
     /* Parse the TPM devices */
     if ((n = virXPathNodeSet("./devices/tpm", ctxt, &nodes)) < 0)
         goto error;
@@ -16262,6 +16414,50 @@ virDomainTPMDefFormat(virBufferPtr buf,
     return 0;
 }
 
+static int
+virDomainMemDevDefFormat(virBufferPtr buf,
+                         virDomainMemDevDefPtr def)
+{
+    const char *type = virDomainMemDevTypeToString(def->type);
+
+    if (!type) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unexpected memdev type %d"), def->type);
+        return -1;
+    }
+
+    virBufferAsprintf(buf, "<memdev type='%s'", type);
+    if (def->merge)
+        virBufferAddLit(buf, " merge='yes'");
+    if (def->dump)
+        virBufferAddLit(buf, " dump='yes'");
+    if (def->prealloc)
+        virBufferAddLit(buf, " prealloc='yes'");
+    virBufferAddLit(buf, ">\n");
+
+    virBufferAdjustIndent(buf, 2);
+
+    virBufferAsprintf(buf, "<name>%s</name>\n", def->name);
+    virBufferAsprintf(buf, "<capacity unit='KiB'>%llu</capacity>\n",
+                      def->capacity);
+
+    if (def->type == VIR_DOMAIN_MEMDEV_FILE || def->hostnodes || def->policy) {
+        virBufferAddLit(buf, "<source");
+        if (def->type == VIR_DOMAIN_MEMDEV_FILE)
+            virBufferAsprintf(buf, " mem-path='%s'", def->mempath);
+        if (def->hostnodes)
+            virBufferAsprintf(buf, " host-nodes='%s'", def->hostnodes);
+        if (def->policy)
+            virBufferAsprintf(buf, " policy='%s'",
+                              virDomainHostNodePolicyTypeToString(def->policy));
+        virBufferAddLit(buf, "/>\n");
+    }
+
+    virBufferAdjustIndent(buf, -2);
+    virBufferAddLit(buf, "</memdev>\n");
+
+    return 0;
+}
 
 static int
 virDomainSoundDefFormat(virBufferPtr buf,
@@ -17916,6 +18112,10 @@ virDomainDefFormatInternal(virDomainDefPtr def,
     if (def->memballoon)
         virDomainMemballoonDefFormat(buf, def->memballoon, flags);
 
+    for (n = 0; n < def->nmemdevs; n++)
+        if (virDomainMemDevDefFormat(buf, def->memdevs[n]) < 0)
+           goto error;
+
     if (def->rng)
         virDomainRNGDefFormat(buf, def->rng, flags);
 
@@ -19291,6 +19491,7 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_SMARTCARD:
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
+    case VIR_DOMAIN_DEVICE_MEMDEV:
     case VIR_DOMAIN_DEVICE_NVRAM:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_INTERNAL_ERROR,
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a6ac95a..33e57bc 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -109,6 +109,9 @@ typedef virDomainChrDef *virDomainChrDefPtr;
 typedef struct _virDomainMemballoonDef virDomainMemballoonDef;
 typedef virDomainMemballoonDef *virDomainMemballoonDefPtr;
 
+typedef struct _virDomainMemDevDef virDomainMemDevDef;
+typedef virDomainMemDevDef *virDomainMemDevDefPtr;
+
 typedef struct _virDomainNVRAMDef virDomainNVRAMDef;
 typedef virDomainNVRAMDef *virDomainNVRAMDefPtr;
 
@@ -151,6 +154,7 @@ typedef enum {
     VIR_DOMAIN_DEVICE_MEMBALLOON,
     VIR_DOMAIN_DEVICE_NVRAM,
     VIR_DOMAIN_DEVICE_RNG,
+    VIR_DOMAIN_DEVICE_MEMDEV,
 
     VIR_DOMAIN_DEVICE_LAST
 } virDomainDeviceType;
@@ -178,6 +182,7 @@ struct _virDomainDeviceDef {
         virDomainMemballoonDefPtr memballoon;
         virDomainNVRAMDefPtr nvram;
         virDomainRNGDefPtr rng;
+        virDomainMemDevDefPtr memdev;
     } data;
 };
 
@@ -1487,6 +1492,37 @@ struct _virDomainNVRAMDef {
     virDomainDeviceInfo info;
 };
 
+enum {
+    VIR_DOMAIN_MEMDEV_RAM,
+    VIR_DOMAIN_MEMDEV_FILE,
+
+    VIR_DOMAIN_MEMDEV_LAST
+};
+
+struct _virDomainMemDevDef {
+    char *name;
+    int type;
+
+    unsigned long long capacity; /* bytes */
+
+    bool merge;
+    bool dump;
+    bool prealloc;
+
+    char *mempath;
+    char *hostnodes;
+    int policy;
+};
+
+enum {
+    VIR_DOMAIN_HOST_NODE_POLICY_DEFAULT = 0,
+    VIR_DOMAIN_HOST_NODE_POLICY_PREFERRED,
+    VIR_DOMAIN_HOST_NODE_POLICY_BIND,
+    VIR_DOMAIN_HOST_NODE_POLICY_INTERLEAVE,
+
+    VIR_DOMAIN_HOST_NODE_POLICY_LAST
+};
+
 typedef enum {
     VIR_DOMAIN_SMBIOS_NONE = 0,
     VIR_DOMAIN_SMBIOS_EMULATE,
@@ -1970,6 +2006,9 @@ struct _virDomainDef {
     size_t nseclabels;
     virSecurityLabelDefPtr *seclabels;
 
+    size_t nmemdevs;
+    virDomainMemDevDefPtr *memdevs;
+
     /* Only 1 */
     virDomainWatchdogDefPtr watchdog;
     virDomainMemballoonDefPtr memballoon;
@@ -2159,6 +2198,7 @@ int virDomainChrSourceDefCopy(virDomainChrSourceDefPtr src,
 void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def);
 void virDomainSoundDefFree(virDomainSoundDefPtr def);
 void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def);
+void virDomainMemDevDefFree(virDomainMemDevDefPtr def);
 void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def);
 void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def);
 void virDomainVideoDefFree(virDomainVideoDefPtr def);
@@ -2575,6 +2615,8 @@ VIR_ENUM_DECL(virDomainSoundCodec)
 VIR_ENUM_DECL(virDomainSoundModel)
 VIR_ENUM_DECL(virDomainMemDump)
 VIR_ENUM_DECL(virDomainMemballoonModel)
+VIR_ENUM_DECL(virDomainMemDev)
+VIR_ENUM_DECL(virDomainHostNodePolicy)
 VIR_ENUM_DECL(virDomainSmbiosMode)
 VIR_ENUM_DECL(virDomainWatchdogModel)
 VIR_ENUM_DECL(virDomainWatchdogAction)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 122c572..06d6d7f 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -293,6 +293,8 @@ virDomainHostdevModeTypeToString;
 virDomainHostdevRemove;
 virDomainHostdevSubsysPCIBackendTypeToString;
 virDomainHostdevSubsysTypeToString;
+virDomainHostNodePolicyTypeFromString;
+virDomainHostNodePolicyTypeToString;
 virDomainHubTypeFromString;
 virDomainHubTypeToString;
 virDomainHypervTypeFromString;
@@ -316,6 +318,8 @@ virDomainLockFailureTypeFromString;
 virDomainLockFailureTypeToString;
 virDomainMemballoonModelTypeFromString;
 virDomainMemballoonModelTypeToString;
+virDomainMemDevTypeFromString;
+virDomainMemDevTypeToString;
 virDomainMemDumpTypeFromString;
 virDomainMemDumpTypeToString;
 virDomainNetDefFormat;
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 08c3d04..718da2b 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -256,6 +256,8 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
               "usb-kbd", /* 165 */
               "host-pci-multidomain",
               "msg-timestamp",
+              "memory-backend-ram",
+              "memory-backend-file",
     );
 
 
@@ -1440,6 +1442,8 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = {
     { "ich9-intel-hda", QEMU_CAPS_DEVICE_ICH9_INTEL_HDA },
     { "pvpanic", QEMU_CAPS_DEVICE_PANIC },
     { "usb-kbd", QEMU_CAPS_DEVICE_USB_KBD },
+    { "memory-backend-ram", QEMU_CAPS_MEMORY_BACKEND_RAM },
+    { "memory-backend-file", QEMU_CAPS_MEMORY_BACKEND_FILE },
 };
 
 static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsVirtioBlk[] = {
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index d755caa..53171be 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -206,6 +206,8 @@ enum virQEMUCapsFlags {
     QEMU_CAPS_DEVICE_USB_KBD     = 165, /* -device usb-kbd */
     QEMU_CAPS_HOST_PCI_MULTIDOMAIN = 166, /* support domain > 0 in host pci address */
     QEMU_CAPS_MSG_TIMESTAMP      = 167, /* -msg timestamp */
+    QEMU_CAPS_MEMORY_BACKEND_RAM = 168,  /* -object memory-backend-ram */
+    QEMU_CAPS_MEMORY_BACKEND_FILE = 169, /* -object memory-backend-file */
 
     QEMU_CAPS_LAST,                   /* this must always be the last item */
 };
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index b351f60..25a6e00 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4743,6 +4743,71 @@ qemuBuildNVRAMDevStr(virDomainNVRAMDefPtr dev)
 }
 
 char *
+qemuBuildMemObjectStr(virDomainMemDevDefPtr dev,
+                      virQEMUCapsPtr qemuCaps)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    switch (dev->type) {
+        case VIR_DOMAIN_MEMDEV_RAM:
+            if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MEMORY_BACKEND_RAM)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("The object memory-backend-ram "
+                                 "is not supported in this QEMU binary"));
+                goto error;
+            }
+            virBufferAddLit(&buf, "memory-backend-ram");
+            break;
+        case VIR_DOMAIN_MEMDEV_FILE:
+            if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_MEMORY_BACKEND_FILE)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("The object memory-backend-file "
+                                 "is not supported in this QEMU binary"));
+                goto error;
+            }
+            virBufferAddLit(&buf, "memory-backend-file");
+            break;
+        default:
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("memdev unsupported with type '%s'"),
+                           virDomainMemDevTypeToString(dev->type));
+            goto error;
+    }
+    virBufferAsprintf(&buf, ",id=%s", dev->name);
+    dev->capacity = VIR_DIV_UP(dev->capacity, 1024) * 1024;
+    virBufferAsprintf(&buf, ",size=%lluK", dev->capacity);
+
+    if (dev->merge)
+        virBufferAddLit(&buf, ",merge=yes");
+    if (dev->dump)
+        virBufferAddLit(&buf, ",dump=yes");
+    if (dev->prealloc)
+        virBufferAddLit(&buf, ",prealloc=yes");
+
+    if (dev->type == VIR_DOMAIN_MEMDEV_FILE && dev->mempath)
+        virBufferAsprintf(&buf, ",mem-path=%s", dev->mempath);
+
+    if (dev->hostnodes)
+        virBufferAsprintf(&buf, ",host-nodes=%s", dev->hostnodes);
+
+    if (dev->policy)
+        virBufferAsprintf(&buf, ",policy=%s",
+                          virDomainHostNodePolicyTypeToString(dev->policy));
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+   virBufferFreeAndReset(&buf);
+   return NULL;
+}
+
+
+char *
 qemuBuildUSBInputDevStr(virDomainDefPtr def,
                         virDomainInputDefPtr dev,
                         virQEMUCapsPtr qemuCaps)
@@ -7394,6 +7459,15 @@ qemuBuildCommandLine(virConnectPtr conn,
     }
     mlock = def->mem.locked;
 
+   for (i = 0; i < def->nmemdevs; i++) {
+       char *objectstr;
+       virDomainMemDevDefPtr memptr = def->memdevs[i];
+
+       if (!(objectstr = qemuBuildMemObjectStr(memptr, qemuCaps)))
+           goto error;
+       virCommandAddArgList(cmd, "-object", objectstr, NULL);
+    }
+
     virCommandAddArg(cmd, "-smp");
     if (!(smp = qemuBuildSmpArgStr(def, qemuCaps)))
         goto error;
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index afbd6ff..72f4e77 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -274,4 +274,8 @@ qemuParseKeywords(const char *str,
 int qemuGetDriveSourceString(virStorageSourcePtr src,
                              virConnectPtr conn,
                              char **source);
+
+char *
+qemuBuildMemObjectStr(virDomainMemDevDefPtr dev,
+                      virQEMUCapsPtr qemuCaps);
 #endif /* __QEMU_COMMAND_H__*/
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 7289055..c9f4df9 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -2818,6 +2818,7 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
     case VIR_DOMAIN_DEVICE_MEMBALLOON:
     case VIR_DOMAIN_DEVICE_NVRAM:
     case VIR_DOMAIN_DEVICE_RNG:
+    case VIR_DOMAIN_DEVICE_MEMDEV:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("don't know how to remove a %s device"),
-- 
1.9.3




More information about the libvir-list mailing list