diff --git a/docs/schemas/capability.rng b/docs/schemas/capability.rng index 106ca73126..65c7c72edd 100644 --- a/docs/schemas/capability.rng +++ b/docs/schemas/capability.rng @@ -290,6 +290,11 @@ + + + + + diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index da92c78c16..5aeb2ab7d7 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -853,6 +853,8 @@ virCapabilitiesFormatXML(virCapsPtr caps) virBufferAddLit(&xml, " canonical) virBufferAsprintf(&xml, " canonical='%s'", machine->canonical); + if (machine->maxCpus > 0) + virBufferAsprintf(&xml, " maxCpus='%d'", machine->maxCpus); virBufferAsprintf(&xml, ">%s\n", machine->name); } @@ -871,6 +873,8 @@ virCapabilitiesFormatXML(virCapsPtr caps) virBufferAddLit(&xml, " canonical) virBufferAsprintf(&xml, " canonical='%s'", machine->canonical); + if (machine->maxCpus > 0) + virBufferAsprintf(&xml, " maxCpus='%d'", machine->maxCpus); virBufferAsprintf(&xml, ">%s\n", machine->name); } virBufferAddLit(&xml, " \n"); diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index abcf6dea4e..6c7efdefdb 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -46,6 +46,7 @@ typedef virCapsGuestMachine *virCapsGuestMachinePtr; struct _virCapsGuestMachine { char *name; char *canonical; + unsigned int maxCpus; }; typedef struct _virCapsGuestDomainInfo virCapsGuestDomainInfo; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index c4e076a1cd..969b001503 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -256,6 +256,7 @@ struct _virQEMUCaps { size_t nmachineTypes; char **machineTypes; char **machineAliases; + unsigned int *machineMaxCpus; }; struct _virQEMUCapsCache { @@ -335,6 +336,7 @@ virQEMUCapsSetDefaultMachine(virQEMUCapsPtr qemuCaps, { char *name = qemuCaps->machineTypes[defIdx]; char *alias = qemuCaps->machineAliases[defIdx]; + unsigned int maxCpus = qemuCaps->machineMaxCpus[defIdx]; memmove(qemuCaps->machineTypes + 1, qemuCaps->machineTypes, @@ -342,8 +344,12 @@ virQEMUCapsSetDefaultMachine(virQEMUCapsPtr qemuCaps, memmove(qemuCaps->machineAliases + 1, qemuCaps->machineAliases, sizeof(qemuCaps->machineAliases[0]) * defIdx); + memmove(qemuCaps->machineMaxCpus + 1, + qemuCaps->machineMaxCpus, + sizeof(qemuCaps->machineMaxCpus[0]) * defIdx); qemuCaps->machineTypes[0] = name; qemuCaps->machineAliases[0] = alias; + qemuCaps->machineMaxCpus[0] = maxCpus; } /* Format is: @@ -390,7 +396,8 @@ virQEMUCapsParseMachineTypesStr(const char *output, } if (VIR_REALLOC_N(qemuCaps->machineTypes, qemuCaps->nmachineTypes + 1) < 0 || - VIR_REALLOC_N(qemuCaps->machineAliases, qemuCaps->nmachineTypes + 1) < 0) { + VIR_REALLOC_N(qemuCaps->machineAliases, qemuCaps->nmachineTypes + 1) < 0 || + VIR_REALLOC_N(qemuCaps->machineMaxCpus, qemuCaps->nmachineTypes + 1) < 0) { VIR_FREE(name); VIR_FREE(canonical); virReportOOMError(); @@ -404,6 +411,8 @@ virQEMUCapsParseMachineTypesStr(const char *output, qemuCaps->machineTypes[qemuCaps->nmachineTypes-1] = name; qemuCaps->machineAliases[qemuCaps->nmachineTypes-1] = NULL; } + /* When parsing from command line we don't have information about maxCpus */ + qemuCaps->machineMaxCpus[qemuCaps->nmachineTypes-1] = 0; } while ((p = next)); @@ -1764,11 +1773,14 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps) goto no_memory; if (VIR_ALLOC_N(ret->machineAliases, qemuCaps->nmachineTypes) < 0) goto no_memory; + if (VIR_ALLOC_N(ret->machineMaxCpus, qemuCaps->nmachineTypes) < 0) + goto no_memory; ret->nmachineTypes = qemuCaps->nmachineTypes; for (i = 0; i < qemuCaps->nmachineTypes; i++) { if (VIR_STRDUP(ret->machineTypes[i], qemuCaps->machineTypes[i]) < 0 || VIR_STRDUP(ret->machineAliases[i], qemuCaps->machineAliases[i]) < 0) goto error; + ret->machineMaxCpus[i] = qemuCaps->machineMaxCpus[i]; } return ret; @@ -1792,6 +1804,7 @@ void virQEMUCapsDispose(void *obj) } VIR_FREE(qemuCaps->machineTypes); VIR_FREE(qemuCaps->machineAliases); + VIR_FREE(qemuCaps->machineMaxCpus); for (i = 0; i < qemuCaps->ncpuDefinitions; i++) { VIR_FREE(qemuCaps->cpuDefinitions[i]); @@ -1932,6 +1945,7 @@ int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps, if (VIR_STRDUP(mach->name, qemuCaps->machineTypes[i]) < 0) goto error; } + mach->maxCpus = qemuCaps->machineMaxCpus[i]; (*machines)[i] = mach; } @@ -1966,6 +1980,25 @@ const char *virQEMUCapsGetCanonicalMachine(virQEMUCapsPtr qemuCaps, } +int virQEMUCapsGetMachineMaxCpus(virQEMUCapsPtr qemuCaps, + const char *name) +{ + size_t i; + + if (!name) + return 0; + + for (i = 0; i < qemuCaps->nmachineTypes; i++) { + if (!qemuCaps->machineMaxCpus[i]) + continue; + if (STREQ(qemuCaps->machineTypes[i], name)) + return qemuCaps->machineMaxCpus[i]; + } + + return 0; +} + + static int virQEMUCapsProbeQMPCommands(virQEMUCapsPtr qemuCaps, qemuMonitorPtr mon) @@ -2083,6 +2116,10 @@ virQEMUCapsProbeQMPMachineTypes(virQEMUCapsPtr qemuCaps, virReportOOMError(); goto cleanup; } + if (VIR_ALLOC_N(qemuCaps->machineMaxCpus, nmachines) < 0) { + virReportOOMError(); + goto cleanup; + } for (i = 0; i < nmachines; i++) { if (VIR_STRDUP(qemuCaps->machineAliases[i], machines[i]->alias) < 0 || @@ -2090,6 +2127,7 @@ virQEMUCapsProbeQMPMachineTypes(virQEMUCapsPtr qemuCaps, goto cleanup; if (machines[i]->isDefault) defIdx = i; + qemuCaps->machineMaxCpus[i] = machines[i]->maxCpus; } qemuCaps->nmachineTypes = nmachines; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 64a4b1d311..708874746a 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -234,7 +234,8 @@ size_t virQEMUCapsGetMachineTypes(virQEMUCapsPtr qemuCaps, char ***names); const char *virQEMUCapsGetCanonicalMachine(virQEMUCapsPtr qemuCaps, const char *name); - +int virQEMUCapsGetMachineMaxCpus(virQEMUCapsPtr qemuCaps, + const char *name); int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps, size_t *nmachines, virCapsGuestMachinePtr **machines); diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 3d9afa315c..86ef635c0d 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -654,6 +654,7 @@ struct _qemuMonitorMachineInfo { char *name; bool isDefault; char *alias; + unsigned int maxCpus; }; int qemuMonitorGetMachines(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 88a0dc9dfb..c0d7960ef4 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4042,6 +4042,12 @@ int qemuMonitorJSONGetMachines(qemuMonitorPtr mon, if (VIR_STRDUP(info->alias, tmp) < 0) goto cleanup; } + if (virJSONValueObjectHasKey(child, "cpu-max") && + virJSONValueObjectGetNumberUint(child, "cpu-max", &info->maxCpus) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-machines reply has malformed 'cpu-max' data")); + goto cleanup; + } } ret = n; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 5a0f18b24b..ac5ffcfa04 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3330,6 +3330,24 @@ error: } +static bool +qemuValidateCpuMax(virDomainDefPtr def, virQEMUCapsPtr qemuCaps) +{ + unsigned int maxCpus; + + maxCpus = virQEMUCapsGetMachineMaxCpus(qemuCaps, def->os.machine); + if (!maxCpus) + return true; + + if (def->maxvcpus > maxCpus) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("Maximum CPUs greater than specified machine type limit")); + return false; + } + + return true; +} + int qemuProcessStart(virConnectPtr conn, virQEMUDriverPtr driver, virDomainObjPtr vm, @@ -3519,6 +3537,9 @@ int qemuProcessStart(virConnectPtr conn, vm->def->emulator))) goto cleanup; + if (!qemuValidateCpuMax(vm->def, priv->qemuCaps)) + goto cleanup; + if (qemuAssignDeviceAliases(vm->def, priv->qemuCaps) < 0) goto cleanup; diff --git a/tests/capabilityschemadata/caps-qemu-kvm.xml b/tests/capabilityschemadata/caps-qemu-kvm.xml index 36c4b49476..1fbc22bc86 100644 --- a/tests/capabilityschemadata/caps-qemu-kvm.xml +++ b/tests/capabilityschemadata/caps-qemu-kvm.xml @@ -33,18 +33,18 @@ 32 /usr/bin/qemu - pc-0.11 - pc - pc-0.10 - isapc + pc-0.11 + pc + pc-0.10 + isapc /usr/bin/qemu-kvm - pc-0.11 - pc - pc-0.10 - isapc + pc-0.11 + pc + pc-0.10 + isapc