This patch adds code that parses and formats configuration for memory
devices.
A simple configuration would be:
<memory model='acpi-dimm'>
<target>
<size unit='KiB'>524287</size>
<node>0</node>
</target>
</memory>
A complete configuration of a memory device:
<memory model='acpi-dimm'>
<source>
<pagesize unit='KiB'>4096</pagesize>
<nodemask>1-3</nodemask>
</source>
<target>
<size unit='KiB'>524287</size>
<node>1</node>
</target>
</memory>
This patch preemptively forbids use of the <memory> device in individual
drivers so the users are warned right away that the device is not
supported.
---
docs/formatdomain.html.in | 79 +++++
docs/schemas/domaincommon.rng | 50 ++++
src/bhyve/bhyve_domain.c | 5 +-
src/conf/domain_conf.c | 326 ++++++++++++++++++++-
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 | 50 ++++
16 files changed, 580 insertions(+), 3 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 6320703..881e941 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -5866,6 +5866,85 @@ qemu-kvm -net nic,model=? /dev/null
</dd>
</dl>
+ <h4><a name="elementsMemory">Memory
devices</a></h4>
+
+ <p>
+ Apart from initial memory the memory device allow to add additional
+ memory for the guest in form of memory modules. These devices also allow
+ hot-add and hot-remove of guest's memory.
+ <span class="since">Since 1.2.13</span>
+ </p>
+
+ <p>
+ Example: usage of the memory devices
+ </p>
+<pre>
+ ...
+ <devices>
+ <memory model='acpi-dimm'>
+ <target>
+ <size unit='KiB'>524287</size>
+ <node>0</node>
+ </target>
+ </memory>
+ <memory model='acpi-dimm'>
+ <source>
+ <pagesize unit='KiB'>4096</pagesize>
+ <nodemask>1-3</nodemask>
+ </source>
+ <target>
+ <size unit='KiB'>524287</size>
+ <node>1</node>
+ </target>
+ </memory>
+ </devices>
+ ...
+</pre>
+ <dl>
+ <dt><code>model</code></dt>
+ <dd>
+ <p>
+ Currently only the <code>acpi-dimm</code> model is supported that
+ will result in adding a virtual DIMM module to the guest. Note that
+ hypervisors require having NUMA enabled for the guest for the memory
+ modules to work.
+ </p>
+ </dd>
+
+ <dt><code>source</code></dt>
+ <dd>
+ <p>
+ The optional source element allows to fine tune the source of the
+ memory used for the given memory device. If the element is not
+ provided defaults configured via <code>numatune</code> are used.
+ </p>
+ <p>
+ <code>pagesize</code> can be used to override the default host
page
+ size used for backing of the memory device.
+ </p>
+ <p>
+ <code>nodemask</code> can be used to override the default set of
NUMA
+ where the memory would be allocated.
+ </p>
+ </dd>
+
+ <dt><code>target</code></dt>
+ <dd>
+ <p>
+ The mandatory <code>target</code> element configures the placement
and
+ sizing the added memory from the perspective of the guest.
+ </p>
+ <p>
+ The mandatory <code>size</code> subelement configures the size of
the
+ added memory as a scaled integer.
+ </p>
+ <p>
+ The mandatory <code>node</code> subelement configures the guest
NUMA
+ node to attach the memory to.
+ </p>
+ </dd>
+ </dl>
+
<h3><a name="seclabel">Security label</a></h3>
<p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 1824741..a8c17a8 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4034,6 +4034,7 @@
<ref name="rng"/>
<ref name="tpm"/>
<ref name="shmem"/>
+ <ref name="memorydev"/>
</choice>
</zeroOrMore>
<optional>
@@ -4445,6 +4446,55 @@
</element>
</define>
+ <define name="memorydev">
+ <element name="memory">
+ <attribute name="model">
+ <choice>
+ <value>acpi-dimm</value>
+ </choice>
+ </attribute>
+ <interleave>
+ <optional>
+ <ref name="memorydev-source"/>
+ </optional>
+ <ref name="memorydev-target"/>
+ <optional>
+ <ref name="address"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="memorydev-source">
+ <element name="source">
+ <interleave>
+ <optional>
+ <element name="pagesize">
+ <ref name="scaledInteger"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="nodemask">
+ <ref name="cpuset"/>
+ </element>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="memorydev-target">
+ <element name="target">
+ <interleave>
+ <element name="size">
+ <ref name="scaledInteger"/>
+ </element>
+ <element name="node">
+ <ref name="unsignedInt"/>
+ </element>
+ </interleave>
+ </element>
+ </define>
+
<define name="rng">
<element name="rng">
<attribute name="model">
diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c
index 25ef852..890963e 100644
--- a/src/bhyve/bhyve_domain.c
+++ b/src/bhyve/bhyve_domain.c
@@ -75,11 +75,14 @@ bhyveDomainDefPostParse(virDomainDefPtr def,
}
static int
-bhyveDomainDeviceDefPostParse(virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
+bhyveDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
const virDomainDef *def ATTRIBUTE_UNUSED,
virCapsPtr caps ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
+ if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
+ return -1;
+
return 0;
}
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b5d9c6f..3eb1426 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",
@@ -786,6 +787,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;
@@ -1010,6 +1017,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)
{
@@ -1941,6 +1969,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)
@@ -2010,6 +2047,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;
@@ -2207,6 +2247,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);
@@ -2744,6 +2788,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:
@@ -3064,6 +3110,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
@@ -3096,6 +3149,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
@@ -7020,7 +7074,13 @@ virDomainDefSetMemoryInitial(virDomainDefPtr def,
unsigned long long
virDomainDefGetMemoryCurrent(virDomainDefPtr def)
{
- return virDomainDefGetMemoryInitial(def);
+ unsigned long long ret = virDomainDefGetMemoryInitial(def);
+ size_t i;
+
+ for (i = 0; i < def->nmems; i++)
+ ret += def->mems[i]->size;
+
+ return ret;
}
@@ -11361,6 +11421,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,
@@ -11495,6 +11668,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;
@@ -14846,6 +15023,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;
@@ -16085,6 +16279,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
@@ -16497,6 +16724,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
@@ -16528,6 +16767,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
@@ -19007,6 +19247,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)
@@ -20596,6 +20911,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");
@@ -21999,6 +22318,9 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
case VIR_DOMAIN_DEVICE_PANIC:
rc = virDomainPanicDefFormat(&buf, src->data.panic);
break;
+ case VIR_DOMAIN_DEVICE_MEMORY:
+ rc = virDomainMemoryDefFormat(&buf, src->data.memory, flags);
+ break;
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_SMARTCARD:
case VIR_DOMAIN_DEVICE_MEMBALLOON:
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 151c1e7..80d2c88 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -132,6 +132,9 @@ typedef virDomainIdMapDef *virDomainIdMapDefPtr;
typedef struct _virDomainPanicDef virDomainPanicDef;
typedef virDomainPanicDef *virDomainPanicDefPtr;
+typedef struct _virDomainMemoryDef virDomainMemoryDef;
+typedef virDomainMemoryDef *virDomainMemoryDefPtr;
+
/* forward declarations virDomainChrSourceDef, required by
* virDomainNetDef
*/
@@ -168,6 +171,7 @@ typedef enum {
VIR_DOMAIN_DEVICE_SHMEM,
VIR_DOMAIN_DEVICE_TPM,
VIR_DOMAIN_DEVICE_PANIC,
+ VIR_DOMAIN_DEVICE_MEMORY,
VIR_DOMAIN_DEVICE_LAST
} virDomainDeviceType;
@@ -198,6 +202,7 @@ struct _virDomainDeviceDef {
virDomainShmemDefPtr shmem;
virDomainTPMDefPtr tpm;
virDomainPanicDefPtr panic;
+ virDomainMemoryDefPtr memory;
} data;
};
@@ -1973,6 +1978,28 @@ struct _virDomainRNGDef {
virDomainDeviceInfo info;
};
+typedef enum {
+ VIR_DOMAIN_MEMORY_MODEL_NONE,
+ VIR_DOMAIN_MEMORY_MODEL_ACPI_DIMM, /* dimm hotpluggable memory device */
+
+ VIR_DOMAIN_MEMORY_MODEL_LAST
+} virDomainMemoryModel;
+
+struct _virDomainMemoryDef {
+ /* source */
+ virBitmapPtr sourceNodes;
+ unsigned long long pagesize; /* kibibytes */
+
+ /* target */
+ int model; /* virDomainMemoryModel */
+ int targetNode;
+ unsigned long long size; /* kibibytes */
+
+ virDomainDeviceInfo info;
+};
+
+void virDomainMemoryDefFree(virDomainMemoryDefPtr def);
+
struct _virDomainIdMapEntry {
unsigned int start;
unsigned int target;
@@ -2193,6 +2220,9 @@ struct _virDomainDef {
size_t nshmems;
virDomainShmemDefPtr *shmems;
+ size_t nmems;
+ virDomainMemoryDefPtr *mems;
+
/* Only 1 */
virDomainWatchdogDefPtr watchdog;
virDomainMemballoonDefPtr memballoon;
@@ -2355,6 +2385,7 @@ bool virDomainObjTaint(virDomainObjPtr obj,
int virDomainDefCheckUnsupportedMemoryHotplug(virDomainDefPtr def);
+int virDomainDeviceDefCheckUnsupportedMemoryDevice(virDomainDeviceDefPtr dev);
void virDomainPanicDefFree(virDomainPanicDefPtr panic);
void virDomainResourceDefFree(virDomainResourceDefPtr resource);
@@ -2900,6 +2931,8 @@ VIR_ENUM_DECL(virDomainRNGBackend)
VIR_ENUM_DECL(virDomainTPMModel)
VIR_ENUM_DECL(virDomainTPMBackend)
VIR_ENUM_DECL(virDomainThreadSched)
+VIR_ENUM_DECL(virDomainMemoryModel)
+VIR_ENUM_DECL(virDomainMemoryBackingModel)
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainNostateReason)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d01b884..3b7cfdb 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -216,6 +216,7 @@ virDomainDefSetMemoryInitial;
virDomainDeleteConfig;
virDomainDeviceAddressIsValid;
virDomainDeviceAddressTypeToString;
+virDomainDeviceDefCheckUnsupportedMemoryDevice;
virDomainDeviceDefCopy;
virDomainDeviceDefFree;
virDomainDeviceDefParse;
@@ -331,6 +332,7 @@ virDomainLockFailureTypeFromString;
virDomainLockFailureTypeToString;
virDomainMemballoonModelTypeFromString;
virDomainMemballoonModelTypeToString;
+virDomainMemoryDefFree;
virDomainNetAppendIpAddress;
virDomainNetDefFormat;
virDomainNetDefFree;
diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c
index 5d186c3..2317434 100644
--- a/src/libxl/libxl_domain.c
+++ b/src/libxl/libxl_domain.c
@@ -546,6 +546,9 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
}
}
+ if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
+ return -1;
+
return 0;
}
diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c
index 1367b0c..c2180cb 100644
--- a/src/lxc/lxc_domain.c
+++ b/src/lxc/lxc_domain.c
@@ -113,6 +113,10 @@ virLXCDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)
dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LXC;
+
+ if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
+ return -1;
+
return 0;
}
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index fe18acc..ddf298b 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -130,6 +130,9 @@ openvzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
return -1;
}
+ if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
+ return -1;
+
return 0;
}
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 46a7411..55dd6b2 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1182,6 +1182,9 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
}
}
+ if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
+ goto cleanup;
+
ret = 0;
cleanup:
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index fa1bcb2..9d6eab9 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7135,6 +7135,9 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
dev->data.rng = NULL;
break;
+ /*TODO: implement later */
+ case VIR_DOMAIN_DEVICE_MEMORY:
+
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_FS:
case VIR_DOMAIN_DEVICE_INPUT:
@@ -7212,6 +7215,8 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
case VIR_DOMAIN_DEVICE_RNG:
ret = qemuDomainDetachRNGDevice(driver, vm, dev->data.rng);
break;
+ case VIR_DOMAIN_DEVICE_MEMORY:
+ /* TODO: Implement later */
case VIR_DOMAIN_DEVICE_FS:
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SOUND:
@@ -7329,6 +7334,7 @@ qemuDomainUpdateDeviceLive(virConnectPtr conn,
case VIR_DOMAIN_DEVICE_HOSTDEV:
case VIR_DOMAIN_DEVICE_CONTROLLER:
case VIR_DOMAIN_DEVICE_REDIRDEV:
+ case VIR_DOMAIN_DEVICE_MEMORY:
case VIR_DOMAIN_DEVICE_CHR:
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_TPM:
@@ -7471,6 +7477,9 @@ qemuDomainAttachDeviceConfig(virQEMUCapsPtr qemuCaps,
dev->data.rng = NULL;
break;
+ case VIR_DOMAIN_DEVICE_MEMORY:
+ /* TODO: implement later */
+
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SOUND:
case VIR_DOMAIN_DEVICE_VIDEO:
@@ -7596,6 +7605,9 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
virDomainRNGDefFree(virDomainRNGRemove(vmdef, idx));
break;
+ case VIR_DOMAIN_DEVICE_MEMORY:
+ /* TODO: implement later */
+
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SOUND:
case VIR_DOMAIN_DEVICE_VIDEO:
@@ -7710,6 +7722,7 @@ qemuDomainUpdateDeviceConfig(virQEMUCapsPtr qemuCaps,
case VIR_DOMAIN_DEVICE_CONTROLLER:
case VIR_DOMAIN_DEVICE_REDIRDEV:
case VIR_DOMAIN_DEVICE_CHR:
+ case VIR_DOMAIN_DEVICE_MEMORY:
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 8d91719..2985416 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -3072,6 +3072,9 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
qemuDomainRemoveRNGDevice(driver, vm, dev->data.rng);
break;
+ /* TODO: implement later */
+ case VIR_DOMAIN_DEVICE_MEMORY:
+
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_FS:
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index d2a1519..834e91b 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -439,6 +439,9 @@ umlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
return -1;
}
+ if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
+ return -1;
+
return 0;
}
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
index f603477..1cceacb 100644
--- a/src/xen/xen_driver.c
+++ b/src/xen/xen_driver.c
@@ -372,6 +372,9 @@ xenDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
}
}
+ if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
+ return -1;
+
return 0;
}
diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c
index c6acfc9..439f767 100644
--- a/src/xenapi/xenapi_driver.c
+++ b/src/xenapi/xenapi_driver.c
@@ -65,6 +65,9 @@ xenapiDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
return -1;
}
+ if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
+ return -1;
+
return 0;
}
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.xml
b/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.xml
new file mode 100644
index 0000000..ec2cb86
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.xml
@@ -0,0 +1,50 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <maxMemory slots='16' unit='KiB'>1099511627776</maxMemory>
+ <memory unit='KiB'>1267710</memory>
+ <currentMemory unit='KiB'>1267710</currentMemory>
+ <vcpu placement='static' cpuset='0-1'>2</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <cpu>
+ <topology sockets='2' cores='1' threads='1'/>
+ <numa>
+ <cell id='0' cpus='0-1' memory='219136'
unit='KiB'/>
+ </numa>
+ </cpu>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk'>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
target='0' unit='0'/>
+ </disk>
+ <controller type='ide' index='0'/>
+ <controller type='usb' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <memballoon model='virtio'/>
+ <memory model='acpi-dimm'>
+ <target>
+ <size unit='KiB'>524287</size>
+ <node>0</node>
+ </target>
+ </memory>
+ <memory model='acpi-dimm'>
+ <source>
+ <nodemask>1-3</nodemask>
+ <pagesize unit='KiB'>4096</pagesize>
+ </source>
+ <target>
+ <size unit='KiB'>524287</size>
+ <node>0</node>
+ </target>
+ </memory>
+ </devices>
+</domain>
--
2.2.2