[PATCH 00/11] Dirty page rate limit support

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> 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. - document dirty page rate limit feature. Please review, thanks! Best regards! *** BLURB HERE *** Hyman Huang(黄勇) (11): 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 NEWS: Document dirty page rate limit APIs NEWS.rst | 13 ++ include/libvirt/libvirt-domain.h | 22 ++++ src/driver-hypervisor.h | 13 ++ src/libvirt-domain.c | 95 +++++++++++++++ src/libvirt_public.syms | 6 + src/qemu/qemu_capabilities.c | 4 + src/qemu/qemu_capabilities.h | 3 + src/qemu/qemu_driver.c | 146 +++++++++++++++++++++++ src/qemu/qemu_monitor.c | 35 ++++++ src/qemu/qemu_monitor.h | 26 ++++ src/qemu/qemu_monitor_json.c | 137 +++++++++++++++++++++ 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 +++++++++++++++++ 18 files changed, 673 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 | 4 ++++ src/qemu/qemu_capabilities.h | 3 +++ tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml | 1 + 3 files changed, 8 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 4fca774..36df9c9 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -673,6 +673,9 @@ VIR_ENUM_IMPL(virQEMUCaps, "iothread.thread-pool-max", /* QEMU_CAPS_IOTHREAD_THREAD_POOL_MAX */ "usb-host.guest-resets-all", /* QEMU_CAPS_USB_HOST_GUESTS_RESETS_ALL */ "migration.blocked-reasons", /* QEMU_CAPS_MIGRATION_BLOCKED_REASONS */ + + /* 435 */ + "set-vcpu-dirty-limit", /* QEMU_CAPS_VCPU_DIRTY_LIMIT */ ); @@ -1223,6 +1226,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = { { "query-dirty-rate", QEMU_CAPS_QUERY_DIRTY_RATE }, { "sev-inject-launch-secret", QEMU_CAPS_SEV_INJECT_LAUNCH_SECRET }, { "calc-dirty-rate", QEMU_CAPS_CALC_DIRTY_RATE }, + { "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 fc8bb6e..eae3d21 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -653,6 +653,9 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_USB_HOST_GUESTS_RESETS_ALL, /* -device usb-host.guest-resets-all */ QEMU_CAPS_MIGRATION_BLOCKED_REASONS, /* query-migrate returns 'blocked-reasons */ + /* 435 */ + 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 ad43385..7e573c9 100644 --- a/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_7.1.0.x86_64.xml @@ -225,6 +225,7 @@ <flag name='iothread.thread-pool-max'/> <flag name='usb-host.guest-resets-all'/> <flag name='migration.blocked-reasons'/> + <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..b0bd2f1 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 = 0, /* render specified virtual CPU for + dirty page rate limit (Since: 8.7.0) */ + VIR_DOMAIN_DIRTYLIMIT_ALL = 1 << 0, /* 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 | 12 +++++++++++ src/qemu/qemu_monitor.h | 5 +++++ src/qemu/qemu_monitor_json.c | 38 +++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 5 +++++ 5 files changed, 107 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 333225d..8c95f24 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20701,6 +20701,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, @@ -20950,6 +20996,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 4739810..dee2904 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4297,3 +4297,15 @@ qemuMonitorGetMigrationBlockers(qemuMonitor *mon, return qemuMonitorJSONGetMigrationBlockers(mon, blockers); } + +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 78e2ebf..83bcf14 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1481,3 +1481,8 @@ qemuMonitorMigrateRecover(qemuMonitor *mon, int qemuMonitorGetMigrationBlockers(qemuMonitor *mon, char ***blockers); + +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 d664e82..fc50604 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -8574,3 +8574,41 @@ qemuMonitorJSONMigrateRecover(qemuMonitor *mon, return qemuMonitorJSONCheckError(cmd, reply); } + +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 5154c19..7b07428 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -812,3 +812,8 @@ qemuMonitorJSONChangeMemoryRequestedSize(qemuMonitor *mon, int qemuMonitorJSONMigrateRecover(qemuMonitor *mon, const char *uri); + +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 451f51d..95104b2 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -13763,6 +13763,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", @@ -14421,5 +14498,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 dee2904..7480856 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4309,3 +4309,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 83bcf14..cf76f43 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1486,3 +1486,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 fc50604..4642a2d 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -8612,3 +8612,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 7b07428..2852061 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -817,3 +817,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 | 52 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index b0bd2f1..1096b4b 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 8c95f24..fbd6a32 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4762,6 +4762,54 @@ 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); + + for (i = 0; i < virDomainDefGetVcpusMax(vm->def) && i < dirtylimit_info.nvcpus + && ncpuinfo < maxinfo; i++) { + virDomainVcpuDef *vcpu = virDomainDefGetVcpu(vm->def, i); + virVcpuInfoPtr vcpuinfo = info + ncpuinfo; + + if (!vcpu->online) + continue; + + 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, @@ -4785,6 +4833,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, 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 95104b2..dbdd46e 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -6934,6 +6934,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 | 44 ++++++++++++++++++++++++++++++++++++++++ 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, 75 insertions(+), 1 deletion(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 1096b4b..45634cd 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..8e32da9 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -13980,3 +13980,47 @@ 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); + virCheckNonNegativeArgGoto(vcpu, 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 fbd6a32..06ad9a9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -20800,6 +20800,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, @@ -21049,6 +21095,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 7480856..67d0171 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4321,3 +4321,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 cf76f43..bad55fc 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1503,3 +1503,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 4642a2d..ef86384 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -8676,3 +8676,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 2852061..12f330e 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -821,3 +821,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 dbdd46e..199913d 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -13785,7 +13785,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.") }, @@ -13793,6 +13792,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} }; @@ -13803,8 +13806,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; @@ -13819,28 +13825,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

From: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> New libvirt APIs for dirty page rate limit are introduced. Document this change. Signed-off-by: Hyman Huang(黄勇) <huangy81@chinatelecom.cn> --- NEWS.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 548828c..27f4179 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -16,6 +16,19 @@ v8.7.0 (unreleased) * **Removed features** * **New features** + * qemu: Add support for enabling dirty page rate limit + + New API ``virDomainSetVcpuDirtyLimit()`` and virsh command + ``vcpudirtylimit`` are added to set dirty page rate limit for virtual + CPUs. + + New API ``virDomainCancelVcpuDirtyLimit()`` and virsh command option + ``vcpudirtylimit --cancel`` are added to cancel dirty page rate limit + for virtual CPUs. + + * qemu: Add support for querying dirty page rate limit + + User can query dirty page rate limit with virsh command ``vcpuinfo``
participants (1)
-
huangy81@chinatelecom.cn