From: Hyman Huang(黄勇) <yong.huang(a)smartx.com>
The upper limit (megabyte/s) of the dirty page rate configured
by the user can be tracked by the XML. To allow this, add the
following XML:
<domain>
...
<vcpu current='2'>3</vcpu>
<vcpus>
<vcpu id='0' hotpluggable='no' dirty_limit='10'
order='1'.../>
<vcpu id='1' hotpluggable='yes' dirty_limit='10'
order='2'.../>
</vcpus>
...
The "dirty_limit" attribute in "vcpu" sub-element within
"vcpus"
element allows to set an upper limit for the individual vCPU. The
value can be set dynamically by limit-dirty-page-rate API.
Note that the dirty limit feature is based on the dirty-ring
feature, so it requires dirty-ring size configuration in XML.
Signed-off-by: Hyman Huang(黄勇) <yong.huang(a)smartx.com>
---
docs/formatdomain.rst | 7 ++++++-
src/conf/domain_conf.c | 26 ++++++++++++++++++++++++
src/conf/domain_conf.h | 8 ++++++++
src/conf/domain_validate.c | 33 +++++++++++++++++++++++++++++++
src/conf/schemas/domaincommon.rng | 5 +++++
5 files changed, 78 insertions(+), 1 deletion(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index bc469e5f9f..337b7ec9cc 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -649,7 +649,7 @@ CPU Allocation
...
<vcpu placement='static' cpuset="1-4,^3,6"
current="1">2</vcpu>
<vcpus>
- <vcpu id='0' enabled='yes' hotpluggable='no'
order='1'/>
+ <vcpu id='0' enabled='yes' hotpluggable='no'
order='1' dirty_limit='64'/>
<vcpu id='1' enabled='no' hotpluggable='yes'/>
</vcpus>
...
@@ -715,6 +715,11 @@ CPU Allocation
be enabled and non-hotpluggable. On PPC64 along with it vCPUs that are in the
same core need to be enabled as well. All non-hotpluggable CPUs present at
boot need to be grouped after vCPU 0. :since:`Since 2.2.0 (QEMU only)`
+ ``dirty_limit`` :since:`Since 9.7.0 (QEMU and KVM only)`
+ The optional attribute ``dirty_limit`` allows to set an upper limit (MB/s)
+ of the dirty page rate for the vCPU. User can change the upper limit value
+ dynamically by using ``limit-dirty-page-rate`` API. Require ``dirty-ring``
+ size configured.
IOThreads Allocation
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 2c8727de54..aff0dba84a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -17088,6 +17088,7 @@ virDomainVcpuParse(virDomainDef *def,
virDomainXMLOption *xmlopt)
{
int n;
+ int rv;
xmlNodePtr vcpuNode;
size_t i;
unsigned int maxvcpus;
@@ -17175,6 +17176,13 @@ virDomainVcpuParse(virDomainDef *def,
if (virXMLPropUInt(nodes[i], "order", 10, VIR_XML_PROP_NONE,
&vcpu->order) < 0)
return -1;
+
+ if ((rv = virXMLPropULongLong(nodes[i], "dirty_limit", 10,
VIR_XML_PROP_NONNEGATIVE,
+ &vcpu->dirty_limit)) < 0) {
+ return -1;
+ } else if (rv > 0) {
+ vcpu->dirtyLimitSet = true;
+ }
}
} else {
if (virDomainDefSetVcpus(def, vcpus) < 0)
@@ -21219,6 +21227,20 @@ virDomainDefVcpuCheckAbiStability(virDomainDef *src,
i);
return false;
}
+
+ if (svcpu->dirtyLimitSet != dvcpu->dirtyLimitSet) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Dirty limit state of vCPU '%1$zu' differs
between source and destination definitions"),
+ i);
+ return false;
+ }
+
+ if (svcpu->dirty_limit != dvcpu->dirty_limit) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Dirty limit of vCPU '%1$zu' differs between
source and destination definitions"),
+ i);
+ return false;
+ }
}
return true;
@@ -26822,6 +26844,10 @@ virDomainCpuDefFormat(virBuffer *buf,
if (vcpu->order != 0)
virBufferAsprintf(buf, " order='%d'", vcpu->order);
+ if (vcpu->dirtyLimitSet) {
+ virBufferAsprintf(buf, " dirty_limit='%llu'",
vcpu->dirty_limit);
+ }
+
virBufferAddLit(buf, "/>\n");
}
virBufferAdjustIndent(buf, -2);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index ca195a52d2..0bca85bec6 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2812,6 +2812,14 @@ struct _virDomainVcpuDef {
virDomainThreadSchedParam sched;
virObject *privateData;
+
+ /* set to true if the dirty page rate upper limit for
+ * the virtual CPU is configured
+ * */
+ bool dirtyLimitSet;
+
+ /* dirty page rate upper limit */
+ unsigned long long dirty_limit;
};
struct _virDomainBlkiotune {
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index b050f21edb..2df9db3467 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -1785,6 +1785,36 @@ virDomainDefValidateIOThreads(const virDomainDef *def)
return 0;
}
+static int
+virDomainDefHasDirtyLimitStartupVcpus(const virDomainDef *def)
+{
+ size_t maxvcpus = virDomainDefGetVcpusMax(def);
+ virDomainVcpuDef *vcpu;
+ size_t i;
+
+ for (i = 0; i < maxvcpus; i++) {
+ vcpu = def->vcpus[i];
+
+ if (vcpu->dirtyLimitSet && (vcpu->dirty_limit != 0))
+ return true;
+ }
+
+ return false;
+}
+
+static int
+virDomainDefDirtyLimitValidate(const virDomainDef *def)
+{
+ if (virDomainDefHasDirtyLimitStartupVcpus(def)) {
+ if (def->kvm_features->dirty_ring_size == 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Dirty limit requires dirty-ring size
configuration"));
+ return -1;
+ }
+ }
+
+ return 0;
+}
static int
virDomainDefValidateInternal(const virDomainDef *def,
@@ -1841,6 +1871,9 @@ virDomainDefValidateInternal(const virDomainDef *def,
if (virDomainDefValidateIOThreads(def) < 0)
return -1;
+ if (virDomainDefDirtyLimitValidate(def) < 0)
+ return -1;
+
return 0;
}
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index 2f9ba31c0a..2e6a744eb4 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -844,6 +844,11 @@
<ref name="unsignedInt"/>
</attribute>
</optional>
+ <optional>
+ <attribute name="dirty_limit">
+ <ref name="unsignedLong"/>
+ </attribute>
+ </optional>
</element>
</zeroOrMore>
</element>
--
2.38.5