diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index c71b4dcf44..b0e51eeca7 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -378,8 +378,7 @@ struct _virQEMUCaps { virArch arch; - size_t ncpuDefinitions; - char **cpuDefinitions; + virDomainCapsCPUModelsPtr cpuDefinitions; size_t nmachineTypes; struct virQEMUCapsMachineType *machineTypes; @@ -618,7 +617,10 @@ virQEMUCapsParseX86Models(const char *output, { const char *p = output; const char *next; - int ret = -1; + virDomainCapsCPUModelsPtr cpus; + + if (!(cpus = virDomainCapsCPUModelsNew(0))) + return -1; do { const char *t; @@ -640,9 +642,6 @@ virQEMUCapsParseX86Models(const char *output, if (*p == '\0' || *p == '\n') continue; - if (VIR_EXPAND_N(qemuCaps->cpuDefinitions, qemuCaps->ncpuDefinitions, 1) < 0) - goto cleanup; - if (next) len = next - p - 1; else @@ -653,14 +652,16 @@ virQEMUCapsParseX86Models(const char *output, len -= 2; } - if (VIR_STRNDUP(qemuCaps->cpuDefinitions[qemuCaps->ncpuDefinitions - 1], p, len) < 0) - goto cleanup; + if (virDomainCapsCPUModelsAdd(cpus, p, len) < 0) + goto error; } while ((p = next)); - ret = 0; + qemuCaps->cpuDefinitions = cpus; + return 0; - cleanup: - return ret; + error: + virObjectUnref(cpus); + return -1; } /* ppc64 parser. @@ -672,11 +673,13 @@ virQEMUCapsParsePPCModels(const char *output, { const char *p = output; const char *next; - int ret = -1; + virDomainCapsCPUModelsPtr cpus; + + if (!(cpus = virDomainCapsCPUModelsNew(0))) + return -1; do { const char *t; - size_t len; if ((next = strchr(p, '\n'))) next++; @@ -697,19 +700,16 @@ virQEMUCapsParsePPCModels(const char *output, if (*p == '\n') continue; - if (VIR_EXPAND_N(qemuCaps->cpuDefinitions, qemuCaps->ncpuDefinitions, 1) < 0) - goto cleanup; - - len = t - p - 1; - - if (VIR_STRNDUP(qemuCaps->cpuDefinitions[qemuCaps->ncpuDefinitions - 1], p, len) < 0) - goto cleanup; + if (virDomainCapsCPUModelsAdd(cpus, p, t - p - 1) < 0) + goto error; } while ((p = next)); - ret = 0; + qemuCaps->cpuDefinitions = cpus; + return 0; - cleanup: - return ret; + error: + virObjectUnref(cpus); + return -1; } static int @@ -2094,11 +2094,9 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps) ret->arch = qemuCaps->arch; - if (VIR_ALLOC_N(ret->cpuDefinitions, qemuCaps->ncpuDefinitions) < 0) - goto error; - ret->ncpuDefinitions = qemuCaps->ncpuDefinitions; - for (i = 0; i < qemuCaps->ncpuDefinitions; i++) { - if (VIR_STRDUP(ret->cpuDefinitions[i], qemuCaps->cpuDefinitions[i]) < 0) + if (qemuCaps->cpuDefinitions) { + ret->cpuDefinitions = virDomainCapsCPUModelsCopy(qemuCaps->cpuDefinitions); + if (!ret->cpuDefinitions) goto error; } @@ -2138,9 +2136,7 @@ void virQEMUCapsDispose(void *obj) } VIR_FREE(qemuCaps->machineTypes); - for (i = 0; i < qemuCaps->ncpuDefinitions; i++) - VIR_FREE(qemuCaps->cpuDefinitions[i]); - VIR_FREE(qemuCaps->cpuDefinitions); + virObjectUnref(qemuCaps->cpuDefinitions); virBitmapFree(qemuCaps->flags); @@ -2278,28 +2274,58 @@ const char *virQEMUCapsGetPackage(virQEMUCapsPtr qemuCaps) } -int virQEMUCapsAddCPUDefinition(virQEMUCapsPtr qemuCaps, - const char *name) +int +virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps, + const char **name, + size_t count) { - char *tmp; + size_t i; - if (VIR_STRDUP(tmp, name) < 0) - return -1; - if (VIR_EXPAND_N(qemuCaps->cpuDefinitions, qemuCaps->ncpuDefinitions, 1) < 0) { - VIR_FREE(tmp); + if (!qemuCaps->cpuDefinitions && + !(qemuCaps->cpuDefinitions = virDomainCapsCPUModelsNew(count))) return -1; + + for (i = 0; i < count; i++) { + if (virDomainCapsCPUModelsAdd(qemuCaps->cpuDefinitions, name[i], -1) < 0) + return -1; } - qemuCaps->cpuDefinitions[qemuCaps->ncpuDefinitions-1] = tmp; + return 0; } -size_t virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps, - char ***names) +int +virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps, + char ***names, + size_t *count) { + size_t i; + char **models = NULL; + + *count = 0; if (names) - *names = qemuCaps->cpuDefinitions; - return qemuCaps->ncpuDefinitions; + *names = NULL; + + if (!qemuCaps->cpuDefinitions) + return 0; + + if (names && VIR_ALLOC_N(models, qemuCaps->cpuDefinitions->nmodels) < 0) + return -1; + + for (i = 0; i < qemuCaps->cpuDefinitions->nmodels; i++) { + virDomainCapsCPUModelPtr cpu = qemuCaps->cpuDefinitions->models + i; + if (models && VIR_STRDUP(models[i], cpu->name) < 0) + goto error; + } + + if (names) + *names = models; + *count = qemuCaps->cpuDefinitions->nmodels; + return 0; + + error: + virStringFreeListCount(models, i); + return -1; } @@ -2615,16 +2641,30 @@ static int virQEMUCapsProbeQMPCPUDefinitions(virQEMUCapsPtr qemuCaps, qemuMonitorPtr mon) { - int ncpuDefinitions; - char **cpuDefinitions; + qemuMonitorCPUDefInfoPtr *cpus; + int ncpus; + int ret = -1; + size_t i; - if ((ncpuDefinitions = qemuMonitorGetCPUDefinitions(mon, &cpuDefinitions)) < 0) + if ((ncpus = qemuMonitorGetCPUDefinitions(mon, &cpus)) < 0) return -1; - qemuCaps->ncpuDefinitions = ncpuDefinitions; - qemuCaps->cpuDefinitions = cpuDefinitions; + if (!(qemuCaps->cpuDefinitions = virDomainCapsCPUModelsNew(ncpus))) + goto cleanup; - return 0; + for (i = 0; i < ncpus; i++) { + if (virDomainCapsCPUModelsAddSteal(qemuCaps->cpuDefinitions, + &cpus[i]->name) < 0) + goto cleanup; + } + + ret = 0; + + cleanup: + for (i = 0; i < ncpus; i++) + qemuMonitorCPUDefInfoFree(cpus[i]); + VIR_FREE(cpus); + return ret; } struct tpmTypeToCaps { @@ -2970,17 +3010,19 @@ virQEMUCapsLoadCache(virQEMUCapsPtr qemuCaps, const char *filename, goto cleanup; } if (n > 0) { - qemuCaps->ncpuDefinitions = n; - if (VIR_ALLOC_N(qemuCaps->cpuDefinitions, - qemuCaps->ncpuDefinitions) < 0) + if (!(qemuCaps->cpuDefinitions = virDomainCapsCPUModelsNew(n))) goto cleanup; for (i = 0; i < n; i++) { - if (!(qemuCaps->cpuDefinitions[i] = virXMLPropString(nodes[i], "name"))) { + if (!(str = virXMLPropString(nodes[i], "name"))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing cpu name in QEMU capabilities cache")); goto cleanup; } + + if (virDomainCapsCPUModelsAddSteal(qemuCaps->cpuDefinitions, + &str) < 0) + goto cleanup; } } VIR_FREE(nodes); @@ -3139,9 +3181,11 @@ virQEMUCapsFormatCache(virQEMUCapsPtr qemuCaps, virBufferAsprintf(&buf, "%s\n", virArchToString(qemuCaps->arch)); - for (i = 0; i < qemuCaps->ncpuDefinitions; i++) { - virBufferEscapeString(&buf, "\n", - qemuCaps->cpuDefinitions[i]); + if (qemuCaps->cpuDefinitions) { + for (i = 0; i < qemuCaps->cpuDefinitions->nmodels; i++) { + virDomainCapsCPUModelPtr cpu = qemuCaps->cpuDefinitions->models + i; + virBufferEscapeString(&buf, "\n", cpu->name); + } } for (i = 0; i < qemuCaps->nmachineTypes; i++) { @@ -3259,10 +3303,8 @@ virQEMUCapsReset(virQEMUCapsPtr qemuCaps) qemuCaps->arch = VIR_ARCH_NONE; qemuCaps->usedQMP = false; - for (i = 0; i < qemuCaps->ncpuDefinitions; i++) - VIR_FREE(qemuCaps->cpuDefinitions[i]); - VIR_FREE(qemuCaps->cpuDefinitions); - qemuCaps->ncpuDefinitions = 0; + virObjectUnref(qemuCaps->cpuDefinitions); + qemuCaps->cpuDefinitions = NULL; for (i = 0; i < qemuCaps->nmachineTypes; i++) { VIR_FREE(qemuCaps->machineTypes[i].name); diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 26ac1fa6c3..e31c51c8a0 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -423,10 +423,12 @@ virArch virQEMUCapsGetArch(virQEMUCapsPtr qemuCaps); unsigned int virQEMUCapsGetVersion(virQEMUCapsPtr qemuCaps); const char *virQEMUCapsGetPackage(virQEMUCapsPtr qemuCaps); unsigned int virQEMUCapsGetKVMVersion(virQEMUCapsPtr qemuCaps); -int virQEMUCapsAddCPUDefinition(virQEMUCapsPtr qemuCaps, - const char *name); -size_t virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps, - char ***names); +int virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps, + const char **name, + size_t count); +int virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps, + char ***names, + size_t *count); const char *virQEMUCapsGetCanonicalMachine(virQEMUCapsPtr qemuCaps, const char *name); int virQEMUCapsGetMachineMaxCpus(virQEMUCapsPtr qemuCaps, diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2130a7e2e8..e611c7f255 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6566,9 +6566,10 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, host = caps->host.cpu; - if (!host || - !host->model || - (ncpus = virQEMUCapsGetCPUDefinitions(qemuCaps, &cpus)) == 0) { + if (virQEMUCapsGetCPUDefinitions(qemuCaps, &cpus, &ncpus) < 0) + goto cleanup; + + if (!host || !host->model || ncpus == 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("CPU specification not supported by hypervisor")); goto cleanup; @@ -6722,6 +6723,7 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, cpuDataFree(hostData); virCPUDefFree(guest); virCPUDefFree(cpu); + virStringFreeListCount(cpus, ncpus); return ret; } diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index b9e2910493..8083a36e99 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3587,7 +3587,7 @@ qemuMonitorMachineInfoFree(qemuMonitorMachineInfoPtr machine) int qemuMonitorGetCPUDefinitions(qemuMonitorPtr mon, - char ***cpus) + qemuMonitorCPUDefInfoPtr **cpus) { VIR_DEBUG("cpus=%p", cpus); @@ -3597,6 +3597,16 @@ qemuMonitorGetCPUDefinitions(qemuMonitorPtr mon, } +void +qemuMonitorCPUDefInfoFree(qemuMonitorCPUDefInfoPtr cpu) +{ + if (!cpu) + return; + VIR_FREE(cpu->name); + VIR_FREE(cpu); +} + + int qemuMonitorGetCommands(qemuMonitorPtr mon, char ***commands) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 615ab3e940..7d78e5b0fb 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -905,8 +905,16 @@ int qemuMonitorGetMachines(qemuMonitorPtr mon, void qemuMonitorMachineInfoFree(qemuMonitorMachineInfoPtr machine); +typedef struct _qemuMonitorCPUDefInfo qemuMonitorCPUDefInfo; +typedef qemuMonitorCPUDefInfo *qemuMonitorCPUDefInfoPtr; + +struct _qemuMonitorCPUDefInfo { + char *name; +}; + int qemuMonitorGetCPUDefinitions(qemuMonitorPtr mon, - char ***cpus); + qemuMonitorCPUDefInfoPtr **cpus); +void qemuMonitorCPUDefInfoFree(qemuMonitorCPUDefInfoPtr cpu); int qemuMonitorGetCommands(qemuMonitorPtr mon, char ***commands); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index de746f172e..e1494df8f6 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4873,14 +4873,15 @@ int qemuMonitorJSONGetMachines(qemuMonitorPtr mon, } -int qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, - char ***cpus) +int +qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, + qemuMonitorCPUDefInfoPtr **cpus) { int ret = -1; virJSONValuePtr cmd; virJSONValuePtr reply = NULL; virJSONValuePtr data; - char **cpulist = NULL; + qemuMonitorCPUDefInfoPtr *cpulist = NULL; int n = 0; size_t i; @@ -4916,13 +4917,18 @@ int qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, goto cleanup; } - /* null-terminated list */ - if (VIR_ALLOC_N(cpulist, n + 1) < 0) + if (VIR_ALLOC_N(cpulist, n) < 0) goto cleanup; for (i = 0; i < n; i++) { virJSONValuePtr child = virJSONValueArrayGet(data, i); const char *tmp; + qemuMonitorCPUDefInfoPtr cpu; + + if (VIR_ALLOC(cpu) < 0) + goto cleanup; + + cpulist[i] = cpu; if (!(tmp = virJSONValueObjectGetString(child, "name"))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -4930,7 +4936,7 @@ int qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, goto cleanup; } - if (VIR_STRDUP(cpulist[i], tmp) < 0) + if (VIR_STRDUP(cpu->name, tmp) < 0) goto cleanup; } @@ -4939,7 +4945,11 @@ int qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, cpulist = NULL; cleanup: - virStringFreeList(cpulist); + if (cpulist) { + for (i = 0; i < n; i++) + qemuMonitorCPUDefInfoFree(cpulist[i]); + VIR_FREE(cpulist); + } virJSONValueFree(cmd); virJSONValueFree(reply); return ret; diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 0eab96ff9e..6a5eb3b8b5 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -347,7 +347,7 @@ int qemuMonitorJSONGetMachines(qemuMonitorPtr mon, ATTRIBUTE_NONNULL(2); int qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, - char ***cpus) + qemuMonitorCPUDefInfoPtr **cpus) ATTRIBUTE_NONNULL(2); int qemuMonitorJSONGetCommands(qemuMonitorPtr mon, diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 9e195d743c..cbc39c67dc 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -412,7 +412,7 @@ testQemuMonitorJSONGetCPUDefinitions(const void *data) virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt); int ret = -1; - char **cpus = NULL; + qemuMonitorCPUDefInfoPtr *cpus = NULL; int ncpus = 0; size_t i; @@ -447,10 +447,10 @@ testQemuMonitorJSONGetCPUDefinitions(const void *data) #define CHECK(i, wantname) \ do { \ - if (STRNEQ(cpus[i], (wantname))) { \ + if (STRNEQ(cpus[i]->name, (wantname))) { \ virReportError(VIR_ERR_INTERNAL_ERROR, \ "name %s is not %s", \ - cpus[i], (wantname)); \ + cpus[i]->name, (wantname)); \ goto cleanup; \ } \ } while (0) @@ -466,7 +466,7 @@ testQemuMonitorJSONGetCPUDefinitions(const void *data) cleanup: qemuMonitorTestFree(test); for (i = 0; i < ncpus; i++) - VIR_FREE(cpus[i]); + qemuMonitorCPUDefInfoFree(cpus[i]); VIR_FREE(cpus); return ret; } diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index e8540779a4..0b378a7bde 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -452,18 +452,18 @@ testAddCPUModels(virQEMUCapsPtr caps, bool skipLegacy) "486", "coreduo", "kvm32", "qemu32", "kvm64", "core2duo", "phenom", "qemu64", }; - size_t i; - for (i = 0; i < ARRAY_CARDINALITY(newModels); i++) { - if (virQEMUCapsAddCPUDefinition(caps, newModels[i]) < 0) - return -1; - } + if (virQEMUCapsAddCPUDefinitions(caps, newModels, + ARRAY_CARDINALITY(newModels)) < 0) + return -1; + if (skipLegacy) return 0; - for (i = 0; i < ARRAY_CARDINALITY(legacyModels); i++) { - if (virQEMUCapsAddCPUDefinition(caps, legacyModels[i]) < 0) - return -1; - } + + if (virQEMUCapsAddCPUDefinitions(caps, legacyModels, + ARRAY_CARDINALITY(legacyModels)) < 0) + return -1; + return 0; }