diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index df5ac28028..83dec62f30 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -6755,6 +6755,12 @@ Example: manually added device with static PCI slot 2 requested
release some memory at the last moment before a guest's process get killed by
Out of Memory killer. :since:`Since 1.3.1, QEMU and KVM only`
+``free-page-reporting``
+ The optional ``free-page-reporting`` attribute allows to enable/disable
+ ("on"/"off", respectively) the ability of the QEMU virtio memory balloon to
+ return unused pages back to the hypervisor to be used by other guests or
+ processes. :since:`Since 6.9.0, QEMU and KVM only`
+
``period``
The optional ``period`` allows the QEMU virtio memory balloon driver to
provide statistics through the ``virsh dommemstat [domain]``
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 7d4b105981..0a0f0ed8a8 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4539,6 +4539,11 @@
+
+
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 51efeb0e42..1d3661c21f 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -15336,6 +15336,7 @@ virDomainMemballoonDefParseXML(virDomainXMLOptionPtr xmlopt,
VIR_XPATH_NODE_AUTORESTORE(ctxt)
unsigned int period = 0;
g_autofree char *model = NULL;
+ g_autofree char *freepage_reporting = NULL;
g_autofree char *deflate = NULL;
def = g_new0(virDomainMemballoonDef, 1);
@@ -15360,6 +15361,13 @@ virDomainMemballoonDefParseXML(virDomainXMLOptionPtr xmlopt,
goto error;
}
+ if ((freepage_reporting = virXMLPropString(node, "free-page-reporting")) &&
+ (def->free_page_reporting = virTristateSwitchTypeFromString(freepage_reporting)) <= 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("invalid free-page-reporting attribute value '%s'"), freepage_reporting);
+ goto error;
+ }
+
ctxt->node = node;
if (virXPathUInt("string(./stats/@period)", ctxt, &period) < -1) {
virReportError(VIR_ERR_XML_ERROR, "%s",
@@ -23538,6 +23546,15 @@ virDomainMemballoonDefCheckABIStability(virDomainMemballoonDefPtr src,
return false;
}
+ if (src->free_page_reporting != dst->free_page_reporting) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target balloon free-page-reporting attribute value "
+ "'%s' does not match source '%s'"),
+ virTristateSwitchTypeToString(dst->free_page_reporting),
+ virTristateSwitchTypeToString(src->free_page_reporting));
+ return false;
+ }
+
if (src->virtio && dst->virtio &&
!virDomainVirtioOptionsCheckABIStability(src->virtio, dst->virtio))
return false;
@@ -27644,6 +27661,10 @@ virDomainMemballoonDefFormat(virBufferPtr buf,
virBufferAsprintf(&attrBuf, " autodeflate='%s'",
virTristateSwitchTypeToString(def->autodeflate));
+ if (def->free_page_reporting != VIR_TRISTATE_SWITCH_ABSENT)
+ virBufferAsprintf(&attrBuf, " free-page-reporting='%s'",
+ virTristateSwitchTypeToString(def->free_page_reporting));
+
if (def->period)
virBufferAsprintf(&childrenBuf, "\n", def->period);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 450686dfb5..902dd58112 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1790,6 +1790,7 @@ struct _virDomainMemballoonDef {
virDomainDeviceInfo info;
int period; /* seconds between collections */
int autodeflate; /* enum virTristateSwitch */
+ int free_page_reporting; /* enum virTristateSwitch */
virDomainVirtioOptionsPtr virtio;
};