[PATCH v1 00/10] Dirty page rate limit support

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> Ping How about this series? hoping to get comments if anyone has played with it. Thanks very much sincerely. Yong v1: - rebase on master and fix conflicts - filter out dirty page limit info for hotpluggable vcpu but not active - drop the documents patch, which can be post later after main series being reviewed. - code clean Abstract ======== Qemu introduced dirty page rate limit feature in 7.1.0, see the details in the following link: https://lore.kernel.org/qemu-devel/cover.1656177590.git.huangy81@chinateleco... So may be it's the right time to enabling this feature in libvirt meanwhile so that upper user can play with it. Expecting the upper app can use this feature to do a vcpu Qos or whatever else. This patch add 2 new apis to implement dirty page rate limit: 1. virDomainSetVcpuDirtyLimit, which set vcpu dirty page rate limit. virsh command 'vcpudirtylimit' also implemented correspondingly. 2. virDomainCancelVcpuDirtyLimit, which cancel vcpu dirty page rate limit. 'cancel' option was introduced to 'vcpudirtylimit' to cancel the limit correspondingly. In addition, function 'qemuMonitorQueryVcpuDirtyLimit' was implemented to query dirty page rate limit, virsh command 'vcpuinfo' was extended so that user can query dirty page rate limit info via 'vcpuinfo'. This series make main modifications as the following: - introduce QEMU_CAPS_VCPU_DIRTY_LIMIT capability so that libvirt can probe before using dirty page rate limit feature. - implement virsh command 'vcpudirtylimit' to set/cancel dirty page rate limit. - extend vcpuinfo api so that it can display dirtylimit info. Please review, thanks! Best regards! Hyman Huang(黄勇) (10): qemu_capabilities: Introduce QEMU_CAPS_VCPU_DIRTY_LIMIT capability libvirt: Add virDomainSetVcpuDirtyLimit API qemu_driver: Implement qemuDomainSetVcpuDirtyLimit virsh: Introduce vcpudirtylimit api qemu_monitor: Implement qemuMonitorQueryVcpuDirtyLimit qemu_driver: Extend qemuDomainGetVcpus for dirtylimit virsh: Extend vcpuinfo api to display dirtylimit info libvirt: Add virDomainCancelVcpuDirtyLimit API qemu_driver: Implement qemuDomainCancelVcpuDirtyLimit virsh: Add cancel option to vcpudirtylimit api include/libvirt/libvirt-domain.h | 22 ++++ src/driver-hypervisor.h | 13 ++ src/libvirt-domain.c | 94 ++++++++++++++ src/libvirt_public.syms | 6 + src/qemu/qemu_capabilities.c | 2 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_driver.c | 156 +++++++++++++++++++++++ src/qemu/qemu_monitor.c | 36 ++++++ src/qemu/qemu_monitor.h | 26 ++++ src/qemu/qemu_monitor_json.c | 138 ++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 13 ++ src/remote/remote_daemon_dispatch.c | 2 + src/remote/remote_driver.c | 4 + src/remote/remote_protocol.x | 30 ++++- src/remote_protocol-structs | 13 ++ tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml | 1 + tools/virsh-domain.c | 112 ++++++++++++++++ 17 files changed, 667 insertions(+), 2 deletions(-) -- 1.8.3.1

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> set-vcpu-dirty-limit/cancel-vcpu-dirty-limit/query-vcpu-dirty-limit were introduced since qemu >=7.1.0. Introduce corresponding capability. Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml | 1 + 3 files changed, 4 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index c5338f6..4f32556 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -676,6 +676,7 @@ VIR_ENUM_IMPL(virQEMUCaps, /* 435 */ "query-stats", /* QEMU_CAPS_QUERY_STATS */ + "set-vcpu-dirty-limit", /* QEMU_CAPS_VCPU_DIRTY_LIMIT */ ); @@ -1226,6 +1227,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = { { "sev-inject-launch-secret", QEMU_CAPS_SEV_INJECT_LAUNCH_SECRET }, { "calc-dirty-rate", QEMU_CAPS_CALC_DIRTY_RATE }, { "query-stats", QEMU_CAPS_QUERY_STATS }, + { "set-vcpu-dirty-limit", QEMU_CAPS_VCPU_DIRTY_LIMIT }, }; struct virQEMUCapsStringFlags virQEMUCapsMigration[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 8e77729..7b2947e 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -655,6 +655,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 435 */ QEMU_CAPS_QUERY_STATS, /* accepts query-stats */ + QEMU_CAPS_VCPU_DIRTY_LIMIT, /* 'set-vcpu-dirty-limit' QMP command present */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml index a7a3bd7..e48a2b1 100644 --- a/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml @@ -223,6 +223,7 @@ <flag name='usb-host.guest-resets-all'/> <flag name='migration.blocked-reasons'/> <flag name='query-stats'/> + <flag name='set-vcpu-dirty-limit'/> <version>7000050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100244</microcodeVersion> -- 1.8.3.1

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> Introduce virDomainSetVcpuDirtyLimit API to set upper limit of dirty page rate. Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> --- include/libvirt/libvirt-domain.h | 16 +++++++++++++ src/driver-hypervisor.h | 7 ++++++ src/libvirt-domain.c | 51 ++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 16 +++++++++++-- src/remote_protocol-structs | 7 ++++++ 7 files changed, 101 insertions(+), 2 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 7430a08..2e49224 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -6452,4 +6452,20 @@ int virDomainStartDirtyRateCalc(virDomainPtr domain, int seconds, unsigned int flags); +/** + * virDomainDirtyLimitFlags: + * + * Since: 8.7.0 + */ +typedef enum { + VIR_DOMAIN_DIRTYLIMIT_VCPU = (1 << 0), /* render specified virtual CPU for + dirty page rate limit (Since: 8.7.0) */ + VIR_DOMAIN_DIRTYLIMIT_ALL = (1 << 1), /* render all virtual CPU for dirty + page rate limit (Since: 8.7.0) */ +} virDomainDirtyLimitFlags; + +int virDomainSetVcpuDirtyLimit(virDomainPtr domain, + int vcpu, + unsigned long long rate, + unsigned int flags); #endif /* LIBVIRT_DOMAIN_H */ diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index 016d5ce..ac59da6 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1441,6 +1441,12 @@ typedef int int seconds, unsigned int flags); +typedef int +(*virDrvDomainSetVcpuDirtyLimit)(virDomainPtr domain, + int vcpu, + unsigned long long rate, + unsigned int flags); + typedef struct _virHypervisorDriver virHypervisorDriver; /** @@ -1712,4 +1718,5 @@ struct _virHypervisorDriver { virDrvDomainAuthorizedSSHKeysSet domainAuthorizedSSHKeysSet; virDrvDomainGetMessages domainGetMessages; virDrvDomainStartDirtyRateCalc domainStartDirtyRateCalc; + virDrvDomainSetVcpuDirtyLimit domainSetVcpuDirtyLimit; }; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 842663a..be9825b 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -13929,3 +13929,54 @@ virDomainStartDirtyRateCalc(virDomainPtr domain, virDispatchError(conn); return -1; } + +/** + * virDomainSetVcpuDirtyLimit: + * @domain: pointer to domain object, or NULL for Domain0 + * @vcpu: (optional) virtual CPU number + * @rate: upper limit of dirty page rate (MB/s) for virtual CPUs + * @flags: bitwise-OR of supported virDomainDirtyLimitFlags + * + * Dynamically set the upper dirty page rate limit of the virtual CPUs. + * + * Returns 0 in case of success, -1 in case of failure. + * + * Since: 8.7.0 + */ +int +virDomainSetVcpuDirtyLimit(virDomainPtr domain, + int vcpu, + unsigned long long rate, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "vcpu=%d, dirty page rate limit=%lld", + vcpu, rate); + + virResetLastError(); + + virCheckDomainReturn(domain, -1); + conn = domain->conn; + + virCheckReadOnlyGoto(conn->flags, error); + virCheckPositiveArgGoto(rate, error); + + VIR_EXCLUSIVE_FLAGS_GOTO(VIR_DOMAIN_DIRTYLIMIT_VCPU, + VIR_DOMAIN_DIRTYLIMIT_ALL, + error); + + if (conn->driver->domainSetVcpuDirtyLimit) { + int ret; + ret = conn->driver->domainSetVcpuDirtyLimit(domain, vcpu, rate, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(domain->conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 297a2c4..8ebcf50 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -927,4 +927,9 @@ LIBVIRT_8.5.0 { virDomainAbortJobFlags; } LIBVIRT_8.4.0; +LIBVIRT_8.7.0 { + global: + virDomainSetVcpuDirtyLimit; +} LIBVIRT_8.5.0; + # .... define new API here using predicted next version number .... diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 0ca365c..f673fed 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8652,6 +8652,7 @@ static virHypervisorDriver hypervisor_driver = { .domainGetMessages = remoteDomainGetMessages, /* 7.1.0 */ .domainStartDirtyRateCalc = remoteDomainStartDirtyRateCalc, /* 7.2.0 */ .domainSetLaunchSecurityState = remoteDomainSetLaunchSecurityState, /* 8.0.0 */ + .domainSetVcpuDirtyLimit = remoteDomainSetVcpuDirtyLimit, /* 8.7.0 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 79ffc63..e6c18a4 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3921,7 +3921,6 @@ struct remote_domain_start_dirty_rate_calc_args { unsigned int flags; }; - struct remote_domain_event_memory_device_size_change_msg { int callbackID; remote_nonnull_domain dom; @@ -3929,6 +3928,13 @@ struct remote_domain_event_memory_device_size_change_msg { unsigned hyper size; }; +struct remote_domain_set_vcpu_dirty_limit_args { + remote_nonnull_domain dom; + int vcpu; + unsigned hyper rate; + unsigned int flags; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -6959,5 +6965,11 @@ enum remote_procedure { * @generate: both * @acl: domain:write */ - REMOTE_PROC_DOMAIN_ABORT_JOB_FLAGS = 442 + REMOTE_PROC_DOMAIN_ABORT_JOB_FLAGS = 442, + + /** + * @generate: both + * @acl: domain:write + */ + REMOTE_PROC_DOMAIN_SET_VCPU_DIRTY_LIMIT = 443 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index ca52224..8ff2a86 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -3268,6 +3268,12 @@ struct remote_domain_event_memory_device_size_change_msg { remote_nonnull_string alias; uint64_t size; }; +struct remote_domain_set_vcpu_dirty_limit_args { + remote_nonnull_domain dom; + int vcpu; + uint64_t rate; + u_int flags; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -3711,4 +3717,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SAVE_PARAMS = 440, REMOTE_PROC_DOMAIN_RESTORE_PARAMS = 441, REMOTE_PROC_DOMAIN_ABORT_JOB_FLAGS = 442, + REMOTE_PROC_DOMAIN_SET_VCPU_DIRTY_LIMIT = 443, }; -- 1.8.3.1

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> Implement qemuDomainSetVcpuDirtyLimit which set dirty page rate limit. Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> --- src/qemu/qemu_driver.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 13 ++++++++++++ src/qemu/qemu_monitor.h | 5 +++++ src/qemu/qemu_monitor_json.c | 39 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++++ 5 files changed, 109 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 707f4cc..981027a 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20766,6 +20766,52 @@ qemuDomainStartDirtyRateCalc(virDomainPtr dom, 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; + + priv = vm->privateData; + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VCPU_DIRTY_LIMIT)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("QEMU does not support setting dirty page rate limit")); + goto cleanup; + } + + if (qemuDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) + goto cleanup; + + if (virDomainSetVcpuDirtyLimitEnsureACL(domain->conn, vm->def) < 0) + goto endjob; + + if (virDomainObjCheckActive(vm) < 0) + goto endjob; + + qemuDomainObjEnterMonitor(vm); + if (flags & VIR_DOMAIN_DIRTYLIMIT_VCPU) { + VIR_DEBUG("Set vcpu[%d] dirty page rate limit %lld", vcpu, rate); + ret = qemuMonitorSetVcpuDirtyLimit(priv->mon, vcpu, rate); + } else { + VIR_DEBUG("Set all vcpus dirty page rate limit %lld of vm", rate); + ret = qemuMonitorSetVcpuDirtyLimit(priv->mon, -1, rate); + } + qemuDomainObjExitMonitor(vm); + + endjob: + qemuDomainObjEndJob(vm); + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} static virHypervisorDriver qemuHypervisorDriver = { .name = QEMU_DRIVER_NAME, @@ -21015,6 +21061,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainGetMessages = qemuDomainGetMessages, /* 7.1.0 */ .domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 7.2.0 */ .domainSetLaunchSecurityState = qemuDomainSetLaunchSecurityState, /* 8.0.0 */ + .domainSetVcpuDirtyLimit = qemuDomainSetVcpuDirtyLimit, /* 8.7.0 */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index c2808c7..49477ff 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4417,3 +4417,16 @@ qemuMonitorExtractQueryStats(virJSONValue *info) return g_steal_pointer(&hash_table); } + + +int +qemuMonitorSetVcpuDirtyLimit(qemuMonitor *mon, + int vcpu, + unsigned long long rate) +{ + VIR_DEBUG("set vcpu %d dirty page rate limit %lld", vcpu, rate); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONSetVcpuDirtyLimit(mon, vcpu, rate); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 63269e1..fade35e 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1529,3 +1529,8 @@ qemuMonitorQueryStats(qemuMonitor *mon, GHashTable * qemuMonitorExtractQueryStats(virJSONValue *info); + +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 70fba50..68a8ca6 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -8665,3 +8665,42 @@ qemuMonitorJSONQueryStats(qemuMonitor *mon, return virJSONValueObjectStealArray(reply, "return"); } + + +int +qemuMonitorJSONSetVcpuDirtyLimit(qemuMonitor *mon, + int vcpu, + unsigned long long rate) +{ + g_autoptr(virJSONValue) cmd = NULL; + g_autoptr(virJSONValue) reply = NULL; + + 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))) { + return -1; + } + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected vcpu index %d"), vcpu); + 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 a53e642..07944c7 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -818,3 +818,8 @@ qemuMonitorJSONQueryStats(qemuMonitor *mon, qemuMonitorQueryStatsTargetType target, char **vcpus, GPtrArray *providers); + +int +qemuMonitorJSONSetVcpuDirtyLimit(qemuMonitor *mon, + int vcpu, + unsigned long long rate); -- 1.8.3.1

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> Introduce vcpudirtylimit virsh api to set dirty page rate limit for virtual CPUs: $ virsh vcpudirtylimit <domain> <rate> [--vcpu <number>] Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> --- tools/virsh-domain.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 20aadb5..8705090 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -13764,6 +13764,83 @@ cmdDomDirtyRateCalc(vshControl *ctl, const vshCmd *cmd) return true; } +/* + * "vcpudirtylimit" command + */ +static const vshCmdInfo info_vcpu_dirty_limit[] = { + {.name = "help", + .data = N_("Set vcpu dirty page rate limit.") + }, + {.name = "desc", + .data = N_("Set dirty page rate limit on virtual CPU.") + }, + {.name = NULL} +}; + +static const vshCmdOptDef opts_vcpu_dirty_limit[] = { + VIRSH_COMMON_OPT_DOMAIN_FULL(0), + {.name = "rate", + .type = VSH_OT_INT, + .flags = VSH_OFLAG_REQ, + .help = N_("Upper limit of dirty page rate (MB/s) for " + "virtual CPUs.") + }, + {.name = "vcpu", + .type = VSH_OT_INT, + .help = N_("Index of a virtual CPU.") + }, + {.name = NULL} +}; + +static bool +cmdVcpuDirtyLimit(vshControl *ctl, const vshCmd *cmd) +{ + g_autoptr(virshDomain) dom = NULL; + int vcpu_idx = -1; + unsigned long long rate = 0; + bool vcpu = vshCommandOptBool(cmd, "vcpu"); + unsigned int flags = 0; + + if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (vcpu) { + if (vshCommandOptInt(ctl, cmd, "vcpu", &vcpu_idx) < 0) + return false; + + if (vcpu_idx < 0) { + vshError(ctl, "%s", _("Invalid vcpu index, using --vcpu " + "to specify cpu index")); + return false; + } + } + + if (vshCommandOptULongLong(ctl, cmd, "rate", &rate) < 0) + return false; + + if (!rate) { + vshError(ctl, "%s", _("Invalid dirty page rate limit")); + return false; + } + + if (vcpu) { + /* set specified vcpu dirty page rate limit of vm */ + if (virDomainSetVcpuDirtyLimit(dom, vcpu_idx, + rate, flags | VIR_DOMAIN_DIRTYLIMIT_VCPU) < 0) + return false; + vshPrintExtra(ctl, _("Set vcpu[%d] dirty page rate limit " + "%lld successfully.\n"), vcpu_idx, rate); + } else { + /* set all vcpu dirty page rate limit of vm */ + if (virDomainSetVcpuDirtyLimit(dom, -1, + rate, flags | VIR_DOMAIN_DIRTYLIMIT_ALL) < 0) + return false; + vshPrintExtra(ctl, _("Set dirty page rate limit %lld on all " + "virtual CPUs successfully.\n"), rate); + } + + return true; +} const vshCmdDef domManagementCmds[] = { {.name = "attach-device", @@ -14422,5 +14499,11 @@ const vshCmdDef domManagementCmds[] = { .info = info_domdirtyrate_calc, .flags = 0 }, + {.name = "vcpudirtylimit", + .handler = cmdVcpuDirtyLimit, + .opts = opts_vcpu_dirty_limit, + .info = info_vcpu_dirty_limit, + .flags = 0 + }, {.name = NULL} }; -- 1.8.3.1

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> Implement qemuMonitorQueryVcpuDirtyLimit which query vcpu dirty limit info by calling qmp 'query-vcpu-dirty-limit'. Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> --- src/qemu/qemu_monitor.c | 12 +++++++++ src/qemu/qemu_monitor.h | 17 ++++++++++++ src/qemu/qemu_monitor_json.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 +++ 4 files changed, 97 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 49477ff..ab4ba2f 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4430,3 +4430,15 @@ qemuMonitorSetVcpuDirtyLimit(qemuMonitor *mon, return qemuMonitorJSONSetVcpuDirtyLimit(mon, vcpu, rate); } + + +int +qemuMonitorQueryVcpuDirtyLimit(qemuMonitor *mon, + qemuMonitorVcpuDirtyLimitInfo *info) +{ + VIR_DEBUG("info=%p", info); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONQueryVcpuDirtyLimit(mon, info); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index fade35e..bd5dd2b 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1534,3 +1534,20 @@ int qemuMonitorSetVcpuDirtyLimit(qemuMonitor *mon, int vcpu, unsigned long long rate); + +typedef struct _qemuMonitorVcpuDirtyLimit qemuMonitorVcpuDirtyLimit; +struct _qemuMonitorVcpuDirtyLimit { + int idx; /* virtual cpu index */ + unsigned long long limit; /* virtual cpu dirty page rate limit in MB/s */ + unsigned long long current; /* virtual cpu dirty page rate in MB/s */ +}; + +typedef struct _qemuMonitorVcpuDirtyLimitInfo qemuMonitorVcpuDirtyLimitInfo; +struct _qemuMonitorVcpuDirtyLimitInfo { + size_t nvcpus; /* number of virtual cpu */ + qemuMonitorVcpuDirtyLimit *limits; /* array of dirty page rate limit */ +}; + +int +qemuMonitorQueryVcpuDirtyLimit(qemuMonitor *mon, + qemuMonitorVcpuDirtyLimitInfo *info); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 68a8ca6..1d4c6f5 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -8704,3 +8704,67 @@ qemuMonitorJSONSetVcpuDirtyLimit(qemuMonitor *mon, return 0; } + +static int +qemuMonitorJSONExtractVcpuDirtyLimitInfo(virJSONValue *data, + qemuMonitorVcpuDirtyLimitInfo *info) +{ + size_t nvcpus; + size_t i; + + nvcpus = virJSONValueArraySize(data); + info->nvcpus = nvcpus; + info->limits = g_new0(qemuMonitorVcpuDirtyLimit, nvcpus); + + for (i = 0; i < nvcpus; i++) { + virJSONValue *entry = virJSONValueArrayGet(data, i); + if (virJSONValueObjectGetNumberInt(entry, "cpu-index", + &info->limits[i].idx) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-vcpu-dirty-limit reply was missing 'cpu-index' data")); + return -1; + } + + if (virJSONValueObjectGetNumberUlong(entry, "limit-rate", + &info->limits[i].limit) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-vcpu-dirty-limit reply was missing 'limit-rate' data")); + return -1; + } + + if (virJSONValueObjectGetNumberUlong(entry, "current-rate", + &info->limits[i].current) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-vcpu-dirty-limit reply was missing 'current-rate' data")); + return -1; + } + } + + return 0; +} + +int +qemuMonitorJSONQueryVcpuDirtyLimit(qemuMonitor *mon, + qemuMonitorVcpuDirtyLimitInfo *info) +{ + g_autoptr(virJSONValue) cmd = NULL; + g_autoptr(virJSONValue) reply = NULL; + virJSONValue *data = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-vcpu-dirty-limit", NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + return -1; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + return -1; + + if (!(data = virJSONValueObjectGetArray(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-vcpu-dirty-limit reply was missing 'return' data")); + return -1; + } + + return qemuMonitorJSONExtractVcpuDirtyLimitInfo(data, info); +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 07944c7..388d5b0 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -823,3 +823,7 @@ int qemuMonitorJSONSetVcpuDirtyLimit(qemuMonitor *mon, int vcpu, unsigned long long rate); + +int +qemuMonitorJSONQueryVcpuDirtyLimit(qemuMonitor *mon, + qemuMonitorVcpuDirtyLimitInfo *info); -- 1.8.3.1

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> Extend qemuDomainGetVcpus for getting dirtylimit info so that 'virsh vcpuinfo' api can display vcpu dirty page rate limit. Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> --- include/libvirt/libvirt-domain.h | 2 ++ src/qemu/qemu_driver.c | 62 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 2e49224..24348d0 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -2365,6 +2365,8 @@ struct _virVcpuInfo { int state; /* value from virVcpuState */ unsigned long long cpuTime; /* CPU time used, in nanoseconds */ int cpu; /* real CPU number, or one of the values from virVcpuHostCpuState */ + unsigned long long limit; /* virtual cpu dirty page rate limit in MB/s */ + unsigned long long current; /* virtual cpu dirty page rate in MB/s */ }; /** diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 981027a..235a187 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4756,6 +4756,64 @@ qemuDomainGetEmulatorPinInfo(virDomainPtr dom, } static int +qemuDomainGetVcpuDirtyLimit(virDomainPtr dom, + virDomainObj *vm, + virVcpuInfoPtr info, + int maxinfo) +{ + qemuDomainObjPrivate *priv = vm->privateData; + qemuMonitorVcpuDirtyLimitInfo dirtylimit_info; + size_t ncpuinfo = 0; + size_t i; + int ret = -1; + + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VCPU_DIRTY_LIMIT)) + return 0; + + if (qemuDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) + goto endjob; + + if (virDomainObjCheckActive(vm) < 0) + goto endjob; + + qemuDomainObjEnterMonitor(vm); + if (qemuMonitorQueryVcpuDirtyLimit(priv->mon, &dirtylimit_info) < 0) { + qemuDomainObjExitMonitor(vm); + goto endjob; + } + qemuDomainObjExitMonitor(vm); + + /* qemu allow to set dirty page limit for hotpluggable vcpu, which + * therefore may return unhotpluggable vcpu dirty limit info for + * qmp command 'query-vcpu-dirty-limit', filter out that */ + for (i = 0; i < dirtylimit_info.nvcpus && ncpuinfo < maxinfo; i++) { + int cpu_index = dirtylimit_info.limits[i].idx; + + /* cpu index greater than array size of cpu info, which means + * the remaining cpus are hotpluggable but not active */ + if (cpu_index >= maxinfo) + break; + + virDomainVcpuDef *vcpu = virDomainDefGetVcpu(vm->def, cpu_index); + + if (!vcpu->online) + continue; + + virVcpuInfoPtr vcpuinfo = info + cpu_index; + + vcpuinfo->current = dirtylimit_info.limits[i].current; + vcpuinfo->limit = dirtylimit_info.limits[i].limit; + + ncpuinfo++; + } + ret = 0; + + endjob: + qemuDomainObjEndJob(vm); + return ret; +} + +static int qemuDomainGetVcpus(virDomainPtr dom, virVcpuInfoPtr info, int maxinfo, @@ -4779,6 +4837,10 @@ qemuDomainGetVcpus(virDomainPtr dom, ret = qemuDomainHelperGetVcpus(vm, info, NULL, NULL, maxinfo, cpumaps, maplen); + /* append dirty limit data to vcpu info */ + if (qemuDomainGetVcpuDirtyLimit(dom, vm, info, maxinfo) < 0) + goto cleanup; + cleanup: virDomainObjEndAPI(&vm); return ret; -- 1.8.3.1

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> Extend vcpuinfo api so that 'virsh vcpuinfo domain' can display dirtylimit info for active virtual cpu, which can be set by using 'virsh vcpudirtylimit'. Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> --- src/remote/remote_daemon_dispatch.c | 2 ++ src/remote/remote_driver.c | 2 ++ src/remote/remote_protocol.x | 2 ++ tools/virsh-domain.c | 5 +++++ 4 files changed, 11 insertions(+) diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c index dc5790f..9d6b66c 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -2891,6 +2891,8 @@ remoteDispatchDomainGetVcpus(virNetServer *server G_GNUC_UNUSED, ret->info.info_val[i].state = info[i].state; ret->info.info_val[i].cpu_time = info[i].cpuTime; ret->info.info_val[i].cpu = info[i].cpu; + ret->info.info_val[i].limit = info[i].limit; + ret->info.info_val[i].current = info[i].current; } /* Don't need to allocate/copy the cpumaps if we make the reasonable diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index f673fed..5fc1a61 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2201,6 +2201,8 @@ remoteDomainGetVcpus(virDomainPtr domain, info[i].state = ret.info.info_val[i].state; info[i].cpuTime = ret.info.info_val[i].cpu_time; info[i].cpu = ret.info.info_val[i].cpu; + info[i].limit = ret.info.info_val[i].limit; + info[i].current = ret.info.info_val[i].current; } for (i = 0; i < ret.cpumaps.cpumaps_len; ++i) diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index e6c18a4..874ce19 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -416,6 +416,8 @@ struct remote_vcpu_info { int state; unsigned hyper cpu_time; int cpu; + unsigned hyper limit; + unsigned hyper current; }; /* Wire encoding of virTypedParameter. diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 8705090..08fe259 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -6935,6 +6935,11 @@ cmdVcpuinfo(vshControl *ctl, const vshCmd *cmd) maxcpu, pretty) < 0) return false; + if (cpuinfo[n].limit != 0) { + vshPrint(ctl, "%-15s %lld\n", _("DirtyRate limit:"), cpuinfo[n].limit); + vshPrint(ctl, "%-15s %lld\n", _("DirtyRate current:"), cpuinfo[n].current); + } + if (n < (ncpus - 1)) vshPrint(ctl, "\n"); } -- 1.8.3.1

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> Introduce virDomainCancelVcpuDirtyLimit API to cancel upper limit of dirty page rate. Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> --- include/libvirt/libvirt-domain.h | 4 ++++ src/driver-hypervisor.h | 6 ++++++ src/libvirt-domain.c | 43 ++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 1 + src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 14 ++++++++++++- src/remote_protocol-structs | 6 ++++++ 7 files changed, 74 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 24348d0..cc48615 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -6470,4 +6470,8 @@ int virDomainSetVcpuDirtyLimit(virDomainPtr domain, int vcpu, unsigned long long rate, unsigned int flags); + +int virDomainCancelVcpuDirtyLimit(virDomainPtr domain, + int vcpu, + unsigned int flags); #endif /* LIBVIRT_DOMAIN_H */ diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index ac59da6..2b14d33 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1447,6 +1447,11 @@ typedef int unsigned long long rate, unsigned int flags); +typedef int +(*virDrvDomainCancelVcpuDirtyLimit)(virDomainPtr domain, + int vcpu, + unsigned int flags); + typedef struct _virHypervisorDriver virHypervisorDriver; /** @@ -1719,4 +1724,5 @@ struct _virHypervisorDriver { virDrvDomainGetMessages domainGetMessages; virDrvDomainStartDirtyRateCalc domainStartDirtyRateCalc; virDrvDomainSetVcpuDirtyLimit domainSetVcpuDirtyLimit; + virDrvDomainCancelVcpuDirtyLimit domainCancelVcpuDirtyLimit; }; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index be9825b..27a8bb6 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -13980,3 +13980,46 @@ virDomainSetVcpuDirtyLimit(virDomainPtr domain, virDispatchError(domain->conn); return -1; } + +/** + * virDomainCancelVcpuDirtyLimit: + * @domain: pointer to domain object, or NULL for Domain0 + * @vcpu: virtual CPU number + * @flags: bitwise-OR of supported virDomainDirtyLimitFlags + * + * Dynamically cancel the upper dirty page rate limit of the virtual CPUs. + * + * Returns 0 in case of success, -1 in case of failure. + * + * Since: 8.7.0 + */ +int +virDomainCancelVcpuDirtyLimit(virDomainPtr domain, + int vcpu, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "cancel vcpu[%d] dirty page rate limit", vcpu); + + virResetLastError(); + + virCheckDomainReturn(domain, -1); + conn = domain->conn; + + virCheckReadOnlyGoto(conn->flags, error); + + if (conn->driver->domainCancelVcpuDirtyLimit) { + int ret; + ret = conn->driver->domainCancelVcpuDirtyLimit(domain, vcpu, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(domain->conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 8ebcf50..d7556f7 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -930,6 +930,7 @@ LIBVIRT_8.5.0 { LIBVIRT_8.7.0 { global: virDomainSetVcpuDirtyLimit; + virDomainCancelVcpuDirtyLimit; } LIBVIRT_8.5.0; # .... define new API here using predicted next version number .... diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 5fc1a61..bdda2aa 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8655,6 +8655,7 @@ static virHypervisorDriver hypervisor_driver = { .domainStartDirtyRateCalc = remoteDomainStartDirtyRateCalc, /* 7.2.0 */ .domainSetLaunchSecurityState = remoteDomainSetLaunchSecurityState, /* 8.0.0 */ .domainSetVcpuDirtyLimit = remoteDomainSetVcpuDirtyLimit, /* 8.7.0 */ + .domainCancelVcpuDirtyLimit = remoteDomainCancelVcpuDirtyLimit, /* 8.7.0 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 874ce19..3a898d0 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3937,6 +3937,12 @@ struct remote_domain_set_vcpu_dirty_limit_args { unsigned int flags; }; +struct remote_domain_cancel_vcpu_dirty_limit_args { + remote_nonnull_domain dom; + int vcpu; + unsigned int flags; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -6973,5 +6979,11 @@ enum remote_procedure { * @generate: both * @acl: domain:write */ - REMOTE_PROC_DOMAIN_SET_VCPU_DIRTY_LIMIT = 443 + REMOTE_PROC_DOMAIN_SET_VCPU_DIRTY_LIMIT = 443, + + /** + * @generate: both + * @acl: domain:write + */ + REMOTE_PROC_DOMAIN_CANCEL_VCPU_DIRTY_LIMIT = 444 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 8ff2a86..c615c87 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -3274,6 +3274,11 @@ struct remote_domain_set_vcpu_dirty_limit_args { uint64_t rate; u_int flags; }; +struct remote_domain_cancel_vcpu_dirty_limit_args { + remote_nonnull_domain dom; + int vcpu; + u_int flags; +}; enum remote_procedure { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -3718,4 +3723,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_RESTORE_PARAMS = 441, REMOTE_PROC_DOMAIN_ABORT_JOB_FLAGS = 442, REMOTE_PROC_DOMAIN_SET_VCPU_DIRTY_LIMIT = 443, + REMOTE_PROC_DOMAIN_SET_VCPU_DIRTY_LIMIT = 444, }; -- 1.8.3.1

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> Implement qemuDomainCancelVcpuDirtyLimit to cancel vcpu dirty page rate limit. Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> --- src/qemu/qemu_driver.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 11 +++++++++++ src/qemu/qemu_monitor.h | 4 ++++ src/qemu/qemu_monitor_json.c | 35 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 ++++ 5 files changed, 101 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 235a187..3783582 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20875,6 +20875,52 @@ qemuDomainSetVcpuDirtyLimit(virDomainPtr domain, return ret; } +static int +qemuDomainCancelVcpuDirtyLimit(virDomainPtr domain, + int vcpu, + unsigned int flags) +{ + virDomainObj *vm = NULL; + qemuDomainObjPrivate *priv; + int ret = -1; + + if (!(vm = qemuDomainObjFromDomain(domain))) + return -1; + + priv = vm->privateData; + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_VCPU_DIRTY_LIMIT)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("QEMU does not support setting vcpu dirty page rate limit")); + goto cleanup; + } + + if (qemuDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) + goto cleanup; + + if (virDomainCancelVcpuDirtyLimitEnsureACL(domain->conn, vm->def) < 0) + goto endjob; + + if (virDomainObjCheckActive(vm) < 0) + goto endjob; + + qemuDomainObjEnterMonitor(vm); + if (flags & VIR_DOMAIN_DIRTYLIMIT_VCPU) { + VIR_DEBUG("Cancel vcpu[%d] dirty page rate limit", vcpu); + ret = qemuMonitorCancelVcpuDirtyLimit(priv->mon, vcpu); + } else { + VIR_DEBUG("Cancel all vcpus dirty page rate limit of vm"); + ret = qemuMonitorCancelVcpuDirtyLimit(priv->mon, -1); + } + qemuDomainObjExitMonitor(vm); + + endjob: + qemuDomainObjEndJob(vm); + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + static virHypervisorDriver qemuHypervisorDriver = { .name = QEMU_DRIVER_NAME, .connectURIProbe = qemuConnectURIProbe, @@ -21124,6 +21170,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 7.2.0 */ .domainSetLaunchSecurityState = qemuDomainSetLaunchSecurityState, /* 8.0.0 */ .domainSetVcpuDirtyLimit = qemuDomainSetVcpuDirtyLimit, /* 8.7.0 */ + .domainCancelVcpuDirtyLimit = qemuDomainCancelVcpuDirtyLimit, /* 8.7.0 */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index ab4ba2f..7274624 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4442,3 +4442,14 @@ qemuMonitorQueryVcpuDirtyLimit(qemuMonitor *mon, return qemuMonitorJSONQueryVcpuDirtyLimit(mon, info); } + +int +qemuMonitorCancelVcpuDirtyLimit(qemuMonitor *mon, + int vcpu) +{ + VIR_DEBUG("cancel vcpu %d dirty page rate limit", vcpu); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONCancelVcpuDirtyLimit(mon, vcpu); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index bd5dd2b..c8c3547 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1551,3 +1551,7 @@ struct _qemuMonitorVcpuDirtyLimitInfo { int qemuMonitorQueryVcpuDirtyLimit(qemuMonitor *mon, qemuMonitorVcpuDirtyLimitInfo *info); + +int +qemuMonitorCancelVcpuDirtyLimit(qemuMonitor *mon, + int vcpu); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 1d4c6f5..261a467 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -8768,3 +8768,38 @@ qemuMonitorJSONQueryVcpuDirtyLimit(qemuMonitor *mon, return qemuMonitorJSONExtractVcpuDirtyLimitInfo(data, info); } + +int +qemuMonitorJSONCancelVcpuDirtyLimit(qemuMonitor *mon, + int vcpu) +{ + g_autoptr(virJSONValue) cmd = NULL; + g_autoptr(virJSONValue) reply = NULL; + + if (vcpu >= 0) { + /* cancel vcpu dirty page rate limit */ + if (!(cmd = qemuMonitorJSONMakeCommand("cancel-vcpu-dirty-limit", + "i:cpu-index", vcpu, + NULL))) { + return -1; + } + } else if (vcpu == -1) { + /* cancel vm dirty page rate limit */ + if (!(cmd = qemuMonitorJSONMakeCommand("cancel-vcpu-dirty-limit", + NULL))) { + return -1; + } + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected vcpu index %d"), vcpu); + 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 388d5b0..7b65f14 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -827,3 +827,7 @@ qemuMonitorJSONSetVcpuDirtyLimit(qemuMonitor *mon, int qemuMonitorJSONQueryVcpuDirtyLimit(qemuMonitor *mon, qemuMonitorVcpuDirtyLimitInfo *info); + +int +qemuMonitorJSONCancelVcpuDirtyLimit(qemuMonitor *mon, + int vcpu); -- 1.8.3.1

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> Add cancel option to vcpudirtylimit api to cancel dirty page rate limit for virtual CPUs. Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> --- tools/virsh-domain.c | 64 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 08fe259..12b08ca 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -13786,7 +13786,6 @@ static const vshCmdOptDef opts_vcpu_dirty_limit[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "rate", .type = VSH_OT_INT, - .flags = VSH_OFLAG_REQ, .help = N_("Upper limit of dirty page rate (MB/s) for " "virtual CPUs.") }, @@ -13794,6 +13793,10 @@ static const vshCmdOptDef opts_vcpu_dirty_limit[] = { .type = VSH_OT_INT, .help = N_("Index of a virtual CPU.") }, + {.name = "cancel", + .type = VSH_OT_BOOL, + .help = N_("Cancel dirty page rate limit.") + }, {.name = NULL} }; @@ -13804,8 +13807,11 @@ cmdVcpuDirtyLimit(vshControl *ctl, const vshCmd *cmd) int vcpu_idx = -1; unsigned long long rate = 0; bool vcpu = vshCommandOptBool(cmd, "vcpu"); + bool cancel = vshCommandOptBool(cmd, "cancel"); unsigned int flags = 0; + VSH_EXCLUSIVE_OPTIONS("cancel", "rate"); + if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) return false; @@ -13820,28 +13826,46 @@ cmdVcpuDirtyLimit(vshControl *ctl, const vshCmd *cmd) } } - if (vshCommandOptULongLong(ctl, cmd, "rate", &rate) < 0) - return false; - - if (!rate) { - vshError(ctl, "%s", _("Invalid dirty page rate limit")); - return false; - } + if (!cancel) { + if (vshCommandOptULongLong(ctl, cmd, "rate", &rate) < 0) + return false; - if (vcpu) { - /* set specified vcpu dirty page rate limit of vm */ - if (virDomainSetVcpuDirtyLimit(dom, vcpu_idx, - rate, flags | VIR_DOMAIN_DIRTYLIMIT_VCPU) < 0) + if (!rate) { + vshError(ctl, "%s", _("Invalid dirty page rate limit")); return false; - vshPrintExtra(ctl, _("Set vcpu[%d] dirty page rate limit " - "%lld successfully.\n"), vcpu_idx, rate); + } + + if (vcpu) { + /* set specified vcpu dirty page rate limit of vm */ + if (virDomainSetVcpuDirtyLimit(dom, vcpu_idx, + rate, flags | VIR_DOMAIN_DIRTYLIMIT_VCPU) < 0) + return false; + vshPrintExtra(ctl, _("Set vcpu[%d] dirty page rate limit " + "%lld successfully.\n"), vcpu_idx, rate); + } else { + /* set all vcpu dirty page rate limit of vm */ + if (virDomainSetVcpuDirtyLimit(dom, -1, + rate, flags | VIR_DOMAIN_DIRTYLIMIT_ALL) < 0) + return false; + vshPrintExtra(ctl, _("Set dirty page rate limit %lld on all " + "virtual CPUs successfully.\n"), rate); + } } else { - /* set all vcpu dirty page rate limit of vm */ - if (virDomainSetVcpuDirtyLimit(dom, -1, - rate, flags | VIR_DOMAIN_DIRTYLIMIT_ALL) < 0) - return false; - vshPrintExtra(ctl, _("Set dirty page rate limit %lld on all " - "virtual CPUs successfully.\n"), rate); + if (vcpu) { + /* cancel specified vcpu dirty page rate limit of vm */ + if (virDomainCancelVcpuDirtyLimit(dom, vcpu_idx, + flags | VIR_DOMAIN_DIRTYLIMIT_VCPU) < 0) + return false; + vshPrintExtra(ctl, _("Cancel vcpu[%d] dirty page rate limit " + "successfully.\n"), vcpu); + } else { + /* cancel all vcpu dirty page rate limit of vm */ + if (virDomainCancelVcpuDirtyLimit(dom, -1, + flags | VIR_DOMAIN_DIRTYLIMIT_ALL) < 0) + return false; + vshPrintExtra(ctl, _("Cancel dirty page rate limit on all " + "virtual CPUs successfully.\n")); + } } return true; -- 1.8.3.1
participants (1)
-
huangy81@chinatelecom.cn