From 4617eedfaeee2b187a1f14691d25746ba3ff31b6 Mon Sep 17 00:00:00 2001 From: Eric Blake 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, " %lu\n", def->vcpus); - } else { + virBufferAddLit(&buf, " cpumask, def->cpumasklen)) == NULL) goto cleanup; - virBufferAsprintf(&buf, " %lu\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\n", def->maxvcpus); if (def->os.bootloader) { virBufferEscapeString(&buf, " %s\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 = <=> uuid.bios = "" def->name = <=> displayName = "" def->mem.max_balloon = <=> memsize = "" # must be a multiple of 4, defaults to 32 def->mem.cur_balloon = <=> sched.mem.max = "" # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon -def->vcpus = <=> numvcpus = "" # must be 1 or a multiple of 2, defaults to 1 +def->maxvcpus = <=> numvcpus = "" # must be 1 or a multiple of 2, defaults to 1 def->cpumask = <=> sched.cpu.affinity = "" @@ -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