[PATCH 0/7] more Hyper-V APIs

This set of patches adds several new APIs and fixes several others. Matt Coleman (7): hyperv: implement domainSetAutostart hyperv: implement nodeGetFreeMemory hyperv: implement domainReboot and domainReset hyperv: implement domainShutdown and domainShutdownFlags hyperv: fix domainSuspend and domainResume on Hyper-V V2 hyperv: fix domainManagedSave on Hyper-V V2 news: more Hyper-V APIs NEWS.rst | 7 +- src/hyperv/hyperv_driver.c | 268 +++++++++++++++++++++++++- src/hyperv/hyperv_wmi_classes.h | 3 + src/hyperv/hyperv_wmi_generator.input | 78 ++++++++ 4 files changed, 348 insertions(+), 8 deletions(-) -- 2.27.0

Co-authored-by: Sri Ramanujam <sramanujam@datto.com> Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 92 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 2ac30fa4c6..6b2acbc405 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1310,6 +1310,97 @@ hypervDomainGetAutostart(virDomainPtr domain, int *autostart) +static int +hypervDomainSetAutostart(virDomainPtr domain, int autostart) +{ + int result = -1; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + Msvm_VirtualSystemSettingData *vssd = NULL; + hypervInvokeParamsListPtr params = NULL; + g_auto(virBuffer) eprQuery = VIR_BUFFER_INITIALIZER; + virHashTablePtr autostartParam = NULL; + hypervWmiClassInfoListPtr embeddedParamClass = NULL; + const char *methodName = NULL, *embeddedParamName = NULL; + g_autofree char *enabledValue = NULL, *disabledValue = NULL; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V1) { + methodName = "ModifyVirtualSystem"; + embeddedParamName = "SystemSettingData"; + embeddedParamClass = Msvm_VirtualSystemGlobalSettingData_WmiInfo; + enabledValue = g_strdup("2"); + disabledValue = g_strdup("0"); + } else if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) { + methodName = "ModifySystemSettings"; + embeddedParamName = "SystemSettings"; + embeddedParamClass = Msvm_VirtualSystemSettingData_WmiInfo; + enabledValue = g_strdup("4"); + disabledValue = g_strdup("2"); + } + + virUUIDFormat(domain->uuid, uuid_string); + + if (hypervGetVSSDFromUUID(priv, uuid_string, &vssd) < 0) + goto cleanup; + + params = hypervCreateInvokeParamsList(priv, methodName, + MSVM_VIRTUALSYSTEMMANAGEMENTSERVICE_SELECTOR, + Msvm_VirtualSystemManagementService_WmiInfo); + + if (!params) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not create params")); + goto cleanup; + } + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V1) { + virBufferEscapeSQL(&eprQuery, + MSVM_COMPUTERSYSTEM_WQL_SELECT "WHERE Name = '%s'", + uuid_string); + + if (hypervAddEprParam(params, "ComputerSystem", priv, &eprQuery, + Msvm_ComputerSystem_WmiInfo) < 0) + goto params_cleanup; + } + + autostartParam = hypervCreateEmbeddedParam(priv, embeddedParamClass); + + if (hypervSetEmbeddedProperty(autostartParam, "AutomaticStartupAction", + autostart ? enabledValue : disabledValue) < 0) { + hypervFreeEmbeddedParam(autostartParam); + goto params_cleanup; + } + + if (hypervSetEmbeddedProperty(autostartParam, "InstanceID", + vssd->data.common->InstanceID) < 0) { + hypervFreeEmbeddedParam(autostartParam); + goto params_cleanup; + } + + if (hypervAddEmbeddedParam(params, priv, embeddedParamName, autostartParam, + embeddedParamClass) < 0) { + hypervFreeEmbeddedParam(autostartParam); + goto params_cleanup; + } + + if (hypervInvokeMethod(priv, params, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not set autostart")); + goto cleanup; + } + + result = 0; + goto cleanup; + + params_cleanup: + hypervFreeInvokeParams(params); + cleanup: + hypervFreeObject(priv, (hypervObject *) vssd); + + return result; +} + + + static int hypervConnectIsEncrypted(virConnectPtr conn) { @@ -1861,6 +1952,7 @@ static virHypervisorDriver hypervHypervisorDriver = { .domainCreate = hypervDomainCreate, /* 0.9.5 */ .domainCreateWithFlags = hypervDomainCreateWithFlags, /* 0.9.5 */ .domainGetAutostart = hypervDomainGetAutostart, /* 6.9.0 */ + .domainSetAutostart = hypervDomainSetAutostart, /* 6.9.0 */ .connectIsEncrypted = hypervConnectIsEncrypted, /* 0.9.5 */ .connectIsSecure = hypervConnectIsSecure, /* 0.9.5 */ .domainIsActive = hypervDomainIsActive, /* 0.9.5 */ -- 2.27.0

On Friday, 9 October 2020 10:31:50 CEST Matt Coleman wrote:
+static int +hypervDomainSetAutostart(virDomainPtr domain, int autostart) +{ + int result = -1; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + Msvm_VirtualSystemSettingData *vssd = NULL; + hypervInvokeParamsListPtr params = NULL; + g_auto(virBuffer) eprQuery = VIR_BUFFER_INITIALIZER; + virHashTablePtr autostartParam = NULL; + hypervWmiClassInfoListPtr embeddedParamClass = NULL; + const char *methodName = NULL, *embeddedParamName = NULL; + g_autofree char *enabledValue = NULL, *disabledValue = NULL; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V1) { + methodName = "ModifyVirtualSystem"; + embeddedParamName = "SystemSettingData"; + embeddedParamClass = Msvm_VirtualSystemGlobalSettingData_WmiInfo; + enabledValue = g_strdup("2"); + disabledValue = g_strdup("0"); + } else if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) { + methodName = "ModifySystemSettings"; + embeddedParamName = "SystemSettings"; + embeddedParamClass = Msvm_VirtualSystemSettingData_WmiInfo; + enabledValue = g_strdup("4"); + disabledValue = g_strdup("2"); + }
It looks like 'enabledValue' and 'disabledValue' can be static strings (like 'methodName' and 'embeddedParamName'). -- Pino Toscano

On Oct 9, 2020, at 4:58 AM, Pino Toscano <ptoscano@redhat.com> wrote:
On Friday, 9 October 2020 10:31:50 CEST Matt Coleman wrote:
+static int +hypervDomainSetAutostart(virDomainPtr domain, int autostart) +{ + int result = -1; + char uuid_string[VIR_UUID_STRING_BUFLEN]; + hypervPrivate *priv = domain->conn->privateData; + Msvm_VirtualSystemSettingData *vssd = NULL; + hypervInvokeParamsListPtr params = NULL; + g_auto(virBuffer) eprQuery = VIR_BUFFER_INITIALIZER; + virHashTablePtr autostartParam = NULL; + hypervWmiClassInfoListPtr embeddedParamClass = NULL; + const char *methodName = NULL, *embeddedParamName = NULL; + g_autofree char *enabledValue = NULL, *disabledValue = NULL; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V1) { + methodName = "ModifyVirtualSystem"; + embeddedParamName = "SystemSettingData"; + embeddedParamClass = Msvm_VirtualSystemGlobalSettingData_WmiInfo; + enabledValue = g_strdup("2"); + disabledValue = g_strdup("0"); + } else if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) { + methodName = "ModifySystemSettings"; + embeddedParamName = "SystemSettings"; + embeddedParamClass = Msvm_VirtualSystemSettingData_WmiInfo; + enabledValue = g_strdup("4"); + disabledValue = g_strdup("2"); + }
It looks like 'enabledValue' and 'disabledValue' can be static strings (like 'methodName' and 'embeddedParamName').
I removed g_autofree and g_strdup() with the following patch applied on top of my initial changes. Can it be squashed into this commit, or do I have to submit a [PATCH v2]? Signed-off-by: Matt Coleman <matt@datto.com> --- diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index c91bc58488..baaace041b 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1450,20 +1450,18 @@ hypervDomainSetAutostart(virDomainPtr domain, int autostart) virHashTablePtr autostartParam = NULL; hypervWmiClassInfoListPtr embeddedParamClass = NULL; const char *methodName = NULL, *embeddedParamName = NULL; - g_autofree char *enabledValue = NULL, *disabledValue = NULL; + char enabledValue[] = "2", disabledValue[] = "0"; if (priv->wmiVersion == HYPERV_WMI_VERSION_V1) { methodName = "ModifyVirtualSystem"; embeddedParamName = "SystemSettingData"; embeddedParamClass = Msvm_VirtualSystemGlobalSettingData_WmiInfo; - enabledValue = g_strdup("2"); - disabledValue = g_strdup("0"); } else if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) { methodName = "ModifySystemSettings"; embeddedParamName = "SystemSettings"; embeddedParamClass = Msvm_VirtualSystemSettingData_WmiInfo; - enabledValue = g_strdup("4"); - disabledValue = g_strdup("2"); + enabledValue[0] = '4'; + disabledValue[0] = '2'; } virUUIDFormat(domain->uuid, uuid_string);

