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 query to check for power management features succeeded, but the host does not support any such feature, then the XML will contain an empty <power_management/> tag. In the event that the PM query itself failed, the XML will not contain any "power_management" tag. Open issues: ----------- 1. Design new APIs in libvirt to actually exploit the host power management features instead of relying on external programs. This was discussed in [4]. 2. Decide on whether to include "pm-utils" package in the libvirt.spec file considering the fact that the package name (pm-utils) may differ from one Linux distribution to another. Please let me know your comments and feedback. Changelog: --------- v1: The idea of exporting host power management capabilities through libvirt was discussed in [1]. The choice to name the new tag as "power_management" was discussed in [2]. v2: A working implementation was presented for review in [3]. 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 [3] http://www.redhat.com/archives/libvir-list/2011-August/msg00238.html [4] http://www.redhat.com/archives/libvir-list/2011-August/msg00248.html Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@xxxxxxxxxxxxxxxxxx> --- docs/formatcaps.html.in | 19 ++++++++++--- docs/schemas/capability.rng | 23 ++++++++++++++++ include/libvirt/virterror.h | 1 + src/conf/capabilities.c | 50 ++++++++++++++++++++++++++++++++++ src/conf/capabilities.h | 8 ++++++ src/libvirt_private.syms | 2 + src/qemu/qemu_capabilities.c | 27 +++++++++++++++++++ src/util/util.c | 61 ++++++++++++++++++++++++++++++++++++++++++ src/util/util.h | 14 ++++++++++ src/util/virterror.c | 3 ++ 10 files changed, 203 insertions(+), 5 deletions(-) diff --git a/docs/formatcaps.html.in b/docs/formatcaps.html.in index a4297ce..ce6f9a6 100644 --- a/docs/formatcaps.html.in +++ b/docs/formatcaps.html.in @@ -28,6 +28,10 @@ BIOS you will see</p> <feature name='xtpr'/> ... </cpu> + <power_management> + <S3/> + <S4/> + <power_management/> </host></span> <!-- xen-3.0-x86_64 --> @@ -61,11 +65,16 @@ BIOS you will see</p> ... </capabilities></pre> <p>The first block (in red) indicates the host hardware capabilities, currently -it is limited to the CPU properties but other information may be available, -it shows the CPU architecture, topology, model name, and additional features -which are not included in the model but the CPU provides them. Features of the -chip are shown within the feature block (the block is similar to what you will -find in a Xen fully virtualized domain description).</p> +it is limited to the CPU properties and the power management features of +the host platform, but other information may be available, it shows the CPU architecture, +topology, model name, and additional features which are not included in the model but the +CPU provides them. Features of the chip are shown within the feature block (the block is +similar to what you will find in a Xen fully virtualized domain description). Further, +the power management features supported by the host are shown, such as Suspend-to-RAM (S3) +and Suspend-to-Disk (S4). In case the query for power management features succeeded but the +host does not support any such feature, then an empty <power_management/> +tag will be shown. Otherwise, if the query itself failed, no such tag will +be displayed (i.e., there will not be any power_management block or empty tag in the XML).</p> <p>The second block (in blue) indicates the paravirtualization support of the Xen support, you will see the os_type of xen to indicate a paravirtual kernel, then architecture information and potential features.</p> diff --git a/docs/schemas/capability.rng b/docs/schemas/capability.rng index 99b4a9a..930374c 100644 --- a/docs/schemas/capability.rng +++ b/docs/schemas/capability.rng @@ -35,6 +35,9 @@ </optional> </element> <optional> + <ref name='power_management'/> + </optional> + <optional> <ref name='migration'/> </optional> <optional> @@ -105,6 +108,26 @@ </zeroOrMore> </define> + <define name='power_management'> + <choice> + <element name='power_management'> + <optional> + <element name='S3'> + <empty/> + </element> + </optional> + <optional> + <element name='S4'> + <empty/> + </element> + </optional> + </element> + <element name='power_management'> + <empty/> + </element> + </choice> + </define> + <define name='migration'> <element name='migration_features'> <optional> diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 9cac437..a831c73 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -82,6 +82,7 @@ typedef enum { VIR_FROM_EVENT = 40, /* Error from event loop impl */ VIR_FROM_LIBXL = 41, /* Error from libxenlight driver */ VIR_FROM_LOCKING = 42, /* Error from lock manager */ + VIR_FROM_CAPABILITIES = 43, /* Error from capabilities */ } virErrorDomain; diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index 2f243ae..d39a3f9 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -29,6 +29,13 @@ #include "util.h" #include "uuid.h" #include "cpu_conf.h" +#include "virterror_internal.h" + + +#define VIR_FROM_THIS VIR_FROM_CAPABILITIES + +VIR_ENUM_IMPL(virHostPMCapability, VIR_HOST_PM_LAST, + "S3", "S4") /** * virCapabilitiesNew: @@ -166,6 +173,8 @@ virCapabilitiesFree(virCapsPtr caps) { virCapabilitiesFreeNUMAInfo(caps); + 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 +210,28 @@ virCapabilitiesAddHostFeature(virCapsPtr caps, return 0; } +/** + * virCapabilitiesAddHostPowerManagement: + * @caps: capabilities to extend + * @feature: the power management feature to be added + * + * Registers a new host power management feature, eg: 'S3' or 'S4' + */ +int +virCapabilitiesAddHostPowerManagement(virCapsPtr caps, + int feature) +{ + if(VIR_RESIZE_N(caps->host.powerMgmt, caps->host.npowerMgmt_max, + caps->host.npowerMgmt, 1) < 0) { + virReportOOMError(); + return -1; + } + + caps->host.powerMgmt[caps->host.npowerMgmt] = feature; + caps->host.npowerMgmt++; + + return 0; +} /** * virCapabilitiesAddHostMigrateTransport: @@ -686,6 +717,25 @@ virCapabilitiesFormatXML(virCapsPtr caps) virBufferAddLit(&xml, " </cpu>\n"); + if(caps->host.isPMQuerySuccess) { + if(caps->host.npowerMgmt) { + /* The PM Query was successful and the host supports + * some PM features. + */ + virBufferAddLit(&xml, " <power_management>\n"); + for (i = 0; i < caps->host.npowerMgmt ; i++) { + virBufferAsprintf(&xml, " <%s/>\n", + virHostPMCapabilityTypeToString(caps->host.powerMgmt[i])); + } + virBufferAddLit(&xml, " </power_management>\n"); + } else { + /* The PM Query was successful but the host does not + * support any PM feature. + */ + 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..afbf732 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -105,6 +105,10 @@ struct _virCapsHost { size_t nfeatures; size_t nfeatures_max; char **features; + bool isPMQuerySuccess; + size_t npowerMgmt; + size_t npowerMgmt_max; + int *powerMgmt; /* enum virHostPMCapability */ int offlineMigrate; int liveMigrate; size_t nmigrateTrans; @@ -186,6 +190,10 @@ virCapabilitiesAddHostFeature(virCapsPtr caps, const char *name); extern int +virCapabilitiesAddHostPowerManagement(virCapsPtr caps, + int feature); + +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..f3d0c0a 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -794,6 +794,7 @@ virCapsPtr qemuCapsInit(virCapsPtr old_caps) struct utsname utsname; virCapsPtr caps; int i; + int status = -1; char *xenner = NULL; /* Really, this never fails - look at the man-page. */ @@ -824,6 +825,32 @@ 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) */ + status = virCheckPMCapability(VIR_HOST_PM_S3); + if(status < 0) { + caps->host.isPMQuerySuccess = false; + VIR_WARN("Failed to get host power management features"); + } else { + /* The PM Query succeeded */ + caps->host.isPMQuerySuccess = true; + if(status == 1) /* S3 is supported */ + virCapabilitiesAddHostPowerManagement(caps, VIR_HOST_PM_S3); + } + + /* Check for Suspend-to-Disk support (S4) */ + status = virCheckPMCapability(VIR_HOST_PM_S4); + if(status < 0) { + caps->host.isPMQuerySuccess = false; + VIR_WARN("Failed to get host power management features"); + } else { + /* The PM Query succeeded */ + caps->host.isPMQuerySuccess = true; + if(status == 1) /* S4 is supported */ + virCapabilitiesAddHostPowerManagement(caps, VIR_HOST_PM_S4); + } + virCapabilitiesAddHostMigrateTransport(caps, "tcp"); diff --git a/src/util/util.c b/src/util/util.c index 03a9e1a..489c4d6 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -2641,3 +2641,64 @@ 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 + * VIR_HOST_PM_S3: Check for Suspend-to-RAM support + * VIR_HOST_PM_S4: Check for Suspend-to-Disk support + * + * Return values: + * 1 if the capability is supported. + * 0 if the query was successful but the capability is + * not supported by the host. + * -1 on error like 'pm-is-supported' is not found. + */ +int +virCheckPMCapability(int capability) +{ + + char *path = NULL; + int status = -1; + int ret = -1; + virCommandPtr cmd; + + if((path = virFindFileInPath("pm-is-supported")) == NULL) { + virUtilError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Failed to get the path of pm-is-supported")); + return -1; + } + + cmd = virCommandNew(path); + switch(capability) { + case VIR_HOST_PM_S3: + /* Check support for suspend (S3) */ + virCommandAddArg(cmd, "--suspend"); + break; + + case VIR_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 + * (i.e., the PM capability is supported) + */ + ret = (status == 0) ? 1 : 0; + +cleanup: + virCommandFree(cmd); + VIR_FREE(path); + return ret; +} + diff --git a/src/util/util.h b/src/util/util.h index af8b15d..dfb8c1a 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -272,4 +272,18 @@ 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 */ + +enum virHostPMCapability { + VIR_HOST_PM_S3, /* Suspend-to-RAM */ + VIR_HOST_PM_S4, /* Suspend-to-Disk */ + + VIR_HOST_PM_LAST +}; + +VIR_ENUM_DECL(virHostPMCapability) + +int virCheckPMCapability(int capability); + #endif /* __VIR_UTIL_H__ */ diff --git a/src/util/virterror.c b/src/util/virterror.c index 9a27feb..26d6011 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -148,6 +148,9 @@ static const char *virErrorDomainName(virErrorDomain domain) { case VIR_FROM_CPU: dom = "CPU "; break; + case VIR_FROM_CAPABILITIES: + dom = "Capabilities "; + break; case VIR_FROM_NWFILTER: dom = "Network Filter "; break; -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list