render / rpms / libvirt

Forked from rpms/libvirt 9 months ago
Clone
e10da2
From e443a003129a172a7332f3cb6e40b3c39363ed5e Mon Sep 17 00:00:00 2001
e10da2
From: Eric Blake <eblake@redhat.com>
e10da2
Date: Thu, 14 Oct 2010 16:17:18 -0600
e10da2
Subject: [PATCH 14/15] vcpu: improve support for setting xen vcpu counts
e10da2
e10da2
Tested with RHEL 5.6 (xendConfigVersion 2, where xend_internal
e10da2
controls live domains and xm_internal controls inactive domains).
e10da2
Hopefully this works with xendConfigVersion 3 (where xend_internal
e10da2
controls everything).
e10da2
e10da2
* src/xen/xen_driver.c (xenUnifiedDomainSetVcpusFlags): Support
e10da2
more flags.
e10da2
(xenUnifiedGetMaxVcpus): Export.
e10da2
* src/xen/xm_internal.h (xenXMDomainSetVcpusFlags): New prototype.
e10da2
* src/xen/xend_internal.h (xenDaemonDomainSetVcpusFlags): Likewise.
e10da2
* src/xen/xen_driver.h (xenUnifiedGetMaxVcpus): Likewise.
e10da2
* src/xen/xm_internal.c (xenXMDomainSetVcpusFlags): New function.
e10da2
* src/xen/xend_internal.c (xenDaemonDomainSetVcpusFlags): Likewise.
e10da2
---
e10da2
 src/xen/xen_driver.c    |   60 ++++++++++++++++++++++++---------
e10da2
 src/xen/xen_driver.h    |    1 +
e10da2
 src/xen/xend_internal.c |   76 +++++++++++++++++++++++++++++++++++++++++++
e10da2
 src/xen/xend_internal.h |    3 ++
e10da2
 src/xen/xm_internal.c   |   83 +++++++++++++++++++++++++++++++++++++++++++++++
e10da2
 src/xen/xm_internal.h   |    2 +
e10da2
 6 files changed, 208 insertions(+), 17 deletions(-)
e10da2
e10da2
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
e10da2
index fe2ff86..66e8518 100644
e10da2
--- a/src/xen/xen_driver.c
e10da2
+++ b/src/xen/xen_driver.c
e10da2
@@ -508,7 +508,7 @@ xenUnifiedIsSecure(virConnectPtr conn)
e10da2
     return ret;
e10da2
 }
e10da2
e10da2
-static int
e10da2
+int
e10da2
 xenUnifiedGetMaxVcpus (virConnectPtr conn, const char *type)
e10da2
 {
e10da2
     GET_PRIVATE(conn);
e10da2
@@ -1073,36 +1073,62 @@ xenUnifiedDomainSetVcpusFlags (virDomainPtr dom, unsigned int nvcpus,
e10da2
                                unsigned int flags)
e10da2
 {
e10da2
     GET_PRIVATE(dom->conn);
e10da2
-    int i;
e10da2
+    int ret;
e10da2
+
e10da2
+    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
e10da2
+                  VIR_DOMAIN_VCPU_CONFIG |
e10da2
+                  VIR_DOMAIN_VCPU_MAXIMUM, -1);
e10da2
e10da2
-    if (flags != VIR_DOMAIN_VCPU_LIVE) {
e10da2
-        xenUnifiedError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"),
e10da2
-                        flags);
e10da2
+    /* At least one of LIVE or CONFIG must be set.  MAXIMUM cannot be
e10da2
+     * mixed with LIVE.  */
e10da2
+    if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0 ||
e10da2
+        (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) ==
e10da2
+         (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) {
e10da2
+        xenUnifiedError(VIR_ERR_INVALID_ARG,
e10da2
+                        _("invalid flag combination: (0x%x)"), flags);
e10da2
+        return -1;
e10da2
+    }
e10da2
+    if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
e10da2
+        xenUnifiedError(VIR_ERR_INVALID_ARG,
e10da2
+                        _("argument out of range: %d"), nvcpus);
e10da2
         return -1;
e10da2
     }
e10da2
e10da2
     /* Try non-hypervisor methods first, then hypervisor direct method
e10da2
      * as a last resort.
e10da2
      */
