<source type="file|anonymous"/>
<access mode="shared|private"/>
<allocation mode="immediate|ondemand"/>
+ <discard/>
</memoryBacking>
...
</domain>
numa node by <code>memAccess</code></dd>
<dt><code>allocation</code></dt>
<dd>Specify when allocate the memory</dd>
+ <dt><code>discard</code></dt>
+ <dd>When set and supported by hypervisor the memory
+ content is discarded just before guest shuts down (or
+ when DIMM module is unplugged). Please note that this is
+ just an optimization and is not guaranteed to work in
+ all cases (e.g. when hypervisor crashes).
+ <span class="since">Since 4.4.0</span> (QEMU/KVM only)
+ </dd>
</dl>
<cpu>
...
<numa>
- <cell id='0' cpus='0-3' memory='512000' unit='KiB'/>
+ <cell id='0' cpus='0-3' memory='512000' unit='KiB' discard='yes'/>
<cell id='1' cpus='4-7' memory='512000' unit='KiB' memAccess='shared'/>
</numa>
...
<code>memAccess</code> can control whether the memory is to be
mapped as "shared" or "private". This is valid only for
hugepages-backed memory and nvdimm modules.
+
+ Each <code>cell</code> element can have an optional
+ <code>discard</code> attribute which fine tunes the discard
+ feature for given numa node as described under
+ <a href="#elementsMemoryBacking">Memory Backing</a>.
+ Accepted values are <code>yes</code> and <code>no</code>.
+ <span class='since'>Since 4.4.0</span>
</p>
<p>
<pre>
...
<devices>
- <memory model='dimm' access='private'>
+ <memory model='dimm' access='private' discard='yes'>
<target>
<size unit='KiB'>524287</size>
<node>0</node>
</p>
</dd>
+ <dt><code>discard</code></dt>
+ <dd>
+ <p>
+ An optional attribute <code>discard</code>
+ (<span class="since">since 4.4.0</span>) that provides
+ capability to fine tune discard of data on per module
+ basis. Accepted values are <code>yes</code> and
+ <code>no</code>. The feature is described here:
+ <a href="#elementsMemoryBacking">Memory Backing</a>.
+ This attribute is allowed only for
+ <code>model='dimm'</code>.
+ </p>
+ </dd>
+
<dt><code>source</code></dt>
<dd>
<p>
</choice>
</attribute>
</optional>
+ <optional>
+ <attribute name="discard">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
<optional>
<element name="distances">
<oneOrMore>
</attribute>
</element>
</optional>
+ <optional>
+ <element name="discard">
+ <empty/>
+ </element>
+ </optional>
</interleave>
</element>
</optional>
</choice>
</attribute>
</optional>
+ <optional>
+ <attribute name="discard">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
<interleave>
<optional>
<ref name="memorydev-source"/>
}
+static int
+virDomainMemoryDefValidate(const virDomainMemoryDef *mem)
+{
+ if (mem->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM &&
+ mem->discard == VIR_TRISTATE_BOOL_YES) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("discard is not supported for nvdimms"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int
virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev,
const virDomainDef *def)
case VIR_DOMAIN_DEVICE_VIDEO:
return virDomainVideoDefValidate(dev->data.video);
+ case VIR_DOMAIN_DEVICE_MEMORY:
+ return virDomainMemoryDefValidate(dev->data.memory);
+
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_FS:
case VIR_DOMAIN_DEVICE_INPUT:
case VIR_DOMAIN_DEVICE_SHMEM:
case VIR_DOMAIN_DEVICE_TPM:
case VIR_DOMAIN_DEVICE_PANIC:
- case VIR_DOMAIN_DEVICE_MEMORY:
case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LAST:
}
VIR_FREE(tmp);
+ if ((tmp = virXMLPropString(memdevNode, "discard"))) {
+ if ((val = virTristateBoolTypeFromString(tmp)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid discard value '%s'"), tmp);
+ goto error;
+ }
+
+ def->discard = val;
+ }
+
/* source */
if ((node = virXPathNode("./source", ctxt)) &&
virDomainMemorySourceDefParseXML(node, ctxt, def) < 0)
if (virXPathBoolean("boolean(./memoryBacking/locked)", ctxt))
def->mem.locked = true;
+ if (virXPathBoolean("boolean(./memoryBacking/discard)", ctxt))
+ def->mem.discard = VIR_TRISTATE_BOOL_YES;
+
/* Extract blkio cgroup tunables */
if (virXPathUInt("string(./blkiotune/weight)", ctxt,
&def->blkio.weight) < 0)
if (def->access)
virBufferAsprintf(buf, " access='%s'",
virDomainMemoryAccessTypeToString(def->access));
+ if (def->discard)
+ virBufferAsprintf(buf, " discard='%s'",
+ virTristateBoolTypeToString(def->discard));
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);
if (mem->allocation)
virBufferAsprintf(&childBuf, "<allocation mode='%s'/>\n",
virDomainMemoryAllocationTypeToString(mem->allocation));
+ if (mem->discard)
+ virBufferAddLit(&childBuf, "<discard/>\n");
if (virXMLFormatElement(buf, "memoryBacking", NULL, &childBuf) < 0)
goto cleanup;
struct _virDomainMemoryDef {
virDomainMemoryAccess access;
+ virTristateBool discard;
/* source */
virBitmapPtr sourceNodes;
int source; /* enum virDomainMemorySource */
int access; /* enum virDomainMemoryAccess */
int allocation; /* enum virDomainMemoryAllocation */
+
+ virTristateBool discard;
};
typedef struct _virDomainPowerManagement virDomainPowerManagement;
virBitmapPtr nodeset; /* host memory nodes where this guest node resides */
virDomainNumatuneMemMode mode; /* memory mode selection */
virDomainMemoryAccess memAccess; /* shared memory access configuration */
+ virTristateBool discard; /* discard-data for memory-backend-file */
struct _virDomainNumaDistance {
unsigned int value; /* locality value for node i->j or j->i */
VIR_FREE(tmp);
}
+ if ((tmp = virXMLPropString(nodes[i], "discard"))) {
+ if ((rc = virTristateBoolTypeFromString(tmp)) <= 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Invalid 'discard' attribute value '%s'"),
+ tmp);
+ goto cleanup;
+ }
+
+ def->mem_nodes[cur_cell].discard = rc;
+ VIR_FREE(tmp);
+ }
+
/* Parse NUMA distances info */
if (virDomainNumaDefNodeDistanceParseXML(def, ctxt, cur_cell) < 0)
goto cleanup;
virDomainNumaPtr def)
{
virDomainMemoryAccess memAccess;
+ virTristateBool discard;
char *cpustr;
size_t ncells = virDomainNumaGetNodeCount(def);
size_t i;
int ndistances;
memAccess = virDomainNumaGetNodeMemoryAccessMode(def, i);
+ discard = virDomainNumaGetNodeDiscard(def, i);
if (!(cpustr = virBitmapFormat(virDomainNumaGetNodeCpumask(def, i))))
return -1;
virBufferAsprintf(buf, " memAccess='%s'",
virDomainMemoryAccessTypeToString(memAccess));
+ if (discard)
+ virBufferAsprintf(buf, " discard='%s'",
+ virTristateBoolTypeToString(discard));
+
ndistances = def->mem_nodes[i].ndistances;
if (ndistances == 0) {
virBufferAddLit(buf, "/>\n");
}
+virTristateBool
+virDomainNumaGetNodeDiscard(virDomainNumaPtr numa,
+ size_t node)
+{
+ return numa->mem_nodes[node].discard;
+}
+
+
unsigned long long
virDomainNumaGetNodeMemorySize(virDomainNumaPtr numa,
size_t node)
virDomainMemoryAccess virDomainNumaGetNodeMemoryAccessMode(virDomainNumaPtr numa,
size_t node)
ATTRIBUTE_NONNULL(1);
+virTristateBool virDomainNumaGetNodeDiscard(virDomainNumaPtr numa,
+ size_t node)
+ ATTRIBUTE_NONNULL(1);
unsigned long long virDomainNumaGetNodeMemorySize(virDomainNumaPtr numa,
size_t node)
ATTRIBUTE_NONNULL(1);
virDomainNumaGetMemorySize;
virDomainNumaGetNodeCount;
virDomainNumaGetNodeCpumask;
+virDomainNumaGetNodeDiscard;
virDomainNumaGetNodeDistance;
virDomainNumaGetNodeMemoryAccessMode;
virDomainNumaGetNodeMemorySize;
<page size='2048' unit='KiB' nodeset='1'/>
<page size='1048576' unit='KiB' nodeset='0,2-3'/>
</hugepages>
+ <discard/>
</memoryBacking>
<vcpu placement='static'>4</vcpu>
<numatune>
<cpu>
<numa>
<cell id='0' cpus='0' memory='1048576' unit='KiB'/>
- <cell id='1' cpus='1' memory='1048576' unit='KiB'/>
+ <cell id='1' cpus='1' memory='1048576' unit='KiB' discard='no'/>
<cell id='2' cpus='2' memory='1048576' unit='KiB'/>
<cell id='3' cpus='3' memory='1048576' unit='KiB'/>
</numa>
</os>
<cpu>
<numa>
- <cell id='0' cpus='0' memory='262144' unit='KiB'/>
- <cell id='1' cpus='1' memory='786432' unit='KiB'/>
+ <cell id='0' cpus='0' memory='262144' unit='KiB' discard='no'/>
+ <cell id='1' cpus='1' memory='786432' unit='KiB' discard='yes'/>
</numa>
</cpu>
<clock offset='utc'/>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</memballoon>
- <memory model='dimm'>
+ <memory model='dimm' discard='no'>
<source>
<nodemask>1-3</nodemask>
<pagesize unit='KiB'>1048576</pagesize>
</target>
<address type='dimm' slot='0'/>
</memory>
- <memory model='dimm' access='private'>
+ <memory model='dimm' access='private' discard='yes'>
<target>
<size unit='KiB'>524287</size>
<node>0</node>
<page size='2048' unit='KiB' nodeset='1'/>
<page size='1048576' unit='KiB' nodeset='0,2-3'/>
</hugepages>
+ <discard/>
</memoryBacking>
<vcpu placement='static'>4</vcpu>
<numatune>
<cpu>
<numa>
<cell id='0' cpus='0' memory='1048576' unit='KiB'/>
- <cell id='1' cpus='1' memory='1048576' unit='KiB'/>
+ <cell id='1' cpus='1' memory='1048576' unit='KiB' discard='no'/>
<cell id='2' cpus='2' memory='1048576' unit='KiB'/>
<cell id='3' cpus='3' memory='1048576' unit='KiB'/>
</numa>
</os>
<cpu>
<numa>
- <cell id='0' cpus='0' memory='262144' unit='KiB'/>
- <cell id='1' cpus='1' memory='786432' unit='KiB'/>
+ <cell id='0' cpus='0' memory='262144' unit='KiB' discard='no'/>
+ <cell id='1' cpus='1' memory='786432' unit='KiB' discard='yes'/>
</numa>
</cpu>
<clock offset='utc'/>