On Wed, Aug 03, 2022 at 00:27:47 +0800, ~hyman wrote: > From: Hyman Huang(黄勇) <yong.huang@xxxxxxxxxx> > > Implement qemuDomainSetVcpuDirtyLimit which set dirty page > rate upper limit. > > Signed-off-by: Hyman Huang(黄勇) <yong.huang@xxxxxxxxxx> > --- > src/qemu/qemu_driver.c | 52 ++++++++++++++++++++++++++++++++++++ > src/qemu/qemu_monitor.c | 13 +++++++++ > src/qemu/qemu_monitor.h | 5 ++++ > src/qemu/qemu_monitor_json.c | 45 +++++++++++++++++++++++++++++++ > src/qemu/qemu_monitor_json.h | 5 ++++ > 5 files changed, 120 insertions(+) > > diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c > index 497923ffee..61b992fc51 100644 > --- a/src/qemu/qemu_driver.c > +++ b/src/qemu/qemu_driver.c > @@ -19912,6 +19912,57 @@ qemuDomainFDAssociate(virDomainPtr domain, > return ret; > } > > +static int > +qemuDomainSetVcpuDirtyLimit(virDomainPtr domain, > + int vcpu, > + unsigned long long rate, > + unsigned int flags) > +{ > + virDomainObj *vm = NULL; > + qemuDomainObjPrivate *priv; > + int ret = -1; > + > + if (!(vm = qemuDomainObjFromDomain(domain))) > + return -1; > + > + if (virDomainSetVcpuDirtyLimitEnsureACL(domain->conn, vm->def)) > + goto cleanup; > + > + priv = vm->privateData; > + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VCPU_DIRTY_LIMIT)) { note that priv->qemuCaps is NULL when the VM is not running, so you'll get ... > + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", > + _("QEMU does not support setting dirty page rate limit")); ... this error. > + goto cleanup; > + } > + > + if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) > + goto cleanup; > + > + if (virDomainObjCheckActive(vm) < 0) Instead of this one. You need to reorder these, but that'll be needed regardless when you add the logic for handlign the virDomainModificationImpact flags. > + goto endjob; > + > + qemuDomainObjEnterMonitor(vm); > + if (flags & VIR_DOMAIN_DIRTYLIMIT_VCPU) { > + if (vcpu < 0) { > + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", > + _("Require cpu index to limit dirty page rate")); So is there a need to pass 'vcpu' as 'int' rather than unsigned int? > + goto endjob; This skips over the call to qemuDomainObjExitMonitor; > + } > + ret = qemuMonitorSetVcpuDirtyLimit(priv->mon, vcpu, rate); > + VIR_DEBUG("Set vcpu[%d] dirty page rate limit %lld", vcpu, rate); > + } else { > + ret = qemuMonitorSetVcpuDirtyLimit(priv->mon, -1, rate); > + VIR_DEBUG("Set all vcpus dirty page rate limit %lld of vm", rate); > + } > + qemuDomainObjExitMonitor(vm); > + > + endjob: > + virDomainObjEndJob(vm); > + > + cleanup: > + virDomainObjEndAPI(&vm); > + return ret; > +} > > static virHypervisorDriver qemuHypervisorDriver = { > .name = QEMU_DRIVER_NAME, > @@ -20162,6 +20213,7 @@ static virHypervisorDriver qemuHypervisorDriver = { > .domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 7.2.0 */ > .domainSetLaunchSecurityState = qemuDomainSetLaunchSecurityState, /* 8.0.0 */ > .domainFDAssociate = qemuDomainFDAssociate, /* 9.0.0 */ > + .domainSetVcpuDirtyLimit = qemuDomainSetVcpuDirtyLimit, /* 9.6.0 */ > }; > > > diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c > index c680c4b804..87926edec6 100644 > --- a/src/qemu/qemu_monitor.c > +++ b/src/qemu/qemu_monitor.c > @@ -4505,3 +4505,16 @@ qemuMonitorGetStatsByQOMPath(virJSONValue *arr, > > return NULL; > } > + > + > +int > +qemuMonitorSetVcpuDirtyLimit(qemuMonitor *mon, > + int vcpu, > + unsigned long long rate) > +{ > + VIR_DEBUG("set vcpu %d dirty page rate limit %lld", vcpu, rate); 'rate' is unsigned. > + > + QEMU_CHECK_MONITOR(mon); > + > + return qemuMonitorJSONSetVcpuDirtyLimit(mon, vcpu, rate); > +} > diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h > index 6c590933aa..07a05365cf 100644 > --- a/src/qemu/qemu_monitor.h > +++ b/src/qemu/qemu_monitor.h > @@ -1579,3 +1579,8 @@ qemuMonitorExtractQueryStats(virJSONValue *info); > virJSONValue * > qemuMonitorGetStatsByQOMPath(virJSONValue *arr, > char *qom_path); > + > +int > +qemuMonitorSetVcpuDirtyLimit(qemuMonitor *mon, > + int vcpu, > + unsigned long long rate); > diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c > index d9e9a4481c..732366ab29 100644 > --- a/src/qemu/qemu_monitor_json.c > +++ b/src/qemu/qemu_monitor_json.c > @@ -8889,3 +8889,48 @@ qemuMonitorJSONQueryStats(qemuMonitor *mon, > > return virJSONValueObjectStealArray(reply, "return"); > } > + > +/** > + * qemuMonitorJSONSetVcpuDirtyLimit: > + * @mon: monitor object > + * @vcpu: virtual cpu index to be set, -1 means all virtual cpus > + * @rate: dirty page rate upper limit to be set > + * > + * Returns -1 on failure. > + */ > +int > +qemuMonitorJSONSetVcpuDirtyLimit(qemuMonitor *mon, > + int vcpu, > + unsigned long long rate) > +{ > + g_autoptr(virJSONValue) cmd = NULL; > + g_autoptr(virJSONValue) reply = NULL; > + > + if (vcpu < -1) > + return -1; This doesn't report an error, why everything else does. Also this doesn't really seem to be needed. > + > + if (vcpu >= 0) { > + /* set vcpu dirty page rate limit */ > + if (!(cmd = qemuMonitorJSONMakeCommand("set-vcpu-dirty-limit", > + "i:cpu-index", vcpu, > + "U:dirty-rate", rate, > + NULL))) { > + return -1; > + } > + } else if (vcpu == -1) { > + /* set vm dirty page rate limit */ > + if (!(cmd = qemuMonitorJSONMakeCommand("set-vcpu-dirty-limit", > + "U:dirty-rate", rate, > + NULL))) { Since both use the same command, you can use e.g. 'k:cpu-index': * k: signed integer value, omitted if negative And get rid of the whole if/elseif thing. > + return -1; > + } > + } > + > + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) > + return -1; > + > + if (qemuMonitorJSONCheckError(cmd, reply) < 0) > + return -1; > + > + return 0; > +} > diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h > index 06023b98ea..89f61b3052 100644 > --- a/src/qemu/qemu_monitor_json.h > +++ b/src/qemu/qemu_monitor_json.h > @@ -825,3 +825,8 @@ qemuMonitorJSONQueryStats(qemuMonitor *mon, > qemuMonitorQueryStatsTargetType target, > char **vcpus, > GPtrArray *providers); > + > +int > +qemuMonitorJSONSetVcpuDirtyLimit(qemuMonitor *mon, > + int vcpu, > + unsigned long long rate); > -- > 2.38.5 >