Re: [PATCHv2 00/14] vcpu - distinguish maximum from current

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

 



On 10/13/2010 11:53 AM, Eric Blake wrote:
Version 2 of the patch series; this addresses most of the points
from v1 (http://thread.gmane.org/gmane.comp.emulators.libvirt/28520).


I'll send an interdiff for how this series differs from v1, if that
helps in the review.

Attached.

--
Eric Blake   eblake@xxxxxxxxxx    +1-801-349-2682
Libvirt virtualization library http://libvirt.org
diff --git c/docs/formatdomain.html.in w/docs/formatdomain.html.in
index 0f5066a..174cd1f 100644
--- c/docs/formatdomain.html.in
+++ w/docs/formatdomain.html.in
@@ -222,7 +222,7 @@
         a range of CPU numbers, or a caret followed by a CPU number to
         be excluded from a previous range.  <span class="since">Since
         0.8.5</span>, the optional attribute <code>current</code> can
-        be used to specify that fewer than the maximum number of
+        be used to specify whether fewer than the maximum number of
         virtual CPUs should be enabled.
       </dd>
     </dl>
diff --git c/include/libvirt/libvirt.h.in w/include/libvirt/libvirt.h.in
index 0361455..d0cc4c0 100644
--- c/include/libvirt/libvirt.h.in
+++ w/include/libvirt/libvirt.h.in
@@ -915,13 +915,14 @@ struct _virVcpuInfo {
 };
 typedef virVcpuInfo *virVcpuInfoPtr;

+/* Flags for controlling virtual CPU hot-plugging.  */
 typedef enum {
     /* Must choose at least one of these two bits; SetVcpus can choose both */
-    VIR_DOMAIN_VCPU_ACTIVE     = (1 << 0), /* Affect active domain */
-    VIR_DOMAIN_VCPU_PERSISTENT = (1 << 1), /* Affect next boot */
+    VIR_DOMAIN_VCPU_LIVE    = (1 << 0), /* Affect active domain */
+    VIR_DOMAIN_VCPU_CONFIG  = (1 << 1), /* Affect next boot */

     /* Additional flags to be bit-wise OR'd in */
-    VIR_DOMAIN_VCPU_MAXIMUM    = (1 << 2), /* Max rather than current count */
+    VIR_DOMAIN_VCPU_MAXIMUM = (1 << 2), /* Max rather than current count */
 } virDomainVcpuFlags;

 int                     virDomainSetVcpus       (virDomainPtr domain,
diff --git c/src/conf/domain_conf.c w/src/conf/domain_conf.c
index e4f0402..dba0b12 100644
--- c/src/conf/domain_conf.c
+++ w/src/conf/domain_conf.c
@@ -4268,23 +4268,33 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
                       &def->mem.swap_hard_limit) < 0)
         def->mem.swap_hard_limit = 0;

-    if (virXPathULong("string(./vcpu[1])", ctxt, &count) < 0)
+    n = virXPathULong("string(./vcpu[1])", ctxt, &count);
+    if (n == -2) {
+        virDomainReportError(VIR_ERR_XML_ERROR, "%s",
+                             _("maximum vcpus must be an integer"));
+        goto error;
+    } else if (n < 0) {
         def->maxvcpus = 1;
-    else {
+    } else {
         def->maxvcpus = count;
         if (def->maxvcpus != count || count == 0) {
-            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+            virDomainReportError(VIR_ERR_XML_ERROR,
                                  _("invalid maxvcpus %lu"), count);
             goto error;
         }
     }

-    if (virXPathULong("string(./vcpu[1]/@current)", ctxt, &count) < 0)
+    n = virXPathULong("string(./vcpu[1]/@current)", ctxt, &count);
+    if (n == -2) {
+        virDomainReportError(VIR_ERR_XML_ERROR, "%s",
+                             _("current vcpus must be an integer"));
+        goto error;
+    } else if (n < 0) {
         def->vcpus = def->maxvcpus;
-    else {
+    } else {
         def->vcpus = count;
         if (def->vcpus != count || count == 0 || def->maxvcpus < count) {
-            virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+            virDomainReportError(VIR_ERR_XML_ERROR,
                                  _("invalid current vcpus %lu"), count);
             goto error;
         }
diff --git c/src/esx/esx_driver.c w/src/esx/esx_driver.c
index cab2f63..465da45 100644
--- c/src/esx/esx_driver.c
+++ w/src/esx/esx_driver.c
@@ -2393,7 +2393,7 @@ esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
     esxVI_ManagedObjectReference *task = NULL;
     esxVI_TaskInfoState taskInfoState;

-    if (flags != VIR_DOMAIN_VCPU_ACTIVE) {
+    if (flags != VIR_DOMAIN_VCPU_LIVE) {
         ESX_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
         return -1;
     }
@@ -2460,7 +2460,7 @@ esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
 static int
 esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
 {
-    return esxDomainSetVcpusFlags(domain, nvcpus, VIR_DOMAIN_VCPU_ACTIVE);
+    return esxDomainSetVcpusFlags(domain, nvcpus, VIR_DOMAIN_VCPU_LIVE);
 }


@@ -2472,7 +2472,7 @@ esxDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
     esxVI_ObjectContent *hostSystem = NULL;
     esxVI_DynamicProperty *dynamicProperty = NULL;

-    if (flags != (VIR_DOMAIN_VCPU_ACTIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
+    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
         ESX_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
         return -1;
     }
@@ -2525,7 +2525,7 @@ esxDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
 static int
 esxDomainGetMaxVcpus(virDomainPtr domain)
 {
-    return esxDomainGetVcpusFlags(domain, (VIR_DOMAIN_VCPU_ACTIVE |
+    return esxDomainGetVcpusFlags(domain, (VIR_DOMAIN_VCPU_LIVE |
                                            VIR_DOMAIN_VCPU_MAXIMUM));
 }

diff --git c/src/libvirt.c w/src/libvirt.c
index def1f74..c9f93c6 100644
--- c/src/libvirt.c
+++ w/src/libvirt.c
@@ -5178,7 +5178,9 @@ error:
  * This function requires privileged access to the hypervisor.
  *
  * This command only changes the runtime configuration of the domain,
- * so can only be called on an active domain.
+ * so can only be called on an active domain.  It is hypervisor-dependent
+ * whether it also affects persistent configuration; for more control,
+ * use virDomainSetVcpusFlags().
  *
  * Returns 0 in case of success, -1 in case of failure.
  */
@@ -5233,13 +5235,13 @@ error:
  * does not support it or if growing the number is arbitrary limited.
  * This function requires privileged access to the hypervisor.
  *
- * @flags must include VIR_DOMAIN_VCPU_ACTIVE to affect a running
- * domain (which will fail if domain is not active), or
- * VIR_DOMAIN_VCPU_PERSISTENT to affect the next boot via the XML
+ * @flags must include VIR_DOMAIN_VCPU_LIVE to affect a running
+ * domain (which may fail if domain is not active), or
+ * VIR_DOMAIN_VCPU_CONFIG to affect the next boot via the XML
  * description of the domain.  Both flags may be set.
  *
  * If @flags includes VIR_DOMAIN_VCPU_MAXIMUM, then
- * VIR_DOMAIN_VCPU_ACTIVE must be clear, and only the maximum virtual
+ * VIR_DOMAIN_VCPU_LIVE must be clear, and only the maximum virtual
  * CPU limit is altered; generally, this value must be less than or
  * equal to virConnectGetMaxVcpus().  Otherwise, this call affects the
  * current virtual CPU limit, which must be less than or equal to the
@@ -5267,7 +5269,9 @@ virDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
         goto error;
     }

-    if (nvcpus < 1) {
+    /* Perform some argument validation common to all implementations.  */
+    if (nvcpus < 1 || (unsigned short) nvcpus != nvcpus ||
+        (flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
         goto error;
     }
@@ -5324,6 +5328,11 @@ virDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
         return (-1);
     }

+    /* Exactly one of these two flags should be set.  */
+    if (!(flags & VIR_DOMAIN_VCPU_LIVE) == !(flags & VIR_DOMAIN_VCPU_CONFIG)) {
+        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        goto error;
+    }
     conn = domain->conn;

     if (conn->driver->domainGetVcpusFlags) {
@@ -5476,9 +5485,9 @@ error:
  *
  * Provides the maximum number of virtual CPUs supported for
  * the guest VM. If the guest is inactive, this is basically
- * the same as virConnectGetMaxVcpus. If the guest is running
+ * the same as virConnectGetMaxVcpus(). If the guest is running
  * this will reflect the maximum number of virtual CPUs the
- * guest was booted with.
+ * guest was booted with.  For more details, see virDomainGetVcpusFlags().
  *
  * Returns the maximum of virtual CPU or -1 in case of error.
  */
diff --git c/src/openvz/openvz_driver.c w/src/openvz/openvz_driver.c
index c3eb099..b7c2754 100644
--- c/src/openvz/openvz_driver.c
+++ w/src/openvz/openvz_driver.c
@@ -1219,7 +1219,7 @@ static int
 openvzDomainGetVcpusFlags(virDomainPtr dom ATTRIBUTE_UNUSED,
                           unsigned int flags)
 {
-    if (flags != (VIR_DOMAIN_VCPU_ACTIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
+    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
         openvzError(VIR_ERR_INVALID_ARG, _("unsupported flags (0x%x)"), flags);
         return -1;
     }
@@ -1229,7 +1229,7 @@ openvzDomainGetVcpusFlags(virDomainPtr dom ATTRIBUTE_UNUSED,

 static int openvzDomainGetMaxVcpus(virDomainPtr dom)
 {
-    return openvzDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_ACTIVE |
+    return openvzDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                            VIR_DOMAIN_VCPU_MAXIMUM));
 }

@@ -1265,7 +1265,7 @@ static int openvzDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
     struct openvz_driver   *driver = dom->conn->privateData;
     int                     ret = -1;

-    if (flags != VIR_DOMAIN_VCPU_ACTIVE) {
+    if (flags != VIR_DOMAIN_VCPU_LIVE) {
         openvzError(VIR_ERR_INVALID_ARG, _("unsupported flags (0x%x)"), flags);
         return -1;
     }
@@ -1298,7 +1298,7 @@ cleanup:
 static int
 openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
 {
-    return openvzDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_ACTIVE);
+    return openvzDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
 }

 static virDrvOpenStatus openvzOpen(virConnectPtr conn,
diff --git c/src/phyp/phyp_driver.c w/src/phyp/phyp_driver.c
index 95fcaca..3d0ed11 100644
--- c/src/phyp/phyp_driver.c
+++ w/src/phyp/phyp_driver.c
@@ -1502,7 +1502,7 @@ phypDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
     phyp_driverPtr phyp_driver = dom->conn->privateData;
     char *managed_system = phyp_driver->managed_system;

-    if (flags != (VIR_DOMAIN_VCPU_ACTIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
+    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
         PHYP_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
         return -1;
     }
@@ -1513,7 +1513,7 @@ phypDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
 static int
 phypGetLparCPUMAX(virDomainPtr dom)
 {
-    return phypDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_ACTIVE |
+    return phypDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                          VIR_DOMAIN_VCPU_MAXIMUM));
 }

@@ -3859,7 +3859,7 @@ phypDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
     unsigned int amount = 0;
     virBuffer buf = VIR_BUFFER_INITIALIZER;

-    if (flags != VIR_DOMAIN_VCPU_ACTIVE) {
+    if (flags != VIR_DOMAIN_VCPU_LIVE) {
         PHYP_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
         return -1;
     }
@@ -3912,7 +3912,7 @@ phypDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
 static int
 phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus)
 {
-    return phypDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_ACTIVE);
+    return phypDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
 }

 static virDrvOpenStatus
diff --git c/src/qemu/qemu_conf.c w/src/qemu/qemu_conf.c
index f8aa5ca..e2ac59f 100644
--- c/src/qemu/qemu_conf.c
+++ w/src/qemu/qemu_conf.c
@@ -3723,7 +3723,7 @@ qemuBuildSmpArgStr(const virDomainDefPtr def,
         }
     } else if (def->vcpus != def->maxvcpus) {
         virBufferFreeAndReset(&buf);
-        // FIXME - consider hot-unplugging cpus after boot
+        /* FIXME - consider hot-unplugging cpus after boot for older qemu */
         qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                         _("setting current vcpu count less than maximum is "
                           "not supported with this QEMU binary"));
diff --git c/src/qemu/qemu_driver.c w/src/qemu/qemu_driver.c
index 4a8d166..69f3d92 100644
--- c/src/qemu/qemu_driver.c
+++ w/src/qemu/qemu_driver.c
@@ -5940,19 +5940,20 @@ qemudDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
 {
     struct qemud_driver *driver = dom->conn->privateData;
     virDomainObjPtr vm;
+    virDomainDefPtr def;
     const char * type;
     int max;
     int ret = -1;

-    virCheckFlags(VIR_DOMAIN_VCPU_ACTIVE |
-                  VIR_DOMAIN_VCPU_PERSISTENT |
+    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
+                  VIR_DOMAIN_VCPU_CONFIG |
                   VIR_DOMAIN_VCPU_MAXIMUM, -1);

-    /* At least one of ACTIVE or PERSISTENT must be set.  MAXIMUM
-     * requires exactly PERSISTENT.  */
-    if ((flags & (VIR_DOMAIN_VCPU_ACTIVE | VIR_DOMAIN_VCPU_PERSISTENT)) == 0 ||
-        (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_ACTIVE)) ==
-         (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_ACTIVE)) {
+    /* At least one of LIVE or CONFIG must be set.  MAXIMUM cannot be
+     * mixed with LIVE.  */
+    if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0 ||
+        (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) ==
+         (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) {
         qemuReportError(VIR_ERR_INVALID_ARG,
                         _("invalid flag combination: (0x%x)"), flags);
         return -1;
@@ -5978,7 +5979,7 @@ qemudDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
     if (qemuDomainObjBeginJob(vm) < 0)
         goto cleanup;

-    if (!virDomainObjIsActive(vm) && (flags & VIR_DOMAIN_VCPU_ACTIVE)) {
+    if (!virDomainObjIsActive(vm) && (flags & VIR_DOMAIN_VCPU_LIVE)) {
         qemuReportError(VIR_ERR_OPERATION_INVALID,
                          "%s", _("domain is not running"));
         goto endjob;
@@ -5997,8 +5998,8 @@ qemudDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
         goto endjob;
     }

-    if ((flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_ACTIVE)) ==
-        VIR_DOMAIN_VCPU_ACTIVE && vm->def->maxvcpus < max) {
+    if ((flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) ==
+        VIR_DOMAIN_VCPU_LIVE && vm->def->maxvcpus < max) {
         max = vm->def->maxvcpus;
     }

@@ -6010,33 +6011,43 @@ qemudDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
     }

     switch (flags) {
-    case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_PERSISTENT:
-        if (!vm->newDef)
-            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                            _("no persistent state"));
-        else {
-            vm->newDef->maxvcpus = nvcpus;
-            if (nvcpus < vm->newDef->vcpus)
-                vm->newDef->vcpus = nvcpus;
-            ret = 0;
+    case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_CONFIG:
+        def = vm->def;
+        if (virDomainObjIsActive(vm)) {
+            if (vm->newDef)
+                def = vm->newDef;
+            else{
+                qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                                _("no persistent state"));
+                goto endjob;
+            }
         }
+        def->maxvcpus = nvcpus;
+        if (nvcpus < vm->newDef->vcpus)
+            def->vcpus = nvcpus;
+        ret = 0;
         break;

-    case VIR_DOMAIN_VCPU_PERSISTENT:
-        if (!vm->newDef)
-            qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                            _("no persistent state"));
-        else {
-            vm->newDef->vcpus = nvcpus;
-            ret = 0;
+    case VIR_DOMAIN_VCPU_CONFIG:
+        def = vm->def;
+        if (virDomainObjIsActive(vm)) {
+            if (vm->newDef)
+                def = vm->newDef;
+            else {
+                qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                                _("no persistent state"));
+                goto endjob;
+            }
         }
+        def->vcpus = nvcpus;
+        ret = 0;
         break;

-    case VIR_DOMAIN_VCPU_ACTIVE:
+    case VIR_DOMAIN_VCPU_LIVE:
         ret = qemudDomainHotplugVcpus(vm, nvcpus);
         break;

-    case VIR_DOMAIN_VCPU_ACTIVE | VIR_DOMAIN_VCPU_PERSISTENT:
+    case VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG:
         ret = qemudDomainHotplugVcpus(vm, nvcpus);
         if (ret == 0 && vm->newDef)
             vm->newDef->vcpus = nvcpus;
@@ -6056,7 +6067,7 @@ cleanup:
 static int
 qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
 {
-    return qemudDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_ACTIVE);
+    return qemudDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
 }


@@ -6223,13 +6234,12 @@ qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
     virDomainDefPtr def;
     int ret = -1;

-    virCheckFlags(VIR_DOMAIN_VCPU_ACTIVE |
-                  VIR_DOMAIN_VCPU_PERSISTENT |
+    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
+                  VIR_DOMAIN_VCPU_CONFIG |
                   VIR_DOMAIN_VCPU_MAXIMUM, -1);

-    /* Exactly one of ACTIVE or PERSISTENT must be set.  */
-    if (!(flags & VIR_DOMAIN_VCPU_ACTIVE) ==
-        !(flags & VIR_DOMAIN_VCPU_PERSISTENT)) {
+    /* Exactly one of LIVE or CONFIG must be set.  */
+    if (!(flags & VIR_DOMAIN_VCPU_LIVE) == !(flags & VIR_DOMAIN_VCPU_CONFIG)) {
         qemuReportError(VIR_ERR_INVALID_ARG,
                         _("invalid flag combination: (0x%x)"), flags);
         return -1;
@@ -6247,7 +6257,7 @@ qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
         goto cleanup;
     }

-    if (flags & VIR_DOMAIN_VCPU_ACTIVE) {
+    if (flags & VIR_DOMAIN_VCPU_LIVE) {
         if (!virDomainObjIsActive(vm)) {
             qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
                             _("domain not active"));
@@ -6269,7 +6279,7 @@ cleanup:
 static int
 qemudDomainGetMaxVcpus(virDomainPtr dom)
 {
-    return qemudDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_ACTIVE |
+    return qemudDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                           VIR_DOMAIN_VCPU_MAXIMUM));
 }

diff --git c/src/test/test_driver.c w/src/test/test_driver.c
index 3da75db..a9d3d89 100644
--- c/src/test/test_driver.c
+++ w/src/test/test_driver.c
@@ -450,6 +450,7 @@ testDomainUpdateVCPUs(virConnectPtr conn,
                 goto cleanup;
     }

+    dom->def->vcpus = nvcpus;
     ret = 0;
 cleanup:
     return ret;
@@ -2032,18 +2033,57 @@ cleanup:
 static int
 testDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
 {
-    if (flags != (VIR_DOMAIN_VCPU_ACTIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
-        testError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
+    testConnPtr privconn = domain->conn->privateData;
+    virDomainObjPtr vm;
+    virDomainDefPtr def;
+    int ret = -1;
+
+    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)) {
+        testError(VIR_ERR_INVALID_ARG,
+                  _("invalid flag combination: (0x%x)"), flags);
         return -1;
     }

-    return testGetMaxVCPUs(domain->conn, "test");
+    testDriverLock(privconn);
+    vm = virDomainFindByUUID(&privconn->domains, domain->uuid);
+    testDriverUnlock(privconn);
+
+    if (!vm) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(domain->uuid, uuidstr);
+        testError(VIR_ERR_NO_DOMAIN,
+                  _("no domain with matching uuid '%s'"), uuidstr);
+        goto cleanup;
+    }
+
+    if (flags & VIR_DOMAIN_VCPU_LIVE) {
+        if (!virDomainObjIsActive(vm)) {
+            testError(VIR_ERR_OPERATION_INVALID, "%s",
+                      _("domain not active"));
+            goto cleanup;
+        }
+        def = vm->def;
+    } else {
+        def = vm->newDef ? vm->newDef : vm->def;
+    }
+
+    ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus;
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    return ret;
 }

 static int
 testDomainGetMaxVcpus(virDomainPtr domain)
 {
-    return testDomainGetVcpusFlags(domain, (VIR_DOMAIN_VCPU_ACTIVE |
+    return testDomainGetVcpusFlags(domain, (VIR_DOMAIN_VCPU_LIVE |
                                             VIR_DOMAIN_VCPU_MAXIMUM));
 }

@@ -2053,21 +2093,30 @@ testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus,
 {
     testConnPtr privconn = domain->conn->privateData;
     virDomainObjPtr privdom = NULL;
+    virDomainDefPtr def;
     int ret = -1, maxvcpus;

-    if (flags != VIR_DOMAIN_VCPU_ACTIVE) {
-        testError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
+    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
+                  VIR_DOMAIN_VCPU_CONFIG |
+                  VIR_DOMAIN_VCPU_MAXIMUM, -1);
+
+    /* At least one of LIVE or CONFIG must be set.  MAXIMUM cannot be
+     * mixed with LIVE.  */
+    if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0 ||
+        (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) ==
+         (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) {
+        testError(VIR_ERR_INVALID_ARG,
+                  _("invalid flag combination: (0x%x)"), flags);
+        return -1;
+    }
+    if (!nrCpus || (maxvcpus = testGetMaxVCPUs(domain->conn, NULL)) < nrCpus) {
+        testError(VIR_ERR_INVALID_ARG,
+                  _("argument out of range: %d"), nrCpus);
         return -1;
     }
-
-    /* Do this first before locking */
-    maxvcpus = testDomainGetMaxVcpus(domain);
-    if (maxvcpus < 0)
-        goto cleanup;

     testDriverLock(privconn);
-    privdom = virDomainFindByName(&privconn->domains,
-                                  domain->name);
+    privdom = virDomainFindByUUID(&privconn->domains, domain->uuid);
     testDriverUnlock(privconn);

     if (privdom == NULL) {
@@ -2075,13 +2124,17 @@ testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus,
         goto cleanup;
     }

-    if (!virDomainObjIsActive(privdom)) {
+    if (!virDomainObjIsActive(privdom) && (flags & VIR_DOMAIN_VCPU_LIVE)) {
         testError(VIR_ERR_OPERATION_INVALID,
                   "%s", _("cannot hotplug vcpus for an inactive domain"));
         goto cleanup;
     }

-    /* We allow more cpus in guest than host */
+    /* We allow more cpus in guest than host, but not more than the
+     * domain's starting limit.  */
+    if ((flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) ==
+        VIR_DOMAIN_VCPU_LIVE && privdom->def->maxvcpus < maxvcpus)
+        maxvcpus = privdom->def->maxvcpus;
     if (nrCpus > maxvcpus) {
         testError(VIR_ERR_INVALID_ARG,
                   "requested cpu amount exceeds maximum (%d > %d)",
@@ -2089,12 +2142,49 @@ testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus,
         goto cleanup;
     }

-    /* Update VCPU state for the running domain */
-    if (testDomainUpdateVCPUs(domain->conn, privdom, nrCpus, 0) < 0)
-        goto cleanup;
+    switch (flags) {
+    case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_CONFIG:
+        def = privdom->def;
+        if (virDomainObjIsActive(privdom)) {
+            if (privdom->newDef)
+                def = privdom->newDef;
+            else {
+                testError(VIR_ERR_OPERATION_INVALID, "%s",
+                          _("no persistent state"));
+                goto cleanup;
+            }
+        }
+        def->maxvcpus = nrCpus;
+        if (nrCpus < def->vcpus)
+            def->vcpus = nrCpus;
+        ret = 0;
+        break;

-    privdom->def->vcpus = nrCpus;
-    ret = 0;
+    case VIR_DOMAIN_VCPU_CONFIG:
+        def = privdom->def;
+        if (virDomainObjIsActive(privdom)) {
+            if (privdom->newDef)
+                def = privdom->newDef;
+            else {
+                testError(VIR_ERR_OPERATION_INVALID, "%s",
+                          _("no persistent state"));
+                goto cleanup;
+            }
+        }
+        def->vcpus = nrCpus;
+        ret = 0;
+        break;
+
+    case VIR_DOMAIN_VCPU_LIVE:
+        ret = testDomainUpdateVCPUs(domain->conn, privdom, nrCpus, 0);
+        break;
+
+    case VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG:
+        ret = testDomainUpdateVCPUs(domain->conn, privdom, nrCpus, 0);
+        if (ret == 0 && privdom->newDef)
+            privdom->newDef->vcpus = nrCpus;
+        break;
+    }

 cleanup:
     if (privdom)
@@ -2105,7 +2195,7 @@ cleanup:
 static int
 testSetVcpus(virDomainPtr domain, unsigned int nrCpus)
 {
-    return testDomainSetVcpusFlags(domain, nrCpus, VIR_DOMAIN_VCPU_ACTIVE);
+    return testDomainSetVcpusFlags(domain, nrCpus, VIR_DOMAIN_VCPU_LIVE);
 }

 static int testDomainGetVcpus(virDomainPtr domain,
diff --git c/src/vbox/vbox_tmpl.c w/src/vbox/vbox_tmpl.c
index 3bb9431..5a859a4 100644
--- c/src/vbox/vbox_tmpl.c
+++ w/src/vbox/vbox_tmpl.c
@@ -1849,7 +1849,7 @@ vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
     PRUint32  CPUCount   = nvcpus;
     nsresult rc;

-    if (flags != VIR_DOMAIN_VCPU_ACTIVE) {
+    if (flags != VIR_DOMAIN_VCPU_LIVE) {
         vboxError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
         return -1;
     }
@@ -1898,7 +1898,7 @@ cleanup:
 static int
 vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
 {
-    return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_ACTIVE);
+    return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
 }

 static int
@@ -1908,7 +1908,7 @@ vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
     ISystemProperties *systemProperties = NULL;
     PRUint32 maxCPUCount = 0;

-    if (flags != (VIR_DOMAIN_VCPU_ACTIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
+    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
         vboxError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
         return -1;
     }
@@ -1933,7 +1933,7 @@ vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
 static int
 vboxDomainGetMaxVcpus(virDomainPtr dom)
 {
-    return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_ACTIVE |
+    return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                          VIR_DOMAIN_VCPU_MAXIMUM));
 }

diff --git c/src/xen/proxy_internal.c w/src/xen/proxy_internal.c
index 335dfc4..3e122f4 100644
--- c/src/xen/proxy_internal.c
+++ w/src/xen/proxy_internal.c
@@ -70,7 +70,6 @@ struct xenUnifiedDriver xenProxyDriver = {
     NULL, /* domainSetVcpus */
     NULL, /* domainPinVcpu */
     NULL, /* domainGetVcpus */
-    NULL, /* domainGetMaxVcpus */
     NULL, /* listDefinedDomains */
     NULL, /* numOfDefinedDomains */
     NULL, /* domainCreate */
diff --git c/src/xen/xen_driver.c w/src/xen/xen_driver.c
index 5c73afd..fe2ff86 100644
--- c/src/xen/xen_driver.c
+++ w/src/xen/xen_driver.c
@@ -1075,7 +1075,7 @@ xenUnifiedDomainSetVcpusFlags (virDomainPtr dom, unsigned int nvcpus,
     GET_PRIVATE(dom->conn);
     int i;

-    if (flags != VIR_DOMAIN_VCPU_ACTIVE) {
+    if (flags != VIR_DOMAIN_VCPU_LIVE) {
         xenUnifiedError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"),
                         flags);
         return -1;
@@ -1102,7 +1102,7 @@ xenUnifiedDomainSetVcpusFlags (virDomainPtr dom, unsigned int nvcpus,
 static int
 xenUnifiedDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus)
 {
-    return xenUnifiedDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_ACTIVE);
+    return xenUnifiedDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
 }

 static int
@@ -1142,27 +1142,40 @@ static int
 xenUnifiedDomainGetVcpusFlags (virDomainPtr dom, unsigned int flags)
 {
     GET_PRIVATE(dom->conn);
-    int i, ret;
+    int ret;

-    if (flags != (VIR_DOMAIN_VCPU_ACTIVE | 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;
 }

 static int
 xenUnifiedDomainGetMaxVcpus (virDomainPtr dom)
 {
-    return xenUnifiedDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_ACTIVE |
+    return xenUnifiedDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                                VIR_DOMAIN_VCPU_MAXIMUM));
 }

diff --git c/src/xen/xen_driver.h w/src/xen/xen_driver.h
index 3e7c1d0..bb68f6a 100644
--- c/src/xen/xen_driver.h
+++ w/src/xen/xen_driver.h
@@ -1,7 +1,7 @@
 /*
  * xen_unified.c: Unified Xen driver.
  *
- * Copyright (C) 2007 Red Hat, Inc.
+ * Copyright (C) 2007, 2010 Red Hat, Inc.
  *
  * See COPYING.LIB for the License of this software
  *
@@ -87,7 +87,6 @@ struct xenUnifiedDriver {
         virDrvDomainSetVcpus		domainSetVcpus;
         virDrvDomainPinVcpu		domainPinVcpu;
         virDrvDomainGetVcpus		domainGetVcpus;
-        virDrvDomainGetMaxVcpus		domainGetMaxVcpus;
         virDrvListDefinedDomains	listDefinedDomains;
         virDrvNumOfDefinedDomains	numOfDefinedDomains;
         virDrvDomainCreate		domainCreate;
diff --git c/src/xen/xen_hypervisor.c w/src/xen/xen_hypervisor.c
index 6246513..32f3683 100644
--- c/src/xen/xen_hypervisor.c
+++ w/src/xen/xen_hypervisor.c
@@ -787,7 +787,6 @@ struct xenUnifiedDriver xenHypervisorDriver = {
     xenHypervisorSetVcpus, /* domainSetVcpus */
     xenHypervisorPinVcpu, /* domainPinVcpu */
     xenHypervisorGetVcpus, /* domainGetVcpus */
-    xenHypervisorGetVcpuMax, /* domainGetMaxVcpus */
     NULL, /* listDefinedDomains */
     NULL, /* numOfDefinedDomains */
     NULL, /* domainCreate */
diff --git c/src/xen/xen_inotify.c w/src/xen/xen_inotify.c
index d24b20f..9b95d67 100644
--- c/src/xen/xen_inotify.c
+++ w/src/xen/xen_inotify.c
@@ -74,7 +74,6 @@ struct xenUnifiedDriver xenInotifyDriver = {
     NULL, /* domainSetVcpus */
     NULL, /* domainPinVcpu */
     NULL, /* domainGetVcpus */
-    NULL, /* domainGetMaxVcpus */
     NULL, /* listDefinedDomains */
     NULL, /* numOfDefinedDomains */
     NULL, /* domainCreate */
diff --git c/src/xen/xend_internal.c w/src/xen/xend_internal.c
index 02f8f5f..e887e9d 100644
--- c/src/xen/xend_internal.c
+++ w/src/xen/xend_internal.c
@@ -44,6 +44,7 @@
 #include "xen_hypervisor.h"
 #include "xs_internal.h" /* To extract VNC port & Serial console TTY */
 #include "memory.h"
+#include "count-one-bits.h"

 /* required for cpumap_t */
 #include <xen/dom0_ops.h>
@@ -2191,8 +2192,9 @@ xenDaemonParseSxpr(virConnectPtr conn,
     }

     def->maxvcpus = sexpr_int(root, "domain/vcpus");
-//    def->vcpus = sexpr_int(root, "domain/vcpu_avail");
-    def->vcpus = def->maxvcpus;
+    def->vcpus = count_one_bits(sexpr_int(root, "domain/vcpu_avail"));
+    if (!def->vcpus || def->maxvcpus < def->vcpus)
+        def->vcpus = def->maxvcpus;

     tmp = sexpr_node(root, "domain/on_poweroff");
     if (tmp != NULL) {
@@ -2434,7 +2436,7 @@ sexpr_to_xend_domain_info(virDomainPtr domain, const struct sexpr *root,
                           virDomainInfoPtr info)
 {
     const char *flags;
-
+    int vcpus;

     if ((root == NULL) || (info == NULL))
         return (-1);
@@ -2465,8 +2467,11 @@ sexpr_to_xend_domain_info(virDomainPtr domain, const struct sexpr *root,
             info->state = VIR_DOMAIN_NOSTATE;
     }
     info->cpuTime = sexpr_float(root, "domain/cpu_time") * 1000000000;
-//    info->nrVirtCpu = sexpr_int(root, "domain/vcpu_avail");
-    info->nrVirtCpu = sexpr_int(root, "domain/vcpus");
+    vcpus = sexpr_int(root, "domain/vcpus");
+    info->nrVirtCpu = count_one_bits(sexpr_int(root, "domain/vcpu_avail"));
+    if (!info->nrVirtCpu || vcpus < info->nrVirtCpu)
+        info->nrVirtCpu = vcpus;
+
     return (0);
 }

@@ -3615,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 < 3)
+        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)
@@ -5083,7 +5140,6 @@ struct xenUnifiedDriver xenDaemonDriver = {
     xenDaemonDomainSetVcpus,     /* domainSetVcpus */
     xenDaemonDomainPinVcpu,      /* domainPinVcpu */
     xenDaemonDomainGetVcpus,     /* domainGetVcpus */
-    NULL,                        /* domainGetMaxVcpus */
     xenDaemonListDefinedDomains, /* listDefinedDomains */
     xenDaemonNumOfDefinedDomains,/* numOfDefinedDomains */
     xenDaemonDomainCreate,       /* domainCreate */
@@ -5669,9 +5725,10 @@ xenDaemonFormatSxpr(virConnectPtr conn,
     virBufferVSprintf(&buf, "(name '%s')", def->name);
     virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)",
                       def->mem.cur_balloon/1024, def->mem.max_balloon/1024);
-//    virBufferVSprintf(&buf, "(vcpus %u)(vcpu_avail %u)", def->maxvcpus,
-//                      def->vcpus);
     virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
+    /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is 32.  */
+    if (def->vcpus < def->maxvcpus)
+        virBufferVSprintf(&buf, "(vcpu_avail %u)", (1U << def->vcpus) - 1);

     if (def->cpumask) {
         char *ranges = virDomainCpuSetFormat(def->cpumask, def->cpumasklen);
@@ -5766,9 +5823,10 @@ xenDaemonFormatSxpr(virConnectPtr conn,
             else
                 virBufferVSprintf(&buf, "(kernel '%s')", def->os.loader);

-//            virBufferVSprintf(&buf, "(vcpus %u)(vcpu_avail %u)",
-//                              def->maxvcpus, def->vcpus);
             virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
+            if (def->vcpus < def->maxvcpus)
+                virBufferVSprintf(&buf, "(vcpu_avail %u)",
+                                  (1U << def->vcpus) - 1);

             for (i = 0 ; i < def->os.nBootDevs ; i++) {
                 switch (def->os.bootDevs[i]) {
diff --git c/src/xen/xend_internal.h w/src/xen/xend_internal.h
index c757716..923cebd 100644
--- c/src/xen/xend_internal.h
+++ w/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 c/src/xen/xm_internal.c w/src/xen/xm_internal.c
index 01485a5..9194c0d 100644
--- c/src/xen/xm_internal.c
+++ w/src/xen/xm_internal.c
@@ -46,6 +46,7 @@
 #include "util.h"
 #include "memory.h"
 #include "logging.h"
+#include "count-one-bits.h"

 #define VIR_FROM_THIS VIR_FROM_XENXM

@@ -105,7 +106,6 @@ struct xenUnifiedDriver xenXMDriver = {
     xenXMDomainSetVcpus, /* domainSetVcpus */
     xenXMDomainPinVcpu, /* domainPinVcpu */
     NULL, /* domainGetVcpus */
-    NULL, /* domainGetMaxVcpus */
     xenXMListDefinedDomains, /* listDefinedDomains */
     xenXMNumOfDefinedDomains, /* numOfDefinedDomains */
     xenXMDomainCreate, /* domainCreate */
@@ -772,14 +772,12 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
     def->mem.max_balloon *= 1024;

     if (xenXMConfigGetULong(conf, "vcpus", &count, 1) < 0 ||
-        (unsigned short) count != count)
+        MAX_VIRT_CPUS < count)
         goto cleanup;
     def->maxvcpus = count;
-//    if (xenXMConfigGetULong(conf, "vcpu_avail", &count, 1) < 0 ||
-//        (unsigned short) count != count)
-//        goto cleanup;
-//    def->vcpus = count;
-    def->vcpus = def->maxvcpus;
+    if (xenXMConfigGetULong(conf, "vcpu_avail", &count, -1) < 0)
+        goto cleanup;
+    def->vcpus = MIN(count_one_bits(count), def->maxvcpus);

     if (xenXMConfigGetString(conf, "cpus", &str, NULL) < 0)
         goto cleanup;
@@ -1657,7 +1655,7 @@ int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus) {
     if (!(entry = virHashLookup(priv->configCache, filename)))
         goto cleanup;

-    entry->def->vcpus = vcpus;
+    entry->def->maxvcpus = entry->def->vcpus = vcpus;

     /* If this fails, should we try to undo our changes to the
      * in-memory representation of the config file. I say not!
@@ -1672,6 +1670,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)
@@ -2250,8 +2295,9 @@ virConfPtr xenXMDomainConfigFormat(virConnectPtr conn,

     if (xenXMConfigSetInt(conf, "vcpus", def->maxvcpus) < 0)
         goto no_memory;
-//    if (xenXMConfigSetInt(conf, "vcpu_avail", def->vcpus) < 0)
-//        goto no_memory;
+    if (def->vcpus < def->maxvcpus &&
+        xenXMConfigSetInt(conf, "vcpu_avail", (1U << def->vcpus) - 1) < 0)
+        goto no_memory;

     if ((def->cpumask != NULL) &&
         ((cpus = virDomainCpuSetFormat(def->cpumask,
diff --git c/src/xen/xm_internal.h w/src/xen/xm_internal.h
index 3ad3456..3295fbd 100644
--- c/src/xen/xm_internal.h
+++ w/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);
diff --git c/src/xen/xs_internal.c w/src/xen/xs_internal.c
index 9296f25..434904c 100644
--- c/src/xen/xs_internal.c
+++ w/src/xen/xs_internal.c
@@ -70,7 +70,6 @@ struct xenUnifiedDriver xenStoreDriver = {
     NULL, /* domainSetVcpus */
     NULL, /* domainPinVcpu */
     NULL, /* domainGetVcpus */
-    NULL, /* domainGetMaxVcpus */
     NULL, /* listDefinedDomains */
     NULL, /* numOfDefinedDomains */
     NULL, /* domainCreate */
diff --git c/src/xenapi/xenapi_driver.c w/src/xenapi/xenapi_driver.c
index 7ce4b8a..5ccdede 100644
--- c/src/xenapi/xenapi_driver.c
+++ w/src/xenapi/xenapi_driver.c
@@ -1006,7 +1006,7 @@ xenapiDomainSetVcpusFlags (virDomainPtr dom, unsigned int nvcpus,
     xen_vm_set *vms;
     xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session;

-    if (flags != VIR_DOMAIN_VCPU_ACTIVE) {
+    if (flags != VIR_DOMAIN_VCPU_LIVE) {
         xenapiError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"),
                     flags);
         return -1;
@@ -1039,7 +1039,7 @@ xenapiDomainSetVcpusFlags (virDomainPtr dom, unsigned int nvcpus,
 static int
 xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus)
 {
-    return xenapiDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_ACTIVE);
+    return xenapiDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
 }

 /*
@@ -1178,7 +1178,7 @@ xenapiDomainGetVcpusFlags (virDomainPtr dom, unsigned int flags)
     enum xen_vm_power_state state;
     xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session;

-    if (flags != (VIR_DOMAIN_VCPU_ACTIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
+    if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
         xenapiError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"),
                     flags);
         return -1;
@@ -1215,7 +1215,7 @@ xenapiDomainGetVcpusFlags (virDomainPtr dom, unsigned int flags)
 static int
 xenapiDomainGetMaxVcpus (virDomainPtr dom)
 {
-    return xenapiDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_ACTIVE |
+    return xenapiDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE |
                                            VIR_DOMAIN_VCPU_MAXIMUM));
 }

diff --git c/src/xenapi/xenapi_utils.c w/src/xenapi/xenapi_utils.c
index c917813..a7e2a4b 100644
--- c/src/xenapi/xenapi_utils.c
+++ w/src/xenapi/xenapi_utils.c
@@ -512,7 +512,7 @@ createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def,

     if (def->maxvcpus) {
         (*record)->vcpus_max = (int64_t) def->maxvcpus;
-        (*record)->vcpus_at_startup = (int64_t) def->maxvcpus; // FIXME
+        (*record)->vcpus_at_startup = (int64_t) def->vcpus;
     }
     if (def->onPoweroff)
         (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff);
diff --git c/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.sexpr w/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.sexpr
new file mode 100644
index 0000000..2be6822
--- /dev/null
+++ w/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.sexpr
@@ -0,0 +1 @@
+(domain (domid 6)(name 'pvtest')(memory 420)(maxmem 420)(vcpus 4)(vcpu_avail 3)(uuid '596a5d2171f48fb2e068e2386a5c413e')(on_poweroff 'destroy')(on_reboot 'destroy')(on_crash 'destroy')(image (linux (kernel '/var/lib/xen/vmlinuz.2Dn2YT')(ramdisk '/var/lib/xen/initrd.img.0u-Vhq')(args ' method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os  ')))(device (vbd (dev 'xvda')(uname 'file:/root/some.img')(mode 'w'))))
diff --git c/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.xml w/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.xml
new file mode 100644
index 0000000..0d6bf11
--- /dev/null
+++ w/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.xml
@@ -0,0 +1,27 @@
+<domain type='xen' id='6'>
+  <name>pvtest</name>
+  <uuid>596a5d21-71f4-8fb2-e068-e2386a5c413e</uuid>
+  <memory>430080</memory>
+  <currentMemory>430080</currentMemory>
+  <vcpu current='2'>4</vcpu>
+  <os>
+    <type>linux</type>
+    <kernel>/var/lib/xen/vmlinuz.2Dn2YT</kernel>
+    <initrd>/var/lib/xen/initrd.img.0u-Vhq</initrd>
+    <cmdline> method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os  </cmdline>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>destroy</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <disk type='file' device='disk'>
+      <driver name='file'/>
+      <source file='/root/some.img'/>
+      <target dev='xvda' bus='xen'/>
+    </disk>
+    <console type='pty'>
+      <target type='xen' port='0'/>
+    </console>
+  </devices>
+</domain>
diff --git c/tests/sexpr2xmltest.c w/tests/sexpr2xmltest.c
index d62b44f..f100dd8 100644
--- c/tests/sexpr2xmltest.c
+++ w/tests/sexpr2xmltest.c
@@ -132,6 +132,7 @@ mymain(int argc, char **argv)
     DO_TEST("pv-vfb-type-crash", "pv-vfb-type-crash", 3);
     DO_TEST("fv-autoport", "fv-autoport", 3);
     DO_TEST("pv-bootloader", "pv-bootloader", 1);
+    DO_TEST("pv-vcpus", "pv-vcpus", 1);

     DO_TEST("disk-file", "disk-file", 2);
     DO_TEST("disk-block", "disk-block", 2);
diff --git c/tests/xmconfigdata/test-paravirt-vcpu.cfg w/tests/xmconfigdata/test-paravirt-vcpu.cfg
new file mode 100644
index 0000000..24c78f4
--- /dev/null
+++ w/tests/xmconfigdata/test-paravirt-vcpu.cfg
@@ -0,0 +1,17 @@
+name = "XenGuest1"
+uuid = "c7a5fdb0-cdaf-9455-926a-d65c16db1809"
+maxmem = 579
+memory = 394
+vcpus = 4
+vcpu_avail = 3
+bootloader = "/usr/bin/pygrub"
+on_poweroff = "destroy"
+on_reboot = "restart"
+on_crash = "restart"
+sdl = 0
+vnc = 1
+vncunused = 1
+vnclisten = "127.0.0.1"
+vncpasswd = "123poi"
+disk = [ "phy:/dev/HostVG/XenGuest1,xvda,w" ]
+vif = [ "mac=00:16:3e:66:94:9c,bridge=br0,script=vif-bridge" ]
diff --git c/tests/xmconfigdata/test-paravirt-vcpu.xml w/tests/xmconfigdata/test-paravirt-vcpu.xml
new file mode 100644
index 0000000..0be9456
--- /dev/null
+++ w/tests/xmconfigdata/test-paravirt-vcpu.xml
@@ -0,0 +1,32 @@
+<domain type='xen'>
+  <name>XenGuest1</name>
+  <uuid>c7a5fdb0-cdaf-9455-926a-d65c16db1809</uuid>
+  <memory>592896</memory>
+  <currentMemory>403456</currentMemory>
+  <vcpu current='2'>4</vcpu>
+  <bootloader>/usr/bin/pygrub</bootloader>
+  <os>
+    <type arch='i686' machine='xenpv'>linux</type>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>restart</on_crash>
+  <devices>
+    <disk type='block' device='disk'>
+      <driver name='phy'/>
+      <source dev='/dev/HostVG/XenGuest1'/>
+      <target dev='xvda' bus='xen'/>
+    </disk>
+    <interface type='bridge'>
+      <mac address='00:16:3e:66:94:9c'/>
+      <source bridge='br0'/>
+      <script path='vif-bridge'/>
+    </interface>
+    <console type='pty'>
+      <target type='xen' port='0'/>
+    </console>
+    <input type='mouse' bus='xen'/>
+    <graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' passwd='123poi'/>
+  </devices>
+</domain>
diff --git c/tests/xmconfigtest.c w/tests/xmconfigtest.c
index 221b322..ea00747 100644
--- c/tests/xmconfigtest.c
+++ w/tests/xmconfigtest.c
@@ -210,6 +210,7 @@ mymain(int argc, char **argv)
     DO_TEST("paravirt-new-pvfb-vncdisplay", 3);
     DO_TEST("paravirt-net-e1000", 3);
     DO_TEST("paravirt-net-vifname", 3);
+    DO_TEST("paravirt-vcpu", 2);
     DO_TEST("fullvirt-old-cdrom", 1);
     DO_TEST("fullvirt-new-cdrom", 2);
     DO_TEST("fullvirt-utc", 2);
diff --git c/tests/xml2sexprdata/xml2sexpr-pv-vcpus.sexpr w/tests/xml2sexprdata/xml2sexpr-pv-vcpus.sexpr
new file mode 100644
index 0000000..e886545
--- /dev/null
+++ w/tests/xml2sexprdata/xml2sexpr-pv-vcpus.sexpr
@@ -0,0 +1 @@
+(vm (name 'pvtest')(memory 420)(maxmem 420)(vcpus 4)(vcpu_avail 3)(uuid '596a5d21-71f4-8fb2-e068-e2386a5c413e')(on_poweroff 'destroy')(on_reboot 'destroy')(on_crash 'destroy')(image (linux (kernel '/var/lib/xen/vmlinuz.2Dn2YT')(ramdisk '/var/lib/xen/initrd.img.0u-Vhq')(args ' method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os  ')))(device (vbd (dev 'xvda')(uname 'file:/root/some.img')(mode 'w'))))
\ No newline at end of file
diff --git c/tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml w/tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml
index a11f713..d061e11 100644
--- c/tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml
+++ w/tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml
@@ -8,7 +8,7 @@
     <cmdline> method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os  </cmdline>
   </os>
   <memory>430080</memory>
-  <vcpu current='1'>2</vcpu>
+  <vcpu current='2'>4</vcpu>
   <on_poweroff>destroy</on_poweroff>
   <on_reboot>destroy</on_reboot>
   <on_crash>destroy</on_crash>
diff --git c/tests/xml2sexprtest.c w/tests/xml2sexprtest.c
index 77cf760..9cf8d39 100644
--- c/tests/xml2sexprtest.c
+++ w/tests/xml2sexprtest.c
@@ -118,6 +118,7 @@ mymain(int argc, char **argv)
     DO_TEST("pv-vfb-new", "pv-vfb-new", "pvtest", 3);
     DO_TEST("pv-vfb-new-auto", "pv-vfb-new-auto", "pvtest", 3);
     DO_TEST("pv-bootloader", "pv-bootloader", "pvtest", 1);
+    DO_TEST("pv-vcpus", "pv-vcpus", "pvtest", 1);

     DO_TEST("disk-file", "disk-file", "pvtest", 2);
     DO_TEST("disk-block", "disk-block", "pvtest", 2);
diff --git c/tools/virsh.c w/tools/virsh.c
index 2f553ba..496853e 100644
--- c/tools/virsh.c
+++ w/tools/virsh.c
@@ -2280,11 +2280,44 @@ cmdFreecell(vshControl *ctl, const vshCmd *cmd)
 }

 /*
+ * "maxvcpus" command
+ */
+static const vshCmdInfo info_maxvcpus[] = {
+    {"help", N_("connection vcpu maximum")},
+    {"desc", N_("Show maximum number of virtual CPUs for guests on this connection.")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_maxvcpus[] = {
+    {"type", VSH_OT_STRING, 0, N_("domain type")},
+    {NULL, 0, 0, NULL}
+};
+
+static int
+cmdMaxvcpus(vshControl *ctl, const vshCmd *cmd)
+{
+    char *type;
+    int vcpus;
+
+    type = vshCommandOptString(cmd, "type", NULL);
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        return FALSE;
+
+    vcpus = virConnectGetMaxVcpus(ctl->conn, type);
+    if (vcpus < 0)
+        return FALSE;
+    vshPrint(ctl, "%d\n", vcpus);
+
+    return TRUE;
+}
+
+/*
  * "vcpucount" command
  */
 static const vshCmdInfo info_vcpucount[] = {
     {"help", N_("domain vcpu counts")},
-    {"desc", N_("Returns the number of domain virtual CPUs.")},
+    {"desc", N_("Returns the number of virtual CPUs used by the domain.")},
     {NULL, NULL}
 };

@@ -2292,8 +2325,8 @@ static const vshCmdOptDef opts_vcpucount[] = {
     {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
     {"maximum", VSH_OT_BOOL, 0, N_("get maximum cap on vcpus")},
     {"current", VSH_OT_BOOL, 0, N_("get current vcpu usage")},
-    {"persistent", VSH_OT_BOOL, 0, N_("get value to be used on next boot")},
-    {"active", VSH_OT_BOOL, 0, N_("get value from running domain")},
+    {"config", VSH_OT_BOOL, 0, N_("get value to be used on next boot")},
+    {"live", VSH_OT_BOOL, 0, N_("get value from running domain")},
     {NULL, 0, 0, NULL}
 };

@@ -2304,9 +2337,9 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
     int ret = TRUE;
     int maximum = vshCommandOptBool(cmd, "maximum");
     int current = vshCommandOptBool(cmd, "current");
-    int persistent = vshCommandOptBool(cmd, "persistent");
-    int active = vshCommandOptBool(cmd, "active");
-    bool all = maximum + current + persistent + active == 0;
+    int config = vshCommandOptBool(cmd, "config");
+    int live = vshCommandOptBool(cmd, "live");
+    bool all = maximum + current + config + live == 0;
     int count;

     if (maximum && current) {
@@ -2314,18 +2347,20 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
                  _("--maximum and --current cannot both be specified"));
         return FALSE;
     }
-    if (persistent && active) {
+    if (config && live) {
         vshError(ctl, "%s",
-                 _("--persistent and --active cannot both be specified"));
+                 _("--config and --live cannot both be specified"));
         return FALSE;
     }
-    if (maximum + current + persistent + active == 1) {
+    /* We want one of each pair of mutually exclusive options; that
+     * is, use of flags requires exactly two options.  */
+    if (maximum + current + config + live == 1) {
         vshError(ctl,
                  _("when using --%s, either --%s or --%s must be specified"),
-                 maximum ? "maximum" : current ? "current"
-                 : persistent ? "persistent" : "active",
-                 maximum + current ? "persistent" : "maximum",
-                 maximum + current ? "active" : "current");
+                 (maximum ? "maximum" : current ? "current"
+                  : config ? "config" : "live"),
+                 maximum + current ? "config" : "maximum",
+                 maximum + current ? "live" : "current");
         return FALSE;
     }

@@ -2338,9 +2373,9 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
     /* In all cases, try the new API first; if it fails because we are
      * talking to an older client, try a fallback API before giving
      * up.  */
-    if (all || (maximum && persistent)) {
+    if (all || (maximum && config)) {
         count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM |
-                                             VIR_DOMAIN_VCPU_PERSISTENT));
+                                             VIR_DOMAIN_VCPU_CONFIG));
         if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
                           || last_error->code == VIR_ERR_INVALID_ARG)) {
             char *tmp;
@@ -2357,7 +2392,7 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
             virshReportError(ctl);
             ret = FALSE;
         } else if (all) {
-            vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("persistent"),
+            vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("config"),
                      count);
         } else {
             vshPrint(ctl, "%d\n", count);
@@ -2366,9 +2401,9 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
         last_error = NULL;
     }

-    if (all || (maximum && active)) {
+    if (all || (maximum && live)) {
         count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM |
-                                             VIR_DOMAIN_VCPU_ACTIVE));
+                                             VIR_DOMAIN_VCPU_LIVE));
         if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
                           || last_error->code == VIR_ERR_INVALID_ARG)) {
             count = virDomainGetMaxVcpus(dom);
@@ -2378,7 +2413,7 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
             virshReportError(ctl);
             ret = FALSE;
         } else if (all) {
-            vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("active"),
+            vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("live"),
                      count);
         } else {
             vshPrint(ctl, "%d\n", count);
@@ -2387,8 +2422,8 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
         last_error = NULL;
     }

-    if (all || (current && persistent)) {
-        count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_PERSISTENT);
+    if (all || (current && config)) {
+        count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_CONFIG);
         if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
                           || last_error->code == VIR_ERR_INVALID_ARG)) {
             char *tmp, *end;
@@ -2415,7 +2450,7 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
             virshReportError(ctl);
             ret = FALSE;
         } else if (all) {
-            vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("persistent"),
+            vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("config"),
                      count);
         } else {
             vshPrint(ctl, "%d\n", count);
@@ -2424,8 +2459,8 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
         last_error = NULL;
     }

-    if (all || (current && active)) {
-        count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_ACTIVE);
+    if (all || (current && live)) {
+        count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_LIVE);
         if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT
                           || last_error->code == VIR_ERR_INVALID_ARG)) {
             virDomainInfo info;
@@ -2437,7 +2472,7 @@ cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
             virshReportError(ctl);
             ret = FALSE;
         } else if (all) {
-            vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("active"),
+            vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("live"),
                      count);
         } else {
             vshPrint(ctl, "%d\n", count);
@@ -2685,8 +2720,8 @@ static const vshCmdOptDef opts_setvcpus[] = {
     {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
     {"count", VSH_OT_DATA, VSH_OFLAG_REQ, N_("number of virtual CPUs")},
     {"maximum", VSH_OT_BOOL, 0, N_("set maximum limit on next boot")},
-    {"persistent", VSH_OT_BOOL, 0, N_("affect next boot")},
-    {"active", VSH_OT_BOOL, 0, N_("affect running domain")},
+    {"config", VSH_OT_BOOL, 0, N_("affect next boot")},
+    {"live", VSH_OT_BOOL, 0, N_("affect running domain")},
     {NULL, 0, 0, NULL}
 };

@@ -2697,11 +2732,11 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
     int count;
     int ret = TRUE;
     int maximum = vshCommandOptBool(cmd, "maximum");
-    int persistent = vshCommandOptBool(cmd, "persistent");
-    int active = vshCommandOptBool(cmd, "active");
+    int config = vshCommandOptBool(cmd, "config");
+    int live = vshCommandOptBool(cmd, "live");
     int flags = ((maximum ? VIR_DOMAIN_VCPU_MAXIMUM : 0) |
-                 (persistent ? VIR_DOMAIN_VCPU_PERSISTENT : 0) |
-                 (active ? VIR_DOMAIN_VCPU_ACTIVE : 0));
+                 (config ? VIR_DOMAIN_VCPU_CONFIG : 0) |
+                 (live ? VIR_DOMAIN_VCPU_LIVE : 0));

     if (!vshConnectionUsability(ctl, ctl->conn))
         return FALSE;
@@ -9721,6 +9756,7 @@ static const vshCmdDef commands[] = {
     {"freecell", cmdFreecell, opts_freecell, info_freecell},
     {"hostname", cmdHostname, NULL, info_hostname},
     {"list", cmdList, opts_list, info_list},
+    {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus},
     {"migrate", cmdMigrate, opts_migrate, info_migrate},
     {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime},

diff --git c/tools/virsh.pod w/tools/virsh.pod
index d52aef7..9634b21 100644
--- c/tools/virsh.pod
+++ w/tools/virsh.pod
@@ -436,7 +436,14 @@ Remove the managed save file for a domain if it exists.  The next time the
 domain is started it will not restore to its previous state but instead will
 do a full boot.

-=item B<migrate> optional I<--live> I<--suspend> I<domain-id> I<desturi> I<migrateuri>
+=item B<maxvcpus> optional I<type>
+
+Provide the maximum number of virtual CPUs supported for a guest VM on
+this connection.  If provided, the I<type> parameter must be a valid
+type attribute for the <domain> element of XML.
+
+=item B<migrate> optional I<--live> I<--suspend> I<domain-id> I<desturi>
+I<migrateuri>

 Migrate domain to another host.  Add --live for live migration; --suspend
 leaves the domain paused on the destination host. The I<desturi> is the
@@ -506,8 +513,8 @@ Change the maximum memory allocation limit in the guest domain. This should
 not change the current memory use. The memory limit is specified in
 kilobytes.

-=item B<setvcpus> I<domain-id> I<count> optional I<--maximum> I<--persistent>
-I<--active>
+=item B<setvcpus> I<domain-id> I<count> optional I<--maximum> I<--config>
+I<--live>

 Change the number of virtual CPUs active in the guest domain. Note that
 I<count> may be limited by host, hypervisor or limit coming from the
@@ -516,14 +523,15 @@ original description of domain.
 For Xen, you can only adjust the virtual CPUs of a running domain if
 the domain is paravirtualized.

-If I<--persistent> is specified, the change will only affect the next
-boot of a domain.  If I<--active> is specified, the domain must be
+If I<--config> is specified, the change will only affect the next
+boot of a domain.  If I<--live> is specified, the domain must be
 running, and the change takes place immediately.  Both flags may be
-specified, if supported by the hypervisor; and I<--active> is implied
-when neither flag is given.
+specified, if supported by the hypervisor.  If neither flag is given,
+then I<--live> is implied and it is up to the hypervisor whether
+I<--config> is also implied.

-If I<--maximum> is specified, then you must use I<--persistent> and
-avoid I<--active>; this flag controls the maximum limit of vcpus that
+If I<--maximum> is specified, then you must use I<--config> and
+avoid I<--live>; this flag controls the maximum limit of vcpus that
 can be hot-plugged the next time the domain is booted.

 =item B<shutdown> I<domain-id>
@@ -565,7 +573,7 @@ Undefine the configuration for an inactive domain. Since it's not running
 the domain name or UUID must be used as the I<domain-id>.

 =item B<vcpucount> I<domain-id>  optional I<--maximum> I<--current>
-I<--persistent> I<--active>
+I<--config> I<--live>

 Print information about the virtual cpu counts of the given
 I<domain-id>.  If no flags are specified, all possible counts are
@@ -574,9 +582,9 @@ numeric value requested.

 I<--maximum> requests information on the maximum cap of vcpus that a
 domain can add via B<setvcpus>, while I<--current> shows the current
-usage; these two flags cannot both be specified.  I<--persistent>
+usage; these two flags cannot both be specified.  I<--config>
 requests information regarding the next time the domain will be
-booted, while I<--active> requires a running domain and lists current
+booted, while I<--live> requires a running domain and lists current
 values; these two flags cannot both be specified.

 =item B<vcpuinfo> I<domain-id>
--
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]