Blob Blame History Raw
From 4617eedfaeee2b187a1f14691d25746ba3ff31b6 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 29 Sep 2010 10:20:07 -0600
Subject: [PATCH 07/15] vcpu: support maxvcpu in domain_conf

Although this patch adds a distinction between maximum vcpus and
current vcpus in the XML, the values should be identical for all
drivers at this point.  Only in subsequent per-driver patches will
a distinction be made.

In general, virDomainGetInfo should prefer the current vcpus.

* src/conf/domain_conf.h (_virDomainDef): Adjust vcpus to unsigned
short, to match virDomainGetInfo limit.  Add maxvcpus member.
* src/conf/domain_conf.c (virDomainDefParseXML)
(virDomainDefFormat): parse and print out vcpu details.
* src/xen/xend_internal.c (xenDaemonParseSxpr)
(xenDaemonFormatSxpr): Manage both vcpu numbers, and require them
to be equal for now.
* src/xen/xm_internal.c (xenXMDomainConfigParse)
(xenXMDomainConfigFormat): Likewise.
* src/phyp/phyp_driver.c (phypDomainDumpXML): Likewise.
* src/openvz/openvz_conf.c (openvzLoadDomains): Likewise.
* src/openvz/openvz_driver.c (openvzDomainDefineXML)
(openvzDomainCreateXML, openvzDomainSetVcpusInternal): Likewise.
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxDomainDefineXML):
Likewise.
* src/xenapi/xenapi_driver.c (xenapiDomainDumpXML): Likewise.
* src/xenapi/xenapi_utils.c (createVMRecordFromXml): Likewise.
* src/esx/esx_vmx.c (esxVMX_ParseConfig, esxVMX_FormatConfig):
Likewise.
* src/qemu/qemu_conf.c (qemuBuildSmpArgStr)
(qemuParseCommandLineSmp, qemuParseCommandLine): Likewise.
* src/qemu/qemu_driver.c (qemudDomainHotplugVcpus): Likewise.
* src/opennebula/one_conf.c (xmlOneTemplate): Likewise.
---
 src/conf/domain_conf.c     |   45 +++++++++++++++++++++++++++++++++++++------
 src/conf/domain_conf.h     |    3 +-
 src/esx/esx_vmx.c          |   24 ++++++++++++++--------
 src/opennebula/one_conf.c  |    9 +++++--
 src/openvz/openvz_conf.c   |    7 +++--
 src/openvz/openvz_driver.c |   15 +++++++++----
 src/phyp/phyp_driver.c     |    2 +-
 src/qemu/qemu_conf.c       |   14 +++++++++++-
 src/qemu/qemu_driver.c     |    5 ++-
 src/vbox/vbox_tmpl.c       |   12 +++++++---
 src/xen/xend_internal.c    |    9 ++++---
 src/xen/xm_internal.c      |   11 ++++++---
 src/xenapi/xenapi_driver.c |    2 +-
 src/xenapi/xenapi_utils.c  |    4 +-
 14 files changed, 114 insertions(+), 48 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 78d7a6a..a997e06 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -4203,6 +4203,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
     int i, n;
     long id = -1;
     virDomainDefPtr def;
+    unsigned long count;

     if (VIR_ALLOC(def) < 0) {
         virReportOOMError();
@@ -4287,8 +4288,37 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
                       &def->mem.swap_hard_limit) < 0)
         def->mem.swap_hard_limit = 0;

