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@xxxxxxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list