On 01/30/2015 08:21 AM, Peter Krempa wrote: > WIP: TODO: docs > > Also forbid the new device in post parse callback in all driver that > implement the callback to warn users right away that the device is not > supported with their hypervisor. > --- > docs/schemas/domaincommon.rng | 50 ++++ > src/bhyve/bhyve_domain.c | 5 +- > src/conf/domain_conf.c | 317 ++++++++++++++++++++- > src/conf/domain_conf.h | 33 +++ > src/libvirt_private.syms | 2 + > src/libxl/libxl_domain.c | 3 + > src/lxc/lxc_domain.c | 4 + > src/openvz/openvz_driver.c | 3 + > src/qemu/qemu_domain.c | 3 + > src/qemu/qemu_driver.c | 13 + > src/qemu/qemu_hotplug.c | 3 + > src/uml/uml_driver.c | 3 + > src/xen/xen_driver.c | 3 + > src/xenapi/xenapi_driver.c | 3 + > .../qemuxml2argv-memory-hotplug-dimm.xml | 47 +++ > 15 files changed, 490 insertions(+), 2 deletions(-) > create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.xml > <...snip...> > diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c > index 0b9fb06..298b574 100644 > --- a/src/conf/domain_conf.c > +++ b/src/conf/domain_conf.c > @@ -236,7 +236,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST, > "rng", > "shmem", > "tpm", > - "panic") > + "panic", > + "memory") > > VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST, > "none", > @@ -779,6 +780,12 @@ VIR_ENUM_DECL(virDomainBlockJob) > VIR_ENUM_IMPL(virDomainBlockJob, VIR_DOMAIN_BLOCK_JOB_TYPE_LAST, > "", "", "copy", "", "active-commit") > > +VIR_ENUM_IMPL(virDomainMemoryModel, VIR_DOMAIN_MEMORY_MODEL_LAST, > + "", "acpi-dimm") > + > +#define VIR_DOMAIN_XML_WRITE_FLAGS VIR_DOMAIN_XML_SECURE > +#define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE > + > static virClassPtr virDomainObjClass; > static virClassPtr virDomainObjListClass; > static virClassPtr virDomainXMLOptionClass; > @@ -1003,6 +1010,27 @@ virDomainDefCheckUnsupportedMemoryHotplug(virDomainDefPtr def) > } > > > +/** > + * virDomainDeviceDefCheckUnsupportedMemoryDevice: > + * @dev: device definition > + * > + * Returns -1 if the device definition describes a memory device and reports an > + * error. Otherwise returns 0. > + */ > +int > +virDomainDeviceDefCheckUnsupportedMemoryDevice(virDomainDeviceDefPtr dev) > +{ > + /* This driver doesn't yet know how to handle memory devices */ > + if (dev->type == VIR_DOMAIN_DEVICE_MEMORY) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", > + _("memory devices are not supported by this driver")); > + return -1; > + } > + > + return 0; > +} > + > + > static void > virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED) > { > @@ -1934,6 +1962,15 @@ void virDomainRedirFilterDefFree(virDomainRedirFilterDefPtr def) > VIR_FREE(def); > } > > +void virDomainMemoryDefFree(virDomainMemoryDefPtr def) > +{ > + if (!def) > + return; > + > + virDomainDeviceInfoClear(&def->info); > + VIR_FREE(def); > +} > + > void virDomainDeviceDefFree(virDomainDeviceDefPtr def) > { > if (!def) > @@ -2003,6 +2040,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) > case VIR_DOMAIN_DEVICE_PANIC: > virDomainPanicDefFree(def->data.panic); > break; > + case VIR_DOMAIN_DEVICE_MEMORY: > + virDomainMemoryDefFree(def->data.memory); > + break; > case VIR_DOMAIN_DEVICE_LAST: > case VIR_DOMAIN_DEVICE_NONE: > break; > @@ -2200,6 +2240,10 @@ void virDomainDefFree(virDomainDefPtr def) > virDomainRNGDefFree(def->rngs[i]); > VIR_FREE(def->rngs); > > + for (i = 0; i < def->nmems; i++) > + virDomainMemoryDefFree(def->mems[i]); > + VIR_FREE(def->mems); > + > virDomainTPMDefFree(def->tpm); > > virDomainPanicDefFree(def->panic); > @@ -2709,6 +2753,8 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device) > return &device->data.tpm->info; > case VIR_DOMAIN_DEVICE_PANIC: > return &device->data.panic->info; > + case VIR_DOMAIN_DEVICE_MEMORY: > + return &device->data.memory->info; > > /* The following devices do not contain virDomainDeviceInfo */ > case VIR_DOMAIN_DEVICE_LEASE: > @@ -2940,6 +2986,13 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def, > return -1; > } > > + device.type = VIR_DOMAIN_DEVICE_MEMORY; > + for (i = 0; i < def->nmems; i++) { > + device.data.memory = def->mems[i]; > + if (cb(def, &device, &def->mems[i]->info, opaque) < 0) > + return -1; > + } > + > /* Coverity is not very happy with this - all dead_error_condition */ > #if !STATIC_ANALYSIS > /* This switch statement is here to trigger compiler warning when adding > @@ -2972,6 +3025,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def, > case VIR_DOMAIN_DEVICE_PANIC: > case VIR_DOMAIN_DEVICE_LAST: > case VIR_DOMAIN_DEVICE_RNG: > + case VIR_DOMAIN_DEVICE_MEMORY: > break; > } > #endif > @@ -11109,6 +11163,119 @@ virDomainPMStateParseXML(xmlXPathContextPtr ctxt, > return ret; > } > > + > +static int > +virDomainMemorySourceDefParseXML(xmlNodePtr node, > + xmlXPathContextPtr ctxt, > + virDomainMemoryDefPtr def) > +{ > + int ret = -1; > + char *nodemask = NULL; > + xmlNodePtr save = ctxt->node; > + ctxt->node = node; > + > + if (virDomainParseMemory("./pagesize", "./pagesize/@unit", ctxt, > + &def->pagesize, false, false) < 0) > + goto cleanup; > + > + if ((nodemask = virXPathString("string(./nodemask)", ctxt))) { > + if (virBitmapParse(nodemask, 0, &def->sourceNodes, > + VIR_DOMAIN_CPUMASK_LEN) < 0) > + goto cleanup; > + } > + > + ret = 0; > + > + cleanup: > + VIR_FREE(nodemask); > + ctxt->node = save; > + return ret; > +} > + > + > +static int > +virDomainMemoryTargetDefParseXML(xmlNodePtr node, > + xmlXPathContextPtr ctxt, > + virDomainMemoryDefPtr def) > +{ > + int ret = -1; > + xmlNodePtr save = ctxt->node; > + ctxt->node = node; > + > + if (virXPathInt("string(./node)", ctxt, &def->targetNode) < 0) { > + virReportError(VIR_ERR_XML_ERROR, "%s", > + _("invalid or missing value of memory device node")); > + goto cleanup; > + } > + > + if (virDomainParseMemory("./size", "./size/@unit", ctxt, > + &def->size, true, false) < 0) > + goto cleanup; > + > + ret = 0; > + > + cleanup: > + ctxt->node = save; > + return ret; > +} > + > + > +static virDomainMemoryDefPtr > +virDomainMemoryDefParseXML(xmlNodePtr memdevNode, > + xmlXPathContextPtr ctxt, > + unsigned int flags) > +{ > + char *tmp = NULL; > + xmlNodePtr save = ctxt->node; > + xmlNodePtr node; > + virDomainMemoryDefPtr def; > + > + ctxt->node = memdevNode; > + > + if (VIR_ALLOC(def) < 0) > + return NULL; > + > + if (!(tmp = virXMLPropString(memdevNode, "model"))) { > + virReportError(VIR_ERR_XML_ERROR, "%s", > + _("missing memory model")); > + goto error; > + } > + > + if ((def->model = virDomainMemoryModelTypeFromString(tmp)) < 0) { > + virReportError(VIR_ERR_XML_ERROR, > + _("invalid memory model '%s'"), tmp); > + goto error; > + } > + VIR_FREE(tmp); > + > + /* source */ > + if ((node = virXPathNode("./source", ctxt)) && > + virDomainMemorySourceDefParseXML(node, ctxt, def) < 0) > + goto error; > + > + /* target */ > + if (!(node = virXPathNode("./target", ctxt))) { > + virReportError(VIR_ERR_XML_ERROR, "%s", > + _("missing <target> element for <memory> device")); > + goto error; > + } > + > + if (virDomainMemoryTargetDefParseXML(node, ctxt, def) < 0) > + goto error; > + > + if (virDomainDeviceInfoParseXML(memdevNode, NULL, &def->info, flags) < 0) > + goto error; > + > + return def; > + > + error: > + VIR_FREE(tmp); > + virDomainMemoryDefFree(def); > + ctxt->node = save; > + return NULL; > +} > + > + > virDomainDeviceDefPtr > virDomainDeviceDefParse(const char *xmlStr, > const virDomainDef *def, > @@ -11243,6 +11410,10 @@ virDomainDeviceDefParse(const char *xmlStr, > if (!(dev->data.panic = virDomainPanicDefParseXML(node))) > goto error; > break; > + case VIR_DOMAIN_DEVICE_MEMORY: > + if (!(dev->data.memory = virDomainMemoryDefParseXML(node, ctxt, flags))) > + goto error; > + break; > case VIR_DOMAIN_DEVICE_NONE: > case VIR_DOMAIN_DEVICE_LAST: > break; > @@ -14438,6 +14609,23 @@ virDomainDefParseXML(xmlDocPtr xml, > ctxt->node = node; > VIR_FREE(nodes); > > + /* analysis of memory devices */ > + if ((n = virXPathNodeSet("./devices/memory", ctxt, &nodes)) < 0) > + goto error; > + if (n && VIR_ALLOC_N(def->mems, n) < 0) > + goto error; > + > + for (i = 0; i < n; i++) { > + virDomainMemoryDefPtr mem = virDomainMemoryDefParseXML(nodes[i], > + ctxt, > + flags); > + if (!mem) > + goto error; > + > + def->mems[def->nmems++] = mem; > + } > + VIR_FREE(nodes); > + > /* analysis of the user namespace mapping */ > if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0) > goto error; > @@ -15677,6 +15865,39 @@ virDomainPanicDefCheckABIStability(virDomainPanicDefPtr src, > return virDomainDeviceInfoCheckABIStability(&src->info, &dst->info); > } > > +static bool > +virDomainMemoryDefCheckABIStability(virDomainMemoryDefPtr src, > + virDomainMemoryDefPtr dst) > +{ > + if (src->model != dst->model) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + _("Target memory device model '%s' " > + "doesn't match source model '%s'"), > + virDomainMemoryModelTypeToString(dst->model), > + virDomainMemoryModelTypeToString(src->model)); > + return false; > + } > + > + if (src->targetNode != dst->targetNode) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + _("Target memory device targetNode '%d' " > + "doesn't match source targetNode '%d'"), > + dst->targetNode, src->targetNode); > + return false; > + } > + > + if (src->size != dst->size) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + _("Target memory device size '%llu' doesn't match " > + "source memory device size '%llu'"), > + dst->size, src->size); > + return false; > + } > + > + return virDomainDeviceInfoCheckABIStability(&src->info, &dst->info); > +} > + > + > /* This compares two configurations and looks for any differences > * which will affect the guest ABI. This is primarily to allow > * validation of custom XML config passed in during migration > @@ -16114,6 +16335,18 @@ virDomainDefCheckABIStability(virDomainDefPtr src, > goto error; > } > > + if (src->nmems != dst->nmems) { > + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + _("Target domain memory device count %zu " > + "does not match source %zu"), dst->nmems, src->nmems); > + goto error; > + } > + > + for (i = 0; i < src->nmems; i++) { > + if (!virDomainMemoryDefCheckABIStability(src->mems[i], dst->mems[i])) > + goto error; > + } > + > /* Coverity is not very happy with this - all dead_error_condition */ > #if !STATIC_ANALYSIS > /* This switch statement is here to trigger compiler warning when adding > @@ -16145,6 +16378,7 @@ virDomainDefCheckABIStability(virDomainDefPtr src, > case VIR_DOMAIN_DEVICE_TPM: > case VIR_DOMAIN_DEVICE_PANIC: > case VIR_DOMAIN_DEVICE_SHMEM: > + case VIR_DOMAIN_DEVICE_MEMORY: > break; > } > #endif > @@ -18616,6 +18850,81 @@ virDomainRNGDefFree(virDomainRNGDefPtr def) > VIR_FREE(def); > } > > + > +static int > +virDomainMemorySourceDefFormat(virBufferPtr buf, > + virDomainMemoryDefPtr def) > +{ > + char *bitmap = NULL; > + int ret = -1; > + > + if (!def->pagesize && !def->sourceNodes) > + return 0; > + > + virBufferAddLit(buf, "<source>\n"); > + virBufferAdjustIndent(buf, 2); > + > + if (def->sourceNodes) { > + if (!(bitmap = virBitmapFormat(def->sourceNodes))) > + goto cleanup; > + > + virBufferAsprintf(buf, "<nodemask>%s</nodemask>\n", bitmap); > + } > + > + if (def->pagesize) > + virBufferAsprintf(buf, "<pagesize unit='KiB'>%llu</pagesize>\n", > + def->pagesize); > + > + virBufferAdjustIndent(buf, -2); > + virBufferAddLit(buf, "</source>\n"); > + > + ret = 0; > + > + cleanup: > + VIR_FREE(bitmap); > + return ret; > +} > + > + > +static void > +virDomainMemoryTargetDefFormat(virBufferPtr buf, > + virDomainMemoryDefPtr def) > +{ > + virBufferAddLit(buf, "<target>\n"); > + virBufferAdjustIndent(buf, 2); > + > + virBufferAsprintf(buf, "<size unit='KiB'>%llu</size>\n", def->size); > + virBufferAsprintf(buf, "<node>%d</node>\n", def->targetNode); > + > + virBufferAdjustIndent(buf, -2); > + virBufferAddLit(buf, "</target>\n"); > +} > + > +static int > +virDomainMemoryDefFormat(virBufferPtr buf, > + virDomainMemoryDefPtr def, > + unsigned int flags) > +{ > + const char *model = virDomainMemoryModelTypeToString(def->model); > + > + virBufferAsprintf(buf, "<memory model='%s'>\n", model); > + virBufferAdjustIndent(buf, 2); > + > + if (virDomainMemorySourceDefFormat(buf, def) < 0) > + return -1; > + > + virDomainMemoryTargetDefFormat(buf, def); > + > + if (virDomainDeviceInfoNeedsFormat(&def->info, flags)) { > + if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0) > + return -1; > + } > + > + virBufferAdjustIndent(buf, -2); > + virBufferAddLit(buf, "</memory>\n"); > + return 0; > +} > + > static void > virDomainVideoAccelDefFormat(virBufferPtr buf, > virDomainVideoAccelDefPtr def) > @@ -20168,6 +20477,10 @@ virDomainDefFormatInternal(virDomainDefPtr def, > if (virDomainShmemDefFormat(buf, def->shmems[n], flags) < 0) > goto error; > > + for (n = 0; n < def->nmems; n++) > + if (virDomainMemoryDefFormat(buf, def->mems[n], flags) < 0) > + goto error; > + > virBufferAdjustIndent(buf, -2); > virBufferAddLit(buf, "</devices>\n"); > > @@ -21570,6 +21883,8 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src, > break; > case VIR_DOMAIN_DEVICE_PANIC: > rc = virDomainPanicDefFormat(&buf, src->data.panic); Coverity found a missing break here John > + case VIR_DOMAIN_DEVICE_MEMORY: > + rc = virDomainMemoryDefFormat(&buf, src->data.memory, flags); > break; > case VIR_DOMAIN_DEVICE_NONE: > case VIR_DOMAIN_DEVICE_SMARTCARD: -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list