Co-authored-by: Sri Ramanujam <sramanujam@datto.com> Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 6b2acbc405..7e2bc002bd 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1401,6 +1401,33 @@ hypervDomainSetAutostart(virDomainPtr domain, int autostart) +static unsigned long long +hypervNodeGetFreeMemory(virConnectPtr conn) +{ + unsigned long long res = 0; + hypervPrivate *priv = conn->privateData; + Win32_OperatingSystem *operatingSystem = NULL; + g_auto(virBuffer) query = { g_string_new(WIN32_OPERATINGSYSTEM_WQL_SELECT), 0 }; + + if (hypervGetWmiClass(Win32_OperatingSystem, &operatingSystem) < 0 || + !operatingSystem) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not get free memory for host %s"), + conn->uri->server); + goto cleanup; + } + + /* Return free memory in bytes */ + res = operatingSystem->data.common->FreePhysicalMemory * 1024; + + cleanup: + hypervFreeObject(priv, (hypervObject *) operatingSystem); + + return res; +} + + + static int hypervConnectIsEncrypted(virConnectPtr conn) { @@ -1953,6 +1980,7 @@ static virHypervisorDriver hypervHypervisorDriver = { .domainCreateWithFlags = hypervDomainCreateWithFlags, /* 0.9.5 */ .domainGetAutostart = hypervDomainGetAutostart, /* 6.9.0 */ .domainSetAutostart = hypervDomainSetAutostart, /* 6.9.0 */ + .nodeGetFreeMemory = hypervNodeGetFreeMemory, /* 6.9.0 */ .connectIsEncrypted = hypervConnectIsEncrypted, /* 0.9.5 */ .connectIsSecure = hypervConnectIsSecure, /* 0.9.5 */ .domainIsActive = hypervDomainIsActive, /* 0.9.5 */ -- 2.27.0

Co-authored-by: Sri Ramanujam <sramanujam@datto.com> Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 48 +++++++++++++++++++++++++++++++++ src/hyperv/hyperv_wmi_classes.h | 1 + 2 files changed, 49 insertions(+) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 7e2bc002bd..ef0a5249c7 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -917,6 +917,52 @@ hypervDomainResume(virDomainPtr domain) +static int +hypervDomainReboot(virDomainPtr domain, unsigned int flags) +{ + int result = -1; + hypervPrivate *priv = domain->conn->privateData; + Msvm_ComputerSystem *computerSystem = NULL; + + virCheckFlags(0, -1); + + if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) + goto cleanup; + + result = hypervInvokeMsvmComputerSystemRequestStateChange(domain, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_REBOOT); + + cleanup: + hypervFreeObject(priv, (hypervObject *)computerSystem); + + return result; +} + + + +static int +hypervDomainReset(virDomainPtr domain, unsigned int flags) +{ + int result = -1; + hypervPrivate *priv = domain->conn->privateData; + Msvm_ComputerSystem *computerSystem = NULL; + + virCheckFlags(0, -1); + + if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) + goto cleanup; + + result = hypervInvokeMsvmComputerSystemRequestStateChange(domain, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_RESET); + + cleanup: + hypervFreeObject(priv, (hypervObject *)computerSystem); + + return result; +} + + + static int hypervDomainDestroyFlags(virDomainPtr domain, unsigned int flags) { @@ -1968,6 +2014,8 @@ static virHypervisorDriver hypervHypervisorDriver = { .domainLookupByName = hypervDomainLookupByName, /* 0.9.5 */ .domainSuspend = hypervDomainSuspend, /* 0.9.5 */ .domainResume = hypervDomainResume, /* 0.9.5 */ + .domainReboot = hypervDomainReboot, /* 6.9.0 */ + .domainReset = hypervDomainReset, /* 6.9.0 */ .domainDestroy = hypervDomainDestroy, /* 0.9.5 */ .domainDestroyFlags = hypervDomainDestroyFlags, /* 0.9.5 */ .domainGetOSType = hypervDomainGetOSType, /* 0.9.5 */ diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h index d32711589a..7f4159dd8e 100644 --- a/src/hyperv/hyperv_wmi_classes.h +++ b/src/hyperv/hyperv_wmi_classes.h @@ -74,6 +74,7 @@ enum _Msvm_ComputerSystem_RequestedState { MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED = 2, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_DISABLED = 3, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_REBOOT = 10, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_RESET = 11, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED = 32768, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_SUSPENDED = 32769, }; -- 2.27.0

Co-authored-by: Sri Ramanujam <sramanujam@datto.com> Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 77 ++++++++++++++++++++++++++ src/hyperv/hyperv_wmi_generator.input | 78 +++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index ef0a5249c7..0b28c1e94b 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -917,6 +917,81 @@ hypervDomainResume(virDomainPtr domain) +static int +hypervDomainShutdownFlags(virDomainPtr domain, unsigned int flags) +{ + int result = -1; + hypervPrivate *priv = domain->conn->privateData; + Msvm_ComputerSystem *computerSystem = NULL; + Msvm_ShutdownComponent *shutdown = NULL; + bool in_transition = false; + char uuid[VIR_UUID_STRING_BUFLEN]; + g_auto(virBuffer) query = VIR_BUFFER_INITIALIZER; + hypervInvokeParamsListPtr params = NULL; + g_autofree char *selector = NULL; + + virCheckFlags(0, -1); + + virUUIDFormat(domain->uuid, uuid); + + if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) + goto cleanup; + + if (!hypervIsMsvmComputerSystemActive(computerSystem, &in_transition) || + in_transition) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Domain is not active or in state transition")); + goto cleanup; + } + + virBufferEscapeSQL(&query, + MSVM_SHUTDOWNCOMPONENT_WQL_SELECT + "WHERE SystemName = '%s'", uuid); + + if (hypervGetWmiClass(Msvm_ShutdownComponent, &shutdown) < 0 || + !shutdown) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Could not get Msvm_ShutdownComponent for domain with UUID '%s'"), + uuid); + goto cleanup; + } + + selector = g_strdup_printf( + "CreationClassName=\"Msvm_ShutdownComponent\"&DeviceID=\"%s\"&" + "SystemCreationClassName=\"Msvm_ComputerSystem\"&SystemName=\"%s\"", + shutdown->data.common->DeviceID, uuid); + + params = hypervCreateInvokeParamsList(priv, "InitiateShutdown", selector, + Msvm_ShutdownComponent_WmiInfo); + + hypervAddSimpleParam(params, "Force", "False"); + hypervAddSimpleParam(params, "Reason", _("Planned shutdown via libvirt")); + + if (hypervInvokeMethod(priv, params, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not shutdown domain with UUID '%s'"), uuid); + goto cleanup; + } + + result = 0; + + cleanup: + hypervFreeObject(priv, (hypervObject *) computerSystem); + hypervFreeObject(priv, (hypervObject *) shutdown); + + return result; +} + + + +static int +hypervDomainShutdown(virDomainPtr domain) +{ + return hypervDomainShutdownFlags(domain, 0); +} + + + static int hypervDomainReboot(virDomainPtr domain, unsigned int flags) { @@ -2014,6 +2089,8 @@ static virHypervisorDriver hypervHypervisorDriver = { .domainLookupByName = hypervDomainLookupByName, /* 0.9.5 */ .domainSuspend = hypervDomainSuspend, /* 0.9.5 */ .domainResume = hypervDomainResume, /* 0.9.5 */ + .domainShutdown = hypervDomainShutdown, /* 6.9.0 */ + .domainShutdownFlags = hypervDomainShutdownFlags, /* 6.9.0 */ .domainReboot = hypervDomainReboot, /* 6.9.0 */ .domainReset = hypervDomainReset, /* 6.9.0 */ .domainDestroy = hypervDomainDestroy, /* 0.9.5 */ diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input index bbca550790..1377138a12 100644 --- a/src/hyperv/hyperv_wmi_generator.input +++ b/src/hyperv/hyperv_wmi_generator.input @@ -1072,3 +1072,81 @@ class v2/Msvm_Keyboard uint16 Password boolean UnicodeSupported end + + +class Msvm_ShutdownComponent + string Caption + string Description + string ElementName + datetime InstallDate + string Name + uint16 OperationalStatus[] + string StatusDescriptions[] + string Status + uint16 HealthState + uint16 EnabledState + string OtherEnabledState + uint16 RequestedState + uint16 EnabledDefault + datetime TimeOfLastStateChange + string SystemCreationClassName + string SystemName + string CreationClassName + string DeviceID + boolean PowerManagementSupported + uint16 PowerManagementCapabilities[] + uint16 Availability + uint16 StatusInfo + uint32 LastErrorCode + string ErrorDescription + boolean ErrorCleared + string OtherIdentifyingInfo[] + uint64 PowerOnHours + uint64 TotalPowerOnHours + string IdentifyingDescriptions[] + uint16 AdditionalAvailability[] + uint64 MaxQuiesceTime + uint16 LocationIndicator +end + + +class v2/Msvm_ShutdownComponent + string InstanceID + string Caption + string Description + string ElementName + datetime InstallDate + string Name + uint16 OperationalStatus[] + string StatusDescriptions[] + string Status + uint16 HealthState + uint16 CommunicationStatus + uint16 DetailedStatus + uint16 OperatingStatus + uint16 PrimaryStatus + uint16 EnabledState + string OtherEnabledState + uint16 RequestedState + uint16 EnabledDefault + datetime TimeOfLastStateChange + uint16 AvailableRequestedStates[] + uint16 TransitioningToState + string SystemCreationClassName + string SystemName + string CreationClassName + string DeviceID + boolean PowerManagementSupported + uint16 PowerManagementCapabilities[] + uint16 Availability + uint16 StatusInfo + uint32 LastErrorCode + string ErrorDescription + boolean ErrorCleared + string OtherIdentifyingInfo[] + uint64 PowerOnHours + uint64 TotalPowerOnHours + string IdentifyingDescriptions[] + uint16 AdditionalAvailability[] + uint64 MaxQuiesceTime +end -- 2.27.0

Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 15 +++++++++++---- src/hyperv/hyperv_wmi_classes.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 0b28c1e94b..89840f7ac4 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -867,6 +867,10 @@ hypervDomainSuspend(virDomainPtr domain) int result = -1; hypervPrivate *priv = domain->conn->privateData; Msvm_ComputerSystem *computerSystem = NULL; + int requestedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) + requestedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_QUIESCE; if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) goto cleanup; @@ -878,8 +882,8 @@ hypervDomainSuspend(virDomainPtr domain) goto cleanup; } - result = hypervInvokeMsvmComputerSystemRequestStateChange - (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED); + result = hypervInvokeMsvmComputerSystemRequestStateChange(domain, + requestedState); cleanup: hypervFreeObject(priv, (hypervObject *)computerSystem); @@ -895,12 +899,15 @@ hypervDomainResume(virDomainPtr domain) int result = -1; hypervPrivate *priv = domain->conn->privateData; Msvm_ComputerSystem *computerSystem = NULL; + int expectedState = MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) + expectedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_QUIESCE; if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) goto cleanup; - if (computerSystem->data.common->EnabledState != - MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED) { + if (computerSystem->data.common->EnabledState != expectedState) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not paused")); goto cleanup; diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h index 7f4159dd8e..0074d8889e 100644 --- a/src/hyperv/hyperv_wmi_classes.h +++ b/src/hyperv/hyperv_wmi_classes.h @@ -73,6 +73,7 @@ enum _Msvm_ComputerSystem_EnabledState { enum _Msvm_ComputerSystem_RequestedState { MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED = 2, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_DISABLED = 3, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_QUIESCE = 9, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_REBOOT = 10, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_RESET = 11, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED = 32768, -- 2.27.0

On Fri, Oct 09, 2020 at 04:31:54AM -0400, Matt Coleman wrote:
Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 15 +++++++++++---- src/hyperv/hyperv_wmi_classes.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 0b28c1e94b..89840f7ac4 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -867,6 +867,10 @@ hypervDomainSuspend(virDomainPtr domain) int result = -1; hypervPrivate *priv = domain->conn->privateData; Msvm_ComputerSystem *computerSystem = NULL; + int requestedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) + requestedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_QUIESCE;
Is quiesce really what we want here ? The libvirt Suspend/Resume APIs are specifically about pausing execution of the guest CPUs. IIUC, quiesce usually just refers to suspending I/O processing, in order to allow snapshots to be taken, but CPUs stay running.
if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) goto cleanup; @@ -878,8 +882,8 @@ hypervDomainSuspend(virDomainPtr domain) goto cleanup; }
- result = hypervInvokeMsvmComputerSystemRequestStateChange - (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED); + result = hypervInvokeMsvmComputerSystemRequestStateChange(domain, + requestedState);
cleanup: hypervFreeObject(priv, (hypervObject *)computerSystem); @@ -895,12 +899,15 @@ hypervDomainResume(virDomainPtr domain) int result = -1; hypervPrivate *priv = domain->conn->privateData; Msvm_ComputerSystem *computerSystem = NULL; + int expectedState = MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) + expectedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_QUIESCE;
if (hypervMsvmComputerSystemFromDomain(domain, &computerSystem) < 0) goto cleanup;
- if (computerSystem->data.common->EnabledState != - MSVM_COMPUTERSYSTEM_ENABLEDSTATE_PAUSED) { + if (computerSystem->data.common->EnabledState != expectedState) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not paused")); goto cleanup; diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h index 7f4159dd8e..0074d8889e 100644 --- a/src/hyperv/hyperv_wmi_classes.h +++ b/src/hyperv/hyperv_wmi_classes.h @@ -73,6 +73,7 @@ enum _Msvm_ComputerSystem_EnabledState { enum _Msvm_ComputerSystem_RequestedState { MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED = 2, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_DISABLED = 3, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_QUIESCE = 9, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_REBOOT = 10, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_RESET = 11, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED = 32768, -- 2.27.0
Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On Oct 9, 2020, at 4:43 AM, Daniel P. Berrangé <berrange@redhat.com> wrote:
On Fri, Oct 09, 2020 at 04:31:54AM -0400, Matt Coleman wrote:
Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 15 +++++++++++---- src/hyperv/hyperv_wmi_classes.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 0b28c1e94b..89840f7ac4 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -867,6 +867,10 @@ hypervDomainSuspend(virDomainPtr domain) int result = -1; hypervPrivate *priv = domain->conn->privateData; Msvm_ComputerSystem *computerSystem = NULL; + int requestedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) + requestedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_QUIESCE;
Is quiesce really what we want here ?
The libvirt Suspend/Resume APIs are specifically about pausing execution of the guest CPUs.
IIUC, quiesce usually just refers to suspending I/O processing, in order to allow snapshots to be taken, but CPUs stay running.
I agree that it’s an odd name, but that’s how Microsoft chose to describe this RequestedState. It’s documented at the following link as... "Quiesce (9) Corresponds to CIM_EnabledLogicalElement.EnabledState = Quiesce, Enabled but paused." https://docs.microsoft.com/en-us/windows/win32/hyperv_v2/requeststatechange-... I didn’t believe the documentation when I first read it, so I paused a VM in Hyper-V Manager and confirmed that its state was indeed Quiesce. -- Matt

