1
From 4617eedfaeee2b187a1f14691d25746ba3ff31b6 Mon Sep 17 00:00:00 2001
2
From: Eric Blake <eblake@redhat.com>
3
Date: Wed, 29 Sep 2010 10:20:07 -0600
4
Subject: [PATCH 07/15] vcpu: support maxvcpu in domain_conf
6
Although this patch adds a distinction between maximum vcpus and
7
current vcpus in the XML, the values should be identical for all
8
drivers at this point. Only in subsequent per-driver patches will
11
In general, virDomainGetInfo should prefer the current vcpus.
13
* src/conf/domain_conf.h (_virDomainDef): Adjust vcpus to unsigned
14
short, to match virDomainGetInfo limit. Add maxvcpus member.
15
* src/conf/domain_conf.c (virDomainDefParseXML)
16
(virDomainDefFormat): parse and print out vcpu details.
17
* src/xen/xend_internal.c (xenDaemonParseSxpr)
18
(xenDaemonFormatSxpr): Manage both vcpu numbers, and require them
20
* src/xen/xm_internal.c (xenXMDomainConfigParse)
21
(xenXMDomainConfigFormat): Likewise.
22
* src/phyp/phyp_driver.c (phypDomainDumpXML): Likewise.
23
* src/openvz/openvz_conf.c (openvzLoadDomains): Likewise.
24
* src/openvz/openvz_driver.c (openvzDomainDefineXML)
25
(openvzDomainCreateXML, openvzDomainSetVcpusInternal): Likewise.
26
* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxDomainDefineXML):
28
* src/xenapi/xenapi_driver.c (xenapiDomainDumpXML): Likewise.
29
* src/xenapi/xenapi_utils.c (createVMRecordFromXml): Likewise.
30
* src/esx/esx_vmx.c (esxVMX_ParseConfig, esxVMX_FormatConfig):
32
* src/qemu/qemu_conf.c (qemuBuildSmpArgStr)
33
(qemuParseCommandLineSmp, qemuParseCommandLine): Likewise.
34
* src/qemu/qemu_driver.c (qemudDomainHotplugVcpus): Likewise.
35
* src/opennebula/one_conf.c (xmlOneTemplate): Likewise.
37
src/conf/domain_conf.c | 45 +++++++++++++++++++++++++++++++++++++------
38
src/conf/domain_conf.h | 3 +-
39
src/esx/esx_vmx.c | 24 ++++++++++++++--------
40
src/opennebula/one_conf.c | 9 +++++--
41
src/openvz/openvz_conf.c | 7 +++--
42
src/openvz/openvz_driver.c | 15 +++++++++----
43
src/phyp/phyp_driver.c | 2 +-
44
src/qemu/qemu_conf.c | 14 +++++++++++-
45
src/qemu/qemu_driver.c | 5 ++-
46
src/vbox/vbox_tmpl.c | 12 +++++++---
47
src/xen/xend_internal.c | 9 ++++---
48
src/xen/xm_internal.c | 11 ++++++---
49
src/xenapi/xenapi_driver.c | 2 +-
50
src/xenapi/xenapi_utils.c | 4 +-
51
14 files changed, 114 insertions(+), 48 deletions(-)
53
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
54
index 78d7a6a..a997e06 100644
55
--- a/src/conf/domain_conf.c
56
+++ b/src/conf/domain_conf.c
57
@@ -4203,6 +4203,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
61
+ unsigned long count;
63
if (VIR_ALLOC(def) < 0) {
65
@@ -4287,8 +4288,37 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
66
&def->mem.swap_hard_limit) < 0)
67
def->mem.swap_hard_limit = 0;
69
- if (virXPathULong("string(./vcpu[1])", ctxt, &def->vcpus) < 0)
71
+ n = virXPathULong("string(./vcpu[1])", ctxt, &count);
73
+ virDomainReportError(VIR_ERR_XML_ERROR, "%s",
74
+ _("maximum vcpus must be an integer"));
79
+ def->maxvcpus = count;
80
+ if (def->maxvcpus != count || count == 0) {
81
+ virDomainReportError(VIR_ERR_XML_ERROR,
82
+ _("invalid maxvcpus %lu"), count);
87
+ n = virXPathULong("string(./vcpu[1]/@current)", ctxt, &count);
89
+ virDomainReportError(VIR_ERR_XML_ERROR, "%s",
90
+ _("current vcpus must be an integer"));
93
+ def->vcpus = def->maxvcpus;
96
+ if (def->vcpus != count || count == 0 || def->maxvcpus < count) {
97
+ virDomainReportError(VIR_ERR_XML_ERROR,
98
+ _("invalid current vcpus %lu"), count);
103
tmp = virXPathString("string(./vcpu[1]/@cpuset)", ctxt);
105
@@ -6462,17 +6492,18 @@ char *virDomainDefFormat(virDomainDefPtr def,
106
if (def->cpumask[n] != 1)
110
- virBufferVSprintf(&buf, " <vcpu>%lu</vcpu>\n", def->vcpus);
112
+ virBufferAddLit(&buf, " <vcpu");
114
char *cpumask = NULL;
116
virDomainCpuSetFormat(def->cpumask, def->cpumasklen)) == NULL)
118
- virBufferVSprintf(&buf, " <vcpu cpuset='%s'>%lu</vcpu>\n",
119
- cpumask, def->vcpus);
120
+ virBufferVSprintf(&buf, " cpuset='%s'", cpumask);
123
+ if (def->vcpus != def->maxvcpus)
124
+ virBufferVSprintf(&buf, " current='%u'", def->vcpus);
125
+ virBufferVSprintf(&buf, ">%u</vcpu>\n", def->maxvcpus);
127
if (def->os.bootloader) {
128
virBufferEscapeString(&buf, " <bootloader>%s</bootloader>\n",
129
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
130
index db09c23..5499f28 100644
131
--- a/src/conf/domain_conf.h
132
+++ b/src/conf/domain_conf.h
133
@@ -885,7 +885,8 @@ struct _virDomainDef {
134
unsigned long min_guarantee;
135
unsigned long swap_hard_limit;
137
- unsigned long vcpus;
138
+ unsigned short vcpus;
139
+ unsigned short maxvcpus;
143
diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c
144
index 7ec8c0e..0a26614 100644
145
--- a/src/esx/esx_vmx.c
146
+++ b/src/esx/esx_vmx.c
147
@@ -50,7 +50,7 @@ def->uuid = <value> <=> uuid.bios = "<value>"
148
def->name = <value> <=> displayName = "<value>"
149
def->mem.max_balloon = <value kilobyte> <=> memsize = "<value megabyte>" # must be a multiple of 4, defaults to 32
150
def->mem.cur_balloon = <value kilobyte> <=> sched.mem.max = "<value megabyte>" # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon
151
-def->vcpus = <value> <=> numvcpus = "<value>" # must be 1 or a multiple of 2, defaults to 1
152
+def->maxvcpus = <value> <=> numvcpus = "<value>" # must be 1 or a multiple of 2, defaults to 1
153
def->cpumask = <uint list> <=> sched.cpu.affinity = "<uint list>"
156
@@ -1075,7 +1075,7 @@ esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx,
160
- def->vcpus = numvcpus;
161
+ def->maxvcpus = def->vcpus = numvcpus;
163
/* vmx:sched.cpu.affinity -> def:cpumask */
164
// VirtualMachine:config.cpuAffinity.affinitySet
165
@@ -2609,16 +2609,22 @@ esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def,
166
(int)(def->mem.cur_balloon / 1024));
169
- /* def:vcpus -> vmx:numvcpus */
170
- if (def->vcpus <= 0 || (def->vcpus % 2 != 0 && def->vcpus != 1)) {
171
+ /* def:maxvcpus -> vmx:numvcpus */
172
+ if (def->vcpus != def->maxvcpus) {
173
+ ESX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
174
+ _("No support for domain XML entry 'vcpu' attribute "
178
+ if (def->maxvcpus <= 0 || (def->maxvcpus % 2 != 0 && def->maxvcpus != 1)) {
179
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
180
_("Expecting domain XML entry 'vcpu' to be an unsigned "
181
"integer (1 or a multiple of 2) but found %d"),
187
- virBufferVSprintf(&buffer, "numvcpus = \"%d\"\n", (int)def->vcpus);
188
+ virBufferVSprintf(&buffer, "numvcpus = \"%d\"\n", def->maxvcpus);
190
/* def:cpumask -> vmx:sched.cpu.affinity */
191
if (def->cpumasklen > 0) {
192
@@ -2632,11 +2638,11 @@ esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def,
196
- if (sched_cpu_affinity_length < def->vcpus) {
197
+ if (sched_cpu_affinity_length < def->maxvcpus) {
198
ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
199
_("Expecting domain XML attribute 'cpuset' of entry "
200
- "'vcpu' to contains at least %d CPU(s)"),
202
+ "'vcpu' to contain at least %d CPU(s)"),
207
diff --git a/src/opennebula/one_conf.c b/src/opennebula/one_conf.c
208
index 44e28dc..2079c51 100644
209
--- a/src/opennebula/one_conf.c
210
+++ b/src/opennebula/one_conf.c
212
/*----------------------------------------------------------------------------------*/
213
-/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad
215
+ * Copyright (C) 2010 Red Hat, Inc.
216
+ * Copyright 2002-2009, Distributed Systems Architecture Group, Universidad
217
* Complutense de Madrid (dsa-research.org)
219
* This library is free software; you can redistribute it and/or
220
@@ -169,9 +171,10 @@ char* xmlOneTemplate(virDomainDefPtr def)
223
virBuffer buf= VIR_BUFFER_INITIALIZER;
224
- virBufferVSprintf(&buf,"#OpenNebula Template automatically generated by libvirt\nNAME = %s\nCPU = %ld\nMEMORY = %ld\n",
225
+ virBufferVSprintf(&buf,"#OpenNebula Template automatically generated "
226
+ "by libvirt\nNAME = %s\nCPU = %d\nMEMORY = %ld\n",
230
(def->mem.max_balloon)/1024);
232
/*Optional Booting OpenNebula Information:*/
233
diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c
234
index ec11bbc..c84a6f3 100644
235
--- a/src/openvz/openvz_conf.c
236
+++ b/src/openvz/openvz_conf.c
237
@@ -507,11 +507,12 @@ int openvzLoadDomains(struct openvz_driver *driver) {
240
} else if (ret > 0) {
241
- dom->def->vcpus = strtoI(temp);
242
+ dom->def->maxvcpus = strtoI(temp);
245
- if (ret == 0 || dom->def->vcpus == 0)
246
- dom->def->vcpus = openvzGetNodeCPUs();
247
+ if (ret == 0 || dom->def->maxvcpus == 0)
248
+ dom->def->maxvcpus = openvzGetNodeCPUs();
249
+ dom->def->vcpus = dom->def->maxvcpus;
251
/* XXX load rest of VM config data .... */
253
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
254
index 0f3cfdf..b7c2754 100644
255
--- a/src/openvz/openvz_driver.c
256
+++ b/src/openvz/openvz_driver.c
257
@@ -925,8 +925,13 @@ openvzDomainDefineXML(virConnectPtr conn, const char *xml)
258
if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
261
- if (vm->def->vcpus > 0) {
262
- if (openvzDomainSetVcpusInternal(vm, vm->def->vcpus) < 0) {
263
+ if (vm->def->vcpus != vm->def->maxvcpus) {
264
+ openvzError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
265
+ _("current vcpu count must equal maximum"));
268
+ if (vm->def->maxvcpus > 0) {
269
+ if (openvzDomainSetVcpusInternal(vm, vm->def->maxvcpus) < 0) {
270
openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
271
_("Could not set number of virtual cpu"));
273
@@ -1019,8 +1024,8 @@ openvzDomainCreateXML(virConnectPtr conn, const char *xml,
274
vm->def->id = vm->pid;
275
vm->state = VIR_DOMAIN_RUNNING;
277
- if (vm->def->vcpus > 0) {
278
- if (openvzDomainSetVcpusInternal(vm, vm->def->vcpus) < 0) {
279
+ if (vm->def->maxvcpus > 0) {
280
+ if (openvzDomainSetVcpusInternal(vm, vm->def->maxvcpus) < 0) {
281
openvzError(VIR_ERR_INTERNAL_ERROR, "%s",
282
_("Could not set number of virtual cpu"));
284
@@ -1249,7 +1254,7 @@ static int openvzDomainSetVcpusInternal(virDomainObjPtr vm,
288
- vm->def->vcpus = nvcpus;
289
+ vm->def->maxvcpus = vm->def->vcpus = nvcpus;
293
diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c
294
index e284ae0..3d0ed11 100644
295
--- a/src/phyp/phyp_driver.c
296
+++ b/src/phyp/phyp_driver.c
297
@@ -3540,7 +3540,7 @@ phypDomainDumpXML(virDomainPtr dom, int flags)
302
+ if ((def.maxvcpus = def.vcpus =
303
phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) {
304
VIR_ERROR0(_("Unable to determine domain's CPU."));
306
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
307
index 83c0f83..38c8351 100644
308
--- a/src/qemu/qemu_conf.c
309
+++ b/src/qemu/qemu_conf.c
310
@@ -3711,7 +3711,7 @@ qemuBuildSmpArgStr(const virDomainDefPtr def,
312
virBuffer buf = VIR_BUFFER_INITIALIZER;
314
- virBufferVSprintf(&buf, "%lu", def->vcpus);
315
+ virBufferVSprintf(&buf, "%u", def->vcpus);
317
if ((qemuCmdFlags & QEMUD_CMD_FLAG_SMP_TOPOLOGY)) {
318
/* sockets, cores, and threads are either all zero
319
@@ -3722,11 +3722,18 @@ qemuBuildSmpArgStr(const virDomainDefPtr def,
320
virBufferVSprintf(&buf, ",threads=%u", def->cpu->threads);
323
- virBufferVSprintf(&buf, ",sockets=%lu", def->vcpus);
324
+ virBufferVSprintf(&buf, ",sockets=%u", def->maxvcpus);
325
virBufferVSprintf(&buf, ",cores=%u", 1);
326
virBufferVSprintf(&buf, ",threads=%u", 1);
329
+ if (def->vcpus != def->maxvcpus) {
330
+ virBufferFreeAndReset(&buf);
331
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
332
+ _("setting current vcpu count less than maximum is "
333
+ "not supported yet"));
337
if (virBufferError(&buf)) {
338
virBufferFreeAndReset(&buf);
339
@@ -6178,6 +6185,8 @@ qemuParseCommandLineSmp(virDomainDefPtr dom,
343
+ dom->maxvcpus = dom->vcpus;
345
if (sockets && cores && threads) {
348
@@ -6247,6 +6256,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
351
def->mem.cur_balloon = def->mem.max_balloon = 64 * 1024;
354
def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
355
def->features = (1 << VIR_DOMAIN_FEATURE_ACPI)
356
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
357
index 7a2ea8f..c66dc04 100644
358
--- a/src/qemu/qemu_driver.c
359
+++ b/src/qemu/qemu_driver.c
360
@@ -2425,8 +2425,9 @@ qemuDetectVcpuPIDs(struct qemud_driver *driver,
362
if (ncpupids != vm->def->vcpus) {
363
qemuReportError(VIR_ERR_INTERNAL_ERROR,
364
- _("got wrong number of vCPU pids from QEMU monitor. got %d, wanted %d"),
365
- ncpupids, (int)vm->def->vcpus);
366
+ _("got wrong number of vCPU pids from QEMU monitor. "
367
+ "got %d, wanted %d"),
368
+ ncpupids, vm->def->vcpus);
372
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
373
index 0cbe8b3..5a859a4 100644
374
--- a/src/vbox/vbox_tmpl.c
375
+++ b/src/vbox/vbox_tmpl.c
376
@@ -2028,7 +2028,7 @@ static char *vboxDomainDumpXML(virDomainPtr dom, int flags) {
377
def->mem.max_balloon = memorySize * 1024;
379
machine->vtbl->GetCPUCount(machine, &CPUCount);
380
- def->vcpus = CPUCount;
381
+ def->maxvcpus = def->vcpus = CPUCount;
383
/* Skip cpumasklen, cpumask, onReboot, onPoweroff, onCrash */
385
@@ -4598,11 +4598,15 @@ static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml) {
386
def->mem.cur_balloon, (unsigned)rc);
389
- rc = machine->vtbl->SetCPUCount(machine, def->vcpus);
390
+ if (def->vcpus != def->maxvcpus) {
391
+ vboxError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
392
+ _("current vcpu count must equal maximum"));
394
+ rc = machine->vtbl->SetCPUCount(machine, def->maxvcpus);
396
vboxError(VIR_ERR_INTERNAL_ERROR,
397
- _("could not set the number of virtual CPUs to: %lu, rc=%08x"),
398
- def->vcpus, (unsigned)rc);
399
+ _("could not set the number of virtual CPUs to: %u, rc=%08x"),
400
+ def->maxvcpus, (unsigned)rc);
403
#if VBOX_API_VERSION < 3001
404
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
405
index 5ffc3c8..456b477 100644
406
--- a/src/xen/xend_internal.c
407
+++ b/src/xen/xend_internal.c
408
@@ -2190,7 +2190,8 @@ xenDaemonParseSxpr(virConnectPtr conn,
412
- def->vcpus = sexpr_int(root, "domain/vcpus");
413
+ def->maxvcpus = sexpr_int(root, "domain/vcpus");
414
+ def->vcpus = def->maxvcpus;
416
tmp = sexpr_node(root, "domain/on_poweroff");
418
@@ -5649,7 +5650,7 @@ xenDaemonFormatSxprInput(virDomainInputDefPtr input,
420
* Generate an SEXPR representing the domain configuration.
422
- * Returns the 0 terminatedi S-Expr string or NULL in case of error.
423
+ * Returns the 0 terminated S-Expr string or NULL in case of error.
424
* the caller must free() the returned value.
427
@@ -5666,7 +5667,7 @@ xenDaemonFormatSxpr(virConnectPtr conn,
428
virBufferVSprintf(&buf, "(name '%s')", def->name);
429
virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)",
430
def->mem.cur_balloon/1024, def->mem.max_balloon/1024);
431
- virBufferVSprintf(&buf, "(vcpus %lu)", def->vcpus);
432
+ virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
435
char *ranges = virDomainCpuSetFormat(def->cpumask, def->cpumasklen);
436
@@ -5761,7 +5762,7 @@ xenDaemonFormatSxpr(virConnectPtr conn,
438
virBufferVSprintf(&buf, "(kernel '%s')", def->os.loader);
440
- virBufferVSprintf(&buf, "(vcpus %lu)", def->vcpus);
441
+ virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
443
for (i = 0 ; i < def->os.nBootDevs ; i++) {
444
switch (def->os.bootDevs[i]) {
445
diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
446
index 8e42a1c..bf20a64 100644
447
--- a/src/xen/xm_internal.c
448
+++ b/src/xen/xm_internal.c
449
@@ -678,6 +678,7 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
451
const char *defaultArch, *defaultMachine;
453
+ unsigned long count;
455
if (VIR_ALLOC(def) < 0) {
457
@@ -770,9 +771,11 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) {
458
def->mem.cur_balloon *= 1024;
459
def->mem.max_balloon *= 1024;
462
- if (xenXMConfigGetULong(conf, "vcpus", &def->vcpus, 1) < 0)
463
+ if (xenXMConfigGetULong(conf, "vcpus", &count, 1) < 0 ||
464
+ (unsigned short) count != count)
466
+ def->maxvcpus = count;
467
+ def->vcpus = def->maxvcpus;
469
if (xenXMConfigGetString(conf, "cpus", &str, NULL) < 0)
471
@@ -1650,7 +1653,7 @@ int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus) {
472
if (!(entry = virHashLookup(priv->configCache, filename)))
475
- entry->def->vcpus = vcpus;
476
+ entry->def->maxvcpus = entry->def->vcpus = vcpus;
478
/* If this fails, should we try to undo our changes to the
479
* in-memory representation of the config file. I say not!
480
@@ -2241,7 +2244,7 @@ virConfPtr xenXMDomainConfigFormat(virConnectPtr conn,
481
if (xenXMConfigSetInt(conf, "memory", def->mem.cur_balloon / 1024) < 0)
484
- if (xenXMConfigSetInt(conf, "vcpus", def->vcpus) < 0)
485
+ if (xenXMConfigSetInt(conf, "vcpus", def->maxvcpus) < 0)
488
if ((def->cpumask != NULL) &&
489
diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c
490
index 7d4ab8d..5ccdede 100644
491
--- a/src/xenapi/xenapi_driver.c
492
+++ b/src/xenapi/xenapi_driver.c
493
@@ -1335,7 +1335,7 @@ xenapiDomainDumpXML (virDomainPtr dom, int flags ATTRIBUTE_UNUSED)
495
defPtr->mem.cur_balloon = memory;
497
- defPtr->vcpus = xenapiDomainGetMaxVcpus(dom);
498
+ defPtr->maxvcpus = defPtr->vcpus = xenapiDomainGetMaxVcpus(dom);
499
enum xen_on_normal_exit action;
500
if (xen_vm_get_actions_after_shutdown(session, &action, vm)) {
501
defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action);
502
diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c
503
index be55491..a7e2a4b 100644
504
--- a/src/xenapi/xenapi_utils.c
505
+++ b/src/xenapi/xenapi_utils.c
506
@@ -510,8 +510,8 @@ createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def,
508
(*record)->memory_dynamic_max = (*record)->memory_static_max;
511
- (*record)->vcpus_max = (int64_t) def->vcpus;
512
+ if (def->maxvcpus) {
513
+ (*record)->vcpus_max = (int64_t) def->maxvcpus;
514
(*record)->vcpus_at_startup = (int64_t) def->vcpus;