-    if (virXPathULong("string(./vcpu[1])", ctxt, &def->vcpus) < 0)
-        def->vcpus = 1;
+    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 {
+        def->maxvcpus = count;
+        if (def->maxvcpus != count || count == 0) {
+            virDomainReportError(VIR_ERR_XML_ERROR,
+                                 _("invalid maxvcpus %lu"), count);
+            goto error;
+        }
+    }
+
+    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 {
+        def->vcpus = count;
+        if (def->vcpus != count || count == 0 || def->maxvcpus < count) {
+            virDomainReportError(VIR_ERR_XML_ERROR,
+                                 _("invalid current vcpus %lu"), count);
+            goto error;
+        }
+    }

     tmp = virXPathString("string(./vcpu[1]/@cpuset)", ctxt);
     if (tmp) {
@@ -6462,17 +6492,18 @@ char *virDomainDefFormat(virDomainDefPtr def,
         if (def->cpumask[n] != 1)
             allones = 0;

-    if (allones) {
-        virBufferAsprintf(&buf, "  <vcpu>%lu</vcpu>\n", def->vcpus);
-    } else {
+    virBufferAddLit(&buf, "  <vcpu");
+    if (!allones) {
         char *cpumask = NULL;
         if ((cpumask =
              virDomainCpuSetFormat(def->cpumask, def->cpumasklen)) == NULL)
             goto cleanup;
-        virBufferAsprintf(&buf, "  <vcpu cpuset='%s'>%lu</vcpu>\n",
-                          cpumask, def->vcpus);
+        virBufferAsprintf(&buf, " cpuset='%s'", cpumask);
         VIR_FREE(cpumask);
     }
+    if (def->vcpus != def->maxvcpus)
+        virBufferAsprintf(&buf, " current='%u'", def->vcpus);
+    virBufferAsprintf(&buf, ">%u</vcpu>\n", def->maxvcpus);

     if (def->os.bootloader) {
         virBufferEscapeString(&buf, "  <bootloader>%s</bootloader>\n",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index db09c23..5499f28 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -885,7 +885,8 @@ struct _virDomainDef {
         unsigned long min_guarantee;
         unsigned long swap_hard_limit;
     } mem;
-    unsigned long vcpus;
+    unsigned short vcpus;
+    unsigned short maxvcpus;
     int cpumasklen;
     char *cpumask;

diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c
index 7ec8c0e..0a26614 100644
--- a/src/esx/esx_vmx.c
+++ b/src/esx/esx_vmx.c
@@ -50,7 +50,7 @@ def->uuid = <value>               <=>   uuid.bios = "<value>"
 def->name = <value>               <=>   displayName = "<value>"
 def->mem.max_balloon = <value kilobyte>    <=>   memsize = "<value megabyte>"            # must be a multiple of 4, defaults to 32
 def->mem.cur_balloon = <value kilobyte>    <=>   sched.mem.max = "<value megabyte>"      # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon
-def->vcpus = <value>              <=>   numvcpus = "<value>"                    # must be 1 or a multiple of 2, defaults to 1
+def->maxvcpus = <value>           <=>   numvcpus = "<value>"                    # must be 1 or a multiple of 2, defaults to 1
 def->cpumask = <uint list>        <=>   sched.cpu.affinity = "<uint list>"


@@ -1075,7 +1075,7 @@ esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx,
         goto cleanup;
     }

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

     /* vmx:sched.cpu.affinity -> def:cpumask */
     // VirtualMachine:config.cpuAffinity.affinitySet
@@ -2609,16 +2609,22 @@ esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def,
                           (int)(def->mem.cur_balloon / 1024));
     }

-    /* def:vcpus -> vmx:numvcpus */
-    if (def->vcpus <= 0 || (def->vcpus % 2 != 0 && def->vcpus != 1)) {
+    /* def:maxvcpus -> vmx:numvcpus */
+    if (def->vcpus != def->maxvcpus) {
+        ESX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
+                  _("No support for domain XML entry 'vcpu' attribute "
+                    "'current'"));
+        goto cleanup;
+    }
+    if (def->maxvcpus <= 0 || (def->maxvcpus % 2 != 0 && def->maxvcpus != 1)) {
         ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                   _("Expecting domain XML entry 'vcpu' to be an unsigned "
                     "integer (1 or a multiple of 2) but found %d"),
-                  (int)def->vcpus);
+                  def->maxvcpus);
         goto cleanup;
     }

-    virBufferAsprintf(&buffer, "numvcpus = \"%d\"\n", (int)def->vcpus);
+    virBufferAsprintf(&buffer, "numvcpus = \"%d\"\n", def->maxvcpus);

     /* def:cpumask -> vmx:sched.cpu.affinity */
     if (def->cpumasklen > 0) {
@@ -2632,11 +2638,11 @@ esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def,
             }
         }

-        if (sched_cpu_affinity_length < def->vcpus) {
+        if (sched_cpu_affinity_length < def->maxvcpus) {
             ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting domain XML attribute 'cpuset' of entry "
-                        "'vcpu' to contains at least %d CPU(s)"),
-                      (int)def->vcpus);
+                        "'vcpu' to contain at least %d CPU(s)"),
+                      def->maxvcpus);
             goto cleanup;
         }