On Fri, Oct 09, 2020 at 04:56:09AM -0400, Matt Coleman wrote:
On Oct 9, 2020, at 4:43 AM, Daniel P. Berrangé <berrange@redhat.com> wrote:
On Fri, Oct 09, 2020 at 04:31:54AM -0400, Matt Coleman wrote:
Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 15 +++++++++++---- src/hyperv/hyperv_wmi_classes.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 0b28c1e94b..89840f7ac4 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -867,6 +867,10 @@ hypervDomainSuspend(virDomainPtr domain) int result = -1; hypervPrivate *priv = domain->conn->privateData; Msvm_ComputerSystem *computerSystem = NULL; + int requestedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_PAUSED; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) + requestedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_QUIESCE;
Is quiesce really what we want here ?
The libvirt Suspend/Resume APIs are specifically about pausing execution of the guest CPUs.
IIUC, quiesce usually just refers to suspending I/O processing, in order to allow snapshots to be taken, but CPUs stay running.
I agree that it’s an odd name, but that’s how Microsoft chose to describe this RequestedState. It’s documented at the following link as...
"Quiesce (9) Corresponds to CIM_EnabledLogicalElement.EnabledState = Quiesce, Enabled but paused."
https://docs.microsoft.com/en-us/windows/win32/hyperv_v2/requeststatechange-...
I didn’t believe the documentation when I first read it, so I paused a VM in Hyper-V Manager and confirmed that its state was indeed Quiesce.
AH, that's ok then. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Signed-off-by: Matt Coleman <matt@datto.com> --- src/hyperv/hyperv_driver.c | 8 ++++++-- src/hyperv/hyperv_wmi_classes.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 89840f7ac4..c91bc58488 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -1645,6 +1645,10 @@ hypervDomainManagedSave(virDomainPtr domain, unsigned int flags) hypervPrivate *priv = domain->conn->privateData; Msvm_ComputerSystem *computerSystem = NULL; bool in_transition = false; + int requestedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_SUSPENDED; + + if (priv->wmiVersion == HYPERV_WMI_VERSION_V2) + requestedState = MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED_BUT_OFFLINE; virCheckFlags(0, -1); @@ -1658,8 +1662,8 @@ hypervDomainManagedSave(virDomainPtr domain, unsigned int flags) goto cleanup; } - result = hypervInvokeMsvmComputerSystemRequestStateChange - (domain, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_SUSPENDED); + result = hypervInvokeMsvmComputerSystemRequestStateChange(domain, + requestedState); cleanup: hypervFreeObject(priv, (hypervObject *)computerSystem); diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h index 0074d8889e..a5213901c8 100644 --- a/src/hyperv/hyperv_wmi_classes.h +++ b/src/hyperv/hyperv_wmi_classes.h @@ -73,6 +73,7 @@ enum _Msvm_ComputerSystem_EnabledState { enum _Msvm_ComputerSystem_RequestedState { MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED = 2, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_DISABLED = 3, + MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_ENABLED_BUT_OFFLINE = 6, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_QUIESCE = 9, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_REBOOT = 10, MSVM_COMPUTERSYSTEM_REQUESTEDSTATE_RESET = 11, -- 2.27.0

Signed-off-by: Matt Coleman <matt@datto.com> --- NEWS.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index e708f06e9e..9404ed7809 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -22,8 +22,11 @@ v6.9.0 (unreleased) * hyperv: implement new APIs The ``virConnectGetCapabilities()``, ``virConnectGetMaxVcpus()``, - ``virConnectGetVersion()``, and ``virDomainGetAutostart()`` APIs have been - implemented in the Hyper-V driver. + ``virConnectGetVersion()``, ``virDomainGetAutostart()``, + ``virDomainSetAutostart()``, ``virNodeGetFreeMemory()``, + ``virDomainReboot()``, ``virDomainReset()``, ``virDomainShutdown()``, and + ``virDomainShutdownFlags()`` APIs have been implemented in the Hyper-V + driver. * **Improvements** -- 2.27.0
participants (3)
-
Daniel P. Berrangé
-
Matt Coleman
-
Pino Toscano