e10da2
-    for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
e10da2
-        if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
e10da2
-            priv->opened[i] &&
e10da2
-            drivers[i]->domainSetVcpus &&
e10da2
-            drivers[i]->domainSetVcpus (dom, nvcpus) == 0)
e10da2
-            return 0;
e10da2
-
e10da2
-    if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
e10da2
-        drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSetVcpus &&
e10da2
-        drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSetVcpus (dom, nvcpus) == 0)
e10da2
-        return 0;
e10da2
+    if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
e10da2
+        ret = xenDaemonDomainSetVcpusFlags(dom, nvcpus, flags);
e10da2
+        if (ret != -2)
e10da2
+            return ret;
e10da2
+    }
e10da2
+    if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
e10da2
+        ret = xenXMDomainSetVcpusFlags(dom, nvcpus, flags);
e10da2
+        if (ret != -2)
e10da2
+            return ret;
e10da2
+    }
e10da2
+    if (flags == VIR_DOMAIN_VCPU_LIVE)
e10da2
+        return xenHypervisorSetVcpus(dom, nvcpus);
e10da2
e10da2
+    xenUnifiedError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
e10da2
     return -1;
e10da2
 }
e10da2
e10da2
 static int
e10da2
 xenUnifiedDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus)
e10da2
 {
e10da2
-    return xenUnifiedDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
e10da2
+    unsigned int flags = VIR_DOMAIN_VCPU_LIVE;
e10da2
+    xenUnifiedPrivatePtr priv;
e10da2
+
e10da2
+    /* Per the documented API, it is hypervisor-dependent whether this
e10da2
+     * affects just _LIVE or _LIVE|_CONFIG; in xen's case, that
e10da2
+     * depends on xendConfigVersion.  */
e10da2
+    if (dom) {
e10da2
+        priv = dom->conn->privateData;
e10da2
+        if (priv->xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4)
e10da2
+            flags |= VIR_DOMAIN_VCPU_CONFIG;
e10da2
+    }
e10da2
+    return xenUnifiedDomainSetVcpusFlags(dom, nvcpus, flags);
e10da2
 }
e10da2
e10da2
 static int
e10da2
diff --git a/src/xen/xen_driver.h b/src/xen/xen_driver.h
e10da2
index 3e7c1d0..115a26a 100644
e10da2
--- a/src/xen/xen_driver.h
e10da2
+++ b/src/xen/xen_driver.h
e10da2
@@ -220,6 +220,7 @@ int  xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr info,
e10da2
 void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
e10da2
                                     virDomainEventPtr event);
e10da2
 unsigned long xenUnifiedVersion(void);
e10da2
+int xenUnifiedGetMaxVcpus(virConnectPtr conn, const char *type);
e10da2
e10da2
 # ifndef PROXY
e10da2
 void xenUnifiedLock(xenUnifiedPrivatePtr priv);
e10da2
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
e10da2
index 3642296..55c2cc4 100644
e10da2
--- a/src/xen/xend_internal.c
e10da2
+++ b/src/xen/xend_internal.c
e10da2
@@ -3535,6 +3535,82 @@ xenDaemonLookupByID(virConnectPtr conn, int id) {
e10da2
 }
