Re: [RFC v3] Export KVM Host Power Management capabilities

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 08/08/2011 09:18 AM, Srivatsa S. Bhat wrote:
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].

As pointed out in [4], until we have additional use for this feature, then this feature in isolation is unlikely to be pushed. That is not meant to discourage you from developing further patches, rather it is just stating that this patch will probably be deferred until it can be pushed as part of a larger series.

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.

No decision to make - libvirt.spec is solely for Fedora, where the package is always named pm-utils. Other distros use other packaging files, and can adjust accordingly, it's just that none of those other packaging files have been contributed for inclusion in upstream libvirt.git.

+  <define name='power_management'>
+    <choice>

No need for a <choice> here.

+      <element name='power_management'>
+        <optional>
+          <element name='S3'>
+            <empty/>
+          </element>
+        </optional>
+        <optional>
+          <element name='S4'>
+            <empty/>
+          </element>
+        </optional>
+      </element>

The two <optional> blocks are sufficient for allowing <power_management/> as an empty element, without any further rng grammar.


+/**
+ * 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++;

After thinking about this more, I'm wondering if it would be smarter to represent power management as a bitmask:

caps->hst.powerMgmt |= 1U << feature;

at which point, you still need isPMQuerySuccess (but see below on naming), but you don't need npowerMgmt. Instead, output would be:

@@ -686,6 +717,25 @@ virCapabilitiesFormatXML(virCapsPtr caps)

      virBufferAddLit(&xml, "</cpu>\n");

+    if(caps->host.isPMQuerySuccess) {

if (caps->host.powerMgmt) {
  unsigned int pm = caps->host.powerMgmt;
  virBufferAddLit(&xml, "<power_management>\n");
  while (pm) {
    int bit = ffs(pm) - 1;
    virBufferAsprintf(&xml, "<%s/>\n",
      virHostPMCapabilityTypeToString(bit);
    pm &= ~bit;
  }
  virBufferAddLit(&xml, "</power_management>\n");
} else {
  virBufferAddLit(&xml, "<power_management/>\n");
}

+++ b/src/conf/capabilities.h
@@ -105,6 +105,10 @@ struct _virCapsHost {
      size_t nfeatures;
      size_t nfeatures_max;
      char **features;
+    bool isPMQuerySuccess;

This isn't typical naming.  For consistency, I'm thinking:

bool powerMgmt_valid;

defaulting to false (powerMgmt is irrelavant), but set to true when powerMgmt contains valid data (where 0 can include valid data).

+    size_t npowerMgmt;
+    size_t npowerMgmt_max;
+    int *powerMgmt;    /* enum virHostPMCapability */

See above about just using 'unsigned int powerMgmt' as a bit-mask of valid capabilities, rather than a dynamically allocated array of ints.

@@ -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);
+    }

You don't want to set caps->host.isPMQuerySuccess (by whatever name) to true unless both commands succeeded. If the first command succeeds but the second fails, then you are better off treating the entire operation as failed.

Hmm, maybe virCheckPMCapability should take no arguments, and return the bitmask directly, rather than making qemuCapsInit have to compute the right bitmask.

  }
+
+/**
+ * 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)
+{

As I mentioned above, it would be nicer to have this return the bitmask up front, rather than to make each caller have to repeatedly call this function for as many capabilities as are currently defined. -1 for unknown, 0 for success but no support, or positive for a bitmask of 1<<bit for each supported bit.

+++ 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;

Better to make these case statements line up with declaration order (VIR_FROM_CAPABILITIES is new, so it should be at the end of the list just before default:).

--
Eric Blake   eblake@xxxxxxxxxx    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list


[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]