This patch exports KVM Host Power Management capabilities as XML so that higher-level systems management software can make use of these features available in the host. The script "pm-is-supported" (from pm-utils package) is run to discover if Suspend-to-RAM (S3) or Suspend-to-Disk (S4) is supported by the host. If either of them are supported, then a new tag "<power_management>" is introduced in the XML under the <host> tag. Eg: When the host supports both S3 and S4, the XML looks like this: <capabilities> <host> <uuid>dc699581-48a2-11cb-b8a8-9a0265a79bbe</uuid> <cpu> <arch>i686</arch> <model>coreduo</model> <vendor>Intel</vendor> <topology sockets='1' cores='2' threads='1'/> <feature name='xtpr'/> <feature name='tm2'/> <feature name='est'/> <feature name='vmx'/> <feature name='pbe'/> <feature name='tm'/> <feature name='ht'/> <feature name='ss'/> <feature name='acpi'/> <feature name='ds'/> </cpu> <power_management> <<<=== New host power management features <S3/> <S4/> </power_management> <migration_features> <live/> <uri_transports> <uri_transport>tcp</uri_transport> </uri_transports> </migration_features> </host> . . . However in case the host does not support any power management feature, then the XML will not contain the <power_management> tag. The initial discussion about this patch was done in [1]. And the choice to name the new tag as "power_management" was discussed in [2]. Please let me know your comments and feedback. References: ---------- [1] Exporting KVM host power saving capabilities through libvirt http://thread.gmane.org/gmane.comp.emulators.libvirt/40886 [2] http://article.gmane.org/gmane.comp.emulators.libvirt/41688 Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@xxxxxxxxxxxxxxxxxx> --- src/conf/capabilities.c | 34 +++++++++++++++++++++++++++ src/conf/capabilities.h | 7 ++++++ src/libvirt_private.syms | 2 ++ src/qemu/qemu_capabilities.c | 10 ++++++++ src/util/util.c | 52 ++++++++++++++++++++++++++++++++++++++++++ src/util/util.h | 7 ++++++ 6 files changed, 112 insertions(+), 0 deletions(-) diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index 2f243ae..94423dc 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -166,6 +166,10 @@ virCapabilitiesFree(virCapsPtr caps) { virCapabilitiesFreeNUMAInfo(caps); + for(i = 0; i < caps->host.npowerMgmt ; i++) + VIR_FREE(caps->host.powerMgmt[i]); + VIR_FREE(caps->host.powerMgmt); + for (i = 0 ; i < caps->host.nmigrateTrans ; i++) VIR_FREE(caps->host.migrateTrans[i]); VIR_FREE(caps->host.migrateTrans); @@ -201,6 +205,27 @@ virCapabilitiesAddHostFeature(virCapsPtr caps, return 0; } +/** + * virCapabilitiesAddHostPowerManagement: + * @caps: capabilities to extend + * @name: name of power management feature + * + * Registers a new host power management feature, eg: 'S3' or 'S4' + */ +int +virCapabilitiesAddHostPowerManagement(virCapsPtr caps, + const char *name) +{ + if(VIR_RESIZE_N(caps->host.powerMgmt, caps->host.npowerMgmt_max, + caps->host.npowerMgmt, 1) < 0) + return -1; + + if((caps->host.powerMgmt[caps->host.npowerMgmt] = strdup(name)) == NULL) + return -1; + caps->host.npowerMgmt++; + + return 0; +} /** * virCapabilitiesAddHostMigrateTransport: @@ -686,6 +711,15 @@ virCapabilitiesFormatXML(virCapsPtr caps) virBufferAddLit(&xml, " </cpu>\n"); + if(caps->host.npowerMgmt) { + virBufferAddLit(&xml, " <power_management>\n"); + for (i = 0; i < caps->host.npowerMgmt ; i++) { + virBufferAsprintf(&xml, " <%s/>\n", + caps->host.powerMgmt[i]); + } + virBufferAddLit(&xml, " </power_management>\n"); + } + if (caps->host.offlineMigrate) { virBufferAddLit(&xml, " <migration_features>\n"); if (caps->host.liveMigrate) diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index e2fa1d6..eb6e561 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -105,6 +105,9 @@ struct _virCapsHost { size_t nfeatures; size_t nfeatures_max; char **features; + size_t npowerMgmt; + size_t npowerMgmt_max; + char **powerMgmt; int offlineMigrate; int liveMigrate; size_t nmigrateTrans; @@ -186,6 +189,10 @@ virCapabilitiesAddHostFeature(virCapsPtr caps, const char *name); extern int +virCapabilitiesAddHostPowerManagement(virCapsPtr caps, + const char *name); + +extern int virCapabilitiesAddHostMigrateTransport(virCapsPtr caps, const char *name); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 830222b..5754fdd 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -41,6 +41,7 @@ virCapabilitiesAddGuestFeature; virCapabilitiesAddHostFeature; virCapabilitiesAddHostMigrateTransport; virCapabilitiesAddHostNUMACell; +virCapabilitiesAddHostPowerManagement; virCapabilitiesAllocMachines; virCapabilitiesDefaultGuestArch; virCapabilitiesDefaultGuestEmulator; @@ -1025,6 +1026,7 @@ safezero; virArgvToString; virAsprintf; virBuildPathInternal; +virCheckPMCapability; virDirCreate; virEmitXMLWarning; virEnumFromString; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 3f36212..6e969a7 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -824,6 +824,16 @@ virCapsPtr qemuCapsInit(virCapsPtr old_caps) old_caps->host.cpu = NULL; } + /* Add the power management features of the host */ + + /* Check for Suspend-to-RAM support (S3) */ + if(virCheckPMCapability(HOST_PM_S3) == 0) + virCapabilitiesAddHostPowerManagement(caps, "S3"); + + /* Check for Suspend-to-Disk support (S4) */ + if(virCheckPMCapability(HOST_PM_S4) == 0) + virCapabilitiesAddHostPowerManagement(caps, "S4"); + virCapabilitiesAddHostMigrateTransport(caps, "tcp"); diff --git a/src/util/util.c b/src/util/util.c index 03a9e1a..9893597 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -2641,3 +2641,55 @@ or other application using the libvirt API.\n\ return 0; } + +/** + * Check the Power Management Capabilities of the host system. + * The script 'pm-is-supported' (from the pm-utils package) is run + * to find out if the capability is supported by the host. + * + * @capability: capability to check for + * HOST_PM_S3: Check for Suspend-to-RAM support + * HOST_PM_S4: Check for Suspend-to-Disk support + * + * Returns 0 if supported, -1 if not supported. + */ +int +virCheckPMCapability(int capability) +{ + + char *path = NULL; + int status = -1, ret = -1; + virCommandPtr cmd; + + if((path = virFindFileInPath("pm-is-supported")) == NULL) + return -1; + + cmd = virCommandNew(path); + switch(capability) { + case HOST_PM_S3: + /* Check support for suspend (S3) */ + virCommandAddArg(cmd, "--suspend"); + break; + + case HOST_PM_S4: + /* Check support for hibernation (S4) */ + virCommandAddArg(cmd, "--hibernate"); + break; + + default: + goto cleanup; + } + + if(virCommandRun(cmd, &status) < 0) + goto cleanup; + + /* Check return code of command == 0 for success */ + if(status == 0) + ret = 0; + +cleanup: + virCommandFree(cmd); + VIR_FREE(path); + return ret; +} + diff --git a/src/util/util.h b/src/util/util.h index af8b15d..c428eb4 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -272,4 +272,11 @@ bool virIsDevMapperDevice(const char *devname) ATTRIBUTE_NONNULL(1); int virEmitXMLWarning(int fd, const char *name, const char *cmd) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + +/* Power Management Capabilities of the host system */ +# define HOST_PM_S3 1 /* Suspend-to-RAM */ +# define HOST_PM_S4 2 /* Suspend-to-Disk */ + +int virCheckPMCapability(int capability); + #endif /* __VIR_UTIL_H__ */ -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list