Implement check whether (maximum) vCPUs doesn't exceed machine type's cpu-max settings. Signed-off-by: Michal Novotny <minovotn@xxxxxxxxxx> --- src/conf/capabilities.h | 1 + src/qemu/qemu_capabilities.c | 40 +++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_capabilities.h | 3 ++- src/qemu/qemu_monitor.h | 1 + src/qemu/qemu_monitor_json.c | 7 +++++++ src/qemu/qemu_process.c | 27 +++++++++++++++++++++++++++ 6 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index abcf6de..16bf3de 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -46,6 +46,7 @@ typedef virCapsGuestMachine *virCapsGuestMachinePtr; struct _virCapsGuestMachine { char *name; char *canonical; + int cpu_max; }; typedef struct _virCapsGuestDomainInfo virCapsGuestDomainInfo; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index d10c8aa..a03a643 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -243,6 +243,7 @@ struct _virQEMUCaps { size_t nmachineTypes; char **machineTypes; char **machineAliases; + int *machineMaxCpus; }; struct _virQEMUCapsCache { @@ -322,6 +323,7 @@ virQEMUCapsSetDefaultMachine(virQEMUCapsPtr qemuCaps, { char *name = qemuCaps->machineTypes[defIdx]; char *alias = qemuCaps->machineAliases[defIdx]; + int cpu_max = qemuCaps->machineMaxCpus[defIdx]; memmove(qemuCaps->machineTypes + 1, qemuCaps->machineTypes, @@ -329,8 +331,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] = cpu_max; } /* Format is: @@ -377,7 +383,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); goto no_memory; @@ -390,6 +397,8 @@ virQEMUCapsParseMachineTypesStr(const char *output, qemuCaps->machineTypes[qemuCaps->nmachineTypes-1] = name; qemuCaps->machineAliases[qemuCaps->nmachineTypes-1] = NULL; } + /* Value 0 means "unknown" as it's not exposed by QEMU binary */ + qemuCaps->machineMaxCpus[qemuCaps->nmachineTypes-1] = 0; } while ((p = next)); @@ -1718,6 +1727,8 @@ 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 (!(ret->machineTypes[i] = strdup(qemuCaps->machineTypes[i]))) @@ -1725,6 +1736,7 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps) if (qemuCaps->machineAliases[i] && !(ret->machineAliases[i] = strdup(qemuCaps->machineAliases[i]))) goto no_memory; + ret->machineMaxCpus[i] = qemuCaps->machineMaxCpus[i]; } return ret; @@ -1885,9 +1897,11 @@ int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps, goto no_memory; if (!(mach->canonical = strdup(qemuCaps->machineTypes[i]))) goto no_memory; + mach->cpu_max = qemuCaps->machineMaxCpus[i]; } else { if (!(mach->name = strdup(qemuCaps->machineTypes[i]))) goto no_memory; + mach->cpu_max = qemuCaps->machineMaxCpus[i]; } (*machines)[i] = mach; } @@ -1923,6 +1937,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) @@ -2073,6 +2106,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 (machines[i]->alias) { @@ -2087,6 +2124,7 @@ virQEMUCapsProbeQMPMachineTypes(virQEMUCapsPtr qemuCaps, } if (machines[i]->isDefault) defIdx = i; + qemuCaps->machineMaxCpus[i] = machines[i]->cpu_max; } qemuCaps->nmachineTypes = nmachines; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 728add5..8205ff7 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -224,7 +224,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 f39f009..c097953 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -650,6 +650,7 @@ struct _qemuMonitorMachineInfo { char *name; bool isDefault; char *alias; + int cpu_max; }; int qemuMonitorGetMachines(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 6fdd650..adbd865 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4024,6 +4024,13 @@ int qemuMonitorJSONGetMachines(qemuMonitorPtr mon, goto cleanup; } } + + if (virJSONValueObjectHasKey(child, "cpu-max") && + virJSONValueObjectGetNumberInt(child, "cpu-max", &info->cpu_max) < 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 ce9f501..9eae8f6 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3266,6 +3266,30 @@ qemuSetUnprivSGIO(virDomainDiskDefPtr disk) return ret; } +static bool +qemuValidateCpuMax(virDomainDefPtr def, virQEMUCapsPtr qemuCaps) +{ + int cpu_max; + + cpu_max = virQEMUCapsGetMachineMaxCpus(qemuCaps, def->os.machine); + if (!cpu_max) + return true; + + if (def->vcpus > cpu_max) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("CPUs greater than specified machine type limit")); + return false; + } + + if (def->maxvcpus > cpu_max) { + 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, @@ -3481,6 +3505,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; -- 1.7.11.7 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list