mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
conf: Add interface to parse and format memory device information
This patch adds code that parses and formats configuration for memory devices. A simple configuration would be: <memory model='dimm'> <target> <size unit='KiB'>524287</size> <node>0</node> </target> </memory> A complete configuration of a memory device: <memory model='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.
This commit is contained in:
parent
62b825a2d0
commit
3e4230d270
@ -684,7 +684,9 @@
|
||||
|
||||
<dl>
|
||||
<dt><code>memory</code></dt>
|
||||
<dd>The maximum allocation of memory for the guest at boot time.
|
||||
<dd>The maximum allocation of memory for the guest at boot time. The
|
||||
memory allocation includes possible additional memory devices specified
|
||||
at start or hotplugged later.
|
||||
The units for this value are determined by the optional
|
||||
attribute <code>unit</code>, which defaults to "KiB"
|
||||
(kibibytes, 2<sup>10</sup> or blocks of 1024 bytes). Valid
|
||||
@ -702,6 +704,9 @@
|
||||
supported by the hypervisor. Some hypervisors also enforce a
|
||||
minimum, such as 4000KiB.
|
||||
|
||||
In case <a href="#elementsCPU">NUMA</a> is configured for the guest the
|
||||
<code>memory</code> element can be omitted.
|
||||
|
||||
In the case of crash, optional attribute <code>dumpCore</code>
|
||||
can be used to control whether the guest memory should be
|
||||
included in the generated coredump or not (values "on", "off").
|
||||
@ -5951,6 +5956,91 @@ qemu-kvm -net nic,model=? /dev/null
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h4><a name="elementsMemory">Memory devices</a></h4>
|
||||
|
||||
<p>
|
||||
In addition to the initial memory assigned to the guest, memory devices
|
||||
allow additional memory to be assigned to the guest in the form of
|
||||
memory modules.
|
||||
|
||||
A memory device can be hot-plugged or hot-unplugged depending on the
|
||||
guests' memory resource needs.
|
||||
|
||||
Some hypervisors may require NUMA configured for the guest.
|
||||
<span class="since">Since 1.2.14</span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Example: usage of the memory devices
|
||||
</p>
|
||||
<pre>
|
||||
...
|
||||
<devices>
|
||||
<memory model='dimm'>
|
||||
<target>
|
||||
<size unit='KiB'>524287</size>
|
||||
<node>0</node>
|
||||
</target>
|
||||
</memory>
|
||||
<memory model='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>dimm</code> model is supported in order to
|
||||
add a virtual DIMM module to the guest.
|
||||
</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 optionally be used to override the default
|
||||
host page size used for backing the memory device.
|
||||
|
||||
The configured value must correspond to a page size supported by the
|
||||
host.
|
||||
</p>
|
||||
<p>
|
||||
<code>nodemask</code> can optionally be used to override the default
|
||||
set of NUMA nodes 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 of 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>
|
||||
|
@ -4071,6 +4071,7 @@
|
||||
<ref name="rng"/>
|
||||
<ref name="tpm"/>
|
||||
<ref name="shmem"/>
|
||||
<ref name="memorydev"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
<optional>
|
||||
@ -4487,6 +4488,55 @@
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="memorydev">
|
||||
<element name="memory">
|
||||
<attribute name="model">
|
||||
<choice>
|
||||
<value>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">
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
@ -780,6 +781,9 @@ 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,
|
||||
"", "dimm")
|
||||
|
||||
static virClassPtr virDomainObjClass;
|
||||
static virClassPtr virDomainObjListClass;
|
||||
static virClassPtr virDomainXMLOptionClass;
|
||||
@ -1004,6 +1008,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)
|
||||
{
|
||||
@ -1937,6 +1962,16 @@ void virDomainRedirFilterDefFree(virDomainRedirFilterDefPtr def)
|
||||
VIR_FREE(def);
|
||||
}
|
||||
|
||||
void virDomainMemoryDefFree(virDomainMemoryDefPtr def)
|
||||
{
|
||||
if (!def)
|
||||
return;
|
||||
|
||||
virBitmapFree(def->sourceNodes);
|
||||
virDomainDeviceInfoClear(&def->info);
|
||||
VIR_FREE(def);
|
||||
}
|
||||
|
||||
void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
|
||||
{
|
||||
if (!def)
|
||||
@ -2006,6 +2041,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;
|
||||
@ -2203,6 +2241,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 +2786,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 +3108,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 +3147,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
|
||||
@ -7083,10 +7135,16 @@ unsigned long long
|
||||
virDomainDefGetMemoryInitial(virDomainDefPtr def)
|
||||
{
|
||||
unsigned long long ret;
|
||||
size_t i;
|
||||
|
||||
/* return NUMA memory size total in case numa is enabled */
|
||||
if ((ret = virDomainNumaGetMemorySize(def->numa)) > 0)
|
||||
if ((ret = virDomainNumaGetMemorySize(def->numa)) > 0) {
|
||||
return ret;
|
||||
} else {
|
||||
ret = def->mem.max_balloon;
|
||||
for (i = 0; i < def->nmems; i++)
|
||||
ret -= def->mems[i]->size;
|
||||
}
|
||||
|
||||
return def->mem.max_balloon;
|
||||
}
|
||||
@ -7118,7 +7176,17 @@ virDomainDefSetMemoryInitial(virDomainDefPtr def,
|
||||
unsigned long long
|
||||
virDomainDefGetMemoryActual(virDomainDefPtr def)
|
||||
{
|
||||
return virDomainDefGetMemoryInitial(def);
|
||||
unsigned long long ret;
|
||||
size_t i;
|
||||
|
||||
if ((ret = virDomainNumaGetMemorySize(def->numa)) > 0) {
|
||||
for (i = 0; i < def->nmems; i++)
|
||||
ret += def->mems[i]->size;
|
||||
} else {
|
||||
ret = def->mem.max_balloon;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -11477,6 +11545,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 (virXPathUInt("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,
|
||||
@ -11611,6 +11792,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;
|
||||
@ -15010,6 +15195,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;
|
||||
@ -16249,6 +16451,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 '%u' "
|
||||
"doesn't match source targetNode '%u'"),
|
||||
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
|
||||
@ -16667,6 +16902,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
|
||||
@ -16698,6 +16945,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
|
||||
@ -19185,6 +19433,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>%u</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)
|
||||
@ -20771,6 +21094,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");
|
||||
|
||||
@ -22175,6 +22502,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:
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
@ -1969,6 +1974,28 @@ struct _virDomainRNGDef {
|
||||
virDomainDeviceInfo info;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
VIR_DOMAIN_MEMORY_MODEL_NONE,
|
||||
VIR_DOMAIN_MEMORY_MODEL_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 */
|
||||
unsigned int targetNode;
|
||||
unsigned long long size; /* kibibytes */
|
||||
|
||||
virDomainDeviceInfo info;
|
||||
};
|
||||
|
||||
void virDomainMemoryDefFree(virDomainMemoryDefPtr def);
|
||||
|
||||
struct _virDomainIdMapEntry {
|
||||
unsigned int start;
|
||||
unsigned int target;
|
||||
@ -2189,6 +2216,9 @@ struct _virDomainDef {
|
||||
size_t nshmems;
|
||||
virDomainShmemDefPtr *shmems;
|
||||
|
||||
size_t nmems;
|
||||
virDomainMemoryDefPtr *mems;
|
||||
|
||||
/* Only 1 */
|
||||
virDomainWatchdogDefPtr watchdog;
|
||||
virDomainMemballoonDefPtr memballoon;
|
||||
@ -2351,6 +2381,7 @@ bool virDomainObjTaint(virDomainObjPtr obj,
|
||||
|
||||
|
||||
int virDomainDefCheckUnsupportedMemoryHotplug(virDomainDefPtr def);
|
||||
int virDomainDeviceDefCheckUnsupportedMemoryDevice(virDomainDeviceDefPtr dev);
|
||||
|
||||
void virDomainPanicDefFree(virDomainPanicDefPtr panic);
|
||||
void virDomainResourceDefFree(virDomainResourceDefPtr resource);
|
||||
@ -2899,6 +2930,8 @@ VIR_ENUM_DECL(virDomainRNGModel)
|
||||
VIR_ENUM_DECL(virDomainRNGBackend)
|
||||
VIR_ENUM_DECL(virDomainTPMModel)
|
||||
VIR_ENUM_DECL(virDomainTPMBackend)
|
||||
VIR_ENUM_DECL(virDomainMemoryModel)
|
||||
VIR_ENUM_DECL(virDomainMemoryBackingModel)
|
||||
/* from libvirt.h */
|
||||
VIR_ENUM_DECL(virDomainState)
|
||||
VIR_ENUM_DECL(virDomainNostateReason)
|
||||
|
@ -216,6 +216,7 @@ virDomainDefSetMemoryInitial;
|
||||
virDomainDeleteConfig;
|
||||
virDomainDeviceAddressIsValid;
|
||||
virDomainDeviceAddressTypeToString;
|
||||
virDomainDeviceDefCheckUnsupportedMemoryDevice;
|
||||
virDomainDeviceDefCopy;
|
||||
virDomainDeviceDefFree;
|
||||
virDomainDeviceDefParse;
|
||||
@ -333,6 +334,7 @@ virDomainLockFailureTypeFromString;
|
||||
virDomainLockFailureTypeToString;
|
||||
virDomainMemballoonModelTypeFromString;
|
||||
virDomainMemballoonModelTypeToString;
|
||||
virDomainMemoryDefFree;
|
||||
virDomainNetAppendIpAddress;
|
||||
virDomainNetDefFormat;
|
||||
virDomainNetDefFree;
|
||||
|
@ -538,6 +538,9 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
|
||||
}
|
||||
}
|
||||
|
||||
if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -130,6 +130,9 @@ openvzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1200,6 +1200,9 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
|
||||
}
|
||||
}
|
||||
|
||||
if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
|
@ -7656,6 +7656,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:
|
||||
@ -7733,6 +7736,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:
|
||||
@ -7850,6 +7855,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:
|
||||
@ -7992,6 +7998,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:
|
||||
@ -8117,6 +8126,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:
|
||||
@ -8223,6 +8235,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:
|
||||
|
@ -3083,6 +3083,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:
|
||||
|
@ -439,6 +439,9 @@ umlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -370,6 +370,9 @@ xenDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
|
||||
}
|
||||
}
|
||||
|
||||
if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,9 @@ xenapiDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (virDomainDeviceDefCheckUnsupportedMemoryDevice(dev) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
50
tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.xml
Normal file
50
tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.xml
Normal file
@ -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='dimm'>
|
||||
<target>
|
||||
<size unit='KiB'>524287</size>
|
||||
<node>0</node>
|
||||
</target>
|
||||
</memory>
|
||||
<memory model='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>
|
Loading…
Reference in New Issue
Block a user