From 290ea33111be7bdf1f1381b90de33eb0e67c1a15 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 6 Oct 2010 17:54:41 -0600
Subject: [PATCH 13/15] vcpu: improve support for getting xen vcpu counts

* src/xen/xen_driver.c (xenUnifiedDomainGetVcpusFlags): Support
more flags.
* src/xen/xend_internal.h (xenDaemonDomainGetVcpusFlags): New
prototype.
* src/xen/xm_internal.h (xenXMDomainGetVcpusFlags): Likewise.
* src/xen/xend_internal.c (virDomainGetVcpusFlags): New function.
* src/xen/xm_internal.c (xenXMDomainGetVcpusFlags): Likewise.
---
 src/xen/xen_driver.c    |   31 +++++++++++++++++++--------
 src/xen/xend_internal.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++
 src/xen/xend_internal.h |    2 +
 src/xen/xm_internal.c   |   47 ++++++++++++++++++++++++++++++++++++++++++
 src/xen/xm_internal.h   |    1 +
 5 files changed, 124 insertions(+), 9 deletions(-)

diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
index d6c9c57..fe2ff86 100644
--- a/src/xen/xen_driver.c
+++ b/src/xen/xen_driver.c
@@ -1142,20 +1142,33 @@ static int
 xenUnifiedDomainGetVcpusFlags (virDomainPtr dom, unsigned int flags)
 {
     GET_PRIVATE(dom->conn);
-    int i, ret;
+    int ret;

-    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
-        xenUnifiedError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"),
-                        flags);
+    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
+                  VIR_DOMAIN_VCPU_CONFIG |
+                  VIR_DOMAIN_VCPU_MAXIMUM, -1);
+
+    /* Exactly one of LIVE or CONFIG must be set.  */
+    if (!(flags & VIR_DOMAIN_VCPU_LIVE) == !(flags & VIR_DOMAIN_VCPU_CONFIG)) {
+        xenUnifiedError(VIR_ERR_INVALID_ARG,
+                        _("invalid flag combination: (0x%x)"), flags);
         return -1;
     }

-    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
-        if (priv->opened[i] && drivers[i]->domainGetMaxVcpus) {
-            ret = drivers[i]->domainGetMaxVcpus (dom);
-            if (ret != 0) return ret;
-        }
+    if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+        ret = xenDaemonDomainGetVcpusFlags(dom, flags);
+        if (ret != -2)
+            return ret;
+    }
+    if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
+        ret = xenXMDomainGetVcpusFlags(dom, flags);
+        if (ret != -2)
+            return ret;
+    }
+    if (flags == (VIR_DOMAIN_VCPU_CONFIG | VIR_DOMAIN_VCPU_MAXIMUM))
+        return xenHypervisorGetVcpuMax(dom);

+    xenUnifiedError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
     return -1;
 }

diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
index dfc6415..3642296 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -3620,6 +3620,58 @@ xenDaemonDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
 }

 /**
+ * xenDaemonDomainGetVcpusFlags:
+ * @domain: pointer to domain object
+ * @flags: bitwise-ORd from virDomainVcpuFlags
+ *
+ * Extract information about virtual CPUs of domain according to flags.
+ *
+ * Returns the number of vcpus on success, -1 if an error message was
+ * issued, and -2 if the unified driver should keep trying.
+
+ */
+int
+xenDaemonDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
+{
+    struct sexpr *root;
+    int ret;
+    xenUnifiedPrivatePtr priv;
+
+    if (domain == NULL || domain->conn == NULL || domain->name == NULL) {
+        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return -1;
+    }
+
+    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+    /* If xendConfigVersion is 2, then we can only report _LIVE (and
+     * xm_internal reports _CONFIG).  If it is 3, then _LIVE and
+     * _CONFIG are always in sync for a running system.  */
+    if (domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
+        return -2;
+    if (domain->id < 0 && (flags & VIR_DOMAIN_VCPU_LIVE)) {
+        virXendError(VIR_ERR_OPERATION_INVALID, "%s",
+                     _("domain not active"));
+        return -1;
+    }
+
+    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
+    if (root == NULL)
+        return -1;
+
+    ret = sexpr_int(root, "domain/vcpus");
+    if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM)) {
+        int vcpus = count_one_bits(sexpr_int(root, "domain/vcpu_avail"));
+        if (vcpus)
+            ret = MIN(vcpus, ret);
+    }
+    if (!ret)
+        ret = -2;
+    sexpr_free(root);
+    return ret;
+}
+
+/**
  * virDomainGetVcpus:
  * @domain: pointer to domain object, or NULL for Domain0
  * @info: pointer to an array of virVcpuInfo structures (OUT)
diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h
index c757716..923cebd 100644
--- a/src/xen/xend_internal.h
+++ b/src/xen/xend_internal.h
@@ -155,6 +155,8 @@ int	xenDaemonDomainPinVcpu		(virDomainPtr domain,
                                          unsigned int vcpu,
                                          unsigned char *cpumap,
                                          int maplen);
+int     xenDaemonDomainGetVcpusFlags    (virDomainPtr domain,
+                                         unsigned int flags);
 int	xenDaemonDomainGetVcpus		(virDomainPtr domain,
                                          virVcpuInfoPtr info,
                                          int maxinfo,
diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
index f7121ab..4ea4245 100644
--- a/src/xen/xm_internal.c
+++ b/src/xen/xm_internal.c
@@ -1671,6 +1671,53 @@ cleanup:
 }

 /**
+ * xenXMDomainGetVcpusFlags:
+ * @domain: pointer to domain object
+ * @flags: bitwise-ORd from virDomainVcpuFlags
+ *
+ * Extract information about virtual CPUs of domain according to flags.
+ *
+ * Returns the number of vcpus on success, -1 if an error message was
+ * issued, and -2 if the unified driver should keep trying.
+ */
+int
+xenXMDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
+{
+    xenUnifiedPrivatePtr priv;
+    const char *filename;
+    xenXMConfCachePtr entry;
+    int ret = -2;
+
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return -1;
+    }
+
+    if (domain->id != -1)
+        return -2;
+    if (flags & VIR_DOMAIN_VCPU_LIVE) {
+        xenXMError(VIR_ERR_OPERATION_FAILED, "%s", _("domain not active"));
+        return -1;
+    }
+
+    priv = domain->conn->privateData;
+    xenUnifiedLock(priv);
+
+    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+        goto cleanup;
+
+    if (!(entry = virHashLookup(priv->configCache, filename)))
+        goto cleanup;
+
+    ret = ((flags & VIR_DOMAIN_VCPU_MAXIMUM) ? entry->def->maxvcpus
+           : entry->def->vcpus);
+
+cleanup:
+    xenUnifiedUnlock(priv);
+    return ret;
+}
+
+/**
  * xenXMDomainPinVcpu:
  * @domain: pointer to domain object
  * @vcpu: virtual CPU number (reserved)
diff --git a/src/xen/xm_internal.h b/src/xen/xm_internal.h
index 3ad3456..3295fbd 100644
--- a/src/xen/xm_internal.h
+++ b/src/xen/xm_internal.h
@@ -45,6 +45,7 @@ int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory);
 int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory);
 unsigned long xenXMDomainGetMaxMemory(virDomainPtr domain);
 int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus);
+int xenXMDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags);
 int xenXMDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
                        unsigned char *cpumap, int maplen);
 virDomainPtr xenXMDomainLookupByName(virConnectPtr conn, const char *domname);
-- 
1.7.2.3