diff --git a/src/opennebula/one_conf.c b/src/opennebula/one_conf.c
index 44e28dc..2079c51 100644
--- a/src/opennebula/one_conf.c
+++ b/src/opennebula/one_conf.c
@@ -1,5 +1,7 @@
 /*----------------------------------------------------------------------------------*/
-/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ * Copyright 2002-2009, Distributed Systems Architecture Group, Universidad
  * Complutense de Madrid (dsa-research.org)
  *
  * This library is free software; you can redistribute it and/or
@@ -169,9 +171,10 @@ char* xmlOneTemplate(virDomainDefPtr def)
 {
     int i;
     virBuffer buf= VIR_BUFFER_INITIALIZER;
-    virBufferAsprintf(&buf,"#OpenNebula Template automatically generated by libvirt\nNAME = %s\nCPU = %ld\nMEMORY = %ld\n",
+    virBufferAsprintf(&buf,"#OpenNebula Template automatically generated "
+                      "by libvirt\nNAME = %s\nCPU = %d\nMEMORY = %ld\n",
                       def->name,
-                      def->vcpus,
+                      def->maxvcpus,
                       (def->mem.max_balloon)/1024);

     /*Optional Booting OpenNebula Information:*/
diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c
index ec11bbc..c84a6f3 100644
--- a/src/openvz/openvz_conf.c
+++ b/src/openvz/openvz_conf.c
@@ -507,11 +507,12 @@ int openvzLoadDomains(struct openvz_driver *driver) {
                         veid);
             goto cleanup;
         } else if (ret > 0) {
-            dom->def->vcpus = strtoI(temp);
+            dom->def->maxvcpus = strtoI(temp);
         }

-        if (ret == 0 || dom->def->vcpus == 0)
-            dom->def->vcpus = openvzGetNodeCPUs();
+        if (ret == 0 || dom->def->maxvcpus == 0)
+            dom->def->maxvcpus = openvzGetNodeCPUs();
+        dom->def->vcpus = dom->def->maxvcpus;

         /* XXX load rest of VM config data .... */

diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index 0f3cfdf..b7c2754 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -925,8 +925,13 @@ openvzDomainDefineXML(virConnectPtr conn, const char *xml)
     if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
         goto cleanup;

-    if (vm->def->vcpus > 0) {
-        if (openvzDomainSetVcpusInternal(vm, vm->def->vcpus) < 0) {
+    if (vm->def->vcpus != vm->def->maxvcpus) {
+        openvzError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                    _("current vcpu count must equal maximum"));
+        goto cleanup;
+    }
+    if (vm->def->maxvcpus > 0) {
+        if (openvzDomainSetVcpusInternal(vm, vm->def->maxvcpus) < 0) {
             openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                         _("Could not set number of virtual cpu"));
              goto cleanup;
@@ -1019,8 +1024,8 @@ openvzDomainCreateXML(virConnectPtr conn, const char *xml,
     vm->def->id = vm->pid;
     vm->state = VIR_DOMAIN_RUNNING;

-    if (vm->def->vcpus > 0) {
-        if (openvzDomainSetVcpusInternal(vm, vm->def->vcpus) < 0) {
+    if (vm->def->maxvcpus > 0) {
+        if (openvzDomainSetVcpusInternal(vm, vm->def->maxvcpus) < 0) {
             openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
                         _("Could not set number of virtual cpu"));
             goto cleanup;
@@ -1249,7 +1254,7 @@ static int openvzDomainSetVcpusInternal(virDomainObjPtr vm,
         return -1;
     }

-    vm->def->vcpus = nvcpus;
+    vm->def->maxvcpus = vm->def->vcpus = nvcpus;
     return 0;
 }

diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c
index e284ae0..3d0ed11 100644
--- a/src/phyp/phyp_driver.c
+++ b/src/phyp/phyp_driver.c
@@ -3540,7 +3540,7 @@ phypDomainDumpXML(virDomainPtr dom, int flags)
         goto err;
     }

-    if ((def.vcpus =
+    if ((def.maxvcpus = def.vcpus =
          phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) {
         VIR_ERROR0(_("Unable to determine domain's CPU."));
         goto err;
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 83c0f83..38c8351 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -3711,7 +3711,7 @@ qemuBuildSmpArgStr(const virDomainDefPtr def,
 {
     virBuffer buf = VIR_BUFFER_INITIALIZER;

-    virBufferAsprintf(&buf, "%lu", def->vcpus);
+    virBufferAsprintf(&buf, "%u", def->vcpus);

     if ((qemuCmdFlags & QEMUD_CMD_FLAG_SMP_TOPOLOGY)) {
         /* sockets, cores, and threads are either all zero
@@ -3722,11 +3722,18 @@ qemuBuildSmpArgStr(const virDomainDefPtr def,
             virBufferAsprintf(&buf, ",threads=%u", def->cpu->threads);
         }
         else {
-            virBufferAsprintf(&buf, ",sockets=%lu", def->vcpus);
+            virBufferAsprintf(&buf, ",sockets=%u", def->maxvcpus);
             virBufferAsprintf(&buf, ",cores=%u", 1);
             virBufferAsprintf(&buf, ",threads=%u", 1);
         }
     }
+    if (def->vcpus != def->maxvcpus) {
+        virBufferFreeAndReset(&buf);
+        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                        _("setting current vcpu count less than maximum is "
+                          "not supported yet"));
+        return NULL;
+    }

     if (virBufferError(&buf)) {
         virBufferFreeAndReset(&buf);
@@ -6178,6 +6185,8 @@ qemuParseCommandLineSmp(virDomainDefPtr dom,
         }
     }

+    dom->maxvcpus = dom->vcpus;
+
     if (sockets && cores && threads) {
         virCPUDefPtr cpu;

@@ -6247,6 +6256,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,

     def->id = -1;
     def->mem.cur_balloon = def->mem.max_balloon = 64 * 1024;
+    def->maxvcpus = 1;
     def->vcpus = 1;
     def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
     def->features = (1 << VIR_DOMAIN_FEATURE_ACPI)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 7a2ea8f..c66dc04 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2425,8 +2425,9 @@ qemuDetectVcpuPIDs(struct qemud_driver *driver,

     if (ncpupids != vm->def->vcpus) {
         qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("got wrong number of vCPU pids from QEMU monitor. got %d, wanted %d"),
-                        ncpupids, (int)vm->def->vcpus);
+                        _("got wrong number of vCPU pids from QEMU monitor. "
+                          "got %d, wanted %d"),
+                        ncpupids, vm->def->vcpus);
         VIR_FREE(cpupids);
         return -1;
     }
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index 0cbe8b3..5a859a4 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -2028,7 +2028,7 @@ static char *vboxDomainDumpXML(virDomainPtr dom, int flags) {
             def->mem.max_balloon = memorySize * 1024;

             machine->vtbl->GetCPUCount(machine, &CPUCount);
-            def->vcpus = CPUCount;
+            def->maxvcpus = def->vcpus = CPUCount;

             /* Skip cpumasklen, cpumask, onReboot, onPoweroff, onCrash */

@@ -4598,11 +4598,15 @@ static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml) {
                   def->mem.cur_balloon, (unsigned)rc);
     }

-    rc = machine->vtbl->SetCPUCount(machine, def->vcpus);
+    if (def->vcpus != def->maxvcpus) {
+        vboxError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                    _("current vcpu count must equal maximum"));
+    }
+    rc = machine->vtbl->SetCPUCount(machine, def->maxvcpus);
     if (NS_FAILED(rc)) {
         vboxError(VIR_ERR_INTERNAL_ERROR,
-                  _("could not set the number of virtual CPUs to: %lu, rc=%08x"),
-                  def->vcpus, (unsigned)rc);
+                  _("could not set the number of virtual CPUs to: %u, rc=%08x"),
+                  def->maxvcpus, (unsigned)rc);
     }

 #if VBOX_API_VERSION < 3001
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
index 5ffc3c8..456b477 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -2190,7 +2190,8 @@ xenDaemonParseSxpr(virConnectPtr conn,
         }
     }

-    def->vcpus = sexpr_int(root, "domain/vcpus");
+    def->maxvcpus = sexpr_int(root, "domain/vcpus");
+    def->vcpus = def->maxvcpus;

     tmp = sexpr_node(root, "domain/on_poweroff");
     if (tmp != NULL) {
@@ -5649,7 +5650,7 @@ xenDaemonFormatSxprInput(virDomainInputDefPtr input,
  *
  * Generate an SEXPR representing the domain configuration.
  *
- * Returns the 0 terminatedi S-Expr string or NULL in case of error.
+ * Returns the 0 terminated S-Expr string or NULL in case of error.
  *         the caller must free() the returned value.
  */
 char *
@@ -5666,7 +5667,7 @@ xenDaemonFormatSxpr(virConnectPtr conn,
     virBufferAsprintf(&buf, "(name '%s')", def->name);
     virBufferAsprintf(&buf, "(memory %lu)(maxmem %lu)",
                       def->mem.cur_balloon/1024, def->mem.max_balloon/1024);
-    virBufferAsprintf(&buf, "(vcpus %lu)", def->vcpus);
+    virBufferAsprintf(&buf, "(vcpus %u)", def->maxvcpus);

     if (def->cpumask) {
         char *ranges = virDomainCpuSetFormat(def->cpumask, def->cpumasklen);
@@ -5761,7 +5762,7 @@ xenDaemonFormatSxpr(virConnectPtr conn,
             else
                 virBufferAsprintf(&buf, "(kernel '%s')", def->os.loader);

-            virBufferAsprintf(&buf, "(vcpus %lu)", def->vcpus);
+            virBufferAsprintf(&buf, "(vcpus %u)", def->maxvcpus);

             for (i = 0 ; i < def->os.nBootDevs ; i++) {
                 switch (def->os.bootDevs[i]) {
diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
index 8e42a1c..bf20a64 100644
--- a/src/xen/xm_internal.c
+++ b/src/xen/xm_internal.c
@@ -678,6 +678,7 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
     int i;
     const char *defaultArch, *defaultMachine;
     int vmlocaltime = 0;
+    unsigned long count;

     if (VIR_ALLOC(def) < 0) {
         virReportOOMError();
@@ -770,9 +771,11 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
     def->mem.cur_balloon *= 1024;
     def->mem.max_balloon *= 1024;

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

     if (xenXMConfigGetString(conf, "cpus", &str, NULL) < 0)
         goto cleanup;
@@ -1650,7 +1653,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!
@@ -2241,7 +2244,7 @@ virConfPtr xenXMDomainConfigFormat(virConnectPtr conn,
     if (xenXMConfigSetInt(conf, "memory", def->mem.cur_balloon / 1024) < 0)
         goto no_memory;

-    if (xenXMConfigSetInt(conf, "vcpus", def->vcpus) < 0)
+    if (xenXMConfigSetInt(conf, "vcpus", def->maxvcpus) < 0)
         goto no_memory;

     if ((def->cpumask != NULL) &&
diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c
index 7d4ab8d..5ccdede 100644
--- a/src/xenapi/xenapi_driver.c
+++ b/src/xenapi/xenapi_driver.c
@@ -1335,7 +1335,7 @@ xenapiDomainDumpXML (virDomainPtr dom, int flags ATTRIBUTE_UNUSED)
     } else {
         defPtr->mem.cur_balloon = memory;
     }
-    defPtr->vcpus = xenapiDomainGetMaxVcpus(dom);
+    defPtr->maxvcpus = defPtr->vcpus = xenapiDomainGetMaxVcpus(dom);
     enum xen_on_normal_exit action;
     if (xen_vm_get_actions_after_shutdown(session, &action, vm)) {
         defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action);
diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c
index be55491..a7e2a4b 100644
--- a/src/xenapi/xenapi_utils.c
+++ b/src/xenapi/xenapi_utils.c
@@ -510,8 +510,8 @@ createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def,
     else
         (*record)->memory_dynamic_max = (*record)->memory_static_max;

-    if (def->vcpus) {
-        (*record)->vcpus_max = (int64_t) def->vcpus;
+    if (def->maxvcpus) {
+        (*record)->vcpus_max = (int64_t) def->maxvcpus;
         (*record)->vcpus_at_startup = (int64_t) def->vcpus;
     }
     if (def->onPoweroff)
-- 
1.7.2.3