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: