Add VIR_DOMAIN_VCPU_ASYNC_UNPLUG for virDomainSetVcpusFlags(). With this flag, success indicates that QEMU accepted the unplug request, while final completion is reported by the vcpu-removed event. Rejected requests continue to be reported by the device-removal-failed event. Wire the flag through the QEMU driver, document its semantics, and add virsh support for setvcpus --async. Signed-off-by: Akash Kulhalli <akash.kulhalli@oracle.com> --- docs/manpages/virsh.rst | 13 +++++++++++-- include/libvirt/libvirt-domain.h | 1 + src/libvirt-domain.c | 10 ++++++++++ src/qemu/qemu_driver.c | 12 ++++++++++-- tools/virsh-domain.c | 8 ++++++++ 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index 80b0ea14a8b3..f4c8e573cd47 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -179,7 +179,8 @@ Most ``virsh`` commands act synchronously, except maybe shutdown, setvcpus and setmem. In those cases the fact that the ``virsh`` program returned, may not mean the action is complete and you must poll periodically to detect that the guest completed the -operation. +operation. This asynchronous behaviour can be enforced with the +``--async`` flag to ``setvcpus`` only. ``virsh`` strives for backward compatibility. Although the ``help`` command only lists the preferred usage of a command, if an older @@ -4810,7 +4811,7 @@ setvcpus :: - setvcpus domain count [--maximum] [[--config] [--live] | [--current]] [--guest] [--hotpluggable] + setvcpus domain count [--maximum] [[--config] [--live] | [--current]] [--guest] [--hotpluggable] [--async] Change the number of virtual CPUs active in a guest domain. By default, this command works on active guest domains. To change the settings for an @@ -4839,6 +4840,14 @@ is up to the hypervisor whether the *--config* flag is also assumed, and therefore whether the XML configuration is adjusted to make the change persistent. +If *--async* is specified, live vCPU unplug requests are fired without waiting +for the guest to comply. This affects only the live unplug part of the +operation; it may optionally be combined with *--config*. Final completion is +reported by the ``vcpu-removed`` domain event, while rejected unplug requests +continue to be reported by ``device-removal-failed``. If the requested count +increases the live vCPU count, or only affects the persistent configuration, +*--async* has no effect. This flag cannot be combined with *--guest*. + If *--guest* is specified, then the count of cpus is modified in the guest instead of the hypervisor. This flag is usable only for live domains and may require guest agent to be configured in the guest. diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 92d5ecb32d65..016b6ea700e9 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -2605,6 +2605,7 @@ typedef enum { VIR_DOMAIN_VCPU_MAXIMUM = (1 << 2), /* Max rather than current count (Since: 0.8.5) */ VIR_DOMAIN_VCPU_GUEST = (1 << 3), /* Modify state of the cpu in the guest (Since: 1.1.0) */ VIR_DOMAIN_VCPU_HOTPLUGGABLE = (1 << 4), /* Make vcpus added hot(un)pluggable (Since: 2.4.0) */ + VIR_DOMAIN_VCPU_ASYNC_UNPLUG = (1 << 5), /* Don't wait for the guest to comply with unplug request(s) (Since: 12.3.0) */ } virDomainVcpuFlags; int virDomainSetVcpus (virDomainPtr domain, diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index db9eea57745c..97af1099f939 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -7773,6 +7773,16 @@ virDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus) * be used with live guests and is incompatible with VIR_DOMAIN_VCPU_MAXIMUM. * The usage of this flag may require a guest agent configured. * + * If @flags includes VIR_DOMAIN_VCPU_ASYNC_UNPLUG, live vCPU hot-unplug + * request(s) are fired without waiting for the guest to comply. Success in + * this mode only means that the unplug request(s) were accepted. Final + * completion is reported by VIR_DOMAIN_EVENT_ID_VCPU_REMOVED, carrying the + * XML ``<vcpu id='...'>`` value for each removed vCPU. Rejected unplug + * requests continue to be reported through the event + * VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED. The success event may be + * delivered before this API call returns. This flag has no effect when this + * operation results in an increase in the live vCPU count. + * * Not all hypervisors can support all flag combinations. * * Returns 0 in case of success, -1 in case of failure. diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 4d9be3d3a9e5..c9c72b29617f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4269,6 +4269,7 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, virDomainObj *vm = NULL; virDomainDef *def; virDomainDef *persistentDef; + bool async_unplug = !!(flags & VIR_DOMAIN_VCPU_ASYNC_UNPLUG); bool hotpluggable = !!(flags & VIR_DOMAIN_VCPU_HOTPLUGGABLE); bool useAgent = !!(flags & VIR_DOMAIN_VCPU_GUEST); int ret = -1; @@ -4277,7 +4278,8 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_GUEST | - VIR_DOMAIN_VCPU_HOTPLUGGABLE, -1); + VIR_DOMAIN_VCPU_HOTPLUGGABLE | + VIR_DOMAIN_VCPU_ASYNC_UNPLUG, -1); if (!(vm = qemuDomainObjFromDomain(dom))) goto cleanup; @@ -4297,13 +4299,19 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0) goto endjob; + if (async_unplug && (useAgent || !def)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("asynchronous mode is supported only for live vcpu unplug")); + goto endjob; + } + if (useAgent) ret = qemuDomainSetVcpusAgent(vm, nvcpus); else if (flags & VIR_DOMAIN_VCPU_MAXIMUM) ret = qemuDomainSetVcpusMax(driver, vm, def, persistentDef, nvcpus); else ret = qemuDomainSetVcpusInternal(driver, vm, def, persistentDef, - nvcpus, hotpluggable, false); + nvcpus, hotpluggable, async_unplug); endjob: if (useAgent) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 08a1ce395378..1fccee4bc9ed 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -7667,6 +7667,10 @@ static const vshCmdOptDef opts_setvcpus[] = { .type = VSH_OT_BOOL, .help = N_("make added vcpus hot(un)pluggable") }, + {.name = "async", + .type = VSH_OT_BOOL, + .help = N_("return after firing vcpu unplug request(s)") + }, {.name = NULL} }; @@ -7681,11 +7685,13 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd) bool current = vshCommandOptBool(cmd, "current"); bool guest = vshCommandOptBool(cmd, "guest"); bool hotpluggable = vshCommandOptBool(cmd, "hotpluggable"); + bool async = vshCommandOptBool(cmd, "async"); unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT; VSH_EXCLUSIVE_OPTIONS_VAR(current, live); VSH_EXCLUSIVE_OPTIONS_VAR(current, config); VSH_EXCLUSIVE_OPTIONS_VAR(guest, config); + VSH_EXCLUSIVE_OPTIONS_VAR(async, guest); VSH_REQUIRE_OPTION_VAR(maximum, config); @@ -7699,6 +7705,8 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd) flags |= VIR_DOMAIN_VCPU_MAXIMUM; if (hotpluggable) flags |= VIR_DOMAIN_VCPU_HOTPLUGGABLE; + if (async) + flags |= VIR_DOMAIN_VCPU_ASYNC_UNPLUG; if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) return false; -- 2.47.3