e10da2
e10da2
 /**
e10da2
+ * xenDaemonDomainSetVcpusFlags:
e10da2
+ * @domain: pointer to domain object
e10da2
+ * @nvcpus: the new number of virtual CPUs for this domain
e10da2
+ * @flags: bitwise-ORd from virDomainVcpuFlags
e10da2
+ *
e10da2
+ * Change virtual CPUs allocation of domain according to flags.
e10da2
+ *
e10da2
+ * Returns 0 on success, -1 if an error message was issued, and -2 if
e10da2
+ * the unified driver should keep trying.
e10da2
+ */
e10da2
+int
e10da2
+xenDaemonDomainSetVcpusFlags(virDomainPtr domain, unsigned int vcpus,
e10da2
+                             unsigned int flags)
e10da2
+{
e10da2
+    char buf[VIR_UUID_BUFLEN];
e10da2
+    xenUnifiedPrivatePtr priv;
e10da2
+    int max;
e10da2
+
e10da2
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
e10da2
+        || (vcpus < 1)) {
e10da2
+        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
e10da2
+        return (-1);
e10da2
+    }
e10da2
+
e10da2
+    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
e10da2
+
e10da2
+    if ((domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ||
e10da2
+        (flags & VIR_DOMAIN_VCPU_MAXIMUM))
e10da2
+        return -2;
e10da2
+
e10da2
+    /* With xendConfigVersion 2, only _LIVE is supported.  With
e10da2
+     * xendConfigVersion 3, only _LIVE|_CONFIG is supported for
e10da2
+     * running domains, or _CONFIG for inactive domains.  */
e10da2
+    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
e10da2
+        if (flags & VIR_DOMAIN_VCPU_CONFIG) {
e10da2
+            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
e10da2
+                         _("Xend version does not support modifying "
e10da2
+                           "persistent config"));
e10da2
+            return -1;
e10da2
+        }
e10da2
+    } else if (domain->id < 0) {
e10da2
+        if (flags & VIR_DOMAIN_VCPU_LIVE) {
e10da2
+            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
e10da2
+                         _("domain not running"));
e10da2
+            return -1;
e10da2
+        }
e10da2
+    } else {
e10da2
+        if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) !=
e10da2
+            (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) {
e10da2
+            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
e10da2
+                         _("Xend only supports modifying both live and "
e10da2
+                           "persistent config"));
e10da2
+        }
e10da2
+    }
e10da2
+
e10da2
+    /* Unfortunately, xend_op does not validate whether this exceeds
e10da2
+     * the maximum.  */
e10da2
+    flags |= VIR_DOMAIN_VCPU_MAXIMUM;
e10da2
+    if ((max = xenDaemonDomainGetVcpusFlags(domain, flags)) < 0) {
e10da2
+        virXendError(VIR_ERR_OPERATION_INVALID, "%s",
e10da2
+                     _("could not determin max vcpus for the domain"));
e10da2
+        return -1;
e10da2
+    }
e10da2
+    if (vcpus > max) {
e10da2
+        virXendError(VIR_ERR_INVALID_ARG,
e10da2
+                     _("requested vcpus is greater than max allowable"
e10da2
+                       " vcpus for the domain: %d > %d"), vcpus, max);
e10da2
+        return -1;
e10da2
+    }
e10da2
+
e10da2
+    snprintf(buf, sizeof(buf), "%d", vcpus);
e10da2
+    return xend_op(domain->conn, domain->name, "op", "set_vcpus", "vcpus",
e10da2
+                   buf, NULL);
e10da2
+}
e10da2
+
e10da2
+/**
e10da2
  * xenDaemonDomainSetVcpus:
e10da2
  * @domain: pointer to domain object
e10da2
  * @nvcpus: the new number of virtual CPUs for this domain
e10da2
diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h
e10da2
index 923cebd..53f5d2c 100644
e10da2
--- a/src/xen/xend_internal.h
e10da2
+++ b/src/xen/xend_internal.h
e10da2
@@ -151,6 +151,9 @@ int xenDaemonDomainUndefine(virDomainPtr domain);
e10da2
e10da2
 int	xenDaemonDomainSetVcpus		(virDomainPtr domain,
e10da2
                                          unsigned int vcpus);
e10da2
+int	xenDaemonDomainSetVcpusFlags	(virDomainPtr domain,
e10da2
+                                         unsigned int vcpus,
e10da2
+                                         unsigned int flags);
e10da2
 int	xenDaemonDomainPinVcpu		(virDomainPtr domain,
e10da2
                                          unsigned int vcpu,
e10da2
                                          unsigned char *cpumap,
e10da2
diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
e10da2
index 4ea4245..2b8e51e 100644
e10da2
--- a/src/xen/xm_internal.c
e10da2
+++ b/src/xen/xm_internal.c
e10da2
@@ -1670,6 +1670,89 @@ cleanup:
e10da2
     return ret;
e10da2
 }
e10da2
e10da2
+/*
e10da2
+ * xenXMDomainSetVcpusFlags:
e10da2
+ * @domain: pointer to domain object
e10da2
+ * @nvcpus: number of vcpus
e10da2
+ * @flags: bitwise-ORd from virDomainVcpuFlags
e10da2
+ *
e10da2
+ * Change virtual CPUs allocation of domain according to flags.
e10da2
+ *
e10da2
+ * Returns 0 on success, -1 if an error message was issued, and -2 if
e10da2
+ * the unified driver should keep trying.
e10da2
+ */
e10da2
+int
e10da2
+xenXMDomainSetVcpusFlags(virDomainPtr domain, unsigned int vcpus,
e10da2
+                         unsigned int flags)
e10da2
+{
e10da2
+    xenUnifiedPrivatePtr priv;
e10da2
+    const char *filename;
e10da2
+    xenXMConfCachePtr entry;
e10da2
+    int ret = -1;
e10da2
+    int max;
e10da2
+
e10da2
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
e10da2
+        xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
e10da2
+        return -1;
e10da2
+    }
e10da2
+    if (domain->conn->flags & VIR_CONNECT_RO) {
e10da2
+        xenXMError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
e10da2
+        return -1;
e10da2
+    }
e10da2
+    if (domain->id != -1)
e10da2
+        return -2;
e10da2
+    if (flags & VIR_DOMAIN_VCPU_LIVE) {
e10da2
+        xenXMError(VIR_ERR_OPERATION_INVALID, "%s",
e10da2
+                   _("domain is not running"));
e10da2
+        return -1;
e10da2
+    }
e10da2
+
e10da2
+    priv = domain->conn->privateData;
e10da2
+    xenUnifiedLock(priv);
e10da2
+
e10da2
+    if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
e10da2
+        goto cleanup;
e10da2
+
e10da2
+    if (!(entry = virHashLookup(priv->configCache, filename)))
e10da2
+        goto cleanup;
e10da2
+
e10da2
+    /* Hypervisor maximum. */
e10da2
+    if ((max = xenUnifiedGetMaxVcpus(domain->conn, NULL)) < 0) {
e10da2
+        xenXMError(VIR_ERR_INTERNAL_ERROR, "%s",
e10da2
+                   _("could not determin max vcpus for the domain"));
e10da2
+        goto cleanup;
e10da2
+    }
e10da2
+    /* Can't specify a current larger than stored maximum; but
e10da2
+     * reducing maximum can silently reduce current.  */
e10da2
+    if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM))
e10da2
+        max = entry->def->maxvcpus;
e10da2
+    if (vcpus > max) {
e10da2
+        xenXMError(VIR_ERR_INVALID_ARG,
e10da2
+                   _("requested vcpus is greater than max allowable"
e10da2
+                     " vcpus for the domain: %d > %d"), vcpus, max);
e10da2
+        goto cleanup;
e10da2
+    }
e10da2
+
e10da2
+    if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
e10da2
+        entry->def->maxvcpus = vcpus;
e10da2
+        if (entry->def->vcpus > vcpus)
e10da2
+            entry->def->vcpus = vcpus;
e10da2
+    } else {
e10da2
+        entry->def->vcpus = vcpus;
e10da2
+    }
e10da2
+
e10da2
+    /* If this fails, should we try to undo our changes to the
e10da2
+     * in-memory representation of the config file. I say not!
e10da2
+     */
e10da2
+    if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
e10da2
+        goto cleanup;
e10da2
+    ret = 0;
e10da2
+
e10da2
+cleanup:
e10da2
+    xenUnifiedUnlock(priv);
e10da2
+    return ret;
e10da2
+}
e10da2
+
e10da2
 /**
e10da2
  * xenXMDomainGetVcpusFlags:
e10da2
  * @domain: pointer to domain object
e10da2
diff --git a/src/xen/xm_internal.h b/src/xen/xm_internal.h
e10da2
index 3295fbd..a46e1a2 100644
e10da2
--- a/src/xen/xm_internal.h
e10da2
+++ b/src/xen/xm_internal.h
e10da2
@@ -45,6 +45,8 @@ int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory);
e10da2
 int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory);
e10da2
 unsigned long xenXMDomainGetMaxMemory(virDomainPtr domain);
e10da2
 int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus);
e10da2
+int xenXMDomainSetVcpusFlags(virDomainPtr domain, unsigned int vcpus,
e10da2
+                             unsigned int flags);
e10da2
 int xenXMDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags);
e10da2
 int xenXMDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
e10da2
                        unsigned char *cpumap, int maplen);
e10da2
-- 
e10da2
1.7.2.3
e10da2