[libvirt] [PATCH v2 00/45] Enhance guest CPU configuration code

Version 2: - review comments addressed; see individual patches for details This patch series does several things: - fixes tests to avoid relying on bugs in our code - adds support for advertising supported CPU modes and models in domain capabilities - starts adding better and higher level APIs to our cpu driver (the old low level APIs will be removed once this process is over) - prepares qemu driver for asking QEMU what a host CPU looks like and what CPU models can be run on it - makes QEMU CPU command line builder build command line and nothing else The added part of domain capabilities XML looks like this: <cpu> <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'> <model fallback='allow'>Broadwell</model> <vendor>Intel</vendor> <feature policy='disable' name='aes'/> <feature policy='require' name='vmx'/> </mode> <mode name='custom' supported='yes'> <model usable='no'>Broadwell</model> <model usable='yes'>Broadwell-noTSX</model> ... </mode> </cpu> and host-passthrough is only advertised as supported for KVM domains, host-model is only supported when guest architecture is compatible with host and overall it should just work the way one would expect (in contrast to the current state of the code). Jiri Denemark (45): cpuGetModels: Switch to virArch domcaps: Add support for listing supported CPU models qemu: Use virDomainCapsCPUModels for cpuDefinitions qemuxml2argvtest: Rename extraFlags as qemuCaps qemuxml2argvtest: Rename "out" labels as "cleanup" qemuxml2argvtest: Get rid of testCompareXMLToArgvHelper qemuxml2argvtest: Reorder functions qemuxml2argvtest: Update qemuCaps after parsing domain XML qemuxml2argvtest: Properly initialize qemuCaps->arch testutilsqemu: Helpers for changing host CPU and arch testutilsqemu: Add default CPU for PPC64 architectures qemu: Separate guest CPU validation from command line creation qemuxml2argvtest: Properly setup CPU models in qemuCaps qemuxml2argvtest: Set correct architecture for KVM guests qemuxml2argvtest: Reorder CPU features qemu: Introduce virQEMUCapsGuestIsNative qemu: Fill in CPU domain capabilities cpu: Special case models == NULL in cpuGetModels cpu: Don't overwrite errors in cpuGetModels domcaps: Show only CPU models supported by libvirt domcaps: Add CPU usable flag schema: Separate CPU related definitions into cputypes.rng qemu: Propagate virCapsPtr to virQEMUCapsNewForBinaryInternal conf: Introduce virCPUDefCopyWithoutModel conf: Introduce virCPUDefStealModel conf: Introduce virCPUDefCopyModelFilter qemu: Store host-model CPU in qemu capabilities cpu: Drop false support for ARM cpu-model Show host model in domain capabilities qemu: Introduce virQEMUCapsGetHostModel qemu: Introduce virQEMUCapsIsCPUModeSupported cpu: Make x86ModelFromCPU easier to read cpu: Make x86ModelFromCPU a bit smarter cpu: Report error for unknown features in x86HasFeature cpu: Add x86FeatureInData cpu: Rework cpuUpdate cpu: Set nfeatures_max correctly in x86Decode cpu: Introduce virCPUTranslate cpu: Rename cpuHasFeature to virCPUDataCheckFeature cpu: Rework virCPUDataCheckFeature cpu: Introduce virCPUCheckFeature cpu: Document missing parameters for cpuCompare* cpu: Rework cpuCompare* APIs qemu: Update guest CPU def in live XML Move CMT feature filtering to QEMU driver docs/formatdomaincaps.html.in | 65 +++ docs/schemas/cputypes.rng | 135 ++++++ docs/schemas/domaincaps.rng | 60 +++ docs/schemas/domaincommon.rng | 129 +----- po/POTFILES.in | 1 + src/conf/cpu_conf.c | 64 ++- src/conf/cpu_conf.h | 21 + src/conf/domain_capabilities.c | 198 +++++++++ src/conf/domain_capabilities.h | 47 +++ src/cpu/cpu.c | 264 +++++++++--- src/cpu/cpu.h | 72 +++- src/cpu/cpu_arm.c | 79 ++-- src/cpu/cpu_ppc64.c | 48 ++- src/cpu/cpu_s390.c | 1 - src/cpu/cpu_x86.c | 463 +++++++++++++-------- src/driver-hypervisor.h | 2 +- src/libvirt-host.c | 3 +- src/libvirt_private.syms | 20 +- src/libxl/libxl_driver.c | 14 +- src/qemu/qemu_capabilities.c | 394 +++++++++++++----- src/qemu/qemu_capabilities.h | 24 +- src/qemu/qemu_capspriv.h | 13 +- src/qemu/qemu_command.c | 216 +++------- src/qemu/qemu_domain.c | 37 +- src/qemu/qemu_driver.c | 41 +- src/qemu/qemu_monitor.c | 12 +- src/qemu/qemu_monitor.h | 10 +- src/qemu/qemu_monitor_json.c | 24 +- src/qemu/qemu_monitor_json.h | 2 +- src/qemu/qemu_parse_command.c | 2 +- src/qemu/qemu_process.c | 95 ++++- src/test/test_driver.c | 12 +- src/vmware/vmware_conf.c | 6 +- tests/cputest.c | 24 +- .../cputestdata/x86-host+host-model-nofallback.xml | 2 +- tests/cputestdata/x86-host+host-model.xml | 2 +- .../x86-host+host-passthrough-features.xml | 4 + tests/cputestdata/x86-host+host-passthrough.xml | 19 +- tests/cputestdata/x86-host+min.xml | 27 +- tests/cputestdata/x86-host+pentium3.xml | 39 +- tests/cputestdata/x86-host-invtsc+host-model.xml | 2 +- .../cputestdata/x86-host-passthrough-features.xml | 4 + tests/domaincapsschemadata/basic.xml | 5 + tests/domaincapsschemadata/full.xml | 12 + tests/domaincapsschemadata/libxl-xenfv-usb.xml | 5 + tests/domaincapsschemadata/libxl-xenfv.xml | 5 + tests/domaincapsschemadata/libxl-xenpv-usb.xml | 5 + tests/domaincapsschemadata/libxl-xenpv.xml | 5 + tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml | 32 ++ .../qemu_2.6.0-gicv2-virt.aarch64.xml | 36 ++ .../qemu_2.6.0-gicv3-virt.aarch64.xml | 36 ++ tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml | 36 ++ tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml | 10 + tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml | 36 ++ tests/domaincapstest.c | 78 +++- tests/qemucapabilitiestest.c | 2 +- tests/qemucapsprobe.c | 2 +- tests/qemumonitorjsontest.c | 8 +- .../qemuxml2argvdata/qemuxml2argv-cpu-Haswell2.xml | 2 +- .../qemuxml2argv-cpu-Haswell3.args | 2 +- tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml | 12 +- .../qemuxml2argv-cpu-exact2-nofallback.args | 3 +- .../qemuxml2argv-cpu-exact2-nofallback.xml | 14 +- .../qemuxml2argvdata/qemuxml2argv-cpu-exact2.args | 3 +- tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.xml | 14 +- .../qemuxml2argv-cpu-fallback.args | 2 +- .../qemuxml2argv-cpu-host-model-cmt.args | 2 +- .../qemuxml2argv-cpu-host-model-fallback.args | 2 +- .../qemuxml2argv-cpu-minimum2.args | 2 +- .../qemuxml2argvdata/qemuxml2argv-cpu-minimum2.xml | 6 +- .../qemuxml2argvdata/qemuxml2argv-cpu-strict1.args | 3 +- .../qemuxml2argvdata/qemuxml2argv-cpu-strict1.xml | 20 +- .../qemuxml2argv-graphics-spice-timeout.xml | 24 +- .../qemuxml2argv-pseries-cpu-exact.args | 2 +- .../qemuxml2argv-pseries-cpu-exact.xml | 2 +- tests/qemuxml2argvtest.c | 312 +++++++------- .../qemuxml2xmlout-graphics-spice-timeout.xml | 24 +- tests/testutilsqemu.c | 128 ++++-- tests/testutilsqemu.h | 11 +- tools/virsh-host.c | 10 +- 80 files changed, 2473 insertions(+), 1137 deletions(-) create mode 100644 docs/schemas/cputypes.rng create mode 100644 tests/cputestdata/x86-host+host-passthrough-features.xml create mode 100644 tests/cputestdata/x86-host-passthrough-features.xml -- 2.10.0

Our internal APIs mostly use virArch rather than strings. Switching cpuGetModels to virArch will save us from unnecessary conversions in the future. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu.c | 17 ++++------------- src/cpu/cpu.h | 3 +-- src/driver-hypervisor.h | 2 +- src/qemu/qemu_driver.c | 11 ++++++++++- src/test/test_driver.c | 12 +++++++++++- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 11a68f0..19afeab 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -747,7 +747,7 @@ cpuModelIsAllowed(const char *model, /** * cpuGetModels: * - * @archName: CPU architecture string + * @arch: CPU architecture * @models: where to store the NULL-terminated list of supported models * * Fetches all CPU models supported by libvirt on @archName. @@ -755,26 +755,17 @@ cpuModelIsAllowed(const char *model, * Returns number of supported CPU models or -1 on error. */ int -cpuGetModels(const char *archName, char ***models) +cpuGetModels(virArch arch, char ***models) { struct cpuArchDriver *driver; - virArch arch; - VIR_DEBUG("arch=%s", archName); - - arch = virArchFromString(archName); - if (arch == VIR_ARCH_NONE) { - virReportError(VIR_ERR_INVALID_ARG, - _("cannot find architecture %s"), - archName); - return -1; - } + VIR_DEBUG("arch=%s", virArchToString(arch)); driver = cpuGetSubDriver(arch); if (driver == NULL) { virReportError(VIR_ERR_INVALID_ARG, _("cannot find a driver for the architecture %s"), - archName); + virArchToString(arch)); return -1; } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index f1d5276..422818e 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -199,8 +199,7 @@ cpuModelIsAllowed(const char *model, ATTRIBUTE_NONNULL(1); int -cpuGetModels(const char *arch, char ***models) - ATTRIBUTE_NONNULL(1); +cpuGetModels(virArch arch, char ***models); /* cpuDataFormat and cpuDataParse are implemented for unit tests only and * have no real-life usage diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index 5cd1fdf..51af732 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -678,7 +678,7 @@ typedef char * typedef int (*virDrvConnectGetCPUModelNames)(virConnectPtr conn, - const char *args, + const char *archName, char ***models, unsigned int flags); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e29180d..c1c522a 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -18363,14 +18363,23 @@ qemuNodeSuspendForDuration(virConnectPtr conn, static int qemuConnectGetCPUModelNames(virConnectPtr conn, - const char *arch, + const char *archName, char ***models, unsigned int flags) { + virArch arch; + virCheckFlags(0, -1); if (virConnectGetCPUModelNamesEnsureACL(conn) < 0) return -1; + if (!(arch = virArchFromString(archName))) { + virReportError(VIR_ERR_INVALID_ARG, + _("cannot find architecture %s"), + archName); + return -1; + } + return cpuGetModels(arch, models); } diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 87799e1..7ef3d2f 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5893,11 +5893,21 @@ testDomainScreenshot(virDomainPtr dom ATTRIBUTE_UNUSED, static int testConnectGetCPUModelNames(virConnectPtr conn ATTRIBUTE_UNUSED, - const char *arch, + const char *archName, char ***models, unsigned int flags) { + virArch arch; + virCheckFlags(0, -1); + + if (!(arch = virArchFromString(archName))) { + virReportError(VIR_ERR_INVALID_ARG, + _("cannot find architecture %s"), + archName); + return -1; + } + return cpuGetModels(arch, models); } -- 2.10.0

The patch adds <cpu> element to domain capabilities XML: <cpu> <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'/> <mode name='custom' supported='yes'> <model>Broadwell</model> <model>Broadwell-noTSX</model> ... </mode> </cpu> Applications can use it to inspect what CPU configuration modes are supported for a specific combination of domain type, emulator binary, guest architecture and machine type. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - switched to VIR_STEAL_PTR - s/alloc/nmodels_max/ and s/count/nmodels/ - added cross reference to formatdomain.html#elementsCPU docs/formatdomaincaps.html.in | 44 ++++++ docs/schemas/domaincaps.rng | 43 ++++++ src/conf/domain_capabilities.c | 149 +++++++++++++++++++++ src/conf/domain_capabilities.h | 33 +++++ src/libvirt_private.syms | 4 + tests/domaincapsschemadata/basic.xml | 5 + tests/domaincapsschemadata/full.xml | 9 ++ tests/domaincapsschemadata/libxl-xenfv-usb.xml | 5 + tests/domaincapsschemadata/libxl-xenfv.xml | 5 + tests/domaincapsschemadata/libxl-xenpv-usb.xml | 5 + tests/domaincapsschemadata/libxl-xenpv.xml | 5 + tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml | 5 + .../qemu_2.6.0-gicv2-virt.aarch64.xml | 5 + .../qemu_2.6.0-gicv3-virt.aarch64.xml | 5 + tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml | 5 + tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml | 5 + tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml | 5 + tests/domaincapstest.c | 9 ++ 18 files changed, 346 insertions(+) diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in index d5a8414..ce43658 100644 --- a/docs/formatdomaincaps.html.in +++ b/docs/formatdomaincaps.html.in @@ -142,6 +142,50 @@ <loader/> element.</dd> </dl> + <h3><a name="elementsCPU">CPU configuration</a></h3> + + <p> + The <code>cpu</code> element exposes options usable for configuring + <a href="formatdomain.html#elementsCPU">guest CPUs</a>. + </p> + +<pre> +<domainCapabilities> + ... + <cpu> + <mode name='host-passthrough' supported='yes'/> + <mode name='host-model' supported='yes'/> + <mode name='custom' supported='yes'> + <model>Broadwell</model> + <model>Broadwell-noTSX</model> + <model>Haswell</model> + ... + </mode> + </cpu> + ... +<domainCapabilities> +</pre> + + <p> + Each CPU mode understood by libvirt is described with a + <code>mode</code> element which tells whether the particular mode + is supported and provides (when applicable) more details about it: + </p> + + <dl> + <dt><code>host-passthrough</code></dt> + <dd>No mode specific details are provided.</dd> + + <dt><code>host-model</code></dt> + <dd>No mode specific details are provided yet.</dd> + + <dt><code>custom</code></dt> + <dd> + The <code>mode</code> element contains a list of supported CPU + models, each described by a dedicated <code>model</code> element. + </dd> + </dl> + <h3><a name="elementsDevices">Devices</a></h3> <p> diff --git a/docs/schemas/domaincaps.rng b/docs/schemas/domaincaps.rng index 97da41f..9f3d225 100644 --- a/docs/schemas/domaincaps.rng +++ b/docs/schemas/domaincaps.rng @@ -29,6 +29,9 @@ <ref name='os'/> </optional> <optional> + <ref name='cpu'/> + </optional> + <optional> <ref name='devices'/> </optional> <optional> @@ -68,6 +71,46 @@ </element> </define> + <define name='cpu'> + <element name='cpu'> + <ref name='cpuHost'/> + <ref name='cpuHostModel'/> + <ref name='cpuCustom'/> + </element> + </define> + + <define name='cpuHost'> + <element name='mode'> + <attribute name='name'> + <value>host-passthrough</value> + </attribute> + <ref name='supported'/> + </element> + </define> + + <define name='cpuHostModel'> + <element name='mode'> + <attribute name='name'> + <value>host-model</value> + </attribute> + <ref name='supported'/> + </element> + </define> + + <define name='cpuCustom'> + <element name='mode'> + <attribute name='name'> + <value>custom</value> + </attribute> + <ref name='supported'/> + <zeroOrMore> + <element name='model'> + <text/> + </element> + </zeroOrMore> + </element> + </define> + <define name='devices'> <element name='devices'> <interleave> diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 1676f0e..e47aa86 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -30,8 +30,10 @@ #define VIR_FROM_THIS VIR_FROM_CAPABILITIES static virClassPtr virDomainCapsClass; +static virClassPtr virDomainCapsCPUModelsClass; static void virDomainCapsDispose(void *obj); +static void virDomainCapsCPUModelsDispose(void *obj); static int virDomainCapsOnceInit(void) { @@ -40,6 +42,14 @@ static int virDomainCapsOnceInit(void) sizeof(virDomainCaps), virDomainCapsDispose))) return -1; + + virDomainCapsCPUModelsClass = virClassNew(virClassForObject(), + "virDomainCapsCPUModelsClass", + sizeof(virDomainCapsCPUModels), + virDomainCapsCPUModelsDispose); + if (!virDomainCapsCPUModelsClass) + return -1; + return 0; } @@ -68,11 +78,25 @@ virDomainCapsDispose(void *obj) VIR_FREE(caps->path); VIR_FREE(caps->machine); + virObjectUnref(caps->cpu.custom); virDomainCapsStringValuesFree(&caps->os.loader.values); } +static void +virDomainCapsCPUModelsDispose(void *obj) +{ + virDomainCapsCPUModelsPtr cpuModels = obj; + size_t i; + + for (i = 0; i < cpuModels->nmodels; i++) + VIR_FREE(cpuModels->models[i].name); + + VIR_FREE(cpuModels->models); +} + + virDomainCapsPtr virDomainCapsNew(const char *path, const char *machine, @@ -100,6 +124,85 @@ virDomainCapsNew(const char *path, } +virDomainCapsCPUModelsPtr +virDomainCapsCPUModelsNew(size_t nmodels) +{ + virDomainCapsCPUModelsPtr cpuModels = NULL; + + if (virDomainCapsInitialize() < 0) + return NULL; + + if (!(cpuModels = virObjectNew(virDomainCapsCPUModelsClass))) + return NULL; + + if (VIR_ALLOC_N(cpuModels->models, nmodels) < 0) + goto error; + cpuModels->nmodels_max = nmodels; + + return cpuModels; + + error: + virObjectUnref(cpuModels); + return NULL; +} + + +virDomainCapsCPUModelsPtr +virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old) +{ + virDomainCapsCPUModelsPtr cpuModels; + size_t i; + + if (!(cpuModels = virDomainCapsCPUModelsNew(old->nmodels))) + return NULL; + + for (i = 0; i < old->nmodels; i++) { + if (virDomainCapsCPUModelsAdd(cpuModels, old->models[i].name, -1) < 0) + goto error; + } + + return cpuModels; + + error: + virObjectUnref(cpuModels); + return NULL; +} + + +int +virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels, + char **name) +{ + if (VIR_RESIZE_N(cpuModels->models, cpuModels->nmodels_max, + cpuModels->nmodels, 1) < 0) + return -1; + + VIR_STEAL_PTR(cpuModels->models[cpuModels->nmodels++].name, *name); + return 0; +} + + +int +virDomainCapsCPUModelsAdd(virDomainCapsCPUModelsPtr cpuModels, + const char *name, + ssize_t nameLen) +{ + char *copy = NULL; + + if (VIR_STRNDUP(copy, name, nameLen) < 0) + goto error; + + if (virDomainCapsCPUModelsAddSteal(cpuModels, ©) < 0) + goto error; + + return 0; + + error: + VIR_FREE(copy); + return -1; +} + + int virDomainCapsEnumSet(virDomainCapsEnumPtr capsEnum, const char *capsEnumName, @@ -234,6 +337,51 @@ virDomainCapsOSFormat(virBufferPtr buf, } static void +virDomainCapsCPUCustomFormat(virBufferPtr buf, + virDomainCapsCPUModelsPtr custom) +{ + size_t i; + + virBufferAdjustIndent(buf, 2); + + for (i = 0; i < custom->nmodels; i++) { + virBufferAsprintf(buf, "<model>%s</model>\n", + custom->models[i].name); + } + + virBufferAdjustIndent(buf, -2); +} + +static void +virDomainCapsCPUFormat(virBufferPtr buf, + virDomainCapsCPUPtr cpu) +{ + virBufferAddLit(buf, "<cpu>\n"); + virBufferAdjustIndent(buf, 2); + + virBufferAsprintf(buf, "<mode name='%s' supported='%s'/>\n", + virCPUModeTypeToString(VIR_CPU_MODE_HOST_PASSTHROUGH), + cpu->hostPassthrough ? "yes" : "no"); + + virBufferAsprintf(buf, "<mode name='%s' supported='%s'/>\n", + virCPUModeTypeToString(VIR_CPU_MODE_HOST_MODEL), + cpu->hostModel ? "yes" : "no"); + + virBufferAsprintf(buf, "<mode name='%s' ", + virCPUModeTypeToString(VIR_CPU_MODE_CUSTOM)); + if (cpu->custom && cpu->custom->nmodels) { + virBufferAddLit(buf, "supported='yes'>\n"); + virDomainCapsCPUCustomFormat(buf, cpu->custom); + virBufferAddLit(buf, "</mode>\n"); + } else { + virBufferAddLit(buf, "supported='no'/>\n"); + } + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</cpu>\n"); +} + +static void virDomainCapsDeviceDiskFormat(virBufferPtr buf, virDomainCapsDeviceDiskPtr const disk) { @@ -333,6 +481,7 @@ virDomainCapsFormatInternal(virBufferPtr buf, virBufferAsprintf(buf, "<vcpu max='%d'/>\n", caps->maxvcpus); virDomainCapsOSFormat(buf, &caps->os); + virDomainCapsCPUFormat(buf, &caps->cpu); virBufferAddLit(buf, "<devices>\n"); virBufferAdjustIndent(buf, 2); diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 492a9cf..149a13f 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -102,6 +102,30 @@ struct _virDomainCapsFeatureGIC { virDomainCapsEnum version; /* Info about virGICVersion */ }; +typedef struct _virDomainCapsCPUModel virDomainCapsCPUModel; +typedef virDomainCapsCPUModel *virDomainCapsCPUModelPtr; +struct _virDomainCapsCPUModel { + char *name; +}; + +typedef struct _virDomainCapsCPUModels virDomainCapsCPUModels; +typedef virDomainCapsCPUModels *virDomainCapsCPUModelsPtr; +struct _virDomainCapsCPUModels { + virObject parent; + + size_t nmodels_max; + size_t nmodels; + virDomainCapsCPUModelPtr models; +}; + +typedef struct _virDomainCapsCPU virDomainCapsCPU; +typedef virDomainCapsCPU *virDomainCapsCPUPtr; +struct _virDomainCapsCPU { + bool hostPassthrough; + bool hostModel; + virDomainCapsCPUModelsPtr custom; +}; + struct _virDomainCaps { virObjectLockable parent; @@ -114,6 +138,7 @@ struct _virDomainCaps { int maxvcpus; virDomainCapsOS os; + virDomainCapsCPU cpu; virDomainCapsDeviceDisk disk; virDomainCapsDeviceGraphics graphics; virDomainCapsDeviceVideo video; @@ -129,6 +154,14 @@ virDomainCapsPtr virDomainCapsNew(const char *path, virArch arch, virDomainVirtType virttype); +virDomainCapsCPUModelsPtr virDomainCapsCPUModelsNew(size_t nmodels); +virDomainCapsCPUModelsPtr virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old); +int virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels, + char **name); +int virDomainCapsCPUModelsAdd(virDomainCapsCPUModelsPtr cpuModels, + const char *name, + ssize_t nameLen); + # define VIR_DOMAIN_CAPS_ENUM_SET(capsEnum, ...) \ do { \ unsigned int __values[] = {__VA_ARGS__}; \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9610e0c..46e805a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -153,6 +153,10 @@ virDomainAuditVcpu; # conf/domain_capabilities.h +virDomainCapsCPUModelsAdd; +virDomainCapsCPUModelsAddSteal; +virDomainCapsCPUModelsCopy; +virDomainCapsCPUModelsNew; virDomainCapsEnumClear; virDomainCapsEnumSet; virDomainCapsFormat; diff --git a/tests/domaincapsschemadata/basic.xml b/tests/domaincapsschemadata/basic.xml index 5513f99..6b788d9 100644 --- a/tests/domaincapsschemadata/basic.xml +++ b/tests/domaincapsschemadata/basic.xml @@ -4,6 +4,11 @@ <machine>my-machine-type</machine> <arch>x86_64</arch> <os supported='no'/> + <cpu> + <mode name='host-passthrough' supported='no'/> + <mode name='host-model' supported='no'/> + <mode name='custom' supported='no'/> + </cpu> <devices> <disk supported='no'/> <graphics supported='no'/> diff --git a/tests/domaincapsschemadata/full.xml b/tests/domaincapsschemadata/full.xml index 2f529ff..80fd1f0 100644 --- a/tests/domaincapsschemadata/full.xml +++ b/tests/domaincapsschemadata/full.xml @@ -19,6 +19,15 @@ </enum> </loader> </os> + <cpu> + <mode name='host-passthrough' supported='yes'/> + <mode name='host-model' supported='yes'/> + <mode name='custom' supported='yes'> + <model>Model1</model> + <model>Model2</model> + <model>Model3</model> + </mode> + </cpu> <devices> <disk supported='yes'> <enum name='diskDevice'> diff --git a/tests/domaincapsschemadata/libxl-xenfv-usb.xml b/tests/domaincapsschemadata/libxl-xenfv-usb.xml index c071d12..6a9e3d9 100644 --- a/tests/domaincapsschemadata/libxl-xenfv-usb.xml +++ b/tests/domaincapsschemadata/libxl-xenfv-usb.xml @@ -17,6 +17,11 @@ </enum> </loader> </os> + <cpu> + <mode name='host-passthrough' supported='no'/> + <mode name='host-model' supported='no'/> + <mode name='custom' supported='no'/> + </cpu> <devices> <disk supported='yes'> <enum name='diskDevice'> diff --git a/tests/domaincapsschemadata/libxl-xenfv.xml b/tests/domaincapsschemadata/libxl-xenfv.xml index 9436ef8..d48e699 100644 --- a/tests/domaincapsschemadata/libxl-xenfv.xml +++ b/tests/domaincapsschemadata/libxl-xenfv.xml @@ -17,6 +17,11 @@ </enum> </loader> </os> + <cpu> + <mode name='host-passthrough' supported='no'/> + <mode name='host-model' supported='no'/> + <mode name='custom' supported='no'/> + </cpu> <devices> <disk supported='yes'> <enum name='diskDevice'> diff --git a/tests/domaincapsschemadata/libxl-xenpv-usb.xml b/tests/domaincapsschemadata/libxl-xenpv-usb.xml index 4dd07bd..d1a3918 100644 --- a/tests/domaincapsschemadata/libxl-xenpv-usb.xml +++ b/tests/domaincapsschemadata/libxl-xenpv-usb.xml @@ -7,6 +7,11 @@ <os supported='yes'> <loader supported='no'/> </os> + <cpu> + <mode name='host-passthrough' supported='no'/> + <mode name='host-model' supported='no'/> + <mode name='custom' supported='no'/> + </cpu> <devices> <disk supported='yes'> <enum name='diskDevice'> diff --git a/tests/domaincapsschemadata/libxl-xenpv.xml b/tests/domaincapsschemadata/libxl-xenpv.xml index ab00a28..c0e3193 100644 --- a/tests/domaincapsschemadata/libxl-xenpv.xml +++ b/tests/domaincapsschemadata/libxl-xenpv.xml @@ -7,6 +7,11 @@ <os supported='yes'> <loader supported='no'/> </os> + <cpu> + <mode name='host-passthrough' supported='no'/> + <mode name='host-model' supported='no'/> + <mode name='custom' supported='no'/> + </cpu> <devices> <disk supported='yes'> <enum name='diskDevice'> diff --git a/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml b/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml index 161d0ab..6da28b0 100644 --- a/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml +++ b/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml @@ -18,6 +18,11 @@ </enum> </loader> </os> + <cpu> + <mode name='host-passthrough' supported='no'/> + <mode name='host-model' supported='no'/> + <mode name='custom' supported='no'/> + </cpu> <devices> <disk supported='yes'> <enum name='diskDevice'> diff --git a/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml index f5f0f1c..ee51684 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml @@ -18,6 +18,11 @@ </enum> </loader> </os> + <cpu> + <mode name='host-passthrough' supported='no'/> + <mode name='host-model' supported='no'/> + <mode name='custom' supported='no'/> + </cpu> <devices> <disk supported='yes'> <enum name='diskDevice'> diff --git a/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml index 1ae8172..88cced9 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml @@ -18,6 +18,11 @@ </enum> </loader> </os> + <cpu> + <mode name='host-passthrough' supported='no'/> + <mode name='host-model' supported='no'/> + <mode name='custom' supported='no'/> + </cpu> <devices> <disk supported='yes'> <enum name='diskDevice'> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml index 4e87cd2..09c0e1c 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml @@ -18,6 +18,11 @@ </enum> </loader> </os> + <cpu> + <mode name='host-passthrough' supported='no'/> + <mode name='host-model' supported='no'/> + <mode name='custom' supported='no'/> + </cpu> <devices> <disk supported='yes'> <enum name='diskDevice'> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml index 583fdf0..40b255e 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml @@ -18,6 +18,11 @@ </enum> </loader> </os> + <cpu> + <mode name='host-passthrough' supported='no'/> + <mode name='host-model' supported='no'/> + <mode name='custom' supported='no'/> + </cpu> <devices> <disk supported='yes'> <enum name='diskDevice'> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml b/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml index c453ce3..6706fec 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml @@ -18,6 +18,11 @@ </enum> </loader> </os> + <cpu> + <mode name='host-passthrough' supported='no'/> + <mode name='host-model' supported='no'/> + <mode name='custom' supported='no'/> + </cpu> <devices> <disk supported='yes'> <enum name='diskDevice'> diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c index 5b7b7d0..907c0ad 100644 --- a/tests/domaincapstest.c +++ b/tests/domaincapstest.c @@ -60,6 +60,7 @@ fillAllCaps(virDomainCapsPtr domCaps) { virDomainCapsOSPtr os = &domCaps->os; virDomainCapsLoaderPtr loader = &os->loader; + virDomainCapsCPUPtr cpu = &domCaps->cpu; virDomainCapsDeviceDiskPtr disk = &domCaps->disk; virDomainCapsDeviceGraphicsPtr graphics = &domCaps->graphics; virDomainCapsDeviceVideoPtr video = &domCaps->video; @@ -77,6 +78,14 @@ fillAllCaps(virDomainCapsPtr domCaps) NULL) < 0) return -1; + cpu->hostPassthrough = true; + cpu->hostModel = true; + if (!(cpu->custom = virDomainCapsCPUModelsNew(3)) || + virDomainCapsCPUModelsAdd(cpu->custom, "Model1", -1) < 0 || + virDomainCapsCPUModelsAdd(cpu->custom, "Model2", -1) < 0 || + virDomainCapsCPUModelsAdd(cpu->custom, "Model3", -1) < 0) + return -1; + disk->supported = true; SET_ALL_BITS(disk->diskDevice); SET_ALL_BITS(disk->bus); -- 2.10.0

The list of supported CPU models in domain capabilities is stored in virDomainCapsCPUModels. Let's use the same object for storing CPU models in QEMU capabilities. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - removed superfluous ret < 0 - adapted to changes in previous patches src/qemu/qemu_capabilities.c | 162 +++++++++++++++++++++++++++---------------- src/qemu/qemu_capabilities.h | 10 +-- src/qemu/qemu_command.c | 8 ++- src/qemu/qemu_monitor.c | 12 +++- src/qemu/qemu_monitor.h | 10 ++- src/qemu/qemu_monitor_json.c | 24 +++++-- src/qemu/qemu_monitor_json.h | 2 +- tests/qemumonitorjsontest.c | 8 +-- tests/qemuxml2argvtest.c | 18 ++--- 9 files changed, 164 insertions(+), 90 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index c71b4dc..b0e51ee 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, "<arch>%s</arch>\n", virArchToString(qemuCaps->arch)); - for (i = 0; i < qemuCaps->ncpuDefinitions; i++) { - virBufferEscapeString(&buf, "<cpu name='%s'/>\n", - qemuCaps->cpuDefinitions[i]); + if (qemuCaps->cpuDefinitions) { + for (i = 0; i < qemuCaps->cpuDefinitions->nmodels; i++) { + virDomainCapsCPUModelPtr cpu = qemuCaps->cpuDefinitions->models + i; + virBufferEscapeString(&buf, "<cpu name='%s'/>\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 26ac1fa..e31c51c 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 038c38f..c657354 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6586,9 +6586,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; @@ -6742,6 +6743,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 b9e2910..8083a36 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 615ab3e..7d78e5b 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 de746f1..e1494df 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 0eab96f..6a5eb3b 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 9e195d7..cbc39c6 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 e854077..0b378a7 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; } -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no changes tests/qemuxml2argvtest.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 0b378a7..d606caf 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -267,7 +267,7 @@ typedef enum { static int testCompareXMLToArgvFiles(const char *xml, const char *cmdline, - virQEMUCapsPtr extraFlags, + virQEMUCapsPtr qemuCaps, const char *migrateURI, virQemuXML2ArgvTestFlags flags, unsigned int parseFlags) @@ -314,7 +314,7 @@ static int testCompareXMLToArgvFiles(const char *xml, if (qemuProcessPrepareMonitorChr(&monitor_chr, priv->libDir) < 0) goto out; - virQEMUCapsSetList(extraFlags, + virQEMUCapsSetList(qemuCaps, QEMU_CAPS_NO_ACPI, QEMU_CAPS_LAST); @@ -325,7 +325,7 @@ static int testCompareXMLToArgvFiles(const char *xml, goto out; } - virQEMUCapsFilterByMachineType(extraFlags, vm->def->os.machine); + virQEMUCapsFilterByMachineType(qemuCaps, vm->def->os.machine); log = virTestLogContentAndReset(); VIR_FREE(log); @@ -333,7 +333,7 @@ static int testCompareXMLToArgvFiles(const char *xml, if (vm->def->os.arch == VIR_ARCH_X86_64 || vm->def->os.arch == VIR_ARCH_I686) { - virQEMUCapsSet(extraFlags, QEMU_CAPS_PCI_MULTIBUS); + virQEMUCapsSet(qemuCaps, QEMU_CAPS_PCI_MULTIBUS); } for (i = 0; i < vm->def->nhostdevs; i++) { @@ -390,7 +390,7 @@ static int testCompareXMLToArgvFiles(const char *xml, struct testInfo { const char *name; - virQEMUCapsPtr extraFlags; + virQEMUCapsPtr qemuCaps; const char *migrateFrom; int migrateFd; unsigned int flags; @@ -418,17 +418,17 @@ testCompareXMLToArgvHelper(const void *data) abs_srcdir, info->name) < 0) goto cleanup; - if (virQEMUCapsGet(info->extraFlags, QEMU_CAPS_MONITOR_JSON)) + if (virQEMUCapsGet(info->qemuCaps, QEMU_CAPS_MONITOR_JSON)) flags |= FLAG_JSON; - if (virQEMUCapsGet(info->extraFlags, QEMU_CAPS_ENABLE_FIPS)) + if (virQEMUCapsGet(info->qemuCaps, QEMU_CAPS_ENABLE_FIPS)) flags |= FLAG_FIPS; if (qemuTestCapsCacheInsert(driver.qemuCapsCache, info->name, - info->extraFlags) < 0) + info->qemuCaps) < 0) goto cleanup; - result = testCompareXMLToArgvFiles(xml, args, info->extraFlags, + result = testCompareXMLToArgvFiles(xml, args, info->qemuCaps, migrateURI, flags, info->parseFlags); cleanup: @@ -475,13 +475,13 @@ testPrepareExtraFlags(struct testInfo *info, { int ret = -1; - if (!(info->extraFlags = virQEMUCapsNew())) + if (!(info->qemuCaps = virQEMUCapsNew())) goto out; - if (testAddCPUModels(info->extraFlags, skipLegacyCPUs) < 0) + if (testAddCPUModels(info->qemuCaps, skipLegacyCPUs) < 0) goto out; - if (testQemuCapsSetGIC(info->extraFlags, gic) < 0) + if (testQemuCapsSetGIC(info->qemuCaps, gic) < 0) goto out; ret = 0; @@ -553,11 +553,11 @@ mymain(void) }; \ if (testPrepareExtraFlags(&info, skipLegacyCPUs, gic) < 0) \ return EXIT_FAILURE; \ - virQEMUCapsSetList(info.extraFlags, __VA_ARGS__, QEMU_CAPS_LAST);\ + virQEMUCapsSetList(info.qemuCaps, __VA_ARGS__, QEMU_CAPS_LAST); \ if (virTestRun("QEMU XML-2-ARGV " name, \ testCompareXMLToArgvHelper, &info) < 0) \ ret = -1; \ - virObjectUnref(info.extraFlags); \ + virObjectUnref(info.qemuCaps); \ } while (0) # define DO_TEST(name, ...) \ -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no changes tests/qemuxml2argvtest.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index d606caf..a257910 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -285,34 +285,34 @@ static int testCompareXMLToArgvFiles(const char *xml, memset(&monitor_chr, 0, sizeof(monitor_chr)); if (!(conn = virGetConnect())) - goto out; + goto cleanup; conn->secretDriver = &fakeSecretDriver; conn->storageDriver = &fakeStorageDriver; if (!(vm = virDomainObjNew(driver.xmlopt))) - goto out; + goto cleanup; if (!(vm->def = virDomainDefParseFile(xml, driver.caps, driver.xmlopt, (VIR_DOMAIN_DEF_PARSE_INACTIVE | parseFlags)))) { if (flags & FLAG_EXPECT_PARSE_ERROR) goto ok; - goto out; + goto cleanup; } priv = vm->privateData; if (virBitmapParse("0-3", &priv->autoNodeset, 4) < 0) - goto out; + goto cleanup; if (!virDomainDefCheckABIStability(vm->def, vm->def)) { VIR_TEST_DEBUG("ABI stability check failed on %s", xml); - goto out; + goto cleanup; } vm->def->id = -1; if (qemuProcessPrepareMonitorChr(&monitor_chr, priv->libDir) < 0) - goto out; + goto cleanup; virQEMUCapsSetList(qemuCaps, QEMU_CAPS_NO_ACPI, @@ -322,7 +322,7 @@ static int testCompareXMLToArgvFiles(const char *xml, STREQ(vm->def->emulator, "/usr/bin/qemu-system-x86_64")) { VIR_FREE(vm->def->os.machine); if (VIR_STRDUP(vm->def->os.machine, "pc-0.11") < 0) - goto out; + goto cleanup; } virQEMUCapsFilterByMachineType(qemuCaps, vm->def->os.machine); @@ -351,14 +351,14 @@ static int testCompareXMLToArgvFiles(const char *xml, VIR_QEMU_PROCESS_START_COLD))) { if (flags & FLAG_EXPECT_FAILURE) goto ok; - goto out; + goto cleanup; } if (!(actualargv = virCommandToString(cmd))) - goto out; + goto cleanup; if (virTestCompareToFile(actualargv, cmdline) < 0) - goto out; + goto cleanup; ret = 0; @@ -366,7 +366,7 @@ static int testCompareXMLToArgvFiles(const char *xml, if (ret == 0 && flags & FLAG_EXPECT_FAILURE) { ret = -1; VIR_TEST_DEBUG("Error expected but there wasn't any.\n"); - goto out; + goto cleanup; } if (!virTestOOMActive()) { if (flags & FLAG_EXPECT_FAILURE) { @@ -377,7 +377,7 @@ static int testCompareXMLToArgvFiles(const char *xml, ret = 0; } - out: + cleanup: VIR_FREE(log); VIR_FREE(actualargv); virDomainChrSourceDefClear(&monitor_chr); @@ -476,17 +476,17 @@ testPrepareExtraFlags(struct testInfo *info, int ret = -1; if (!(info->qemuCaps = virQEMUCapsNew())) - goto out; + goto cleanup; if (testAddCPUModels(info->qemuCaps, skipLegacyCPUs) < 0) - goto out; + goto cleanup; if (testQemuCapsSetGIC(info->qemuCaps, gic) < 0) - goto out; + goto cleanup; ret = 0; - out: + cleanup: return ret; } -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no changes tests/qemuxml2argvtest.c | 109 ++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a257910..bd140fc 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -265,14 +265,25 @@ typedef enum { FLAG_FIPS = 1 << 3, } virQemuXML2ArgvTestFlags; -static int testCompareXMLToArgvFiles(const char *xml, - const char *cmdline, - virQEMUCapsPtr qemuCaps, - const char *migrateURI, - virQemuXML2ArgvTestFlags flags, - unsigned int parseFlags) +struct testInfo { + const char *name; + virQEMUCapsPtr qemuCaps; + const char *migrateFrom; + int migrateFd; + unsigned int flags; + unsigned int parseFlags; +}; + +static int +testCompareXMLToArgv(const void *data) { + const struct testInfo *info = data; + char *xml = NULL; + char *args = NULL; + char *migrateURI = NULL; char *actualargv = NULL; + unsigned int flags = info->flags; + unsigned int parseFlags = info->parseFlags; int ret = -1; virDomainObjPtr vm = NULL; virDomainChrSourceDef monitor_chr; @@ -286,15 +297,37 @@ static int testCompareXMLToArgvFiles(const char *xml, if (!(conn = virGetConnect())) goto cleanup; + conn->secretDriver = &fakeSecretDriver; conn->storageDriver = &fakeStorageDriver; + if (virQEMUCapsGet(info->qemuCaps, QEMU_CAPS_MONITOR_JSON)) + flags |= FLAG_JSON; + + if (virQEMUCapsGet(info->qemuCaps, QEMU_CAPS_ENABLE_FIPS)) + flags |= FLAG_FIPS; + + if (qemuTestCapsCacheInsert(driver.qemuCapsCache, info->name, + info->qemuCaps) < 0) + goto cleanup; + + if (virAsprintf(&xml, "%s/qemuxml2argvdata/qemuxml2argv-%s.xml", + abs_srcdir, info->name) < 0 || + virAsprintf(&args, "%s/qemuxml2argvdata/qemuxml2argv-%s.args", + abs_srcdir, info->name) < 0) + goto cleanup; + + if (info->migrateFrom && + !(migrateURI = qemuMigrationIncomingURI(info->migrateFrom, + info->migrateFd))) + goto cleanup; + if (!(vm = virDomainObjNew(driver.xmlopt))) goto cleanup; + parseFlags |= VIR_DOMAIN_DEF_PARSE_INACTIVE; if (!(vm->def = virDomainDefParseFile(xml, driver.caps, driver.xmlopt, - (VIR_DOMAIN_DEF_PARSE_INACTIVE | - parseFlags)))) { + parseFlags))) { if (flags & FLAG_EXPECT_PARSE_ERROR) goto ok; goto cleanup; @@ -314,7 +347,7 @@ static int testCompareXMLToArgvFiles(const char *xml, if (qemuProcessPrepareMonitorChr(&monitor_chr, priv->libDir) < 0) goto cleanup; - virQEMUCapsSetList(qemuCaps, + virQEMUCapsSetList(info->qemuCaps, QEMU_CAPS_NO_ACPI, QEMU_CAPS_LAST); @@ -325,7 +358,7 @@ static int testCompareXMLToArgvFiles(const char *xml, goto cleanup; } - virQEMUCapsFilterByMachineType(qemuCaps, vm->def->os.machine); + virQEMUCapsFilterByMachineType(info->qemuCaps, vm->def->os.machine); log = virTestLogContentAndReset(); VIR_FREE(log); @@ -333,7 +366,7 @@ static int testCompareXMLToArgvFiles(const char *xml, if (vm->def->os.arch == VIR_ARCH_X86_64 || vm->def->os.arch == VIR_ARCH_I686) { - virQEMUCapsSet(qemuCaps, QEMU_CAPS_PCI_MULTIBUS); + virQEMUCapsSet(info->qemuCaps, QEMU_CAPS_PCI_MULTIBUS); } for (i = 0; i < vm->def->nhostdevs; i++) { @@ -357,7 +390,7 @@ static int testCompareXMLToArgvFiles(const char *xml, if (!(actualargv = virCommandToString(cmd))) goto cleanup; - if (virTestCompareToFile(actualargv, cmdline) < 0) + if (virTestCompareToFile(actualargv, args) < 0) goto cleanup; ret = 0; @@ -384,58 +417,10 @@ static int testCompareXMLToArgvFiles(const char *xml, virCommandFree(cmd); virObjectUnref(vm); virObjectUnref(conn); - return ret; -} - - -struct testInfo { - const char *name; - virQEMUCapsPtr qemuCaps; - const char *migrateFrom; - int migrateFd; - unsigned int flags; - unsigned int parseFlags; -}; - -static int -testCompareXMLToArgvHelper(const void *data) -{ - int result = -1; - const struct testInfo *info = data; - char *xml = NULL; - char *args = NULL; - unsigned int flags = info->flags; - char *migrateURI = NULL; - - if (info->migrateFrom && - !(migrateURI = qemuMigrationIncomingURI(info->migrateFrom, - info->migrateFd))) - goto cleanup; - - if (virAsprintf(&xml, "%s/qemuxml2argvdata/qemuxml2argv-%s.xml", - abs_srcdir, info->name) < 0 || - virAsprintf(&args, "%s/qemuxml2argvdata/qemuxml2argv-%s.args", - abs_srcdir, info->name) < 0) - goto cleanup; - - if (virQEMUCapsGet(info->qemuCaps, QEMU_CAPS_MONITOR_JSON)) - flags |= FLAG_JSON; - - if (virQEMUCapsGet(info->qemuCaps, QEMU_CAPS_ENABLE_FIPS)) - flags |= FLAG_FIPS; - - if (qemuTestCapsCacheInsert(driver.qemuCapsCache, info->name, - info->qemuCaps) < 0) - goto cleanup; - - result = testCompareXMLToArgvFiles(xml, args, info->qemuCaps, - migrateURI, flags, info->parseFlags); - - cleanup: VIR_FREE(migrateURI); VIR_FREE(xml); VIR_FREE(args); - return result; + return ret; } @@ -555,7 +540,7 @@ mymain(void) return EXIT_FAILURE; \ virQEMUCapsSetList(info.qemuCaps, __VA_ARGS__, QEMU_CAPS_LAST); \ if (virTestRun("QEMU XML-2-ARGV " name, \ - testCompareXMLToArgvHelper, &info) < 0) \ + testCompareXMLToArgv, &info) < 0) \ ret = -1; \ virObjectUnref(info.qemuCaps); \ } while (0) -- 2.10.0

testCompareXMLToArgv will soon need to call a few function which are defined further in the code. Let's move them up a bit. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no changes tests/qemuxml2argvtest.c | 104 ++++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index bd140fc..6c7bc4b 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -274,6 +274,59 @@ struct testInfo { unsigned int parseFlags; }; + +static int +testAddCPUModels(virQEMUCapsPtr caps, bool skipLegacy) +{ + const char *newModels[] = { + "Opteron_G3", "Opteron_G2", "Opteron_G1", + "Nehalem", "Penryn", "Conroe", + "Haswell-noTSX", "Haswell", + }; + const char *legacyModels[] = { + "n270", "athlon", "pentium3", "pentium2", "pentium", + "486", "coreduo", "kvm32", "qemu32", "kvm64", + "core2duo", "phenom", "qemu64", + }; + + if (virQEMUCapsAddCPUDefinitions(caps, newModels, + ARRAY_CARDINALITY(newModels)) < 0) + return -1; + + if (skipLegacy) + return 0; + + if (virQEMUCapsAddCPUDefinitions(caps, legacyModels, + ARRAY_CARDINALITY(legacyModels)) < 0) + return -1; + + return 0; +} + + +static int +testPrepareExtraFlags(struct testInfo *info, + bool skipLegacyCPUs, + int gic) +{ + int ret = -1; + + if (!(info->qemuCaps = virQEMUCapsNew())) + goto cleanup; + + if (testAddCPUModels(info->qemuCaps, skipLegacyCPUs) < 0) + goto cleanup; + + if (testQemuCapsSetGIC(info->qemuCaps, gic) < 0) + goto cleanup; + + ret = 0; + + cleanup: + return ret; +} + + static int testCompareXMLToArgv(const void *data) { @@ -425,57 +478,6 @@ testCompareXMLToArgv(const void *data) static int -testAddCPUModels(virQEMUCapsPtr caps, bool skipLegacy) -{ - const char *newModels[] = { - "Opteron_G3", "Opteron_G2", "Opteron_G1", - "Nehalem", "Penryn", "Conroe", - "Haswell-noTSX", "Haswell", - }; - const char *legacyModels[] = { - "n270", "athlon", "pentium3", "pentium2", "pentium", - "486", "coreduo", "kvm32", "qemu32", "kvm64", - "core2duo", "phenom", "qemu64", - }; - - if (virQEMUCapsAddCPUDefinitions(caps, newModels, - ARRAY_CARDINALITY(newModels)) < 0) - return -1; - - if (skipLegacy) - return 0; - - if (virQEMUCapsAddCPUDefinitions(caps, legacyModels, - ARRAY_CARDINALITY(legacyModels)) < 0) - return -1; - - return 0; -} - - -static int -testPrepareExtraFlags(struct testInfo *info, - bool skipLegacyCPUs, - int gic) -{ - int ret = -1; - - if (!(info->qemuCaps = virQEMUCapsNew())) - goto cleanup; - - if (testAddCPUModels(info->qemuCaps, skipLegacyCPUs) < 0) - goto cleanup; - - if (testQemuCapsSetGIC(info->qemuCaps, gic) < 0) - goto cleanup; - - ret = 0; - - cleanup: - return ret; -} - -static int mymain(void) { int ret = 0; -- 2.10.0

Some parts of qemuCaps depend on guest architecture, machine type, and possibly other things that we know only once the domain XML has been parsed. Let's move all these updates into a dedicated function. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no changes tests/qemuxml2argvtest.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 6c7bc4b..0790843 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -272,6 +272,7 @@ struct testInfo { int migrateFd; unsigned int flags; unsigned int parseFlags; + bool skipLegacyCPUs; }; @@ -305,17 +306,15 @@ testAddCPUModels(virQEMUCapsPtr caps, bool skipLegacy) static int -testPrepareExtraFlags(struct testInfo *info, - bool skipLegacyCPUs, - int gic) +testInitQEMUCaps(struct testInfo *info, + int gic) { int ret = -1; if (!(info->qemuCaps = virQEMUCapsNew())) goto cleanup; - if (testAddCPUModels(info->qemuCaps, skipLegacyCPUs) < 0) - goto cleanup; + virQEMUCapsSet(info->qemuCaps, QEMU_CAPS_NO_ACPI); if (testQemuCapsSetGIC(info->qemuCaps, gic) < 0) goto cleanup; @@ -328,6 +327,27 @@ testPrepareExtraFlags(struct testInfo *info, static int +testUpdateQEMUCaps(const struct testInfo *info, + virDomainObjPtr vm) +{ + int ret = -1; + + if (testAddCPUModels(info->qemuCaps, info->skipLegacyCPUs) < 0) + goto cleanup; + + virQEMUCapsFilterByMachineType(info->qemuCaps, vm->def->os.machine); + + if (ARCH_IS_X86(vm->def->os.arch)) + virQEMUCapsSet(info->qemuCaps, QEMU_CAPS_PCI_MULTIBUS); + + ret = 0; + + cleanup: + return ret; +} + + +static int testCompareXMLToArgv(const void *data) { const struct testInfo *info = data; @@ -400,10 +420,6 @@ testCompareXMLToArgv(const void *data) if (qemuProcessPrepareMonitorChr(&monitor_chr, priv->libDir) < 0) goto cleanup; - virQEMUCapsSetList(info->qemuCaps, - QEMU_CAPS_NO_ACPI, - QEMU_CAPS_LAST); - if (STREQ(vm->def->os.machine, "pc") && STREQ(vm->def->emulator, "/usr/bin/qemu-system-x86_64")) { VIR_FREE(vm->def->os.machine); @@ -411,17 +427,13 @@ testCompareXMLToArgv(const void *data) goto cleanup; } - virQEMUCapsFilterByMachineType(info->qemuCaps, vm->def->os.machine); + if (testUpdateQEMUCaps(info, vm) < 0) + goto cleanup; log = virTestLogContentAndReset(); VIR_FREE(log); virResetLastError(); - if (vm->def->os.arch == VIR_ARCH_X86_64 || - vm->def->os.arch == VIR_ARCH_I686) { - virQEMUCapsSet(info->qemuCaps, QEMU_CAPS_PCI_MULTIBUS); - } - for (i = 0; i < vm->def->nhostdevs; i++) { virDomainHostdevDefPtr hostdev = vm->def->hostdevs[i]; @@ -536,9 +548,11 @@ mymain(void) parseFlags, gic, ...) \ do { \ static struct testInfo info = { \ - name, NULL, migrateFrom, migrateFd, (flags), parseFlags \ + name, NULL, migrateFrom, migrateFd, (flags), parseFlags, \ + false \ }; \ - if (testPrepareExtraFlags(&info, skipLegacyCPUs, gic) < 0) \ + info.skipLegacyCPUs = skipLegacyCPUs; \ + if (testInitQEMUCaps(&info, gic) < 0) \ return EXIT_FAILURE; \ virQEMUCapsSetList(info.qemuCaps, __VA_ARGS__, QEMU_CAPS_LAST); \ if (virTestRun("QEMU XML-2-ARGV " name, \ -- 2.10.0

qemuCaps->arch should match the guest architecture from domain XML. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no changes src/qemu/qemu_capabilities.c | 9 +++++++++ src/qemu/qemu_capspriv.h | 3 +++ tests/qemuxml2argvtest.c | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index b0e51ee..538cedb 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2250,6 +2250,15 @@ const char *virQEMUCapsGetBinary(virQEMUCapsPtr qemuCaps) return qemuCaps->binary; } + +void +virQEMUCapsSetArch(virQEMUCapsPtr qemuCaps, + virArch arch) +{ + qemuCaps->arch = arch; +} + + virArch virQEMUCapsGetArch(virQEMUCapsPtr qemuCaps) { return qemuCaps->arch; diff --git a/src/qemu/qemu_capspriv.h b/src/qemu/qemu_capspriv.h index aeb1293..c409acb 100644 --- a/src/qemu/qemu_capspriv.h +++ b/src/qemu/qemu_capspriv.h @@ -56,4 +56,7 @@ char *virQEMUCapsFormatCache(virQEMUCapsPtr qemuCaps, time_t selfCTime, unsigned long selfVersion); +void +virQEMUCapsSetArch(virQEMUCapsPtr qemuCaps, + virArch arch); #endif diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 0790843..1b1918a 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -27,6 +27,10 @@ # include "storage/storage_driver.h" # include "virmock.h" +# define __QEMU_CAPSRIV_H_ALLOW__ +# include "qemu/qemu_capspriv.h" +# undef __QEMU_CAPSRIV_H_ALLOW__ + # include "testutilsqemu.h" # define VIR_FROM_THIS VIR_FROM_QEMU @@ -332,6 +336,8 @@ testUpdateQEMUCaps(const struct testInfo *info, { int ret = -1; + virQEMUCapsSetArch(info->qemuCaps, vm->def->os.arch); + if (testAddCPUModels(info->qemuCaps, info->skipLegacyCPUs) < 0) goto cleanup; -- 2.10.0

Changing a host architecture or a CPU is not as easy as assigning a new value to the appropriate element in virCaps since there is a relation between the CPU and host architecture (we don't really want to test anything on an AArch64 host with core2duo CPU). This patch introduces qemuTestSetHostArch and qemuTestSetHostCPU helpers which will make sure the host architecture matches the host CPU. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - cpuPower8 separated into a new patch - switched to qemuTestSetHostCPU() in testQemuCapsInit() tests/testutilsqemu.c | 37 ++++++++++++++++++++++++++++++++----- tests/testutilsqemu.h | 7 +++++-- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index 11dd20e..b569e0d 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -334,7 +334,7 @@ virCapsPtr testQemuCapsInit(void) !(cpuHaswell = virCPUDefCopy(&cpuHaswellData))) goto cleanup; - caps->host.cpu = cpuDefault; + qemuTestSetHostCPU(caps, NULL); caps->host.nnumaCell_max = 4; @@ -440,15 +440,42 @@ virCapsPtr testQemuCapsInit(void) cleanup: virCapabilitiesFreeMachines(machines, nmachines); - if (caps->host.cpu != cpuDefault) - virCPUDefFree(cpuDefault); - if (caps->host.cpu != cpuHaswell) - virCPUDefFree(cpuHaswell); + caps->host.cpu = NULL; + virCPUDefFree(cpuDefault); + virCPUDefFree(cpuHaswell); virObjectUnref(caps); return NULL; } +void +qemuTestSetHostArch(virCapsPtr caps, + virArch arch) +{ + if (arch == VIR_ARCH_NONE) + arch = VIR_ARCH_X86_64; + caps->host.arch = arch; + qemuTestSetHostCPU(caps, NULL); +} + + +void +qemuTestSetHostCPU(virCapsPtr caps, + virCPUDefPtr cpu) +{ + virArch arch = caps->host.arch; + + if (!cpu) { + if (ARCH_IS_X86(arch)) + cpu = cpuDefault; + } + + if (cpu) + caps->host.arch = cpu->arch; + caps->host.cpu = cpu; +} + + virQEMUCapsPtr qemuTestParseCapabilities(const char *capsFile) { diff --git a/tests/testutilsqemu.h b/tests/testutilsqemu.h index f2b71e9..7c678c9 100644 --- a/tests/testutilsqemu.h +++ b/tests/testutilsqemu.h @@ -19,8 +19,11 @@ virQEMUCapsPtr qemuTestParseCapabilities(const char *capsFile); extern virCPUDefPtr cpuDefault; extern virCPUDefPtr cpuHaswell; -void testQemuCapsSetCPU(virCapsPtr caps, - virCPUDefPtr hostCPU); + +void qemuTestSetHostArch(virCapsPtr caps, + virArch arch); +void qemuTestSetHostCPU(virCapsPtr caps, + virCPUDefPtr cpu); int qemuTestDriverInit(virQEMUDriver *driver); void qemuTestDriverFree(virQEMUDriver *driver); -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - new patch (separated from patch 10/41) tests/testutilsqemu.c | 16 +++++++++++++++- tests/testutilsqemu.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index b569e0d..f59746a 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -16,6 +16,7 @@ virCPUDefPtr cpuDefault; virCPUDefPtr cpuHaswell; +virCPUDefPtr cpuPower8; static virCPUFeatureDef cpuDefaultFeatures[] = { { (char *) "lahf_lm", -1 }, @@ -92,6 +93,15 @@ static virCPUDef cpuHaswellData = { cpuHaswellFeatures, /* features */ }; +static virCPUDef cpuPower8Data = { + .type = VIR_CPU_TYPE_HOST, + .arch = VIR_ARCH_PPC64, + .model = (char *) "POWER8", + .sockets = 1, + .cores = 8, + .threads = 8, +}; + static virCapsGuestMachinePtr *testQemuAllocMachines(int *nmachines) { virCapsGuestMachinePtr *machines; @@ -331,7 +341,8 @@ virCapsPtr testQemuCapsInit(void) goto cleanup; if (!(cpuDefault = virCPUDefCopy(&cpuDefaultData)) || - !(cpuHaswell = virCPUDefCopy(&cpuHaswellData))) + !(cpuHaswell = virCPUDefCopy(&cpuHaswellData)) || + !(cpuPower8 = virCPUDefCopy(&cpuPower8Data))) goto cleanup; qemuTestSetHostCPU(caps, NULL); @@ -443,6 +454,7 @@ virCapsPtr testQemuCapsInit(void) caps->host.cpu = NULL; virCPUDefFree(cpuDefault); virCPUDefFree(cpuHaswell); + virCPUDefFree(cpuPower8); virObjectUnref(caps); return NULL; } @@ -468,6 +480,8 @@ qemuTestSetHostCPU(virCapsPtr caps, if (!cpu) { if (ARCH_IS_X86(arch)) cpu = cpuDefault; + else if (ARCH_IS_PPC64(arch)) + cpu = cpuPower8; } if (cpu) diff --git a/tests/testutilsqemu.h b/tests/testutilsqemu.h index 7c678c9..6d35116f 100644 --- a/tests/testutilsqemu.h +++ b/tests/testutilsqemu.h @@ -19,6 +19,7 @@ virQEMUCapsPtr qemuTestParseCapabilities(const char *capsFile); extern virCPUDefPtr cpuDefault; extern virCPUDefPtr cpuHaswell; +extern virCPUDefPtr cpuPower8; void qemuTestSetHostArch(virCapsPtr caps, virArch arch); -- 2.10.0

qemu_command.c should deal with translating our domain definition into a QEMU command line and nothing else. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change src/qemu/qemu_command.c | 71 ++++---------------------------- src/qemu/qemu_process.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++ tests/qemuxml2argvtest.c | 8 ++-- 3 files changed, 117 insertions(+), 67 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index c657354..d6462d3 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6572,9 +6572,6 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, size_t ncpus = 0; char **cpus = NULL; virCPUDataPtr data = NULL; - virCPUDataPtr hostData = NULL; - char *compare_msg = NULL; - virCPUCompareResult cmp; const char *preferred; virCapsPtr caps = NULL; bool compareAgainstHost = ((def->virtType == VIR_DOMAIN_VIRT_KVM || @@ -6586,15 +6583,6 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, host = caps->host.cpu; - 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; - } - if (!(cpu = virCPUDefCopy(def->cpu))) goto cleanup; @@ -6603,53 +6591,9 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, cpuUpdate(cpu, host) < 0) goto cleanup; - /* For non-KVM, CPU features are emulated, so host compat doesn't matter */ - if (compareAgainstHost) { - bool noTSX = false; - - cmp = cpuGuestData(host, cpu, &data, &compare_msg); - switch (cmp) { - case VIR_CPU_COMPARE_INCOMPATIBLE: - if (cpuEncode(host->arch, host, NULL, &hostData, - NULL, NULL, NULL, NULL) == 0 && - (!cpuHasFeature(hostData, "hle") || - !cpuHasFeature(hostData, "rtm")) && - (STREQ_NULLABLE(cpu->model, "Haswell") || - STREQ_NULLABLE(cpu->model, "Broadwell"))) - noTSX = true; - - if (compare_msg) { - if (noTSX) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("guest and host CPU are not compatible: " - "%s; try using '%s-noTSX' CPU model"), - compare_msg, cpu->model); - } else { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("guest and host CPU are not compatible: " - "%s"), - compare_msg); - } - } else { - if (noTSX) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("guest CPU is not compatible with host " - "CPU; try using '%s-noTSX' CPU model"), - cpu->model); - } else { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("guest CPU is not compatible with host " - "CPU")); - } - } - /* fall through */ - case VIR_CPU_COMPARE_ERROR: - goto cleanup; - - default: - break; - } - } + if (compareAgainstHost && + cpuGuestData(host, cpu, &data, NULL) == VIR_CPU_COMPARE_ERROR) + goto cleanup; /* Only 'svm' requires --enable-nesting. The nested * 'vmx' patches now simply hook off the CPU features @@ -6674,7 +6618,7 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, virBufferAddLit(buf, "host"); if (def->os.arch == VIR_ARCH_ARMV7L && - host->arch == VIR_ARCH_AARCH64) { + caps->host.arch == VIR_ARCH_AARCH64) { if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_AARCH64_OFF)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("QEMU binary does not support CPU " @@ -6693,7 +6637,6 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, } else { featCpu = cpu; } - } else { if (VIR_ALLOC(guest) < 0) goto cleanup; @@ -6709,6 +6652,10 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, guest->type = VIR_CPU_TYPE_GUEST; guest->fallback = cpu->fallback; + + if (virQEMUCapsGetCPUDefinitions(qemuCaps, &cpus, &ncpus) < 0) + goto cleanup; + if (cpuDecode(guest, data, (const char **)cpus, ncpus, preferred) < 0) goto cleanup; @@ -6738,9 +6685,7 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, ret = 0; cleanup: virObjectUnref(caps); - VIR_FREE(compare_msg); cpuDataFree(data); - cpuDataFree(hostData); virCPUDefFree(guest); virCPUDefFree(cpu); virStringFreeListCount(cpus, ncpus); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index cecd321..b2d1127 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4437,6 +4437,108 @@ qemuProcessStartValidateXML(virQEMUDriverPtr driver, return 0; } + +static int +qemuProcessStartValidateGuestCPU(virDomainObjPtr vm, + virQEMUCapsPtr qemuCaps, + virCapsPtr caps, + unsigned int flags) +{ + int ret = -1; + virCPUDefPtr host = NULL; + virCPUDefPtr cpu = NULL; + size_t ncpus = 0; + char **cpus = NULL; + bool noTSX = false; + virCPUCompareResult cmp; + virCPUDataPtr data = NULL; + virCPUDataPtr hostData = NULL; + char *compare_msg = NULL; + + if (!vm->def->cpu || + (vm->def->cpu->mode == VIR_CPU_MODE_CUSTOM && + !vm->def->cpu->model)) + return 0; + + if ((vm->def->virtType != VIR_DOMAIN_VIRT_KVM && + vm->def->cpu->mode == VIR_CPU_MODE_CUSTOM) || + vm->def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) + return 0; + + host = caps->host.cpu; + + 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; + } + + if (!(cpu = virCPUDefCopy(vm->def->cpu))) + goto cleanup; + + if (cpu->mode == VIR_CPU_MODE_HOST_MODEL && + flags & VIR_QEMU_PROCESS_START_NEW && + cpuUpdate(cpu, host) < 0) + goto cleanup; + + cmp = cpuGuestData(host, cpu, &data, &compare_msg); + switch (cmp) { + case VIR_CPU_COMPARE_INCOMPATIBLE: + if (cpuEncode(host->arch, host, NULL, &hostData, + NULL, NULL, NULL, NULL) == 0 && + (!cpuHasFeature(hostData, "hle") || + !cpuHasFeature(hostData, "rtm")) && + (STREQ_NULLABLE(cpu->model, "Haswell") || + STREQ_NULLABLE(cpu->model, "Broadwell"))) + noTSX = true; + + if (compare_msg) { + if (noTSX) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("guest and host CPU are not compatible: " + "%s; try using '%s-noTSX' CPU model"), + compare_msg, cpu->model); + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("guest and host CPU are not compatible: " + "%s"), + compare_msg); + } + } else { + if (noTSX) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("guest CPU is not compatible with host " + "CPU; try using '%s-noTSX' CPU model"), + cpu->model); + } else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("guest CPU is not compatible with host " + "CPU")); + } + } + /* fall through */ + case VIR_CPU_COMPARE_ERROR: + goto cleanup; + + default: + break; + } + + ret = 0; + + cleanup: + VIR_FREE(compare_msg); + cpuDataFree(data); + cpuDataFree(hostData); + virCPUDefFree(cpu); + virStringFreeListCount(cpus, ncpus); + return ret; +} + + /** * qemuProcessStartValidate: * @vm: domain object @@ -4506,6 +4608,9 @@ qemuProcessStartValidate(virQEMUDriverPtr driver, } } + if (qemuProcessStartValidateGuestCPU(vm, qemuCaps, caps, flags) < 0) + return -1; + return 0; } diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 1b1918a..8190556 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1416,13 +1416,13 @@ mymain(void) DO_TEST_FAILURE("cpu-host-passthrough", NONE); DO_TEST_FAILURE("cpu-qemu-host-passthrough", QEMU_CAPS_KVM); - driver.caps->host.cpu = cpuHaswell; + qemuTestSetHostCPU(driver.caps, cpuHaswell); DO_TEST("cpu-Haswell", QEMU_CAPS_KVM); DO_TEST("cpu-Haswell2", QEMU_CAPS_KVM); DO_TEST("cpu-Haswell3", QEMU_CAPS_KVM); DO_TEST("cpu-Haswell-noTSX", QEMU_CAPS_KVM); DO_TEST("cpu-host-model-cmt", NONE); - driver.caps->host.cpu = cpuDefault; + qemuTestSetHostCPU(driver.caps, NULL); DO_TEST("encrypted-disk", NONE); DO_TEST("encrypted-disk-usage", NONE); @@ -1974,14 +1974,14 @@ mymain(void) QEMU_CAPS_KVM, QEMU_CAPS_MACHINE_OPT, QEMU_CAPS_MACH_VIRT_GIC_VERSION); - driver.caps->host.cpu->arch = VIR_ARCH_AARCH64; + qemuTestSetHostArch(driver.caps, VIR_ARCH_AARCH64); DO_TEST("aarch64-kvm-32-on-64", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_VIRTIO_MMIO, QEMU_CAPS_KVM, QEMU_CAPS_CPU_AARCH64_OFF); DO_TEST_FAILURE("aarch64-kvm-32-on-64", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_VIRTIO_MMIO, QEMU_CAPS_KVM); - driver.caps->host.cpu->arch = cpuDefault->arch; + qemuTestSetHostArch(driver.caps, VIR_ARCH_NONE); DO_TEST("kvm-pit-device", QEMU_CAPS_KVM_PIT_TICK_POLICY); DO_TEST("kvm-pit-delay", QEMU_CAPS_NO_KVM_PIT); -- 2.10.0

Adding x86 CPU models into a list of supported CPUs for non-x86 architectures is not a very good idea. Each architecture we test needs to maintain its own list of supported CPU models. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change .../qemuxml2argv-pseries-cpu-exact.args | 2 +- .../qemuxml2argv-pseries-cpu-exact.xml | 2 +- tests/qemuxml2argvtest.c | 37 +++++++++++++++------- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.args index 4d27f05..803c1aa 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.args @@ -8,7 +8,7 @@ QEMU_AUDIO_DRV=none \ -name QEMUGuest1 \ -S \ -M pseries \ --cpu POWER7_v2.3 \ +-cpu POWER7 \ -m 512 \ -smp 1,sockets=1,cores=1,threads=1 \ -uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.xml index b54dae2..830e781 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-exact.xml @@ -7,7 +7,7 @@ <type arch='ppc64' machine='pseries'>hvm</type> </os> <cpu match='exact'> - <model>POWER7_v2.3</model> + <model>POWER7</model> <vendor>IBM</vendor> </cpu> <clock offset='utc'/> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 8190556..2812ab6 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -283,27 +283,42 @@ struct testInfo { static int testAddCPUModels(virQEMUCapsPtr caps, bool skipLegacy) { - const char *newModels[] = { + virArch arch = virQEMUCapsGetArch(caps); + const char *x86Models[] = { "Opteron_G3", "Opteron_G2", "Opteron_G1", "Nehalem", "Penryn", "Conroe", "Haswell-noTSX", "Haswell", }; - const char *legacyModels[] = { + const char *x86LegacyModels[] = { "n270", "athlon", "pentium3", "pentium2", "pentium", "486", "coreduo", "kvm32", "qemu32", "kvm64", "core2duo", "phenom", "qemu64", }; + const char *armModels[] = { + "cortex-a9", "cortex-a8", "cortex-a57", "cortex-a53", + }; + const char *ppc64Models[] = { + "POWER8", "POWER7", + }; - if (virQEMUCapsAddCPUDefinitions(caps, newModels, - ARRAY_CARDINALITY(newModels)) < 0) - return -1; + if (ARCH_IS_X86(arch)) { + if (virQEMUCapsAddCPUDefinitions(caps, x86Models, + ARRAY_CARDINALITY(x86Models)) < 0) + return -1; - if (skipLegacy) - return 0; - - if (virQEMUCapsAddCPUDefinitions(caps, legacyModels, - ARRAY_CARDINALITY(legacyModels)) < 0) - return -1; + if (!skipLegacy && + virQEMUCapsAddCPUDefinitions(caps, x86LegacyModels, + ARRAY_CARDINALITY(x86LegacyModels)) < 0) + return -1; + } else if (ARCH_IS_ARM(arch)) { + if (virQEMUCapsAddCPUDefinitions(caps, armModels, + ARRAY_CARDINALITY(armModels)) < 0) + return -1; + } else if (ARCH_IS_PPC64(arch)) { + if (virQEMUCapsAddCPUDefinitions(caps, ppc64Models, + ARRAY_CARDINALITY(ppc64Models)) < 0) + return -1; + } return 0; } -- 2.10.0

Testing PPC64/AArch64 KVM domains on x86_64 host only works because we have a lot of bugs in our code. Since this series is going to fix them, we need to make sure the host architecture matches guest for KVM domains. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change tests/qemuxml2argvtest.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 2812ab6..156a45a 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1535,10 +1535,14 @@ mymain(void) QEMU_CAPS_NODEFCONFIG); DO_TEST("pseries-cpu-exact", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); + + qemuTestSetHostArch(driver.caps, VIR_ARCH_PPC64); DO_TEST("pseries-cpu-compat", QEMU_CAPS_KVM, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); DO_TEST("pseries-cpu-le", QEMU_CAPS_KVM, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); + qemuTestSetHostArch(driver.caps, VIR_ARCH_NONE); + DO_TEST("pseries-panic-missing", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); DO_TEST("pseries-panic-no-address", @@ -1906,6 +1910,7 @@ mymain(void) DO_TEST("aarch64-virt-default-nic", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_VIRTIO_MMIO); + qemuTestSetHostArch(driver.caps, VIR_ARCH_AARCH64); DO_TEST("aarch64-cpu-passthrough", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_VIRTIO_MMIO, QEMU_CAPS_KVM); @@ -1988,8 +1993,6 @@ mymain(void) DO_TEST_FAILURE("aarch64-gic-not-arm", QEMU_CAPS_KVM, QEMU_CAPS_MACHINE_OPT, QEMU_CAPS_MACH_VIRT_GIC_VERSION); - - qemuTestSetHostArch(driver.caps, VIR_ARCH_AARCH64); DO_TEST("aarch64-kvm-32-on-64", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_VIRTIO_MMIO, QEMU_CAPS_KVM, QEMU_CAPS_CPU_AARCH64_OFF); -- 2.10.0

The x86 CPU driver translated each CPU definition from domain XML into CPUID data and then back to CPU definition. This effectively sorted the list of CPU features according to their CPUID values. Since this is going to change, we need to reorder CPU features in a few test files to make sure the generated QEMU command lines will not change. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change .../qemuxml2argvdata/qemuxml2argv-cpu-Haswell2.xml | 2 +- tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml | 12 ++-- .../qemuxml2argv-cpu-exact2-nofallback.xml | 14 ++--- tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.xml | 14 ++--- .../qemuxml2argvdata/qemuxml2argv-cpu-minimum2.xml | 6 +- .../qemuxml2argvdata/qemuxml2argv-cpu-strict1.xml | 20 +++---- .../qemuxml2argv-graphics-spice-timeout.xml | 24 ++++---- .../qemuxml2xmlout-graphics-spice-timeout.xml | 24 ++++---- tests/testutilsqemu.c | 70 +++++++++++----------- 9 files changed, 93 insertions(+), 93 deletions(-) diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-Haswell2.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-Haswell2.xml index 0d4efa1..6a6722d 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-Haswell2.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-Haswell2.xml @@ -10,8 +10,8 @@ </os> <cpu mode='custom' match='exact'> <model fallback='forbid'>Haswell</model> - <feature policy='disable' name='rtm'/> <feature policy='disable' name='hle'/> + <feature policy='disable' name='rtm'/> </cpu> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml index 1d1e815..ebf5830 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml @@ -10,13 +10,13 @@ </os> <cpu match='exact'> <model fallback='allow'>qemu64</model> - <feature policy='disable' name='svm'/> - <feature policy='disable' name='lm'/> - <feature policy='disable' name='nx'/> - <feature policy='disable' name='syscall'/> - <feature policy='disable' name='clflush'/> - <feature policy='disable' name='pse36'/> <feature policy='disable' name='mca'/> + <feature policy='disable' name='pse36'/> + <feature policy='disable' name='clflush'/> + <feature policy='disable' name='syscall'/> + <feature policy='disable' name='nx'/> + <feature policy='disable' name='lm'/> + <feature policy='disable' name='svm'/> </cpu> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.xml index 6b9b7d4..f51f9ed 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.xml @@ -10,18 +10,18 @@ </os> <cpu match='exact'> <model fallback='forbid'>core2duo</model> - <feature name='lahf_lm' policy='require'/> + <feature name='ds' policy='require'/> + <feature name='ht' policy='require'/> + <feature name='tm' policy='optional'/> + <feature name='ds_cpl' policy='require'/> <feature name='xtpr' policy='require'/> + <feature name='3dnowext' policy='force'/> + <feature name='lahf_lm' policy='require'/> + <feature name='nx' policy='disable'/> <feature name='cx16' policy='disable'/> <feature name='tm2' policy='disable'/> - <feature name='ds_cpl' policy='require'/> <feature name='pbe' policy='disable'/> - <feature name='tm' policy='optional'/> - <feature name='ht' policy='require'/> <feature name='ss' policy='disable'/> - <feature name='ds' policy='require'/> - <feature name='nx' policy='disable'/> - <feature name='3dnowext' policy='force'/> <feature name='sse4a' policy='optional'/> <feature name='wdt' policy='forbid'/> </cpu> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.xml index eaea564..7fa77c5 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.xml @@ -10,18 +10,18 @@ </os> <cpu match='exact'> <model>core2duo</model> - <feature name='lahf_lm' policy='require'/> + <feature name='ds' policy='require'/> + <feature name='ht' policy='require'/> + <feature name='tm' policy='optional'/> + <feature name='ds_cpl' policy='require'/> <feature name='xtpr' policy='require'/> + <feature name='3dnowext' policy='force'/> + <feature name='lahf_lm' policy='require'/> + <feature name='nx' policy='disable'/> <feature name='cx16' policy='disable'/> <feature name='tm2' policy='disable'/> - <feature name='ds_cpl' policy='require'/> <feature name='pbe' policy='disable'/> - <feature name='tm' policy='optional'/> - <feature name='ht' policy='require'/> <feature name='ss' policy='disable'/> - <feature name='ds' policy='require'/> - <feature name='nx' policy='disable'/> - <feature name='3dnowext' policy='force'/> <feature name='sse4a' policy='optional'/> <feature name='wdt' policy='forbid'/> </cpu> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum2.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum2.xml index b8bbf25..fe6739c 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum2.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum2.xml @@ -10,10 +10,10 @@ </os> <cpu match='minimum'> <model>qemu64</model> - <feature policy='disable' name='svm'/> - <feature policy='disable' name='lm'/> - <feature policy='disable' name='nx'/> <feature policy='disable' name='syscall'/> + <feature policy='disable' name='nx'/> + <feature policy='disable' name='lm'/> + <feature policy='disable' name='svm'/> </cpu> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-strict1.xml b/tests/qemuxml2argvdata/qemuxml2argv-cpu-strict1.xml index a9fc9c5..84c77ea 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-strict1.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-strict1.xml @@ -10,21 +10,21 @@ </os> <cpu match='strict'> <model>core2duo</model> - <feature name='lahf_lm' policy='require'/> + <feature name='ds' policy='require'/> + <feature name='acpi' policy='optional'/> + <feature name='ht' policy='require'/> + <feature name='tm' policy='optional'/> + <feature name='ds_cpl' policy='require'/> + <feature name='vmx' policy='optional'/> + <feature name='est' policy='optional'/> <feature name='xtpr' policy='require'/> + <feature name='3dnowext' policy='force'/> + <feature name='lahf_lm' policy='require'/> + <feature name='nx' policy='disable'/> <feature name='cx16' policy='disable'/> <feature name='tm2' policy='disable'/> - <feature name='est' policy='optional'/> - <feature name='vmx' policy='optional'/> - <feature name='ds_cpl' policy='require'/> <feature name='pbe' policy='disable'/> - <feature name='tm' policy='optional'/> - <feature name='ht' policy='require'/> <feature name='ss' policy='disable'/> - <feature name='acpi' policy='optional'/> - <feature name='ds' policy='require'/> - <feature name='nx' policy='disable'/> - <feature name='3dnowext' policy='force'/> <feature name='sse4a' policy='optional'/> <feature name='wdt' policy='forbid'/> </cpu> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml index bfb189c..b00a8b7 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice-timeout.xml @@ -19,19 +19,19 @@ <model>core2duo</model> <vendor>Intel</vendor> <topology sockets='1' cores='2' threads='1'/> - <feature policy='require' name='lahf_lm'/> - <feature policy='require' name='xtpr'/> - <feature policy='require' name='cx16'/> - <feature policy='require' name='tm2'/> - <feature policy='require' name='est'/> - <feature policy='require' name='vmx'/> - <feature policy='require' name='ds_cpl'/> - <feature policy='require' name='pbe'/> - <feature policy='require' name='tm'/> - <feature policy='require' name='ht'/> - <feature policy='require' name='ss'/> - <feature policy='require' name='acpi'/> <feature policy='require' name='ds'/> + <feature policy='require' name='acpi'/> + <feature policy='require' name='ss'/> + <feature policy='require' name='ht'/> + <feature policy='require' name='tm'/> + <feature policy='require' name='pbe'/> + <feature policy='require' name='ds_cpl'/> + <feature policy='require' name='vmx'/> + <feature policy='require' name='est'/> + <feature policy='require' name='tm2'/> + <feature policy='require' name='cx16'/> + <feature policy='require' name='xtpr'/> + <feature policy='require' name='lahf_lm'/> </cpu> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml index 912b542..5f881f1 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-graphics-spice-timeout.xml @@ -19,19 +19,19 @@ <model fallback='allow'>core2duo</model> <vendor>Intel</vendor> <topology sockets='1' cores='2' threads='1'/> - <feature policy='require' name='lahf_lm'/> - <feature policy='require' name='xtpr'/> - <feature policy='require' name='cx16'/> - <feature policy='require' name='tm2'/> - <feature policy='require' name='est'/> - <feature policy='require' name='vmx'/> - <feature policy='require' name='ds_cpl'/> - <feature policy='require' name='pbe'/> - <feature policy='require' name='tm'/> - <feature policy='require' name='ht'/> - <feature policy='require' name='ss'/> - <feature policy='require' name='acpi'/> <feature policy='require' name='ds'/> + <feature policy='require' name='acpi'/> + <feature policy='require' name='ss'/> + <feature policy='require' name='ht'/> + <feature policy='require' name='tm'/> + <feature policy='require' name='pbe'/> + <feature policy='require' name='ds_cpl'/> + <feature policy='require' name='vmx'/> + <feature policy='require' name='est'/> + <feature policy='require' name='tm2'/> + <feature policy='require' name='cx16'/> + <feature policy='require' name='xtpr'/> + <feature policy='require' name='lahf_lm'/> </cpu> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index f59746a..8c2c8b4 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -19,19 +19,19 @@ virCPUDefPtr cpuHaswell; virCPUDefPtr cpuPower8; static virCPUFeatureDef cpuDefaultFeatures[] = { - { (char *) "lahf_lm", -1 }, - { (char *) "xtpr", -1 }, - { (char *) "cx16", -1 }, - { (char *) "tm2", -1 }, - { (char *) "est", -1 }, - { (char *) "vmx", -1 }, - { (char *) "ds_cpl", -1 }, - { (char *) "pbe", -1 }, - { (char *) "tm", -1 }, - { (char *) "ht", -1 }, - { (char *) "ss", -1 }, + { (char *) "ds", -1 }, { (char *) "acpi", -1 }, - { (char *) "ds", -1 } + { (char *) "ss", -1 }, + { (char *) "ht", -1 }, + { (char *) "tm", -1 }, + { (char *) "pbe", -1 }, + { (char *) "ds_cpl", -1 }, + { (char *) "vmx", -1 }, + { (char *) "est", -1 }, + { (char *) "tm2", -1 }, + { (char *) "cx16", -1 }, + { (char *) "xtpr", -1 }, + { (char *) "lahf_lm", -1 }, }; static virCPUDef cpuDefaultData = { VIR_CPU_TYPE_HOST, /* type */ @@ -51,30 +51,30 @@ static virCPUDef cpuDefaultData = { }; static virCPUFeatureDef cpuHaswellFeatures[] = { - { (char *) "lahf_lm", -1 }, - { (char *) "invtsc", -1 }, - { (char *) "abm", -1 }, - { (char *) "pdpe1gb", -1 }, - { (char *) "cmt", -1 }, - { (char *) "rdrand", -1 }, - { (char *) "f16c", -1 }, - { (char *) "osxsave", -1 }, - { (char *) "pdcm", -1 }, - { (char *) "xtpr", -1 }, - { (char *) "tm2", -1 }, - { (char *) "est", -1 }, - { (char *) "smx", -1 }, - { (char *) "vmx", -1 }, - { (char *) "ds_cpl", -1 }, - { (char *) "monitor", -1 }, - { (char *) "dtes64", -1 }, - { (char *) "pbe", -1 }, - { (char *) "tm", -1 }, - { (char *) "ht", -1 }, - { (char *) "ss", -1 }, - { (char *) "acpi", -1 }, - { (char *) "ds", -1 }, { (char *) "vme", -1 }, + { (char *) "ds", -1 }, + { (char *) "acpi", -1 }, + { (char *) "ss", -1 }, + { (char *) "ht", -1 }, + { (char *) "tm", -1 }, + { (char *) "pbe", -1 }, + { (char *) "dtes64", -1 }, + { (char *) "monitor", -1 }, + { (char *) "ds_cpl", -1 }, + { (char *) "vmx", -1 }, + { (char *) "smx", -1 }, + { (char *) "est", -1 }, + { (char *) "tm2", -1 }, + { (char *) "xtpr", -1 }, + { (char *) "pdcm", -1 }, + { (char *) "osxsave", -1 }, + { (char *) "f16c", -1 }, + { (char *) "rdrand", -1 }, + { (char *) "cmt", -1 }, + { (char *) "pdpe1gb", -1 }, + { (char *) "abm", -1 }, + { (char *) "invtsc", -1 }, + { (char *) "lahf_lm", -1 }, }; static virCPUDef cpuHaswellData = { VIR_CPU_TYPE_HOST, /* type */ -- 2.10.0

To have a single place where we decide whether a guest can run natively on a host. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change src/qemu/qemu_capabilities.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 538cedb..e201d26 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -433,6 +433,29 @@ static const char *virQEMUCapsArchToString(virArch arch) return virArchToString(arch); } + +/* Checks whether a domain with @guest arch can run natively on @host. + */ +static bool +virQEMUCapsGuestIsNative(virArch host, + virArch guest) +{ + if (host == guest) + return true; + + if (host == VIR_ARCH_X86_64 && guest == VIR_ARCH_I686) + return true; + + if (host == VIR_ARCH_AARCH64 && guest == VIR_ARCH_ARMV7L) + return true; + + if (ARCH_IS_PPC64(host) && ARCH_IS_PPC64(guest)) + return true; + + return false; +} + + /* Given a host and guest architectures, find a suitable QEMU target. * * This is meant to be used as a second attempt if qemu-system-$guestarch @@ -446,12 +469,8 @@ virQEMUCapsFindTarget(virArch hostarch, if (ARCH_IS_PPC64(guestarch)) guestarch = VIR_ARCH_PPC64; - /* armv7l guests on aarch64 hosts can use the aarch64 target - * i686 guests on x86_64 hosts can use the x86_64 target */ - if ((guestarch == VIR_ARCH_ARMV7L && hostarch == VIR_ARCH_AARCH64) || - (guestarch == VIR_ARCH_I686 && hostarch == VIR_ARCH_X86_64)) { - return hostarch; - } + if (virQEMUCapsGuestIsNative(hostarch, guestarch)) + guestarch = hostarch; return guestarch; } @@ -813,7 +832,6 @@ virQEMUCapsInitGuest(virCapsPtr caps, char *binary = NULL; virQEMUCapsPtr qemubinCaps = NULL; virQEMUCapsPtr kvmbinCaps = NULL; - bool native_kvm, x86_32on64_kvm, arm_32on64_kvm, ppc64_kvm; int ret = -1; /* Check for existence of base emulator, or alternate base @@ -835,14 +853,7 @@ virQEMUCapsInitGuest(virCapsPtr caps, * - hostarch is aarch64 and guest arch is armv7l (needs -cpu aarch64=off) * - hostarch and guestarch are both ppc64* */ - native_kvm = (hostarch == guestarch); - x86_32on64_kvm = (hostarch == VIR_ARCH_X86_64 && - guestarch == VIR_ARCH_I686); - arm_32on64_kvm = (hostarch == VIR_ARCH_AARCH64 && - guestarch == VIR_ARCH_ARMV7L); - ppc64_kvm = (ARCH_IS_PPC64(hostarch) && ARCH_IS_PPC64(guestarch)); - - if (native_kvm || x86_32on64_kvm || arm_32on64_kvm || ppc64_kvm) { + if (virQEMUCapsGuestIsNative(hostarch, guestarch)) { const char *kvmbins[] = { "/usr/libexec/qemu-kvm", /* RHEL */ "qemu-kvm", /* Fedora */ @@ -858,7 +869,7 @@ virQEMUCapsInitGuest(virCapsPtr caps, * arm is different in that 32-on-64 _only_ works with * qemu-system-aarch64. So we have to add it to the kvmbins list */ - if (arm_32on64_kvm) + if (hostarch == VIR_ARCH_AARCH64 && guestarch == VIR_ARCH_ARMV7L) kvmbins[3] = "qemu-system-aarch64"; for (i = 0; i < ARRAY_CARDINALITY(kvmbins); ++i) { -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - removed superfluous check for caps != NULL src/qemu/qemu_capabilities.c | 24 +- src/qemu/qemu_capabilities.h | 3 +- src/qemu/qemu_driver.c | 7 +- tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml | 31 +- .../qemu_2.6.0-gicv2-virt.aarch64.xml | 37 +- .../qemu_2.6.0-gicv3-virt.aarch64.xml | 37 +- tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml | 37 +- tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml | 437 ++++++++++++++++++++- tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml | 35 +- tests/domaincapstest.c | 56 ++- 10 files changed, 682 insertions(+), 22 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index e201d26..87749c9 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4284,6 +4284,26 @@ virQEMUCapsFillDomainOSCaps(virDomainCapsOSPtr os, static int +virQEMUCapsFillDomainCPUCaps(virCapsPtr caps, + virQEMUCapsPtr qemuCaps, + virDomainCapsPtr domCaps) +{ + + if (domCaps->virttype == VIR_DOMAIN_VIRT_KVM && + virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch)) + domCaps->cpu.hostPassthrough = true; + + if (qemuCaps->cpuDefinitions && caps->host.cpu) + domCaps->cpu.hostModel = virQEMUCapsGuestIsNative(caps->host.arch, + qemuCaps->arch); + + domCaps->cpu.custom = virObjectRef(qemuCaps->cpuDefinitions); + + return 0; +} + + +static int virQEMUCapsFillDomainDeviceDiskCaps(virQEMUCapsPtr qemuCaps, const char *machine, virDomainCapsDeviceDiskPtr disk) @@ -4490,7 +4510,8 @@ virQEMUCapsFillDomainFeatureGICCaps(virQEMUCapsPtr qemuCaps, int -virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps, +virQEMUCapsFillDomainCaps(virCapsPtr caps, + virDomainCapsPtr domCaps, virQEMUCapsPtr qemuCaps, virFirmwarePtr *firmwares, size_t nfirmwares) @@ -4513,6 +4534,7 @@ virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps, } if (virQEMUCapsFillDomainOSCaps(os, firmwares, nfirmwares) < 0 || + virQEMUCapsFillDomainCPUCaps(caps, qemuCaps, domCaps) < 0 || virQEMUCapsFillDomainDeviceDiskCaps(qemuCaps, domCaps->machine, disk) < 0 || virQEMUCapsFillDomainDeviceGraphicsCaps(qemuCaps, graphics) < 0 || diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index e31c51c..dcd358a 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -501,7 +501,8 @@ int virQEMUCapsInitGuestFromBinary(virCapsPtr caps, virQEMUCapsPtr kvmbinCaps, virArch guestarch); -int virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps, +int virQEMUCapsFillDomainCaps(virCapsPtr caps, + virDomainCapsPtr domCaps, virQEMUCapsPtr qemuCaps, virFirmwarePtr *firmwares, size_t nfirmwares); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c1c522a..2acff16 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -18631,6 +18631,7 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, virDomainCapsPtr domCaps = NULL; int arch = virArchFromHost(); /* virArch */ virQEMUDriverConfigPtr cfg = NULL; + virCapsPtr caps = NULL; virCheckFlags(0, ret); @@ -18639,6 +18640,9 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, cfg = virQEMUDriverGetConfig(driver); + if (!(caps = virQEMUDriverGetCapabilities(driver, false))) + goto cleanup; + if (qemuHostdevHostSupportsPassthroughLegacy() || qemuHostdevHostSupportsPassthroughVFIO()) virttype = VIR_DOMAIN_VIRT_KVM; @@ -18710,13 +18714,14 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype))) goto cleanup; - if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps, + if (virQEMUCapsFillDomainCaps(caps, domCaps, qemuCaps, cfg->firmwares, cfg->nfirmwares) < 0) goto cleanup; ret = virDomainCapsFormat(domCaps); cleanup: virObjectUnref(cfg); + virObjectUnref(caps); virObjectUnref(domCaps); virObjectUnref(qemuCaps); return ret; diff --git a/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml b/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml index 6da28b0..4ee2f95 100644 --- a/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml +++ b/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml @@ -19,9 +19,34 @@ </loader> </os> <cpu> - <mode name='host-passthrough' supported='no'/> - <mode name='host-model' supported='no'/> - <mode name='custom' supported='no'/> + <mode name='host-passthrough' supported='yes'/> + <mode name='host-model' supported='yes'/> + <mode name='custom' supported='yes'> + <model>Opteron_G5</model> + <model>Opteron_G4</model> + <model>Opteron_G3</model> + <model>Opteron_G2</model> + <model>Opteron_G1</model> + <model>Haswell</model> + <model>SandyBridge</model> + <model>Westmere</model> + <model>Nehalem</model> + <model>Penryn</model> + <model>Conroe</model> + <model>n270</model> + <model>athlon</model> + <model>pentium3</model> + <model>pentium2</model> + <model>pentium</model> + <model>486</model> + <model>coreduo</model> + <model>kvm32</model> + <model>qemu32</model> + <model>kvm64</model> + <model>core2duo</model> + <model>phenom</model> + <model>qemu64</model> + </mode> </cpu> <devices> <disk supported='yes'> diff --git a/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml index ee51684..9e96f47 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml @@ -19,9 +19,40 @@ </loader> </os> <cpu> - <mode name='host-passthrough' supported='no'/> - <mode name='host-model' supported='no'/> - <mode name='custom' supported='no'/> + <mode name='host-passthrough' supported='yes'/> + <mode name='host-model' supported='yes'/> + <mode name='custom' supported='yes'> + <model>pxa262</model> + <model>pxa270-a0</model> + <model>arm1136</model> + <model>cortex-a15</model> + <model>pxa260</model> + <model>arm1136-r2</model> + <model>pxa261</model> + <model>pxa255</model> + <model>arm926</model> + <model>arm11mpcore</model> + <model>pxa250</model> + <model>ti925t</model> + <model>cortex-a57</model> + <model>sa1110</model> + <model>arm1176</model> + <model>cortex-a53</model> + <model>sa1100</model> + <model>pxa270-c5</model> + <model>cortex-a9</model> + <model>cortex-a8</model> + <model>pxa270-c0</model> + <model>arm1026</model> + <model>pxa270-b1</model> + <model>cortex-m3</model> + <model>cortex-m4</model> + <model>pxa270-b0</model> + <model>arm946</model> + <model>cortex-r5</model> + <model>pxa270-a1</model> + <model>pxa270</model> + </mode> </cpu> <devices> <disk supported='yes'> diff --git a/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml index 88cced9..c081b35 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml @@ -19,9 +19,40 @@ </loader> </os> <cpu> - <mode name='host-passthrough' supported='no'/> - <mode name='host-model' supported='no'/> - <mode name='custom' supported='no'/> + <mode name='host-passthrough' supported='yes'/> + <mode name='host-model' supported='yes'/> + <mode name='custom' supported='yes'> + <model>pxa262</model> + <model>pxa270-a0</model> + <model>arm1136</model> + <model>cortex-a15</model> + <model>pxa260</model> + <model>arm1136-r2</model> + <model>pxa261</model> + <model>pxa255</model> + <model>arm926</model> + <model>arm11mpcore</model> + <model>pxa250</model> + <model>ti925t</model> + <model>cortex-a57</model> + <model>sa1110</model> + <model>arm1176</model> + <model>cortex-a53</model> + <model>sa1100</model> + <model>pxa270-c5</model> + <model>cortex-a9</model> + <model>cortex-a8</model> + <model>pxa270-c0</model> + <model>arm1026</model> + <model>pxa270-b1</model> + <model>cortex-m3</model> + <model>cortex-m4</model> + <model>pxa270-b0</model> + <model>arm946</model> + <model>cortex-r5</model> + <model>pxa270-a1</model> + <model>pxa270</model> + </mode> </cpu> <devices> <disk supported='yes'> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml index 09c0e1c..811d2b7 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml @@ -19,9 +19,40 @@ </loader> </os> <cpu> - <mode name='host-passthrough' supported='no'/> - <mode name='host-model' supported='no'/> - <mode name='custom' supported='no'/> + <mode name='host-passthrough' supported='yes'/> + <mode name='host-model' supported='yes'/> + <mode name='custom' supported='yes'> + <model>pxa262</model> + <model>pxa270-a0</model> + <model>arm1136</model> + <model>cortex-a15</model> + <model>pxa260</model> + <model>arm1136-r2</model> + <model>pxa261</model> + <model>pxa255</model> + <model>arm926</model> + <model>arm11mpcore</model> + <model>pxa250</model> + <model>ti925t</model> + <model>cortex-a57</model> + <model>sa1110</model> + <model>arm1176</model> + <model>cortex-a53</model> + <model>sa1100</model> + <model>pxa270-c5</model> + <model>cortex-a9</model> + <model>cortex-a8</model> + <model>pxa270-c0</model> + <model>arm1026</model> + <model>pxa270-b1</model> + <model>cortex-m3</model> + <model>cortex-m4</model> + <model>pxa270-b0</model> + <model>arm946</model> + <model>cortex-r5</model> + <model>pxa270-a1</model> + <model>pxa270</model> + </mode> </cpu> <devices> <disk supported='yes'> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml index 40b255e..a0aa811 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml @@ -19,9 +19,440 @@ </loader> </os> <cpu> - <mode name='host-passthrough' supported='no'/> - <mode name='host-model' supported='no'/> - <mode name='custom' supported='no'/> + <mode name='host-passthrough' supported='yes'/> + <mode name='host-model' supported='yes'/> + <mode name='custom' supported='yes'> + <model>default</model> + <model>ppc</model> + <model>ppc32</model> + <model>ppc64</model> + <model>970mp</model> + <model>970fx</model> + <model>970</model> + <model>POWER8NVL</model> + <model>POWER8</model> + <model>POWER8E</model> + <model>POWER7+</model> + <model>POWER7</model> + <model>POWER5gs</model> + <model>POWER5+</model> + <model>Apollo7PM</model> + <model>7457A</model> + <model>7447A</model> + <model>Apollo7</model> + <model>7457</model> + <model>Apollo6</model> + <model>7455</model> + <model>7445</model> + <model>7451</model> + <model>7441</model> + <model>Vger</model> + <model>7450</model> + <model>7448</model> + <model>Nitro</model> + <model>7410</model> + <model>G4</model> + <model>Max</model> + <model>7400</model> + <model>Goldfinger</model> + <model>755</model> + <model>745</model> + <model>LoneStar</model> + <model>750l</model> + <model>750gx</model> + <model>750fx</model> + <model>750cxe</model> + <model>750cx</model> + <model>750cl</model> + <model>Conan/Doyle</model> + <model>G3</model> + <model>Typhoon</model> + <model>750</model> + <model>Arthur</model> + <model>740</model> + <model>Mach5</model> + <model>Sirocco</model> + <model>604e</model> + <model>Goldeneye</model> + <model>603r</model> + <model>Vaillant</model> + <model>Stretch</model> + <model>603e</model> + <model>Vanilla</model> + <model>601v</model> + <model>601</model> + <model>MPC8560</model> + <model>MPC8555E</model> + <model>MPC8555</model> + <model>MPC8548E</model> + <model>MPC8548</model> + <model>MPC8547E</model> + <model>MPC8545E</model> + <model>MPC8545</model> + <model>MPC8544E</model> + <model>MPC8544</model> + <model>MPC8543E</model> + <model>MPC8543</model> + <model>MPC8541E</model> + <model>MPC8541</model> + <model>MPC8540</model> + <model>MPC8533E</model> + <model>MPC8533</model> + <model>e500v2</model> + <model>e500v1</model> + <model>e500</model> + <model>MPC8347EA</model> + <model>MPC8347E</model> + <model>MPC8347A</model> + <model>MPC8347</model> + <model>e300</model> + <model>e200</model> + <model>MPC8280</model> + <model>MPC8275</model> + <model>MPC8272</model> + <model>MPC8271</model> + <model>MPC8270</model> + <model>MPC8266_HiP4</model> + <model>MPC8266_HiP3</model> + <model>MPC8266</model> + <model>MPC8265_HiP4</model> + <model>MPC8265_HiP3</model> + <model>MPC8265</model> + <model>MPC8264_HiP4</model> + <model>MPC8264_HiP3</model> + <model>MPC8264</model> + <model>MPC8260_HiP4</model> + <model>MPC8260_HiP3</model> + <model>MPC8260</model> + <model>MPC8255_HiP4</model> + <model>MPC8255_HiP3</model> + <model>MPC8255</model> + <model>MPC8250_HiP4</model> + <model>MPC8250_HiP3</model> + <model>MPC8250</model> + <model>MPC8248</model> + <model>MPC8247</model> + <model>MPC8245</model> + <model>MPC8241</model> + <model>PowerQUICC-II</model> + <model>MPC82xx</model> + <model>MPC5200B</model> + <model>MPC5200</model> + <model>MPC52xx</model> + <model>MPC8240</model> + <model>440EP</model> + <model>x2vp50</model> + <model>x2vp7</model> + <model>405GPe</model> + <model>405GP</model> + <model>405CR</model> + <model>405</model> + <model>403</model> + <model>750cl_v1.0</model> + <model>750cxe_v2.1</model> + <model>7457A_v1.2</model> + <model>755_v2.7</model> + <model>MPC8347ET</model> + <model>MPC8545E_v20</model> + <model>750_v2.1</model> + <model>755_v2.2</model> + <model>745_v2.0</model> + <model>7455_v1.0</model> + <model>MPC8547E_v21</model> + <model>STB25</model> + <model>POWER8_v2.0</model> + <model>401G2</model> + <model>MPC8349A</model> + <model>750e</model> + <model>MPC8545_v21</model> + <model>MPC8548_v11</model> + <model>970fx_v2.0</model> + <model>750fx_v2.0</model> + <model>POWER8E_v2.1</model> + <model>Cobra</model> + <model>603p</model> + <model>7400_v2.7</model> + <model>MPC8378E</model> + <model>e500v2_v10</model> + <model>e500mc</model> + <model>603e7v1</model> + <model>970mp_v1.0</model> + <model>MPC8555E_v11</model> + <model>440-Xilinx-w-dfpu</model> + <model>740e</model> + <model>405CRc</model> + <model>7447A_v1.1</model> + <model>MPC8543_v11</model> + <model>MPC8533E_v10</model> + <model>MPC8540_v21</model> + <model>e500v2_v21</model> + <model>e300c1</model> + <model>7400_v2.2</model> + <model>970fx_v1.0</model> + <model>750gx_v1.2</model> + <model>750fx_v1.0</model> + <model>MPC8641</model> + <model>MPC8544E_v10</model> + <model>405D4</model> + <model>7457_v1.1</model> + <model>970fx_v3.0</model> + <model>604e_v2.2</model> + <model>755_v2.6</model> + <model>7410_v1.4</model> + <model>Npe4GS3</model> + <model>745_v2.4</model> + <model>750_v2.0</model> + <model>7445_v3.2</model> + <model>750l_v3.2</model> + <model>MPC8540_v10</model> + <model>750_v1.0</model> + <model>MPC8343A</model> + <model>MPC8378</model> + <model>G2HiP3</model> + <model>750cxe_v3.0</model> + <model>e500_v10</model> + <model>STB03</model> + <model>MPC8567</model> + <model>MPC8545_v20</model> + <model>MPC8548_v10</model> + <model>755_v1.1</model> + <model>603e7v</model> + <model>Npe405H2</model> + <model>750_v3.0</model> + <model>Npe405H</model> + <model>7400_v2.6</model> + <model>405GPa</model> + <model>MPC8548_v21</model> + <model>MPC8541E_v10</model> + <model>750l_v2.2</model> + <model>MPC8555E_v10</model> + <model>7457A_v1.1</model> + <model>e200z6</model> + <model>MPC8379E</model> + <model>e500v2_v20</model> + <model>MPC8347AP</model> + <model>401B2</model> + <model>MPC8349E</model> + <model>755_v2.1</model> + <model>MPC8543_v21</model> + <model>MPC8547E_v20</model> + <model>745_v2.8</model> + <model>7455_v3.4</model> + <model>7448_v1.1</model> + <model>740_v2.2</model> + <model>7400_v1.1</model> + <model>MPC8567E</model> + <model>7441_v2.10</model> + <model>603e_v1.4</model> + <model>G2leGP1</model> + <model>7451_v2.10</model> + <model>MPC8343E</model> + <model>750cx_v2.2</model> + <model>Npe405L</model> + <model>603e7</model> + <model>401A1</model> + <model>MPC8377</model> + <model>7448_v2.1</model> + <model>7441_v2.3</model> + <model>7400_v2.1</model> + <model>405CRb</model> + <model>604</model> + <model>MPC8540_v20</model> + <model>MPC8543_v10</model> + <model>7447A_v1.0</model> + <model>7445_v2.1</model> + <model>e500_v20</model> + <model>750gx_v1.1</model> + <model>MPC8543E_v11</model> + <model>750cxe_v2.4</model> + <model>MPC8548_v20</model> + <model>MPC8347AT</model> + <model>POWER8NVL_v1.0</model> + <model>7457A_v1.0</model> + <model>7457_v1.0</model> + <model>7450_v1.2</model> + <model>MPC8572</model> + <model>755_v2.5</model> + <model>7410_v1.3</model> + <model>745_v2.3</model> + <model>750l_v2.1</model> + <model>405GPR</model> + <model>755_v2.0</model> + <model>MPC8541_v11</model> + <model>401C2</model> + <model>e500v2_v30</model> + <model>7455_v3.3</model> + <model>405EZ</model> + <model>MPC8568E</model> + <model>755_v1.0</model> + <model>603e_v1.3</model> + <model>MPC8560_v10</model> + <model>MPC8560_v21</model> + <model>G2H4</model> + <model>MPC8533_v11</model> + <model>740_v3.1</model> + <model>e200z5</model> + <model>MPC8349</model> + <model>7400_v2.0</model> + <model>405CRa</model> + <model>MPC8543E_v10</model> + <model>MPC8543E_v21</model> + <model>750cxe_v2.3</model> + <model>MPC8543_v20</model> + <model>745_v2.7</model> + <model>403GC</model> + <model>e5500</model> + <model>7448_v1.0</model> + <model>MPC5200_v12</model> + <model>740_v2.1</model> + <model>745_v2.2</model> + <model>7400_v1.0</model> + <model>7410_v1.2</model> + <model>x2vp4</model> + <model>MPC8555_v11</model> + <model>MPC8541_v10</model> + <model>405LP</model> + <model>750fx_v2.3</model> + <model>405EP</model> + <model>601_v2</model> + <model>MPC8544_v11</model> + <model>401D2</model> + <model>MPC8572E</model> + <model>604e_v1.0</model> + <model>750cx_v2.1</model> + <model>MPC5200B_v21</model> + <model>750l_v3.0</model> + <model>e300c4</model> + <model>7448_v2.0</model> + <model>7450_v2.1</model> + <model>G2leGP</model> + <model>750cxe_v3.1b</model> + <model>7400_v2.9</model> + <model>G2GP</model> + <model>603</model> + <model>405GPd</model> + <model>MPC8548E_v11</model> + <model>603e7t</model> + <model>IOP480</model> + <model>750gx_v1.0</model> + <model>MPC8560_v20</model> + <model>405D2</model> + <model>750fl</model> + <model>750l_v2.0</model> + <model>x2vp20</model> + <model>e600</model> + <model>7450_v1.1</model> + <model>755_v2.4</model> + <model>7445_v1.0</model> + <model>G2LS</model> + <model>MPC8543E_v20</model> + <model>7447_v1.1</model> + <model>603e_v2.2</model> + <model>603e_v4</model> + <model>7455_v3.2</model> + <model>740_v2.0</model> + <model>MPC8347P</model> + <model>440EPb</model> + <model>MPC603</model> + <model>603e_v1.2</model> + <model>750fx_v2.2</model> + <model>740_v1.0</model> + <model>MPC8544_v10</model> + <model>601_v1</model> + <model>745_v1.1</model> + <model>POWER7+_v2.1</model> + <model>750cx_v2.0</model> + <model>MPC8347EAP</model> + <model>401E2</model> + <model>MPC8641D</model> + <model>e300c3</model> + <model>MPC8533_v10</model> + <model>7441_v2.1</model> + <model>740_v3.0</model> + <model>POWER5+_v2.1</model> + <model>602</model> + <model>MPC8548E_v10</model> + <model>G2leLS</model> + <model>MPC8343</model> + <model>750cx_v1.0</model> + <model>750cxe_v2.2</model> + <model>604e_v2.4</model> + <model>755_v2.8</model> + <model>MPC8548E_v21</model> + <model>745_v2.6</model> + <model>G2le</model> + <model>403GB</model> + <model>MPC8545E_v21</model> + <model>POWER7_v2.3</model> + <model>750_v2.2</model> + <model>7450_v1.0</model> + <model>MPC5200_v11</model> + <model>755_v2.3</model> + <model>MPC8347EP</model> + <model>7410_v1.1</model> + <model>750gl</model> + <model>403GCX</model> + <model>750p</model> + <model>745_v2.1</model> + <model>7445_v3.4</model> + <model>G2</model> + <model>MPC8555_v10</model> + <model>MPC8347T</model> + <model>603e_v3</model> + <model>970_v2.2</model> + <model>440-Xilinx</model> + <model>740p</model> + <model>MPC5200B_v20</model> + <model>440EPX</model> + <model>603e_v1.1</model> + <model>7451_v2.3</model> + <model>7450_v2.0</model> + <model>7400_v2.8</model> + <model>7455_v2.1</model> + <model>405GPc</model> + <model>MPC8347EAT</model> + <model>970mp_v1.1</model> + <model>603e7v2</model> + <model>604r</model> + <model>7447A_v1.2</model> + <model>MPC8533E_v11</model> + <model>e500v2_v22</model> + <model>401F2</model> + <model>MPC8343EA</model> + <model>7457_v1.2</model> + <model>970fx_v3.1</model> + <model>7447_v1.0</model> + <model>745_v2.5</model> + <model>MPC8548E_v20</model> + <model>MPC8610</model> + <model>403GA</model> + <model>750cxe_v2.4b</model> + <model>MPC5200_v10</model> + <model>7410_v1.0</model> + <model>G2leGP3</model> + <model>603e_v4.1</model> + <model>7445_v3.3</model> + <model>440EPa</model> + <model>970fx_v2.1</model> + <model>MPC8377E</model> + <model>750fx_v2.1</model> + <model>601_v0</model> + <model>STB04</model> + <model>745_v1.0</model> + <model>G2HiP4</model> + <model>750cl_v2.0</model> + <model>750cxr</model> + <model>MPC8349EA</model> + <model>750cxe_v3.1</model> + <model>401</model> + <model>MPC8379</model> + <model>MPC8568</model> + <model>e300c2</model> + <model>750_v3.1</model> + <model>MPC8544E_v11</model> + <model>405GPb</model> + <model>MPC8541E_v11</model> + </mode> </cpu> <devices> <disk supported='yes'> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml b/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml index 6706fec..80101a4 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml @@ -19,9 +19,38 @@ </loader> </os> <cpu> - <mode name='host-passthrough' supported='no'/> - <mode name='host-model' supported='no'/> - <mode name='custom' supported='no'/> + <mode name='host-passthrough' supported='yes'/> + <mode name='host-model' supported='yes'/> + <mode name='custom' supported='yes'> + <model>Opteron_G5</model> + <model>Opteron_G4</model> + <model>Opteron_G3</model> + <model>Opteron_G2</model> + <model>Opteron_G1</model> + <model>Broadwell</model> + <model>Broadwell-noTSX</model> + <model>Haswell</model> + <model>Haswell-noTSX</model> + <model>IvyBridge</model> + <model>SandyBridge</model> + <model>Westmere</model> + <model>Nehalem</model> + <model>Penryn</model> + <model>Conroe</model> + <model>n270</model> + <model>athlon</model> + <model>pentium3</model> + <model>pentium2</model> + <model>pentium</model> + <model>486</model> + <model>coreduo</model> + <model>kvm32</model> + <model>qemu32</model> + <model>kvm64</model> + <model>core2duo</model> + <model>phenom</model> + <model>qemu64</model> + </mode> </cpu> <devices> <disk supported='yes'> diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c index 907c0ad..10b7452 100644 --- a/tests/domaincapstest.c +++ b/tests/domaincapstest.c @@ -109,6 +109,54 @@ fillAllCaps(virDomainCapsPtr domCaps) #if WITH_QEMU # include "testutilsqemu.h" +static virCPUDef aarch64Cpu = { + 0, 0, 0, 0, NULL, NULL, 0, NULL, 1, 1, 1, 0, 0, NULL, +}; + +static virCPUDef ppc64leCpu = { + VIR_CPU_TYPE_HOST, 0, 0, + VIR_ARCH_PPC64LE, (char *) "POWER8", + NULL, 0, NULL, 1, 1, 1, 0, 0, NULL, +}; + +static virCPUDef x86Cpu = { + VIR_CPU_TYPE_HOST, 0, 0, + VIR_ARCH_X86_64, (char *) "Broadwell", + NULL, 0, NULL, 1, 1, 1, 0, 0, NULL, +}; + +static int +fakeHostCPU(virCapsPtr caps, + virArch arch) +{ + virCPUDefPtr cpu; + + switch (arch) { + case VIR_ARCH_AARCH64: + cpu = &aarch64Cpu; + break; + + case VIR_ARCH_PPC64LE: + cpu = &ppc64leCpu; + break; + + case VIR_ARCH_X86_64: + cpu = &x86Cpu; + break; + + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + "cannot fake host CPU for arch %s", + virArchToString(arch)); + return -1; + } + + if (!(caps->host.cpu = virCPUDefCopy(cpu))) + return -1; + + return 0; +} + static int fillQemuCaps(virDomainCapsPtr domCaps, const char *name, @@ -118,6 +166,7 @@ fillQemuCaps(virDomainCapsPtr domCaps, { int ret = -1; char *path = NULL; + virCapsPtr caps = NULL; virQEMUCapsPtr qemuCaps = NULL; virDomainCapsLoaderPtr loader = &domCaps->os.loader; @@ -136,7 +185,11 @@ fillQemuCaps(virDomainCapsPtr domCaps, virQEMUCapsGetDefaultMachine(qemuCaps)) < 0) goto cleanup; - if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps, + if (!(caps = virCapabilitiesNew(domCaps->arch, false, false)) || + fakeHostCPU(caps, domCaps->arch) < 0) + goto cleanup; + + if (virQEMUCapsFillDomainCaps(caps, domCaps, qemuCaps, cfg->firmwares, cfg->nfirmwares) < 0) goto cleanup; @@ -164,6 +217,7 @@ fillQemuCaps(virDomainCapsPtr domCaps, ret = 0; cleanup: + virObjectUnref(caps); virObjectUnref(qemuCaps); VIR_FREE(path); return ret; -- 2.10.0

Some CPU drivers (such as arm) do not provide list of CPUs libvirt supports and just pass any CPU model from domain XML directly to QEMU. Such driver need to return models == NULL and success from cpuGetModels. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - s/vshPrint/vshPrintExtra/ src/cpu/cpu.c | 15 +++++++++------ src/libvirt-host.c | 3 ++- tools/virsh-host.c | 10 +++++++--- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 19afeab..d2b7ce3 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -750,9 +750,13 @@ cpuModelIsAllowed(const char *model, * @arch: CPU architecture * @models: where to store the NULL-terminated list of supported models * - * Fetches all CPU models supported by libvirt on @archName. + * Fetches all CPU models supported by libvirt on @archName. If there are + * no restrictions on CPU models on @archName (i.e., the CPU model is just + * passed directly to a hypervisor), this function returns 0 and sets + * @models to NULL. * - * Returns number of supported CPU models or -1 on error. + * Returns number of supported CPU models, 0 if any CPU model is supported, + * or -1 on error. */ int cpuGetModels(virArch arch, char ***models) @@ -770,10 +774,9 @@ cpuGetModels(virArch arch, char ***models) } if (!driver->getModels) { - virReportError(VIR_ERR_NO_SUPPORT, - _("CPU driver for %s has no CPU model support"), - virArchToString(arch)); - return -1; + if (models) + *models = NULL; + return 0; } return driver->getModels(models); diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 2a3de03..335798a 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -1005,7 +1005,8 @@ virConnectCompareCPU(virConnectPtr conn, * * Get the list of supported CPU models for a specific architecture. * - * Returns -1 on error, number of elements in @models on success. + * Returns -1 on error, number of elements in @models on success (0 means + * libvirt accepts any CPU model). */ int virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, char ***models, diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 2337ce8..2fd3686 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1149,9 +1149,13 @@ cmdCPUModelNames(vshControl *ctl, const vshCmd *cmd) return false; } - for (i = 0; i < nmodels; i++) { - vshPrint(ctl, "%s\n", models[i]); - VIR_FREE(models[i]); + if (nmodels == 0) { + vshPrintExtra(ctl, "%s\n", _("all CPU models are accepted")); + } else { + for (i = 0; i < nmodels; i++) { + vshPrint(ctl, "%s\n", models[i]); + VIR_FREE(models[i]); + } } VIR_FREE(models); -- 2.10.0

cpuGetSubDriver already reports a useful error. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index d2b7ce3..fae3885 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -765,13 +765,8 @@ cpuGetModels(virArch arch, char ***models) VIR_DEBUG("arch=%s", virArchToString(arch)); - driver = cpuGetSubDriver(arch); - if (driver == NULL) { - virReportError(VIR_ERR_INVALID_ARG, - _("cannot find a driver for the architecture %s"), - virArchToString(arch)); + if (!(driver = cpuGetSubDriver(arch))) return -1; - } if (!driver->getModels) { if (models) -- 2.10.0

Listing all CPU models supported by QEMU in domain capabilities makes little sense when libvirt will refuse any model it doesn't know about. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - adapted to changes in previous patches - fixed compile failure after "util: Make virStringArrayHasString() const-correct" src/conf/domain_capabilities.c | 27 ++ src/conf/domain_capabilities.h | 2 + src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 10 +- tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml | 428 ---------------------- 5 files changed, 39 insertions(+), 429 deletions(-) diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index e47aa86..828fa70 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -169,6 +169,33 @@ virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old) } +virDomainCapsCPUModelsPtr +virDomainCapsCPUModelsFilter(virDomainCapsCPUModelsPtr old, + const char **models) +{ + virDomainCapsCPUModelsPtr cpuModels; + size_t i; + + if (!(cpuModels = virDomainCapsCPUModelsNew(0))) + return NULL; + + for (i = 0; i < old->nmodels; i++) { + if (models && !virStringArrayHasString(models, old->models[i].name)) + continue; + + if (virDomainCapsCPUModelsAdd(cpuModels, + old->models[i].name, -1) < 0) + goto error; + } + + return cpuModels; + + error: + virObjectUnref(cpuModels); + return NULL; +} + + int virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels, char **name) diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 149a13f..57f0161 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -156,6 +156,8 @@ virDomainCapsPtr virDomainCapsNew(const char *path, virDomainCapsCPUModelsPtr virDomainCapsCPUModelsNew(size_t nmodels); virDomainCapsCPUModelsPtr virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old); +virDomainCapsCPUModelsPtr virDomainCapsCPUModelsFilter(virDomainCapsCPUModelsPtr old, + const char **models); int virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels, char **name); int virDomainCapsCPUModelsAdd(virDomainCapsCPUModelsPtr cpuModels, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 46e805a..b773951 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -156,6 +156,7 @@ virDomainAuditVcpu; virDomainCapsCPUModelsAdd; virDomainCapsCPUModelsAddSteal; virDomainCapsCPUModelsCopy; +virDomainCapsCPUModelsFilter; virDomainCapsCPUModelsNew; virDomainCapsEnumClear; virDomainCapsEnumSet; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 87749c9..92b8b02 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4288,6 +4288,8 @@ virQEMUCapsFillDomainCPUCaps(virCapsPtr caps, virQEMUCapsPtr qemuCaps, virDomainCapsPtr domCaps) { + virDomainCapsCPUModelsPtr filtered = NULL; + char **models = NULL; if (domCaps->virttype == VIR_DOMAIN_VIRT_KVM && virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch)) @@ -4297,7 +4299,13 @@ virQEMUCapsFillDomainCPUCaps(virCapsPtr caps, domCaps->cpu.hostModel = virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch); - domCaps->cpu.custom = virObjectRef(qemuCaps->cpuDefinitions); + if (qemuCaps->cpuDefinitions && + cpuGetModels(domCaps->arch, &models) >= 0) { + filtered = virDomainCapsCPUModelsFilter(qemuCaps->cpuDefinitions, + (const char **) models); + virStringFreeList(models); + } + domCaps->cpu.custom = filtered; return 0; } diff --git a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml index a0aa811..d969274 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml @@ -22,436 +22,8 @@ <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'/> <mode name='custom' supported='yes'> - <model>default</model> - <model>ppc</model> - <model>ppc32</model> - <model>ppc64</model> - <model>970mp</model> - <model>970fx</model> - <model>970</model> - <model>POWER8NVL</model> <model>POWER8</model> - <model>POWER8E</model> - <model>POWER7+</model> <model>POWER7</model> - <model>POWER5gs</model> - <model>POWER5+</model> - <model>Apollo7PM</model> - <model>7457A</model> - <model>7447A</model> - <model>Apollo7</model> - <model>7457</model> - <model>Apollo6</model> - <model>7455</model> - <model>7445</model> - <model>7451</model> - <model>7441</model> - <model>Vger</model> - <model>7450</model> - <model>7448</model> - <model>Nitro</model> - <model>7410</model> - <model>G4</model> - <model>Max</model> - <model>7400</model> - <model>Goldfinger</model> - <model>755</model> - <model>745</model> - <model>LoneStar</model> - <model>750l</model> - <model>750gx</model> - <model>750fx</model> - <model>750cxe</model> - <model>750cx</model> - <model>750cl</model> - <model>Conan/Doyle</model> - <model>G3</model> - <model>Typhoon</model> - <model>750</model> - <model>Arthur</model> - <model>740</model> - <model>Mach5</model> - <model>Sirocco</model> - <model>604e</model> - <model>Goldeneye</model> - <model>603r</model> - <model>Vaillant</model> - <model>Stretch</model> - <model>603e</model> - <model>Vanilla</model> - <model>601v</model> - <model>601</model> - <model>MPC8560</model> - <model>MPC8555E</model> - <model>MPC8555</model> - <model>MPC8548E</model> - <model>MPC8548</model> - <model>MPC8547E</model> - <model>MPC8545E</model> - <model>MPC8545</model> - <model>MPC8544E</model> - <model>MPC8544</model> - <model>MPC8543E</model> - <model>MPC8543</model> - <model>MPC8541E</model> - <model>MPC8541</model> - <model>MPC8540</model> - <model>MPC8533E</model> - <model>MPC8533</model> - <model>e500v2</model> - <model>e500v1</model> - <model>e500</model> - <model>MPC8347EA</model> - <model>MPC8347E</model> - <model>MPC8347A</model> - <model>MPC8347</model> - <model>e300</model> - <model>e200</model> - <model>MPC8280</model> - <model>MPC8275</model> - <model>MPC8272</model> - <model>MPC8271</model> - <model>MPC8270</model> - <model>MPC8266_HiP4</model> - <model>MPC8266_HiP3</model> - <model>MPC8266</model> - <model>MPC8265_HiP4</model> - <model>MPC8265_HiP3</model> - <model>MPC8265</model> - <model>MPC8264_HiP4</model> - <model>MPC8264_HiP3</model> - <model>MPC8264</model> - <model>MPC8260_HiP4</model> - <model>MPC8260_HiP3</model> - <model>MPC8260</model> - <model>MPC8255_HiP4</model> - <model>MPC8255_HiP3</model> - <model>MPC8255</model> - <model>MPC8250_HiP4</model> - <model>MPC8250_HiP3</model> - <model>MPC8250</model> - <model>MPC8248</model> - <model>MPC8247</model> - <model>MPC8245</model> - <model>MPC8241</model> - <model>PowerQUICC-II</model> - <model>MPC82xx</model> - <model>MPC5200B</model> - <model>MPC5200</model> - <model>MPC52xx</model> - <model>MPC8240</model> - <model>440EP</model> - <model>x2vp50</model> - <model>x2vp7</model> - <model>405GPe</model> - <model>405GP</model> - <model>405CR</model> - <model>405</model> - <model>403</model> - <model>750cl_v1.0</model> - <model>750cxe_v2.1</model> - <model>7457A_v1.2</model> - <model>755_v2.7</model> - <model>MPC8347ET</model> - <model>MPC8545E_v20</model> - <model>750_v2.1</model> - <model>755_v2.2</model> - <model>745_v2.0</model> - <model>7455_v1.0</model> - <model>MPC8547E_v21</model> - <model>STB25</model> - <model>POWER8_v2.0</model> - <model>401G2</model> - <model>MPC8349A</model> - <model>750e</model> - <model>MPC8545_v21</model> - <model>MPC8548_v11</model> - <model>970fx_v2.0</model> - <model>750fx_v2.0</model> - <model>POWER8E_v2.1</model> - <model>Cobra</model> - <model>603p</model> - <model>7400_v2.7</model> - <model>MPC8378E</model> - <model>e500v2_v10</model> - <model>e500mc</model> - <model>603e7v1</model> - <model>970mp_v1.0</model> - <model>MPC8555E_v11</model> - <model>440-Xilinx-w-dfpu</model> - <model>740e</model> - <model>405CRc</model> - <model>7447A_v1.1</model> - <model>MPC8543_v11</model> - <model>MPC8533E_v10</model> - <model>MPC8540_v21</model> - <model>e500v2_v21</model> - <model>e300c1</model> - <model>7400_v2.2</model> - <model>970fx_v1.0</model> - <model>750gx_v1.2</model> - <model>750fx_v1.0</model> - <model>MPC8641</model> - <model>MPC8544E_v10</model> - <model>405D4</model> - <model>7457_v1.1</model> - <model>970fx_v3.0</model> - <model>604e_v2.2</model> - <model>755_v2.6</model> - <model>7410_v1.4</model> - <model>Npe4GS3</model> - <model>745_v2.4</model> - <model>750_v2.0</model> - <model>7445_v3.2</model> - <model>750l_v3.2</model> - <model>MPC8540_v10</model> - <model>750_v1.0</model> - <model>MPC8343A</model> - <model>MPC8378</model> - <model>G2HiP3</model> - <model>750cxe_v3.0</model> - <model>e500_v10</model> - <model>STB03</model> - <model>MPC8567</model> - <model>MPC8545_v20</model> - <model>MPC8548_v10</model> - <model>755_v1.1</model> - <model>603e7v</model> - <model>Npe405H2</model> - <model>750_v3.0</model> - <model>Npe405H</model> - <model>7400_v2.6</model> - <model>405GPa</model> - <model>MPC8548_v21</model> - <model>MPC8541E_v10</model> - <model>750l_v2.2</model> - <model>MPC8555E_v10</model> - <model>7457A_v1.1</model> - <model>e200z6</model> - <model>MPC8379E</model> - <model>e500v2_v20</model> - <model>MPC8347AP</model> - <model>401B2</model> - <model>MPC8349E</model> - <model>755_v2.1</model> - <model>MPC8543_v21</model> - <model>MPC8547E_v20</model> - <model>745_v2.8</model> - <model>7455_v3.4</model> - <model>7448_v1.1</model> - <model>740_v2.2</model> - <model>7400_v1.1</model> - <model>MPC8567E</model> - <model>7441_v2.10</model> - <model>603e_v1.4</model> - <model>G2leGP1</model> - <model>7451_v2.10</model> - <model>MPC8343E</model> - <model>750cx_v2.2</model> - <model>Npe405L</model> - <model>603e7</model> - <model>401A1</model> - <model>MPC8377</model> - <model>7448_v2.1</model> - <model>7441_v2.3</model> - <model>7400_v2.1</model> - <model>405CRb</model> - <model>604</model> - <model>MPC8540_v20</model> - <model>MPC8543_v10</model> - <model>7447A_v1.0</model> - <model>7445_v2.1</model> - <model>e500_v20</model> - <model>750gx_v1.1</model> - <model>MPC8543E_v11</model> - <model>750cxe_v2.4</model> - <model>MPC8548_v20</model> - <model>MPC8347AT</model> - <model>POWER8NVL_v1.0</model> - <model>7457A_v1.0</model> - <model>7457_v1.0</model> - <model>7450_v1.2</model> - <model>MPC8572</model> - <model>755_v2.5</model> - <model>7410_v1.3</model> - <model>745_v2.3</model> - <model>750l_v2.1</model> - <model>405GPR</model> - <model>755_v2.0</model> - <model>MPC8541_v11</model> - <model>401C2</model> - <model>e500v2_v30</model> - <model>7455_v3.3</model> - <model>405EZ</model> - <model>MPC8568E</model> - <model>755_v1.0</model> - <model>603e_v1.3</model> - <model>MPC8560_v10</model> - <model>MPC8560_v21</model> - <model>G2H4</model> - <model>MPC8533_v11</model> - <model>740_v3.1</model> - <model>e200z5</model> - <model>MPC8349</model> - <model>7400_v2.0</model> - <model>405CRa</model> - <model>MPC8543E_v10</model> - <model>MPC8543E_v21</model> - <model>750cxe_v2.3</model> - <model>MPC8543_v20</model> - <model>745_v2.7</model> - <model>403GC</model> - <model>e5500</model> - <model>7448_v1.0</model> - <model>MPC5200_v12</model> - <model>740_v2.1</model> - <model>745_v2.2</model> - <model>7400_v1.0</model> - <model>7410_v1.2</model> - <model>x2vp4</model> - <model>MPC8555_v11</model> - <model>MPC8541_v10</model> - <model>405LP</model> - <model>750fx_v2.3</model> - <model>405EP</model> - <model>601_v2</model> - <model>MPC8544_v11</model> - <model>401D2</model> - <model>MPC8572E</model> - <model>604e_v1.0</model> - <model>750cx_v2.1</model> - <model>MPC5200B_v21</model> - <model>750l_v3.0</model> - <model>e300c4</model> - <model>7448_v2.0</model> - <model>7450_v2.1</model> - <model>G2leGP</model> - <model>750cxe_v3.1b</model> - <model>7400_v2.9</model> - <model>G2GP</model> - <model>603</model> - <model>405GPd</model> - <model>MPC8548E_v11</model> - <model>603e7t</model> - <model>IOP480</model> - <model>750gx_v1.0</model> - <model>MPC8560_v20</model> - <model>405D2</model> - <model>750fl</model> - <model>750l_v2.0</model> - <model>x2vp20</model> - <model>e600</model> - <model>7450_v1.1</model> - <model>755_v2.4</model> - <model>7445_v1.0</model> - <model>G2LS</model> - <model>MPC8543E_v20</model> - <model>7447_v1.1</model> - <model>603e_v2.2</model> - <model>603e_v4</model> - <model>7455_v3.2</model> - <model>740_v2.0</model> - <model>MPC8347P</model> - <model>440EPb</model> - <model>MPC603</model> - <model>603e_v1.2</model> - <model>750fx_v2.2</model> - <model>740_v1.0</model> - <model>MPC8544_v10</model> - <model>601_v1</model> - <model>745_v1.1</model> - <model>POWER7+_v2.1</model> - <model>750cx_v2.0</model> - <model>MPC8347EAP</model> - <model>401E2</model> - <model>MPC8641D</model> - <model>e300c3</model> - <model>MPC8533_v10</model> - <model>7441_v2.1</model> - <model>740_v3.0</model> - <model>POWER5+_v2.1</model> - <model>602</model> - <model>MPC8548E_v10</model> - <model>G2leLS</model> - <model>MPC8343</model> - <model>750cx_v1.0</model> - <model>750cxe_v2.2</model> - <model>604e_v2.4</model> - <model>755_v2.8</model> - <model>MPC8548E_v21</model> - <model>745_v2.6</model> - <model>G2le</model> - <model>403GB</model> - <model>MPC8545E_v21</model> - <model>POWER7_v2.3</model> - <model>750_v2.2</model> - <model>7450_v1.0</model> - <model>MPC5200_v11</model> - <model>755_v2.3</model> - <model>MPC8347EP</model> - <model>7410_v1.1</model> - <model>750gl</model> - <model>403GCX</model> - <model>750p</model> - <model>745_v2.1</model> - <model>7445_v3.4</model> - <model>G2</model> - <model>MPC8555_v10</model> - <model>MPC8347T</model> - <model>603e_v3</model> - <model>970_v2.2</model> - <model>440-Xilinx</model> - <model>740p</model> - <model>MPC5200B_v20</model> - <model>440EPX</model> - <model>603e_v1.1</model> - <model>7451_v2.3</model> - <model>7450_v2.0</model> - <model>7400_v2.8</model> - <model>7455_v2.1</model> - <model>405GPc</model> - <model>MPC8347EAT</model> - <model>970mp_v1.1</model> - <model>603e7v2</model> - <model>604r</model> - <model>7447A_v1.2</model> - <model>MPC8533E_v11</model> - <model>e500v2_v22</model> - <model>401F2</model> - <model>MPC8343EA</model> - <model>7457_v1.2</model> - <model>970fx_v3.1</model> - <model>7447_v1.0</model> - <model>745_v2.5</model> - <model>MPC8548E_v20</model> - <model>MPC8610</model> - <model>403GA</model> - <model>750cxe_v2.4b</model> - <model>MPC5200_v10</model> - <model>7410_v1.0</model> - <model>G2leGP3</model> - <model>603e_v4.1</model> - <model>7445_v3.3</model> - <model>440EPa</model> - <model>970fx_v2.1</model> - <model>MPC8377E</model> - <model>750fx_v2.1</model> - <model>601_v0</model> - <model>STB04</model> - <model>745_v1.0</model> - <model>G2HiP4</model> - <model>750cl_v2.0</model> - <model>750cxr</model> - <model>MPC8349EA</model> - <model>750cxe_v3.1</model> - <model>401</model> - <model>MPC8379</model> - <model>MPC8568</model> - <model>e300c2</model> - <model>750_v3.1</model> - <model>MPC8544E_v11</model> - <model>405GPb</model> - <model>MPC8541E_v11</model> </mode> </cpu> <devices> -- 2.10.0

In case a hypervisor is able to tell us a list of supported CPU models and whether each CPU models can be used on the current host, we can propagate this to domain capabilities. This is a better alternative to calling virConnectCompareCPU for each supported CPU model. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - adapted to changes in previous patches - s/says/indicates/ - models are not grouped by usability anymore docs/formatdomaincaps.html.in | 10 ++-- docs/schemas/domaincaps.rng | 7 +++ src/conf/domain_capabilities.c | 28 +++++++--- src/conf/domain_capabilities.h | 16 +++++- src/libvirt_private.syms | 2 + src/qemu/qemu_capabilities.c | 15 ++++-- tests/domaincapsschemadata/full.xml | 6 +-- tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml | 48 ++++++++--------- .../qemu_2.6.0-gicv2-virt.aarch64.xml | 60 +++++++++++----------- .../qemu_2.6.0-gicv3-virt.aarch64.xml | 60 +++++++++++----------- tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml | 60 +++++++++++----------- tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml | 4 +- tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml | 56 ++++++++++---------- tests/domaincapstest.c | 9 ++-- 14 files changed, 213 insertions(+), 168 deletions(-) diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in index ce43658..045ba93 100644 --- a/docs/formatdomaincaps.html.in +++ b/docs/formatdomaincaps.html.in @@ -156,9 +156,9 @@ <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'/> <mode name='custom' supported='yes'> - <model>Broadwell</model> - <model>Broadwell-noTSX</model> - <model>Haswell</model> + <model usable='no'>Broadwell</model> + <model usable='yes'>Broadwell-noTSX</model> + <model usable='no'>Haswell</model> ... </mode> </cpu> @@ -183,6 +183,10 @@ <dd> The <code>mode</code> element contains a list of supported CPU models, each described by a dedicated <code>model</code> element. + The <code>usable</code> attribute specifies whether the model can + be used on the host. A special value <code>unknown</code> indicates + libvirt does not have enough information to provide the usability + data. </dd> </dl> diff --git a/docs/schemas/domaincaps.rng b/docs/schemas/domaincaps.rng index 9f3d225..5a605a7 100644 --- a/docs/schemas/domaincaps.rng +++ b/docs/schemas/domaincaps.rng @@ -105,6 +105,13 @@ <ref name='supported'/> <zeroOrMore> <element name='model'> + <attribute name='usable'> + <choice> + <value>yes</value> + <value>no</value> + <value>unknown</value> + </choice> + </attribute> <text/> </element> </zeroOrMore> diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 828fa70..9ec416e 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -29,6 +29,9 @@ #define VIR_FROM_THIS VIR_FROM_CAPABILITIES +VIR_ENUM_IMPL(virDomainCapsCPUUsable, VIR_DOMCAPS_CPU_USABLE_LAST, + "unknown", "yes", "no"); + static virClassPtr virDomainCapsClass; static virClassPtr virDomainCapsCPUModelsClass; @@ -157,7 +160,9 @@ virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old) return NULL; for (i = 0; i < old->nmodels; i++) { - if (virDomainCapsCPUModelsAdd(cpuModels, old->models[i].name, -1) < 0) + if (virDomainCapsCPUModelsAdd(cpuModels, + old->models[i].name, -1, + old->models[i].usable) < 0) goto error; } @@ -184,7 +189,8 @@ virDomainCapsCPUModelsFilter(virDomainCapsCPUModelsPtr old, continue; if (virDomainCapsCPUModelsAdd(cpuModels, - old->models[i].name, -1) < 0) + old->models[i].name, -1, + old->models[i].usable) < 0) goto error; } @@ -198,13 +204,16 @@ virDomainCapsCPUModelsFilter(virDomainCapsCPUModelsPtr old, int virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels, - char **name) + char **name, + virDomainCapsCPUUsable usable) { if (VIR_RESIZE_N(cpuModels->models, cpuModels->nmodels_max, cpuModels->nmodels, 1) < 0) return -1; - VIR_STEAL_PTR(cpuModels->models[cpuModels->nmodels++].name, *name); + cpuModels->models[cpuModels->nmodels].usable = usable; + VIR_STEAL_PTR(cpuModels->models[cpuModels->nmodels].name, *name); + cpuModels->nmodels++; return 0; } @@ -212,14 +221,15 @@ virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels, int virDomainCapsCPUModelsAdd(virDomainCapsCPUModelsPtr cpuModels, const char *name, - ssize_t nameLen) + ssize_t nameLen, + virDomainCapsCPUUsable usable) { char *copy = NULL; if (VIR_STRNDUP(copy, name, nameLen) < 0) goto error; - if (virDomainCapsCPUModelsAddSteal(cpuModels, ©) < 0) + if (virDomainCapsCPUModelsAddSteal(cpuModels, ©, usable) < 0) goto error; return 0; @@ -372,8 +382,10 @@ virDomainCapsCPUCustomFormat(virBufferPtr buf, virBufferAdjustIndent(buf, 2); for (i = 0; i < custom->nmodels; i++) { - virBufferAsprintf(buf, "<model>%s</model>\n", - custom->models[i].name); + virDomainCapsCPUModelPtr model = custom->models + i; + virBufferAsprintf(buf, "<model usable='%s'>%s</model>\n", + virDomainCapsCPUUsableTypeToString(model->usable), + model->name); } virBufferAdjustIndent(buf, -2); diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 57f0161..3ec05dc 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -102,10 +102,20 @@ struct _virDomainCapsFeatureGIC { virDomainCapsEnum version; /* Info about virGICVersion */ }; +typedef enum { + VIR_DOMCAPS_CPU_USABLE_UNKNOWN, + VIR_DOMCAPS_CPU_USABLE_YES, + VIR_DOMCAPS_CPU_USABLE_NO, + + VIR_DOMCAPS_CPU_USABLE_LAST +} virDomainCapsCPUUsable; +VIR_ENUM_DECL(virDomainCapsCPUUsable); + typedef struct _virDomainCapsCPUModel virDomainCapsCPUModel; typedef virDomainCapsCPUModel *virDomainCapsCPUModelPtr; struct _virDomainCapsCPUModel { char *name; + virDomainCapsCPUUsable usable; }; typedef struct _virDomainCapsCPUModels virDomainCapsCPUModels; @@ -159,10 +169,12 @@ virDomainCapsCPUModelsPtr virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr o virDomainCapsCPUModelsPtr virDomainCapsCPUModelsFilter(virDomainCapsCPUModelsPtr old, const char **models); int virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels, - char **name); + char **name, + virDomainCapsCPUUsable usable); int virDomainCapsCPUModelsAdd(virDomainCapsCPUModelsPtr cpuModels, const char *name, - ssize_t nameLen); + ssize_t nameLen, + virDomainCapsCPUUsable usable); # define VIR_DOMAIN_CAPS_ENUM_SET(capsEnum, ...) \ do { \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b773951..f954453 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -158,6 +158,8 @@ virDomainCapsCPUModelsAddSteal; virDomainCapsCPUModelsCopy; virDomainCapsCPUModelsFilter; virDomainCapsCPUModelsNew; +virDomainCapsCPUUsableTypeFromString; +virDomainCapsCPUUsableTypeToString; virDomainCapsEnumClear; virDomainCapsEnumSet; virDomainCapsFormat; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 92b8b02..86e40ba 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -671,7 +671,8 @@ virQEMUCapsParseX86Models(const char *output, len -= 2; } - if (virDomainCapsCPUModelsAdd(cpus, p, len) < 0) + if (virDomainCapsCPUModelsAdd(cpus, p, len, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) goto error; } while ((p = next)); @@ -719,7 +720,8 @@ virQEMUCapsParsePPCModels(const char *output, if (*p == '\n') continue; - if (virDomainCapsCPUModelsAdd(cpus, p, t - p - 1) < 0) + if (virDomainCapsCPUModelsAdd(cpus, p, t - p - 1, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) goto error; } while ((p = next)); @@ -2306,7 +2308,8 @@ virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps, return -1; for (i = 0; i < count; i++) { - if (virDomainCapsCPUModelsAdd(qemuCaps->cpuDefinitions, name[i], -1) < 0) + if (virDomainCapsCPUModelsAdd(qemuCaps->cpuDefinitions, name[i], -1, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) return -1; } @@ -2674,7 +2677,8 @@ virQEMUCapsProbeQMPCPUDefinitions(virQEMUCapsPtr qemuCaps, for (i = 0; i < ncpus; i++) { if (virDomainCapsCPUModelsAddSteal(qemuCaps->cpuDefinitions, - &cpus[i]->name) < 0) + &cpus[i]->name, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) goto cleanup; } @@ -3041,7 +3045,8 @@ virQEMUCapsLoadCache(virQEMUCapsPtr qemuCaps, const char *filename, } if (virDomainCapsCPUModelsAddSteal(qemuCaps->cpuDefinitions, - &str) < 0) + &str, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0) goto cleanup; } } diff --git a/tests/domaincapsschemadata/full.xml b/tests/domaincapsschemadata/full.xml index 80fd1f0..b75e86c 100644 --- a/tests/domaincapsschemadata/full.xml +++ b/tests/domaincapsschemadata/full.xml @@ -23,9 +23,9 @@ <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'/> <mode name='custom' supported='yes'> - <model>Model1</model> - <model>Model2</model> - <model>Model3</model> + <model usable='unknown'>Model1</model> + <model usable='no'>Model2</model> + <model usable='yes'>Model3</model> </mode> </cpu> <devices> diff --git a/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml b/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml index 4ee2f95..2b17dd0 100644 --- a/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml +++ b/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml @@ -22,30 +22,30 @@ <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'/> <mode name='custom' supported='yes'> - <model>Opteron_G5</model> - <model>Opteron_G4</model> - <model>Opteron_G3</model> - <model>Opteron_G2</model> - <model>Opteron_G1</model> - <model>Haswell</model> - <model>SandyBridge</model> - <model>Westmere</model> - <model>Nehalem</model> - <model>Penryn</model> - <model>Conroe</model> - <model>n270</model> - <model>athlon</model> - <model>pentium3</model> - <model>pentium2</model> - <model>pentium</model> - <model>486</model> - <model>coreduo</model> - <model>kvm32</model> - <model>qemu32</model> - <model>kvm64</model> - <model>core2duo</model> - <model>phenom</model> - <model>qemu64</model> + <model usable='unknown'>Opteron_G5</model> + <model usable='unknown'>Opteron_G4</model> + <model usable='unknown'>Opteron_G3</model> + <model usable='unknown'>Opteron_G2</model> + <model usable='unknown'>Opteron_G1</model> + <model usable='unknown'>Haswell</model> + <model usable='unknown'>SandyBridge</model> + <model usable='unknown'>Westmere</model> + <model usable='unknown'>Nehalem</model> + <model usable='unknown'>Penryn</model> + <model usable='unknown'>Conroe</model> + <model usable='unknown'>n270</model> + <model usable='unknown'>athlon</model> + <model usable='unknown'>pentium3</model> + <model usable='unknown'>pentium2</model> + <model usable='unknown'>pentium</model> + <model usable='unknown'>486</model> + <model usable='unknown'>coreduo</model> + <model usable='unknown'>kvm32</model> + <model usable='unknown'>qemu32</model> + <model usable='unknown'>kvm64</model> + <model usable='unknown'>core2duo</model> + <model usable='unknown'>phenom</model> + <model usable='unknown'>qemu64</model> </mode> </cpu> <devices> diff --git a/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml index 9e96f47..8a54f9e 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml @@ -22,36 +22,36 @@ <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'/> <mode name='custom' supported='yes'> - <model>pxa262</model> - <model>pxa270-a0</model> - <model>arm1136</model> - <model>cortex-a15</model> - <model>pxa260</model> - <model>arm1136-r2</model> - <model>pxa261</model> - <model>pxa255</model> - <model>arm926</model> - <model>arm11mpcore</model> - <model>pxa250</model> - <model>ti925t</model> - <model>cortex-a57</model> - <model>sa1110</model> - <model>arm1176</model> - <model>cortex-a53</model> - <model>sa1100</model> - <model>pxa270-c5</model> - <model>cortex-a9</model> - <model>cortex-a8</model> - <model>pxa270-c0</model> - <model>arm1026</model> - <model>pxa270-b1</model> - <model>cortex-m3</model> - <model>cortex-m4</model> - <model>pxa270-b0</model> - <model>arm946</model> - <model>cortex-r5</model> - <model>pxa270-a1</model> - <model>pxa270</model> + <model usable='unknown'>pxa262</model> + <model usable='unknown'>pxa270-a0</model> + <model usable='unknown'>arm1136</model> + <model usable='unknown'>cortex-a15</model> + <model usable='unknown'>pxa260</model> + <model usable='unknown'>arm1136-r2</model> + <model usable='unknown'>pxa261</model> + <model usable='unknown'>pxa255</model> + <model usable='unknown'>arm926</model> + <model usable='unknown'>arm11mpcore</model> + <model usable='unknown'>pxa250</model> + <model usable='unknown'>ti925t</model> + <model usable='unknown'>cortex-a57</model> + <model usable='unknown'>sa1110</model> + <model usable='unknown'>arm1176</model> + <model usable='unknown'>cortex-a53</model> + <model usable='unknown'>sa1100</model> + <model usable='unknown'>pxa270-c5</model> + <model usable='unknown'>cortex-a9</model> + <model usable='unknown'>cortex-a8</model> + <model usable='unknown'>pxa270-c0</model> + <model usable='unknown'>arm1026</model> + <model usable='unknown'>pxa270-b1</model> + <model usable='unknown'>cortex-m3</model> + <model usable='unknown'>cortex-m4</model> + <model usable='unknown'>pxa270-b0</model> + <model usable='unknown'>arm946</model> + <model usable='unknown'>cortex-r5</model> + <model usable='unknown'>pxa270-a1</model> + <model usable='unknown'>pxa270</model> </mode> </cpu> <devices> diff --git a/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml index c081b35..8d8087f 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml @@ -22,36 +22,36 @@ <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'/> <mode name='custom' supported='yes'> - <model>pxa262</model> - <model>pxa270-a0</model> - <model>arm1136</model> - <model>cortex-a15</model> - <model>pxa260</model> - <model>arm1136-r2</model> - <model>pxa261</model> - <model>pxa255</model> - <model>arm926</model> - <model>arm11mpcore</model> - <model>pxa250</model> - <model>ti925t</model> - <model>cortex-a57</model> - <model>sa1110</model> - <model>arm1176</model> - <model>cortex-a53</model> - <model>sa1100</model> - <model>pxa270-c5</model> - <model>cortex-a9</model> - <model>cortex-a8</model> - <model>pxa270-c0</model> - <model>arm1026</model> - <model>pxa270-b1</model> - <model>cortex-m3</model> - <model>cortex-m4</model> - <model>pxa270-b0</model> - <model>arm946</model> - <model>cortex-r5</model> - <model>pxa270-a1</model> - <model>pxa270</model> + <model usable='unknown'>pxa262</model> + <model usable='unknown'>pxa270-a0</model> + <model usable='unknown'>arm1136</model> + <model usable='unknown'>cortex-a15</model> + <model usable='unknown'>pxa260</model> + <model usable='unknown'>arm1136-r2</model> + <model usable='unknown'>pxa261</model> + <model usable='unknown'>pxa255</model> + <model usable='unknown'>arm926</model> + <model usable='unknown'>arm11mpcore</model> + <model usable='unknown'>pxa250</model> + <model usable='unknown'>ti925t</model> + <model usable='unknown'>cortex-a57</model> + <model usable='unknown'>sa1110</model> + <model usable='unknown'>arm1176</model> + <model usable='unknown'>cortex-a53</model> + <model usable='unknown'>sa1100</model> + <model usable='unknown'>pxa270-c5</model> + <model usable='unknown'>cortex-a9</model> + <model usable='unknown'>cortex-a8</model> + <model usable='unknown'>pxa270-c0</model> + <model usable='unknown'>arm1026</model> + <model usable='unknown'>pxa270-b1</model> + <model usable='unknown'>cortex-m3</model> + <model usable='unknown'>cortex-m4</model> + <model usable='unknown'>pxa270-b0</model> + <model usable='unknown'>arm946</model> + <model usable='unknown'>cortex-r5</model> + <model usable='unknown'>pxa270-a1</model> + <model usable='unknown'>pxa270</model> </mode> </cpu> <devices> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml index 811d2b7..83c03db 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml @@ -22,36 +22,36 @@ <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'/> <mode name='custom' supported='yes'> - <model>pxa262</model> - <model>pxa270-a0</model> - <model>arm1136</model> - <model>cortex-a15</model> - <model>pxa260</model> - <model>arm1136-r2</model> - <model>pxa261</model> - <model>pxa255</model> - <model>arm926</model> - <model>arm11mpcore</model> - <model>pxa250</model> - <model>ti925t</model> - <model>cortex-a57</model> - <model>sa1110</model> - <model>arm1176</model> - <model>cortex-a53</model> - <model>sa1100</model> - <model>pxa270-c5</model> - <model>cortex-a9</model> - <model>cortex-a8</model> - <model>pxa270-c0</model> - <model>arm1026</model> - <model>pxa270-b1</model> - <model>cortex-m3</model> - <model>cortex-m4</model> - <model>pxa270-b0</model> - <model>arm946</model> - <model>cortex-r5</model> - <model>pxa270-a1</model> - <model>pxa270</model> + <model usable='unknown'>pxa262</model> + <model usable='unknown'>pxa270-a0</model> + <model usable='unknown'>arm1136</model> + <model usable='unknown'>cortex-a15</model> + <model usable='unknown'>pxa260</model> + <model usable='unknown'>arm1136-r2</model> + <model usable='unknown'>pxa261</model> + <model usable='unknown'>pxa255</model> + <model usable='unknown'>arm926</model> + <model usable='unknown'>arm11mpcore</model> + <model usable='unknown'>pxa250</model> + <model usable='unknown'>ti925t</model> + <model usable='unknown'>cortex-a57</model> + <model usable='unknown'>sa1110</model> + <model usable='unknown'>arm1176</model> + <model usable='unknown'>cortex-a53</model> + <model usable='unknown'>sa1100</model> + <model usable='unknown'>pxa270-c5</model> + <model usable='unknown'>cortex-a9</model> + <model usable='unknown'>cortex-a8</model> + <model usable='unknown'>pxa270-c0</model> + <model usable='unknown'>arm1026</model> + <model usable='unknown'>pxa270-b1</model> + <model usable='unknown'>cortex-m3</model> + <model usable='unknown'>cortex-m4</model> + <model usable='unknown'>pxa270-b0</model> + <model usable='unknown'>arm946</model> + <model usable='unknown'>cortex-r5</model> + <model usable='unknown'>pxa270-a1</model> + <model usable='unknown'>pxa270</model> </mode> </cpu> <devices> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml index d969274..14a087b 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml @@ -22,8 +22,8 @@ <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'/> <mode name='custom' supported='yes'> - <model>POWER8</model> - <model>POWER7</model> + <model usable='unknown'>POWER8</model> + <model usable='unknown'>POWER7</model> </mode> </cpu> <devices> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml b/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml index 80101a4..4294c64 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml @@ -22,34 +22,34 @@ <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'/> <mode name='custom' supported='yes'> - <model>Opteron_G5</model> - <model>Opteron_G4</model> - <model>Opteron_G3</model> - <model>Opteron_G2</model> - <model>Opteron_G1</model> - <model>Broadwell</model> - <model>Broadwell-noTSX</model> - <model>Haswell</model> - <model>Haswell-noTSX</model> - <model>IvyBridge</model> - <model>SandyBridge</model> - <model>Westmere</model> - <model>Nehalem</model> - <model>Penryn</model> - <model>Conroe</model> - <model>n270</model> - <model>athlon</model> - <model>pentium3</model> - <model>pentium2</model> - <model>pentium</model> - <model>486</model> - <model>coreduo</model> - <model>kvm32</model> - <model>qemu32</model> - <model>kvm64</model> - <model>core2duo</model> - <model>phenom</model> - <model>qemu64</model> + <model usable='unknown'>Opteron_G5</model> + <model usable='unknown'>Opteron_G4</model> + <model usable='unknown'>Opteron_G3</model> + <model usable='unknown'>Opteron_G2</model> + <model usable='unknown'>Opteron_G1</model> + <model usable='unknown'>Broadwell</model> + <model usable='unknown'>Broadwell-noTSX</model> + <model usable='unknown'>Haswell</model> + <model usable='unknown'>Haswell-noTSX</model> + <model usable='unknown'>IvyBridge</model> + <model usable='unknown'>SandyBridge</model> + <model usable='unknown'>Westmere</model> + <model usable='unknown'>Nehalem</model> + <model usable='unknown'>Penryn</model> + <model usable='unknown'>Conroe</model> + <model usable='unknown'>n270</model> + <model usable='unknown'>athlon</model> + <model usable='unknown'>pentium3</model> + <model usable='unknown'>pentium2</model> + <model usable='unknown'>pentium</model> + <model usable='unknown'>486</model> + <model usable='unknown'>coreduo</model> + <model usable='unknown'>kvm32</model> + <model usable='unknown'>qemu32</model> + <model usable='unknown'>kvm64</model> + <model usable='unknown'>core2duo</model> + <model usable='unknown'>phenom</model> + <model usable='unknown'>qemu64</model> </mode> </cpu> <devices> diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c index 10b7452..511066d 100644 --- a/tests/domaincapstest.c +++ b/tests/domaincapstest.c @@ -81,9 +81,12 @@ fillAllCaps(virDomainCapsPtr domCaps) cpu->hostPassthrough = true; cpu->hostModel = true; if (!(cpu->custom = virDomainCapsCPUModelsNew(3)) || - virDomainCapsCPUModelsAdd(cpu->custom, "Model1", -1) < 0 || - virDomainCapsCPUModelsAdd(cpu->custom, "Model2", -1) < 0 || - virDomainCapsCPUModelsAdd(cpu->custom, "Model3", -1) < 0) + virDomainCapsCPUModelsAdd(cpu->custom, "Model1", -1, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0 || + virDomainCapsCPUModelsAdd(cpu->custom, "Model2", -1, + VIR_DOMCAPS_CPU_USABLE_NO) < 0 || + virDomainCapsCPUModelsAdd(cpu->custom, "Model3", -1, + VIR_DOMCAPS_CPU_USABLE_YES) < 0) return -1; disk->supported = true; -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change docs/schemas/cputypes.rng | 135 ++++++++++++++++++++++++++++++++++++++++++ docs/schemas/domaincommon.rng | 129 +--------------------------------------- 2 files changed, 136 insertions(+), 128 deletions(-) create mode 100644 docs/schemas/cputypes.rng diff --git a/docs/schemas/cputypes.rng b/docs/schemas/cputypes.rng new file mode 100644 index 0000000..7cc9dd3 --- /dev/null +++ b/docs/schemas/cputypes.rng @@ -0,0 +1,135 @@ +<?xml version="1.0"?> +<!-- CPU-related definitions used in multiple grammars --> +<grammar xmlns="http://relaxng.org/ns/structure/1.0" + datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> + + <define name="cpuMode"> + <attribute name="mode"> + <choice> + <value>custom</value> + <value>host-model</value> + <value>host-passthrough</value> + </choice> + </attribute> + </define> + + <define name="cpuMatch"> + <attribute name="match"> + <choice> + <value>minimum</value> + <value>exact</value> + <value>strict</value> + </choice> + </attribute> + </define> + + <define name="cpuModel"> + <element name="model"> + <optional> + <attribute name="fallback"> + <choice> + <value>allow</value> + <value>forbid</value> + </choice> + </attribute> + </optional> + <optional> + <attribute name="vendor_id"> + <data type="string"> + <param name='pattern'>[^,]{12}</param> + </data> + </attribute> + </optional> + <choice> + <text/> + <empty/> + </choice> + </element> + </define> + + <define name="cpuVendor"> + <element name="vendor"> + <text/> + </element> + </define> + + <define name="cpuFeature"> + <element name="feature"> + <attribute name="policy"> + <choice> + <value>force</value> + <value>require</value> + <value>optional</value> + <value>disable</value> + <value>forbid</value> + </choice> + </attribute> + <attribute name="name"> + <ref name="featureName"/> + </attribute> + <empty/> + </element> + </define> + + <define name="cpuTopology"> + <element name="topology"> + <attribute name="sockets"> + <ref name="positiveInteger"/> + </attribute> + <attribute name="cores"> + <ref name="positiveInteger"/> + </attribute> + <attribute name="threads"> + <ref name="positiveInteger"/> + </attribute> + </element> + </define> + + <define name="cpuNuma"> + <element name="numa"> + <oneOrMore> + <ref name="numaCell"/> + </oneOrMore> + </element> + </define> + + <define name="numaCell"> + <element name="cell"> + <optional> + <attribute name="id"> + <ref name="unsignedInt"/> + </attribute> + </optional> + <attribute name="cpus"> + <ref name="cpuset"/> + </attribute> + <attribute name="memory"> + <ref name="memoryKB"/> + </attribute> + <optional> + <attribute name="unit"> + <ref name="unit"/> + </attribute> + </optional> + <optional> + <attribute name="memAccess"> + <choice> + <value>shared</value> + <value>private</value> + </choice> + </attribute> + </optional> + </element> + </define> + + <!-- Memory as an attribute is in KiB, no way to express a unit --> + <define name="memoryKB"> + <data type="unsignedLong"/> + </define> + <define name="featureName"> + <data type="string"> + <param name='pattern'>[a-zA-Z0-9\-_\.]+</param> + </data> + </define> + +</grammar> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 751d914..95c7882 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4,6 +4,7 @@ <include href='basictypes.rng'/> <include href='storagecommon.rng'/> <include href='networkcommon.rng'/> + <include href='cputypes.rng'/> <!-- description and title element, may be placed anywhere under the root @@ -4414,125 +4415,6 @@ </element> </define> - <define name="cpuMode"> - <attribute name="mode"> - <choice> - <value>custom</value> - <value>host-model</value> - <value>host-passthrough</value> - </choice> - </attribute> - </define> - - <define name="cpuMatch"> - <attribute name="match"> - <choice> - <value>minimum</value> - <value>exact</value> - <value>strict</value> - </choice> - </attribute> - </define> - - <define name="cpuModel"> - <element name="model"> - <optional> - <attribute name="fallback"> - <choice> - <value>allow</value> - <value>forbid</value> - </choice> - </attribute> - </optional> - <optional> - <attribute name="vendor_id"> - <data type="string"> - <param name='pattern'>[^,]{12}</param> - </data> - </attribute> - </optional> - <choice> - <text/> - <empty/> - </choice> - </element> - </define> - - <define name="cpuVendor"> - <element name="vendor"> - <text/> - </element> - </define> - - <define name="cpuFeature"> - <element name="feature"> - <attribute name="policy"> - <choice> - <value>force</value> - <value>require</value> - <value>optional</value> - <value>disable</value> - <value>forbid</value> - </choice> - </attribute> - <attribute name="name"> - <ref name="featureName"/> - </attribute> - <empty/> - </element> - </define> - - <define name="cpuTopology"> - <element name="topology"> - <attribute name="sockets"> - <ref name="positiveInteger"/> - </attribute> - <attribute name="cores"> - <ref name="positiveInteger"/> - </attribute> - <attribute name="threads"> - <ref name="positiveInteger"/> - </attribute> - </element> - </define> - - <define name="cpuNuma"> - <element name="numa"> - <oneOrMore> - <ref name="numaCell"/> - </oneOrMore> - </element> - </define> - - <define name="numaCell"> - <element name="cell"> - <optional> - <attribute name="id"> - <ref name="unsignedInt"/> - </attribute> - </optional> - <attribute name="cpus"> - <ref name="cpuset"/> - </attribute> - <attribute name="memory"> - <ref name="memoryKB"/> - </attribute> - <optional> - <attribute name="unit"> - <ref name="unit"/> - </attribute> - </optional> - <optional> - <attribute name="memAccess"> - <choice> - <value>shared</value> - <value>private</value> - </choice> - </attribute> - </optional> - </element> - </define> - <!-- System information specification: Placeholder for system specific informations likes the ones @@ -5477,10 +5359,6 @@ <param name="maxInclusive">1000</param> </data> </define> - <!-- Memory as an attribute is in KiB, no way to express a unit --> - <define name="memoryKB"> - <data type="unsignedLong"/> - </define> <define name="domainName"> <data type="string"> <!-- Use literal newline instead of \n for bug in libxml2 2.7.6 --> @@ -5564,11 +5442,6 @@ <param name="pattern">[0-9]{1,20}</param> </data> </define> - <define name="featureName"> - <data type="string"> - <param name='pattern'>[a-zA-Z0-9\-_\.]+</param> - </data> - </define> <define name="timeDelta"> <data type="string"> <param name="pattern">(-|\+)?[0-9]+</param> -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - adapted to changes in previous patches - fix build after rebase src/qemu/qemu_capabilities.c | 25 +++++++++++++++---------- src/qemu/qemu_capabilities.h | 6 ++++-- src/qemu/qemu_capspriv.h | 3 ++- src/qemu/qemu_domain.c | 18 +++++++++++------- src/qemu/qemu_driver.c | 9 ++++++--- src/qemu/qemu_process.c | 14 +++++++++++--- tests/qemucapsprobe.c | 2 +- 7 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 86e40ba..3aa348c 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -843,7 +843,7 @@ virQEMUCapsInitGuest(virCapsPtr caps, /* Ignore binary if extracting version info fails */ if (binary) { - if (!(qemubinCaps = virQEMUCapsCacheLookup(cache, binary))) { + if (!(qemubinCaps = virQEMUCapsCacheLookup(caps, cache, binary))) { virResetLastError(); VIR_FREE(binary); } @@ -883,7 +883,7 @@ virQEMUCapsInitGuest(virCapsPtr caps, if (!kvmbin) continue; - if (!(kvmbinCaps = virQEMUCapsCacheLookup(cache, kvmbin))) { + if (!(kvmbinCaps = virQEMUCapsCacheLookup(caps, cache, kvmbin))) { virResetLastError(); VIR_FREE(kvmbin); continue; @@ -2047,7 +2047,7 @@ int virQEMUCapsGetDefaultVersion(virCapsPtr caps, return -1; } - qemucaps = virQEMUCapsCacheLookup(capsCache, capsdata->emulator); + qemucaps = virQEMUCapsCacheLookup(caps, capsCache, capsdata->emulator); VIR_FREE(capsdata); if (!qemucaps) return -1; @@ -3871,7 +3871,8 @@ virQEMUCapsLogProbeFailure(const char *binary) virQEMUCapsPtr -virQEMUCapsNewForBinaryInternal(const char *binary, +virQEMUCapsNewForBinaryInternal(virCapsPtr caps ATTRIBUTE_UNUSED, + const char *binary, const char *libDir, const char *cacheDir, uid_t runUid, @@ -3949,13 +3950,14 @@ virQEMUCapsNewForBinaryInternal(const char *binary, } static virQEMUCapsPtr -virQEMUCapsNewForBinary(const char *binary, +virQEMUCapsNewForBinary(virCapsPtr caps, + const char *binary, const char *libDir, const char *cacheDir, uid_t runUid, gid_t runGid) { - return virQEMUCapsNewForBinaryInternal(binary, libDir, cacheDir, + return virQEMUCapsNewForBinaryInternal(caps, binary, libDir, cacheDir, runUid, runGid, false); } @@ -4050,7 +4052,9 @@ virQEMUCapsCacheNew(const char *libDir, const char *qemuTestCapsName; virQEMUCapsPtr -virQEMUCapsCacheLookup(virQEMUCapsCachePtr cache, const char *binary) +virQEMUCapsCacheLookup(virCapsPtr caps, + virQEMUCapsCachePtr cache, + const char *binary) { virQEMUCapsPtr ret = NULL; @@ -4070,7 +4074,7 @@ virQEMUCapsCacheLookup(virQEMUCapsCachePtr cache, const char *binary) if (!ret) { VIR_DEBUG("Creating capabilities for %s", binary); - ret = virQEMUCapsNewForBinary(binary, cache->libDir, + ret = virQEMUCapsNewForBinary(caps, binary, cache->libDir, cache->cacheDir, cache->runUid, cache->runGid); if (ret) { @@ -4090,11 +4094,12 @@ virQEMUCapsCacheLookup(virQEMUCapsCachePtr cache, const char *binary) virQEMUCapsPtr -virQEMUCapsCacheLookupCopy(virQEMUCapsCachePtr cache, +virQEMUCapsCacheLookupCopy(virCapsPtr caps, + virQEMUCapsCachePtr cache, const char *binary, const char *machineType) { - virQEMUCapsPtr qemuCaps = virQEMUCapsCacheLookup(cache, binary); + virQEMUCapsPtr qemuCaps = virQEMUCapsCacheLookup(caps, cache, binary); virQEMUCapsPtr ret; if (!qemuCaps) diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index dcd358a..c05adfd 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -452,9 +452,11 @@ void virQEMUCapsSetGICCapabilities(virQEMUCapsPtr qemuCaps, virQEMUCapsCachePtr virQEMUCapsCacheNew(const char *libDir, const char *cacheDir, uid_t uid, gid_t gid); -virQEMUCapsPtr virQEMUCapsCacheLookup(virQEMUCapsCachePtr cache, +virQEMUCapsPtr virQEMUCapsCacheLookup(virCapsPtr caps, + virQEMUCapsCachePtr cache, const char *binary); -virQEMUCapsPtr virQEMUCapsCacheLookupCopy(virQEMUCapsCachePtr cache, +virQEMUCapsPtr virQEMUCapsCacheLookupCopy(virCapsPtr caps, + virQEMUCapsCachePtr cache, const char *binary, const char *machineType); virQEMUCapsPtr virQEMUCapsCacheLookupByArch(virQEMUCapsCachePtr cache, diff --git a/src/qemu/qemu_capspriv.h b/src/qemu/qemu_capspriv.h index c409acb..ac3693b 100644 --- a/src/qemu/qemu_capspriv.h +++ b/src/qemu/qemu_capspriv.h @@ -40,7 +40,8 @@ struct _virQEMUCapsCache { virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps); virQEMUCapsPtr -virQEMUCapsNewForBinaryInternal(const char *binary, +virQEMUCapsNewForBinaryInternal(virCapsPtr caps, + const char *binary, const char *libDir, const char *cacheDir, uid_t runUid, diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 3f16dbe..0e30381 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2359,7 +2359,8 @@ qemuDomainDefPostParse(virDomainDefPtr def, !(def->emulator = virDomainDefGetDefaultEmulator(def, caps))) goto cleanup; - if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, + if (!(qemuCaps = virQEMUCapsCacheLookup(caps, + driver->qemuCapsCache, def->emulator))) goto cleanup; @@ -2390,7 +2391,7 @@ qemuDomainDefPostParse(virDomainDefPtr def, static int qemuDomainDefValidate(const virDomainDef *def, - virCapsPtr caps ATTRIBUTE_UNUSED, + virCapsPtr caps, void *opaque) { virQEMUDriverPtr driver = opaque; @@ -2398,7 +2399,8 @@ qemuDomainDefValidate(const virDomainDef *def, size_t topologycpus; int ret = -1; - if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, + if (!(qemuCaps = virQEMUCapsCacheLookup(caps, + driver->qemuCapsCache, def->emulator))) goto cleanup; @@ -2552,7 +2554,7 @@ qemuDomainChrDefDropDefaultPath(virDomainChrDefPtr chr, static int qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, const virDomainDef *def, - virCapsPtr caps ATTRIBUTE_UNUSED, + virCapsPtr caps, unsigned int parseFlags, void *opaque) { @@ -2561,7 +2563,8 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); int ret = -1; - qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator); + qemuCaps = virQEMUCapsCacheLookup(caps, driver->qemuCapsCache, + def->emulator); if (dev->type == VIR_DOMAIN_DEVICE_NET && dev->data.net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV && @@ -2758,7 +2761,7 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, static int qemuDomainDefAssignAddresses(virDomainDef *def, - virCapsPtr caps ATTRIBUTE_UNUSED, + virCapsPtr caps, unsigned int parseFlags ATTRIBUTE_UNUSED, void *opaque) { @@ -2767,7 +2770,8 @@ qemuDomainDefAssignAddresses(virDomainDef *def, int ret = -1; bool newDomain = parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE; - if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, + if (!(qemuCaps = virQEMUCapsCacheLookup(caps, + driver->qemuCapsCache, def->emulator))) goto cleanup; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2acff16..ca47b4e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8373,7 +8373,8 @@ static int qemuDomainUpdateDeviceFlags(virDomainPtr dom, if (priv->qemuCaps) qemuCaps = virObjectRef(priv->qemuCaps); - else if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, vm->def->emulator))) + else if (!(qemuCaps = virQEMUCapsCacheLookup(caps, driver->qemuCapsCache, + vm->def->emulator))) goto endjob; if (flags & VIR_DOMAIN_AFFECT_CONFIG) { @@ -15742,7 +15743,8 @@ static virDomainPtr qemuDomainQemuAttach(virConnectPtr conn, virAsprintf(&def->name, "attach-pid-%u", pid_value) < 0) goto cleanup; - if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator))) + if (!(qemuCaps = virQEMUCapsCacheLookup(caps, driver->qemuCapsCache, + def->emulator))) goto cleanup; if (qemuAssignDeviceAliases(def, qemuCaps) < 0) @@ -18667,7 +18669,8 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, if (emulatorbin) { virArch arch_from_caps; - if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, + if (!(qemuCaps = virQEMUCapsCacheLookup(caps, + driver->qemuCapsCache, emulatorbin))) goto cleanup; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index b2d1127..83e64b2 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3248,6 +3248,7 @@ qemuProcessReconnect(void *opaque) int ret; unsigned int stopFlags = 0; bool jobStarted = false; + virCapsPtr caps = NULL; VIR_FREE(data); @@ -3258,6 +3259,9 @@ qemuProcessReconnect(void *opaque) cfg = virQEMUDriverGetConfig(driver); priv = obj->privateData; + if (!(caps = virQEMUDriverGetCapabilities(driver, false))) + goto error; + if (qemuDomainObjBeginJob(driver, obj, QEMU_JOB_MODIFY) < 0) goto error; jobStarted = true; @@ -3327,7 +3331,8 @@ qemuProcessReconnect(void *opaque) * caps in the domain status, so re-query them */ if (!priv->qemuCaps && - !(priv->qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache, + !(priv->qemuCaps = virQEMUCapsCacheLookupCopy(caps, + driver->qemuCapsCache, obj->def->emulator, obj->def->os.machine))) goto error; @@ -3427,6 +3432,7 @@ qemuProcessReconnect(void *opaque) virDomainObjEndAPI(&obj); virObjectUnref(conn); virObjectUnref(cfg); + virObjectUnref(caps); virNWFilterUnlockFilterUpdates(); return; @@ -4656,7 +4662,8 @@ qemuProcessInit(virQEMUDriverPtr driver, VIR_DEBUG("Determining emulator version"); virObjectUnref(priv->qemuCaps); - if (!(priv->qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache, + if (!(priv->qemuCaps = virQEMUCapsCacheLookupCopy(caps, + driver->qemuCapsCache, vm->def->emulator, vm->def->os.machine))) goto cleanup; @@ -6272,7 +6279,8 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED, VIR_DEBUG("Determining emulator version"); virObjectUnref(priv->qemuCaps); - if (!(priv->qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache, + if (!(priv->qemuCaps = virQEMUCapsCacheLookupCopy(caps, + driver->qemuCapsCache, vm->def->emulator, vm->def->os.machine))) goto error; diff --git a/tests/qemucapsprobe.c b/tests/qemucapsprobe.c index ced0512..fb9f3e9 100644 --- a/tests/qemucapsprobe.c +++ b/tests/qemucapsprobe.c @@ -70,7 +70,7 @@ main(int argc, char **argv) if (virThreadCreate(&thread, false, eventLoop, NULL) < 0) return EXIT_FAILURE; - if (!(caps = virQEMUCapsNewForBinaryInternal(argv[1], "/tmp", NULL, + if (!(caps = virQEMUCapsNewForBinaryInternal(NULL, argv[1], "/tmp", NULL, -1, -1, true))) return EXIT_FAILURE; -- 2.10.0

Useful for copying a CPU definition without model related parts (i.e., without model name, feature list, vendor). Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change src/conf/cpu_conf.c | 16 +++++++++++++++- src/conf/cpu_conf.h | 3 +++ src/libvirt_private.syms | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index b71528e..c6e847a 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -114,8 +114,9 @@ virCPUDefCopyModel(virCPUDefPtr dst, return 0; } + virCPUDefPtr -virCPUDefCopy(const virCPUDef *cpu) +virCPUDefCopyWithoutModel(const virCPUDef *cpu) { virCPUDefPtr copy; @@ -131,6 +132,18 @@ virCPUDefCopy(const virCPUDef *cpu) copy->threads = cpu->threads; copy->arch = cpu->arch; + return copy; +} + + +virCPUDefPtr +virCPUDefCopy(const virCPUDef *cpu) +{ + virCPUDefPtr copy; + + if (!(copy = virCPUDefCopyWithoutModel(cpu))) + return NULL; + if (virCPUDefCopyModel(copy, cpu, false) < 0) goto error; @@ -141,6 +154,7 @@ virCPUDefCopy(const virCPUDef *cpu) return NULL; } + virCPUDefPtr virCPUDefParseXML(xmlNodePtr node, xmlXPathContextPtr ctxt, diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 705ba6d..2bbab9e 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -127,6 +127,9 @@ virCPUDefPtr virCPUDefCopy(const virCPUDef *cpu); virCPUDefPtr +virCPUDefCopyWithoutModel(const virCPUDef *cpu); + +virCPUDefPtr virCPUDefParseXML(xmlNodePtr node, xmlXPathContextPtr ctxt, virCPUType mode); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f954453..d4ae5af 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -66,6 +66,7 @@ virCapabilitiesSetNetPrefix; virCPUDefAddFeature; virCPUDefCopy; virCPUDefCopyModel; +virCPUDefCopyWithoutModel; virCPUDefFormat; virCPUDefFormatBuf; virCPUDefFree; -- 2.10.0

The function moves CPU model related parts from one CPU definition to another. It can be used to avoid unnecessary copies from a temporary CPU definitions which will be freed anyway. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - s/virCPUDefMoveModel/virCPUDefStealModel/ src/conf/cpu_conf.c | 17 +++++++++++++++++ src/conf/cpu_conf.h | 4 ++++ src/libvirt_private.syms | 1 + 3 files changed, 22 insertions(+) diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index c6e847a..2e78b76 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -115,6 +115,23 @@ virCPUDefCopyModel(virCPUDefPtr dst, } +void +virCPUDefStealModel(virCPUDefPtr dst, + virCPUDefPtr src) +{ + virCPUDefFreeModel(dst); + + VIR_STEAL_PTR(dst->model, src->model); + VIR_STEAL_PTR(dst->vendor, src->vendor); + VIR_STEAL_PTR(dst->vendor_id, src->vendor_id); + VIR_STEAL_PTR(dst->features, src->features); + dst->nfeatures_max = src->nfeatures_max; + src->nfeatures_max = 0; + dst->nfeatures = src->nfeatures; + src->nfeatures = 0; +} + + virCPUDefPtr virCPUDefCopyWithoutModel(const virCPUDef *cpu) { diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 2bbab9e..a5dd208 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -123,6 +123,10 @@ virCPUDefCopyModel(virCPUDefPtr dst, const virCPUDef *src, bool resetPolicy); +void +virCPUDefStealModel(virCPUDefPtr dst, + virCPUDefPtr src); + virCPUDefPtr virCPUDefCopy(const virCPUDef *cpu); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d4ae5af..adf330a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -72,6 +72,7 @@ virCPUDefFormatBuf; virCPUDefFree; virCPUDefFreeModel; virCPUDefParseXML; +virCPUDefStealModel; virCPUDefUpdateFeature; virCPUModeTypeToString; -- 2.10.0

The function filters all CPU features through a given callback while copying CPU model related parts of a CPU definition. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - removed ATTRIBUTE_NONNULL from cpu_conf.c src/conf/cpu_conf.c | 31 ++++++++++++++++++++++++------- src/conf/cpu_conf.h | 14 ++++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 2e78b76..f174529 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -86,28 +86,45 @@ virCPUDefCopyModel(virCPUDefPtr dst, const virCPUDef *src, bool resetPolicy) { + return virCPUDefCopyModelFilter(dst, src, resetPolicy, NULL, NULL); +} + + +int +virCPUDefCopyModelFilter(virCPUDefPtr dst, + const virCPUDef *src, + bool resetPolicy, + virCPUDefFeatureFilter filter, + void *opaque) +{ size_t i; + size_t n; if (VIR_STRDUP(dst->model, src->model) < 0 || VIR_STRDUP(dst->vendor, src->vendor) < 0 || VIR_STRDUP(dst->vendor_id, src->vendor_id) < 0 || VIR_ALLOC_N(dst->features, src->nfeatures) < 0) return -1; - dst->nfeatures_max = dst->nfeatures = src->nfeatures; + dst->nfeatures_max = src->nfeatures; + dst->nfeatures = 0; - for (i = 0; i < dst->nfeatures; i++) { + for (i = 0; i < src->nfeatures; i++) { + if (filter && !filter(src->features[i].name, opaque)) + continue; + + n = dst->nfeatures++; if (dst->type != src->type && resetPolicy) { if (dst->type == VIR_CPU_TYPE_HOST) - dst->features[i].policy = -1; + dst->features[n].policy = -1; else if (src->features[i].policy == -1) - dst->features[i].policy = VIR_CPU_FEATURE_REQUIRE; + dst->features[n].policy = VIR_CPU_FEATURE_REQUIRE; else - dst->features[i].policy = src->features[i].policy; + dst->features[n].policy = src->features[i].policy; } else { - dst->features[i].policy = src->features[i].policy; + dst->features[n].policy = src->features[i].policy; } - if (VIR_STRDUP(dst->features[i].name, src->features[i].name) < 0) + if (VIR_STRDUP(dst->features[n].name, src->features[i].name) < 0) return -1; } diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index a5dd208..e084392 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -123,6 +123,20 @@ virCPUDefCopyModel(virCPUDefPtr dst, const virCPUDef *src, bool resetPolicy); +/* + * Returns true if feature @name should copied, false otherwise. + */ +typedef bool (*virCPUDefFeatureFilter)(const char *name, + void *opaque); + +int +virCPUDefCopyModelFilter(virCPUDefPtr dst, + const virCPUDef *src, + bool resetPolicy, + virCPUDefFeatureFilter filter, + void *opaque) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + void virCPUDefStealModel(virCPUDefPtr dst, virCPUDefPtr src); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index adf330a..3f5df71 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -66,6 +66,7 @@ virCapabilitiesSetNetPrefix; virCPUDefAddFeature; virCPUDefCopy; virCPUDefCopyModel; +virCPUDefCopyModelFilter; virCPUDefCopyWithoutModel; virCPUDefFormat; virCPUDefFormatBuf; -- 2.10.0

Host capabilities provide libvirt's view of the host CPU, but for a useful support for host-model CPUs we really need a hypervisor's view of the CPU. And since the view can be differ with emulator, qemu capabilities is the best place to store the host CPU model. This patch just copies the CPU model from host capabilities, but this will change in the future. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - s/cpuModel/hostCpuModel/ - fixed memory leak in virQEMUCapsDispose - added virResetLastError to virQEMUCapsInitHostCPUModel src/qemu/qemu_capabilities.c | 71 ++++++++++++++++++++++++++++++++++++++------ src/qemu/qemu_capspriv.h | 7 ++++- tests/domaincapstest.c | 10 +++---- tests/qemucapabilitiestest.c | 2 +- tests/qemuxml2argvtest.c | 7 +++-- tests/testutilsqemu.c | 5 ++-- tests/testutilsqemu.h | 3 +- 7 files changed, 84 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 3aa348c..8fabe8d 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -385,6 +385,12 @@ struct _virQEMUCaps { size_t ngicCapabilities; virGICCapability *gicCapabilities; + + /* Anything below is not stored in the cache since the values are + * re-computed from the other fields or external data sources every + * time we probe QEMU or load the results from the cache. + */ + virCPUDefPtr hostCPUModel; }; struct virQEMUCapsSearchData { @@ -2113,6 +2119,10 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps) goto error; } + if (qemuCaps->hostCPUModel && + !(ret->hostCPUModel = virCPUDefCopy(qemuCaps->hostCPUModel))) + goto error; + if (VIR_ALLOC_N(ret->machineTypes, qemuCaps->nmachineTypes) < 0) goto error; ret->nmachineTypes = qemuCaps->nmachineTypes; @@ -2157,6 +2167,8 @@ void virQEMUCapsDispose(void *obj) VIR_FREE(qemuCaps->binary); VIR_FREE(qemuCaps->gicCapabilities); + + virCPUDefFree(qemuCaps->hostCPUModel); } void @@ -2902,6 +2914,38 @@ int virQEMUCapsProbeQMP(virQEMUCapsPtr qemuCaps, } +void +virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps, + virCapsHostPtr host) +{ + virCPUDefPtr cpu = NULL; + + if (!virQEMUCapsGuestIsNative(host->arch, qemuCaps->arch)) + goto error; + + if (host->cpu && host->cpu->model) { + if (VIR_ALLOC(cpu) < 0) + goto error; + + cpu->sockets = cpu->cores = cpu->threads = 0; + cpu->type = VIR_CPU_TYPE_GUEST; + cpu->mode = VIR_CPU_MODE_CUSTOM; + cpu->match = VIR_CPU_MATCH_EXACT; + + if (virCPUDefCopyModel(cpu, host->cpu, true) < 0) + goto error; + } + + qemuCaps->hostCPUModel = cpu; + return; + + error: + virCPUDefFree(cpu); + qemuCaps->hostCPUModel = NULL; + virResetLastError(); +} + + /* * Parsing a doc that looks like * @@ -2920,8 +2964,11 @@ int virQEMUCapsProbeQMP(virQEMUCapsPtr qemuCaps, * </qemuCaps> */ int -virQEMUCapsLoadCache(virQEMUCapsPtr qemuCaps, const char *filename, - time_t *qemuctime, time_t *selfctime, +virQEMUCapsLoadCache(virCapsPtr caps, + virQEMUCapsPtr qemuCaps, + const char *filename, + time_t *qemuctime, + time_t *selfctime, unsigned long *selfvers) { xmlDocPtr doc = NULL; @@ -3154,6 +3201,8 @@ virQEMUCapsLoadCache(virQEMUCapsPtr qemuCaps, const char *filename, } VIR_FREE(nodes); + virQEMUCapsInitHostCPUModel(qemuCaps, &caps->host); + ret = 0; cleanup: VIR_FREE(str); @@ -3344,7 +3393,9 @@ virQEMUCapsReset(virQEMUCapsPtr qemuCaps) static int -virQEMUCapsInitCached(virQEMUCapsPtr qemuCaps, const char *cacheDir) +virQEMUCapsInitCached(virCapsPtr caps, + virQEMUCapsPtr qemuCaps, + const char *cacheDir) { char *capsdir = NULL; char *capsfile = NULL; @@ -3386,8 +3437,8 @@ virQEMUCapsInitCached(virQEMUCapsPtr qemuCaps, const char *cacheDir) goto cleanup; } - if (virQEMUCapsLoadCache(qemuCaps, capsfile, &qemuctime, &selfctime, - &selfvers) < 0) { + if (virQEMUCapsLoadCache(caps, qemuCaps, capsfile, + &qemuctime, &selfctime, &selfvers) < 0) { VIR_WARN("Failed to load cached caps from '%s' for '%s': %s", capsfile, qemuCaps->binary, virGetLastErrorMessage()); virResetLastError(); @@ -3871,7 +3922,7 @@ virQEMUCapsLogProbeFailure(const char *binary) virQEMUCapsPtr -virQEMUCapsNewForBinaryInternal(virCapsPtr caps ATTRIBUTE_UNUSED, +virQEMUCapsNewForBinaryInternal(virCapsPtr caps, const char *binary, const char *libDir, const char *cacheDir, @@ -3911,7 +3962,7 @@ virQEMUCapsNewForBinaryInternal(virCapsPtr caps ATTRIBUTE_UNUSED, if (!cacheDir) rv = 0; - else if ((rv = virQEMUCapsInitCached(qemuCaps, cacheDir)) < 0) + else if ((rv = virQEMUCapsInitCached(caps, qemuCaps, cacheDir)) < 0) goto error; if (rv == 0) { @@ -3937,16 +3988,18 @@ virQEMUCapsNewForBinaryInternal(virCapsPtr caps ATTRIBUTE_UNUSED, if (cacheDir && virQEMUCapsRememberCached(qemuCaps, cacheDir) < 0) goto error; + + virQEMUCapsInitHostCPUModel(qemuCaps, &caps->host); } + cleanup: VIR_FREE(qmperr); return qemuCaps; error: - VIR_FREE(qmperr); virObjectUnref(qemuCaps); qemuCaps = NULL; - return NULL; + goto cleanup; } static virQEMUCapsPtr diff --git a/src/qemu/qemu_capspriv.h b/src/qemu/qemu_capspriv.h index ac3693b..22c5a8a 100644 --- a/src/qemu/qemu_capspriv.h +++ b/src/qemu/qemu_capspriv.h @@ -48,7 +48,8 @@ virQEMUCapsNewForBinaryInternal(virCapsPtr caps, gid_t runGid, bool qmpOnly); -int virQEMUCapsLoadCache(virQEMUCapsPtr qemuCaps, +int virQEMUCapsLoadCache(virCapsPtr caps, + virQEMUCapsPtr qemuCaps, const char *filename, time_t *qemuctime, time_t *selfctime, @@ -60,4 +61,8 @@ char *virQEMUCapsFormatCache(virQEMUCapsPtr qemuCaps, void virQEMUCapsSetArch(virQEMUCapsPtr qemuCaps, virArch arch); + +void +virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps, + virCapsHostPtr host); #endif diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c index 511066d..99971c2 100644 --- a/tests/domaincapstest.c +++ b/tests/domaincapstest.c @@ -173,9 +173,13 @@ fillQemuCaps(virDomainCapsPtr domCaps, virQEMUCapsPtr qemuCaps = NULL; virDomainCapsLoaderPtr loader = &domCaps->os.loader; + if (!(caps = virCapabilitiesNew(domCaps->arch, false, false)) || + fakeHostCPU(caps, domCaps->arch) < 0) + goto cleanup; + if (virAsprintf(&path, "%s/qemucapabilitiesdata/%s.%s.xml", abs_srcdir, name, arch) < 0 || - !(qemuCaps = qemuTestParseCapabilities(path))) + !(qemuCaps = qemuTestParseCapabilities(caps, path))) goto cleanup; if (machine && @@ -188,10 +192,6 @@ fillQemuCaps(virDomainCapsPtr domCaps, virQEMUCapsGetDefaultMachine(qemuCaps)) < 0) goto cleanup; - if (!(caps = virCapabilitiesNew(domCaps->arch, false, false)) || - fakeHostCPU(caps, domCaps->arch) < 0) - goto cleanup; - if (virQEMUCapsFillDomainCaps(caps, domCaps, qemuCaps, cfg->firmwares, cfg->nfirmwares) < 0) diff --git a/tests/qemucapabilitiestest.c b/tests/qemucapabilitiestest.c index 3924bce..10cfa43 100644 --- a/tests/qemucapabilitiestest.c +++ b/tests/qemucapabilitiestest.c @@ -97,7 +97,7 @@ testQemuCapsCopy(const void *opaque) false, false))) goto cleanup; - if (!(orig = qemuTestParseCapabilities(capsFile))) + if (!(orig = qemuTestParseCapabilities(caps, capsFile))) goto cleanup; if (!(copy = virQEMUCapsNewCopy(orig))) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 156a45a..7080484 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -347,7 +347,8 @@ testInitQEMUCaps(struct testInfo *info, static int testUpdateQEMUCaps(const struct testInfo *info, - virDomainObjPtr vm) + virDomainObjPtr vm, + virCapsPtr caps) { int ret = -1; @@ -356,6 +357,8 @@ testUpdateQEMUCaps(const struct testInfo *info, if (testAddCPUModels(info->qemuCaps, info->skipLegacyCPUs) < 0) goto cleanup; + virQEMUCapsInitHostCPUModel(info->qemuCaps, &caps->host); + virQEMUCapsFilterByMachineType(info->qemuCaps, vm->def->os.machine); if (ARCH_IS_X86(vm->def->os.arch)) @@ -448,7 +451,7 @@ testCompareXMLToArgv(const void *data) goto cleanup; } - if (testUpdateQEMUCaps(info, vm) < 0) + if (testUpdateQEMUCaps(info, vm, driver.caps) < 0) goto cleanup; log = virTestLogContentAndReset(); diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index 8c2c8b4..e66903a 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -491,7 +491,8 @@ qemuTestSetHostCPU(virCapsPtr caps, virQEMUCapsPtr -qemuTestParseCapabilities(const char *capsFile) +qemuTestParseCapabilities(virCapsPtr caps, + const char *capsFile) { virQEMUCapsPtr qemuCaps = NULL; time_t qemuctime; @@ -499,7 +500,7 @@ qemuTestParseCapabilities(const char *capsFile) unsigned long version; if (!(qemuCaps = virQEMUCapsNew()) || - virQEMUCapsLoadCache(qemuCaps, capsFile, + virQEMUCapsLoadCache(caps, qemuCaps, capsFile, &qemuctime, &selfctime, &version) < 0) goto error; diff --git a/tests/testutilsqemu.h b/tests/testutilsqemu.h index 6d35116f..047a64d 100644 --- a/tests/testutilsqemu.h +++ b/tests/testutilsqemu.h @@ -15,7 +15,8 @@ enum { virCapsPtr testQemuCapsInit(void); virDomainXMLOptionPtr testQemuXMLConfInit(void); -virQEMUCapsPtr qemuTestParseCapabilities(const char *capsFile); +virQEMUCapsPtr qemuTestParseCapabilities(virCapsPtr caps, + const char *capsFile); extern virCPUDefPtr cpuDefault; extern virCPUDefPtr cpuHaswell; -- 2.10.0

The ARM CPU driver wrongly reported host CPU model as "host", which made host-model to be just an alias for host-passthrough. Let's drop this insanity. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu_arm.c | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 6090253..a3aed6b 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -37,36 +37,6 @@ static const virArch archs[] = { VIR_ARCH_AARCH64, }; -static virCPUDataPtr -armNodeData(virArch arch) -{ - virCPUDataPtr data; - - if (VIR_ALLOC(data) < 0) - return NULL; - - data->arch = arch; - - return data; -} - -static int -armDecode(virCPUDefPtr cpu, - const virCPUData *data ATTRIBUTE_UNUSED, - const char **models ATTRIBUTE_UNUSED, - unsigned int nmodels ATTRIBUTE_UNUSED, - const char *preferred ATTRIBUTE_UNUSED, - unsigned int flags) -{ - virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, -1); - - if (cpu->model == NULL && - VIR_STRDUP(cpu->model, "host") < 0) - return -1; - - return 0; -} - static void armDataFree(virCPUDataPtr data) { @@ -128,10 +98,10 @@ struct cpuArchDriver cpuDriverArm = { .arch = archs, .narch = ARRAY_CARDINALITY(archs), .compare = armCompare, - .decode = armDecode, + .decode = NULL, .encode = NULL, .free = armDataFree, - .nodeData = armNodeData, + .nodeData = NULL, .guestData = armGuestData, .baseline = armBaseline, .update = armUpdate, -- 2.10.0

The domain capabilities XML is capable of showing whether each guest CPU mode is supported or not with a possibility to provide additional details. This patch enhances host-model capability to advertise the exact CPU model which will be used as a host-model: <cpu> ... <mode name='host-model' supported='yes'> <model fallback='allow'>Broadwell</model> <vendor>Intel</vendor> <feature policy='disable' name='aes'/> <feature policy='require' name='vmx'/> </mode> ... </cpu> Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - adapted to changes in previous patches - s/says/indicates/ docs/formatdomaincaps.html.in | 21 +++++++++++++++++++-- docs/schemas/domaincaps.rng | 10 ++++++++++ src/conf/domain_capabilities.c | 16 +++++++++++++--- src/conf/domain_capabilities.h | 2 +- src/qemu/qemu_capabilities.c | 4 +--- tests/domaincapsschemadata/full.xml | 5 ++++- tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml | 4 +++- .../qemu_2.6.0-gicv2-virt.aarch64.xml | 2 +- .../qemu_2.6.0-gicv3-virt.aarch64.xml | 2 +- tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml | 2 +- tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml | 4 +++- tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml | 4 +++- tests/domaincapstest.c | 10 ++++++++-- 13 files changed, 68 insertions(+), 18 deletions(-) diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in index 045ba93..648e3d4 100644 --- a/docs/formatdomaincaps.html.in +++ b/docs/formatdomaincaps.html.in @@ -154,7 +154,12 @@ ... <cpu> <mode name='host-passthrough' supported='yes'/> - <mode name='host-model' supported='yes'/> + <mode name='host-model' supported='yes'> + <model fallback='allow'>Broadwell</model> + <vendor>Intel</vendor> + <feature policy='disable' name='aes'/> + <feature policy='require' name='vmx'/> + </mode> <mode name='custom' supported='yes'> <model usable='no'>Broadwell</model> <model usable='yes'>Broadwell-noTSX</model> @@ -177,7 +182,19 @@ <dd>No mode specific details are provided.</dd> <dt><code>host-model</code></dt> - <dd>No mode specific details are provided yet.</dd> + <dd> + If <code>host-model</code> is supported by the hypervisor, the + <code>mode</code> describes the guest CPU which will be used when + starting a domain with <code>host-model</code> CPU. The hypervisor + specifics (such as unsupported CPU models or features, machine type, + etc.) may be accounted for in this guest CPU specification and thus + the CPU can be different from the one shown in host capabilities XML. + This is indicated by the <code>fallback</code> attribute of the + <code>model</code> sub element: <code>allow</code> means not all + specifics were accounted for and thus the CPU a guest will see may + be different; <code>forbid</code> indicates that the CPU a guest will + see should match this CPU definition. + </dd> <dt><code>custom</code></dt> <dd> diff --git a/docs/schemas/domaincaps.rng b/docs/schemas/domaincaps.rng index 5a605a7..20cbc4e 100644 --- a/docs/schemas/domaincaps.rng +++ b/docs/schemas/domaincaps.rng @@ -2,6 +2,7 @@ <!-- A Relax NG schema for the libvirt domain capabilities XML format --> <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <include href='basictypes.rng'/> + <include href='cputypes.rng'/> <start> <ref name='domainCapabilities'/> </start> @@ -94,6 +95,15 @@ <value>host-model</value> </attribute> <ref name='supported'/> + <optional> + <ref name="cpuModel"/> + <optional> + <ref name="cpuVendor"/> + </optional> + <zeroOrMore> + <ref name="cpuFeature"/> + </zeroOrMore> + </optional> </element> </define> diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 9ec416e..beedd70 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -402,9 +402,19 @@ virDomainCapsCPUFormat(virBufferPtr buf, virCPUModeTypeToString(VIR_CPU_MODE_HOST_PASSTHROUGH), cpu->hostPassthrough ? "yes" : "no"); - virBufferAsprintf(buf, "<mode name='%s' supported='%s'/>\n", - virCPUModeTypeToString(VIR_CPU_MODE_HOST_MODEL), - cpu->hostModel ? "yes" : "no"); + virBufferAsprintf(buf, "<mode name='%s' ", + virCPUModeTypeToString(VIR_CPU_MODE_HOST_MODEL)); + if (cpu->hostModel) { + virBufferAddLit(buf, "supported='yes'>\n"); + virBufferAdjustIndent(buf, 2); + + virCPUDefFormatBuf(buf, cpu->hostModel, false); + + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</mode>\n"); + } else { + virBufferAddLit(buf, "supported='no'/>\n"); + } virBufferAsprintf(buf, "<mode name='%s' ", virCPUModeTypeToString(VIR_CPU_MODE_CUSTOM)); diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 3ec05dc..13a65e3 100644 --- a/src/conf/domain_capabilities.h +++ b/src/conf/domain_capabilities.h @@ -132,7 +132,7 @@ typedef struct _virDomainCapsCPU virDomainCapsCPU; typedef virDomainCapsCPU *virDomainCapsCPUPtr; struct _virDomainCapsCPU { bool hostPassthrough; - bool hostModel; + virCPUDefPtr hostModel; virDomainCapsCPUModelsPtr custom; }; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 8fabe8d..5ef6c9c 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4358,9 +4358,7 @@ virQEMUCapsFillDomainCPUCaps(virCapsPtr caps, virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch)) domCaps->cpu.hostPassthrough = true; - if (qemuCaps->cpuDefinitions && caps->host.cpu) - domCaps->cpu.hostModel = virQEMUCapsGuestIsNative(caps->host.arch, - qemuCaps->arch); + domCaps->cpu.hostModel = virCPUDefCopy(qemuCaps->hostCPUModel); if (qemuCaps->cpuDefinitions && cpuGetModels(domCaps->arch, &models) >= 0) { diff --git a/tests/domaincapsschemadata/full.xml b/tests/domaincapsschemadata/full.xml index b75e86c..eaf6eb6 100644 --- a/tests/domaincapsschemadata/full.xml +++ b/tests/domaincapsschemadata/full.xml @@ -21,7 +21,10 @@ </os> <cpu> <mode name='host-passthrough' supported='yes'/> - <mode name='host-model' supported='yes'/> + <mode name='host-model' supported='yes'> + <model>host</model> + <vendor>CPU Vendorrr</vendor> + </mode> <mode name='custom' supported='yes'> <model usable='unknown'>Model1</model> <model usable='no'>Model2</model> diff --git a/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml b/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml index 2b17dd0..4aa475c 100644 --- a/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml +++ b/tests/domaincapsschemadata/qemu_1.7.0.x86_64.xml @@ -20,7 +20,9 @@ </os> <cpu> <mode name='host-passthrough' supported='yes'/> - <mode name='host-model' supported='yes'/> + <mode name='host-model' supported='yes'> + <model fallback='allow'>Broadwell</model> + </mode> <mode name='custom' supported='yes'> <model usable='unknown'>Opteron_G5</model> <model usable='unknown'>Opteron_G4</model> diff --git a/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml index 8a54f9e..796c3af 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0-gicv2-virt.aarch64.xml @@ -20,7 +20,7 @@ </os> <cpu> <mode name='host-passthrough' supported='yes'/> - <mode name='host-model' supported='yes'/> + <mode name='host-model' supported='no'/> <mode name='custom' supported='yes'> <model usable='unknown'>pxa262</model> <model usable='unknown'>pxa270-a0</model> diff --git a/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml index 8d8087f..5a5f82c 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0-gicv3-virt.aarch64.xml @@ -20,7 +20,7 @@ </os> <cpu> <mode name='host-passthrough' supported='yes'/> - <mode name='host-model' supported='yes'/> + <mode name='host-model' supported='no'/> <mode name='custom' supported='yes'> <model usable='unknown'>pxa262</model> <model usable='unknown'>pxa270-a0</model> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml b/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml index 83c03db..90b57ff 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.aarch64.xml @@ -20,7 +20,7 @@ </os> <cpu> <mode name='host-passthrough' supported='yes'/> - <mode name='host-model' supported='yes'/> + <mode name='host-model' supported='no'/> <mode name='custom' supported='yes'> <model usable='unknown'>pxa262</model> <model usable='unknown'>pxa270-a0</model> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml index 14a087b..962be6f 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.ppc64le.xml @@ -20,7 +20,9 @@ </os> <cpu> <mode name='host-passthrough' supported='yes'/> - <mode name='host-model' supported='yes'/> + <mode name='host-model' supported='yes'> + <model fallback='allow'>POWER8</model> + </mode> <mode name='custom' supported='yes'> <model usable='unknown'>POWER8</model> <model usable='unknown'>POWER7</model> diff --git a/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml b/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml index 4294c64..a8975e8 100644 --- a/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml +++ b/tests/domaincapsschemadata/qemu_2.6.0.x86_64.xml @@ -20,7 +20,9 @@ </os> <cpu> <mode name='host-passthrough' supported='yes'/> - <mode name='host-model' supported='yes'/> + <mode name='host-model' supported='yes'> + <model fallback='allow'>Broadwell</model> + </mode> <mode name='custom' supported='yes'> <model usable='unknown'>Opteron_G5</model> <model usable='unknown'>Opteron_G4</model> diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c index 99971c2..e70fa05 100644 --- a/tests/domaincapstest.c +++ b/tests/domaincapstest.c @@ -65,8 +65,14 @@ fillAllCaps(virDomainCapsPtr domCaps) virDomainCapsDeviceGraphicsPtr graphics = &domCaps->graphics; virDomainCapsDeviceVideoPtr video = &domCaps->video; virDomainCapsDeviceHostdevPtr hostdev = &domCaps->hostdev; - domCaps->maxvcpus = 255; + virCPUDef host = { + VIR_CPU_TYPE_HOST, 0, 0, + VIR_ARCH_X86_64, (char *) "host", + NULL, 0, (char *) "CPU Vendorrr", + 0, 0, 0, 0, 0, NULL, + }; + domCaps->maxvcpus = 255; os->supported = true; loader->supported = true; @@ -79,7 +85,7 @@ fillAllCaps(virDomainCapsPtr domCaps) return -1; cpu->hostPassthrough = true; - cpu->hostModel = true; + cpu->hostModel = virCPUDefCopy(&host); if (!(cpu->custom = virDomainCapsCPUModelsNew(3)) || virDomainCapsCPUModelsAdd(cpu->custom, "Model1", -1, VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0 || -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - adapted to changes in previous patches src/qemu/qemu_capabilities.c | 7 +++++++ src/qemu/qemu_capabilities.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 5ef6c9c..18927cb 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2364,6 +2364,13 @@ virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps, } +virCPUDefPtr +virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps) +{ + return qemuCaps->hostCPUModel; +} + + int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps, size_t *nmachines, virCapsGuestMachinePtr **machines) diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index c05adfd..b1d512e 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -429,6 +429,7 @@ int virQEMUCapsAddCPUDefinitions(virQEMUCapsPtr qemuCaps, int virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps, char ***names, size_t *count); +virCPUDefPtr virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps); const char *virQEMUCapsGetCanonicalMachine(virQEMUCapsPtr qemuCaps, const char *name); int virQEMUCapsGetMachineMaxCpus(virQEMUCapsPtr qemuCaps, -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - adapted to changes in previous patches - removed redundant check for qemuCaps->cpuDefinitions != NULL src/qemu/qemu_capabilities.c | 54 ++++++++++++++++++++++++++++++++++---------- src/qemu/qemu_capabilities.h | 4 ++++ 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 18927cb..985b585 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2371,6 +2371,32 @@ virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps) } +bool +virQEMUCapsIsCPUModeSupported(virQEMUCapsPtr qemuCaps, + virCapsPtr caps, + virDomainVirtType type, + virCPUMode mode) +{ + switch (mode) { + case VIR_CPU_MODE_HOST_PASSTHROUGH: + return type == VIR_DOMAIN_VIRT_KVM && + virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch); + + case VIR_CPU_MODE_HOST_MODEL: + return !!qemuCaps->hostCPUModel; + + case VIR_CPU_MODE_CUSTOM: + return qemuCaps->cpuDefinitions && + qemuCaps->cpuDefinitions->nmodels > 0; + + case VIR_CPU_MODE_LAST: + break; + } + + return false; +} + + int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps, size_t *nmachines, virCapsGuestMachinePtr **machines) @@ -4358,22 +4384,26 @@ virQEMUCapsFillDomainCPUCaps(virCapsPtr caps, virQEMUCapsPtr qemuCaps, virDomainCapsPtr domCaps) { - virDomainCapsCPUModelsPtr filtered = NULL; - char **models = NULL; - - if (domCaps->virttype == VIR_DOMAIN_VIRT_KVM && - virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch)) + if (virQEMUCapsIsCPUModeSupported(qemuCaps, caps, domCaps->virttype, + VIR_CPU_MODE_HOST_PASSTHROUGH)) domCaps->cpu.hostPassthrough = true; - domCaps->cpu.hostModel = virCPUDefCopy(qemuCaps->hostCPUModel); + if (virQEMUCapsIsCPUModeSupported(qemuCaps, caps, domCaps->virttype, + VIR_CPU_MODE_HOST_MODEL)) + domCaps->cpu.hostModel = virCPUDefCopy(qemuCaps->hostCPUModel); - if (qemuCaps->cpuDefinitions && - cpuGetModels(domCaps->arch, &models) >= 0) { - filtered = virDomainCapsCPUModelsFilter(qemuCaps->cpuDefinitions, - (const char **) models); - virStringFreeList(models); + if (virQEMUCapsIsCPUModeSupported(qemuCaps, caps, domCaps->virttype, + VIR_CPU_MODE_CUSTOM)) { + virDomainCapsCPUModelsPtr filtered = NULL; + char **models = NULL; + + if (cpuGetModels(domCaps->arch, &models) >= 0) { + filtered = virDomainCapsCPUModelsFilter(qemuCaps->cpuDefinitions, + (const char **) models); + virStringFreeList(models); + } + domCaps->cpu.custom = filtered; } - domCaps->cpu.custom = filtered; return 0; } diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index b1d512e..ba0ef48 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -430,6 +430,10 @@ int virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps, char ***names, size_t *count); virCPUDefPtr virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps); +bool virQEMUCapsIsCPUModeSupported(virQEMUCapsPtr qemuCaps, + virCapsPtr caps, + virDomainVirtType type, + virCPUMode mode); const char *virQEMUCapsGetCanonicalMachine(virQEMUCapsPtr qemuCaps, const char *name); int virQEMUCapsGetMachineMaxCpus(virQEMUCapsPtr qemuCaps, -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu_x86.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index ee5b57d..cf8f17d 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1019,21 +1019,28 @@ x86ModelFromCPU(const virCPUDef *cpu, virCPUx86ModelPtr model = NULL; size_t i; + /* host CPU only contains required features; requesting other features + * just returns an empty model + */ + if (cpu->type == VIR_CPU_TYPE_HOST && + policy != VIR_CPU_FEATURE_REQUIRE) + return x86ModelNew(); + if (policy == VIR_CPU_FEATURE_REQUIRE) { if (!(model = x86ModelFind(map, cpu->model))) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown CPU model %s"), cpu->model); - goto error; + return NULL; } - if (!(model = x86ModelCopy(model))) - goto error; - } else if (!(model = x86ModelNew())) { - goto error; - } else if (cpu->type == VIR_CPU_TYPE_HOST) { - return model; + model = x86ModelCopy(model); + } else { + model = x86ModelNew(); } + if (!model) + return NULL; + for (i = 0; i < cpu->nfeatures; i++) { virCPUx86FeaturePtr feature; -- 2.10.0

x86ModelFromCPU is used to provide CPUID data for features matching @policy. This patch allows callers to set @policy to -1 to get combined CPUID for all CPU features (including those implicitly provided a CPU model) specified in CPU def. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - added coverity[dead_error_condition] comment src/cpu/cpu_x86.c | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index cf8f17d..904b59c 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1011,6 +1011,15 @@ x86ModelFind(virCPUx86MapPtr map, } +/* + * Computes CPU model data from a CPU definition associated with features + * matching @policy. If @policy equals -1, the computed model will describe + * all CPU features, i.e., it will contain: + * + * features from model + * + required and forced features + * - disabled and forbidden features + */ static virCPUx86ModelPtr x86ModelFromCPU(const virCPUDef *cpu, virCPUx86MapPtr map, @@ -1023,10 +1032,11 @@ x86ModelFromCPU(const virCPUDef *cpu, * just returns an empty model */ if (cpu->type == VIR_CPU_TYPE_HOST && - policy != VIR_CPU_FEATURE_REQUIRE) + policy != VIR_CPU_FEATURE_REQUIRE && + policy != -1) return x86ModelNew(); - if (policy == VIR_CPU_FEATURE_REQUIRE) { + if (policy == VIR_CPU_FEATURE_REQUIRE || policy == -1) { if (!(model = x86ModelFind(map, cpu->model))) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown CPU model %s"), cpu->model); @@ -1043,9 +1053,15 @@ x86ModelFromCPU(const virCPUDef *cpu, for (i = 0; i < cpu->nfeatures; i++) { virCPUx86FeaturePtr feature; + virCPUFeaturePolicy fpol; - if (cpu->type == VIR_CPU_TYPE_GUEST - && cpu->features[i].policy != policy) + if (cpu->features[i].policy == -1) + fpol = VIR_CPU_FEATURE_REQUIRE; + else + fpol = cpu->features[i].policy; + + if ((policy == -1 && fpol == VIR_CPU_FEATURE_OPTIONAL) || + (policy != -1 && fpol != policy)) continue; if (!(feature = x86FeatureFind(map, cpu->features[i].name))) { @@ -1054,8 +1070,27 @@ x86ModelFromCPU(const virCPUDef *cpu, goto error; } - if (x86DataAdd(&model->data, &feature->data)) + if (policy == -1) { + switch (fpol) { + case VIR_CPU_FEATURE_FORCE: + case VIR_CPU_FEATURE_REQUIRE: + if (x86DataAdd(&model->data, &feature->data) < 0) + goto error; + break; + + case VIR_CPU_FEATURE_DISABLE: + case VIR_CPU_FEATURE_FORBID: + x86DataSubtract(&model->data, &feature->data); + break; + + /* coverity[dead_error_condition] */ + case VIR_CPU_FEATURE_OPTIONAL: + case VIR_CPU_FEATURE_LAST: + break; + } + } else if (x86DataAdd(&model->data, &feature->data) < 0) { goto error; + } } return model; -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu_x86.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 904b59c..d0e1a1a 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2653,8 +2653,11 @@ x86HasFeature(const virCPUData *data, return -1; if (!(feature = x86FeatureFind(map, name)) && - !(feature = x86FeatureFindInternal(name))) + !(feature = x86FeatureFindInternal(name))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown CPU feature %s"), name); goto cleanup; + } ret = x86DataIsSubset(&data->data.x86, &feature->data) ? 1 : 0; -- 2.10.0

The function checks CPUID data for a given feature. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu_x86.c | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index d0e1a1a..8c95b7a 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -767,6 +767,27 @@ x86FeatureFindInternal(const char *name) } +static int +x86FeatureInData(const char *name, + const virCPUx86Data *data, + virCPUx86MapPtr map) +{ + virCPUx86FeaturePtr feature; + + if (!(feature = x86FeatureFind(map, name)) && + !(feature = x86FeatureFindInternal(name))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown CPU feature %s"), name); + return -1; + } + + if (x86DataIsSubset(data, &feature->data)) + return 1; + else + return 0; +} + + static bool x86FeatureIsMigratable(const char *name, void *cpu_map) @@ -2526,15 +2547,12 @@ x86UpdateCustom(virCPUDefPtr guest, for (i = 0; i < guest->nfeatures; i++) { if (guest->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) { - virCPUx86FeaturePtr feature; - if (!(feature = x86FeatureFind(map, guest->features[i].name))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown CPU feature %s"), - guest->features[i].name); - goto cleanup; - } + int supported = x86FeatureInData(guest->features[i].name, + &host_model->data, map); - if (x86DataIsSubset(&host_model->data, &feature->data)) + if (supported < 0) + goto cleanup; + else if (supported) guest->features[i].policy = VIR_CPU_FEATURE_REQUIRE; else guest->features[i].policy = VIR_CPU_FEATURE_DISABLE; @@ -2646,23 +2664,11 @@ x86HasFeature(const virCPUData *data, const char *name) { virCPUx86MapPtr map; - virCPUx86FeaturePtr feature; - int ret = -1; if (!(map = virCPUx86GetMap())) return -1; - if (!(feature = x86FeatureFind(map, name)) && - !(feature = x86FeatureFindInternal(name))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unknown CPU feature %s"), name); - goto cleanup; - } - - ret = x86DataIsSubset(&data->data.x86, &feature->data) ? 1 : 0; - - cleanup: - return ret; + return x86FeatureInData(name, &data->data.x86, map); } static int -- 2.10.0

The reworked API is now called virCPUUpdate and it should change the provided CPU definition into a one which can be consumed by the QEMU command line builder: - host-passthrough remains unchanged - host-model is turned into custom CPU with a model and features copied from host - custom CPU with minimum match is converted similarly to host-model - optional features are updated according to host's CPU Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - adapted to changes in previous patches - s/by/by the/ in the commit message - removed ATTRIBUTE_NONNULL(3) - s/host->arch/arch/ po/POTFILES.in | 1 + src/cpu/cpu.c | 61 ++++-- src/cpu/cpu.h | 11 +- src/cpu/cpu_arm.c | 36 +++- src/cpu/cpu_ppc64.c | 32 ++-- src/cpu/cpu_x86.c | 212 ++++++++------------- src/libvirt_private.syms | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_domain.c | 2 +- src/qemu/qemu_process.c | 2 +- tests/cputest.c | 14 +- .../cputestdata/x86-host+host-model-nofallback.xml | 2 +- tests/cputestdata/x86-host+host-model.xml | 2 +- .../x86-host+host-passthrough-features.xml | 4 + tests/cputestdata/x86-host+host-passthrough.xml | 19 +- tests/cputestdata/x86-host+min.xml | 27 +-- tests/cputestdata/x86-host+pentium3.xml | 39 ++-- tests/cputestdata/x86-host-invtsc+host-model.xml | 2 +- .../cputestdata/x86-host-passthrough-features.xml | 4 + 19 files changed, 228 insertions(+), 246 deletions(-) create mode 100644 tests/cputestdata/x86-host+host-passthrough-features.xml create mode 100644 tests/cputestdata/x86-host-passthrough-features.xml diff --git a/po/POTFILES.in b/po/POTFILES.in index 25dbc84..1469240 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -43,6 +43,7 @@ src/conf/virchrdev.c src/conf/virdomainobjlist.c src/conf/virsecretobj.c src/cpu/cpu.c +src/cpu/cpu_arm.c src/cpu/cpu_map.c src/cpu/cpu_ppc64.c src/cpu/cpu_x86.c diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index fae3885..e6f6335 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -579,38 +579,71 @@ cpuBaseline(virCPUDefPtr *cpus, /** - * cpuUpdate: + * virCPUUpdate: * - * @guest: guest CPU definition + * @arch: CPU architecture + * @guest: guest CPU definition to be updated * @host: host CPU definition * * Updates @guest CPU definition according to @host CPU. This is required to - * support guest CPU definition which are relative to host CPU, such as CPUs - * with VIR_CPU_MODE_CUSTOM and optional features or VIR_CPU_MATCH_MINIMUM, or - * CPUs with non-custom mode (VIR_CPU_MODE_HOST_MODEL, - * VIR_CPU_MODE_HOST_PASSTHROUGH). + * support guest CPU definitions specified relatively to host CPU, such as + * CPUs with VIR_CPU_MODE_CUSTOM and optional features or + * VIR_CPU_MATCH_MINIMUM, or CPUs with VIR_CPU_MODE_HOST_MODEL. + * When the guest CPU was not specified relatively, the function does nothing + * and returns success. * * Returns 0 on success, -1 on error. */ int -cpuUpdate(virCPUDefPtr guest, - const virCPUDef *host) +virCPUUpdate(virArch arch, + virCPUDefPtr guest, + const virCPUDef *host) { struct cpuArchDriver *driver; - VIR_DEBUG("guest=%p, host=%p", guest, host); + VIR_DEBUG("arch=%s, guest=%p mode=%s model=%s, host=%p model=%s", + virArchToString(arch), guest, virCPUModeTypeToString(guest->mode), + NULLSTR(guest->model), host, NULLSTR(host ? host->model : NULL)); - if ((driver = cpuGetSubDriver(host->arch)) == NULL) + if (!(driver = cpuGetSubDriver(arch))) return -1; - if (driver->update == NULL) { + if (guest->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) + return 0; + + if (guest->mode == VIR_CPU_MODE_CUSTOM && + guest->match != VIR_CPU_MATCH_MINIMUM) { + size_t i; + bool optional = false; + + for (i = 0; i < guest->nfeatures; i++) { + if (guest->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) { + optional = true; + break; + } + } + + if (!optional) + return 0; + } + + /* We get here if guest CPU is either + * - host-model + * - custom with minimum match + * - custom with optional features + */ + if (!driver->update) { virReportError(VIR_ERR_NO_SUPPORT, - _("cannot update guest CPU data for %s architecture"), - virArchToString(host->arch)); + _("cannot update guest CPU for %s architecture"), + virArchToString(arch)); return -1; } - return driver->update(guest, host); + if (driver->update(guest, host) < 0) + return -1; + + VIR_DEBUG("model=%s", NULLSTR(guest->model)); + return 0; } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 422818e..dac7688 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -87,8 +87,8 @@ typedef virCPUDefPtr unsigned int flags); typedef int -(*cpuArchUpdate) (virCPUDefPtr guest, - const virCPUDef *host); +(*virCPUArchUpdate)(virCPUDefPtr guest, + const virCPUDef *host); typedef int (*cpuArchHasFeature) (const virCPUData *data, @@ -114,7 +114,7 @@ struct cpuArchDriver { cpuArchNodeData nodeData; cpuArchGuestData guestData; cpuArchBaseline baseline; - cpuArchUpdate update; + virCPUArchUpdate update; cpuArchHasFeature hasFeature; cpuArchDataFormat dataFormat; cpuArchDataParse dataParse; @@ -182,9 +182,10 @@ cpuBaseline (virCPUDefPtr *cpus, ATTRIBUTE_NONNULL(1); int -cpuUpdate (virCPUDefPtr guest, +virCPUUpdate(virArch arch, + virCPUDefPtr guest, const virCPUDef *host) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + ATTRIBUTE_NONNULL(2); int cpuHasFeature(const virCPUData *data, diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index a3aed6b..e8ab954 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -43,15 +43,41 @@ armDataFree(virCPUDataPtr data) VIR_FREE(data); } + static int -armUpdate(virCPUDefPtr guest, - const virCPUDef *host) +virCPUarmUpdate(virCPUDefPtr guest, + const virCPUDef *host) { + int ret = -1; + virCPUDefPtr updated = NULL; + + if (guest->mode != VIR_CPU_MODE_HOST_MODEL) + return 0; + + if (!host) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("unknown host CPU model")); + goto cleanup; + } + + if (!(updated = virCPUDefCopyWithoutModel(guest))) + goto cleanup; + + updated->mode = VIR_CPU_MODE_CUSTOM; + if (virCPUDefCopyModel(updated, host, true) < 0) + goto cleanup; + + virCPUDefStealModel(guest, updated); + guest->mode = VIR_CPU_MODE_CUSTOM; guest->match = VIR_CPU_MATCH_EXACT; - virCPUDefFreeModel(guest); - return virCPUDefCopyModel(guest, host, true); + ret = 0; + + cleanup: + virCPUDefFree(updated); + return ret; } + static virCPUCompareResult armGuestData(virCPUDefPtr host ATTRIBUTE_UNUSED, virCPUDefPtr guest ATTRIBUTE_UNUSED, @@ -104,6 +130,6 @@ struct cpuArchDriver cpuDriverArm = { .nodeData = NULL, .guestData = armGuestData, .baseline = armBaseline, - .update = armUpdate, + .update = virCPUarmUpdate, .hasFeature = NULL, }; diff --git a/src/cpu/cpu_ppc64.c b/src/cpu/cpu_ppc64.c index ad2d6a7..00faa22 100644 --- a/src/cpu/cpu_ppc64.c +++ b/src/cpu/cpu_ppc64.c @@ -751,27 +751,21 @@ ppc64DriverGuestData(virCPUDefPtr host, } static int -ppc64DriverUpdate(virCPUDefPtr guest, - const virCPUDef *host) +virCPUppc64Update(virCPUDefPtr guest, + const virCPUDef *host ATTRIBUTE_UNUSED) { - switch ((virCPUMode) guest->mode) { - case VIR_CPU_MODE_HOST_PASSTHROUGH: + /* + * - host-passthrough doesn't even get here + * - host-model is used for host CPU running in a compatibility mode and + * it needs to remain unchanged + * - custom doesn't support any optional features, there's nothing to + * update + */ + + if (guest->mode == VIR_CPU_MODE_CUSTOM) guest->match = VIR_CPU_MATCH_EXACT; - guest->fallback = VIR_CPU_FALLBACK_FORBID; - virCPUDefFreeModel(guest); - return virCPUDefCopyModel(guest, host, true); - case VIR_CPU_MODE_HOST_MODEL: - case VIR_CPU_MODE_CUSTOM: - return 0; - - case VIR_CPU_MODE_LAST: - break; - } - - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unexpected CPU mode: %d"), guest->mode); - return -1; + return 0; } static virCPUDefPtr @@ -915,7 +909,7 @@ struct cpuArchDriver cpuDriverPPC64 = { .nodeData = ppc64DriverNodeData, .guestData = ppc64DriverGuestData, .baseline = ppc64DriverBaseline, - .update = ppc64DriverUpdate, + .update = virCPUppc64Update, .hasFeature = NULL, .getModels = ppc64DriverGetModels, }; diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 8c95b7a..bd26703 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1122,40 +1122,6 @@ x86ModelFromCPU(const virCPUDef *cpu, } -static int -x86ModelSubtractCPU(virCPUx86ModelPtr model, - const virCPUDef *cpu, - virCPUx86MapPtr map) -{ - virCPUx86ModelPtr cpu_model; - size_t i; - - if (!(cpu_model = x86ModelFind(map, cpu->model))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown CPU model %s"), - cpu->model); - return -1; - } - - x86DataSubtract(&model->data, &cpu_model->data); - - for (i = 0; i < cpu->nfeatures; i++) { - virCPUx86FeaturePtr feature; - - if (!(feature = x86FeatureFind(map, cpu->features[i].name))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown CPU feature %s"), - cpu->features[i].name); - return -1; - } - - x86DataSubtract(&model->data, &feature->data); - } - - return 0; -} - - static virCPUx86CompareResult x86ModelCompare(virCPUx86ModelPtr model1, virCPUx86ModelPtr model2) @@ -2533,23 +2499,85 @@ x86Baseline(virCPUDefPtr *cpus, static int -x86UpdateCustom(virCPUDefPtr guest, +x86UpdateHostModel(virCPUDefPtr guest, + const virCPUDef *host, + virCPUx86MapPtr map) +{ + virCPUDefPtr updated = NULL; + size_t i; + int ret = -1; + + if (!(updated = virCPUDefCopyWithoutModel(host))) + goto cleanup; + + /* Remove non-migratable features by default */ + updated->type = VIR_CPU_TYPE_GUEST; + updated->mode = VIR_CPU_MODE_CUSTOM; + if (virCPUDefCopyModel(updated, host, true) < 0) + goto cleanup; + + i = 0; + while (i < updated->nfeatures) { + if (x86FeatureIsMigratable(updated->features[i].name, map) && + STRNEQ(updated->features[i].name, "cmt") && + STRNEQ(updated->features[i].name, "mbm_total") && + STRNEQ(updated->features[i].name, "mbm_local")) { + i++; + } else { + VIR_FREE(updated->features[i].name); + VIR_DELETE_ELEMENT_INPLACE(updated->features, i, updated->nfeatures); + } + } + + if (guest->vendor_id) { + VIR_FREE(updated->vendor_id); + if (VIR_STRDUP(updated->vendor_id, guest->vendor_id) < 0) + goto cleanup; + } + + for (i = 0; i < guest->nfeatures; i++) { + if (virCPUDefUpdateFeature(updated, + guest->features[i].name, + guest->features[i].policy) < 0) + goto cleanup; + } + + virCPUDefStealModel(guest, updated); + guest->mode = VIR_CPU_MODE_CUSTOM; + guest->match = VIR_CPU_MATCH_EXACT; + ret = 0; + + cleanup: + virCPUDefFree(updated); + return ret; +} + + +static int +virCPUx86Update(virCPUDefPtr guest, const virCPUDef *host) { + virCPUx86ModelPtr model = NULL; + virCPUx86MapPtr map; int ret = -1; size_t i; - virCPUx86MapPtr map; - virCPUx86ModelPtr host_model = NULL; - if (!(map = virCPUx86GetMap()) || - !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE))) + if (!host) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("unknown host CPU model")); + return -1; + } + + if (!(map = virCPUx86GetMap())) + return -1; + + if (!(model = x86ModelFromCPU(host, map, -1))) goto cleanup; for (i = 0; i < guest->nfeatures; i++) { if (guest->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) { int supported = x86FeatureInData(guest->features[i].name, - &host_model->data, map); - + &model->data, map); if (supported < 0) goto cleanup; else if (supported) @@ -2559,107 +2587,19 @@ x86UpdateCustom(virCPUDefPtr guest, } } - if (guest->match == VIR_CPU_MATCH_MINIMUM) { - guest->match = VIR_CPU_MATCH_EXACT; - if (x86ModelSubtractCPU(host_model, guest, map) || - x86DataToCPUFeatures(guest, VIR_CPU_FEATURE_REQUIRE, - &host_model->data, map)) - goto cleanup; - } - - ret = 0; + if (guest->mode == VIR_CPU_MODE_HOST_MODEL || + guest->match == VIR_CPU_MATCH_MINIMUM) + ret = x86UpdateHostModel(guest, host, map); + else + ret = 0; cleanup: - x86ModelFree(host_model); + x86ModelFree(model); return ret; } static int -x86UpdateHostModel(virCPUDefPtr guest, - const virCPUDef *host, - bool passthrough) -{ - virCPUDefPtr oldguest = NULL; - virCPUx86MapPtr map; - size_t i; - int ret = -1; - - if (!(map = virCPUx86GetMap())) - goto cleanup; - - /* update the host model according to the desired configuration */ - if (!(oldguest = virCPUDefCopy(guest))) - goto cleanup; - - virCPUDefFreeModel(guest); - if (virCPUDefCopyModel(guest, host, true) < 0) - goto cleanup; - - if (oldguest->vendor_id) { - VIR_FREE(guest->vendor_id); - if (VIR_STRDUP(guest->vendor_id, oldguest->vendor_id) < 0) - goto cleanup; - } - - /* Remove non-migratable features and CMT related features which QEMU - * knows nothing about. - * Note: this only works as long as no CPU model contains non-migratable - * features directly */ - i = 0; - while (i < guest->nfeatures) { - if (x86FeatureIsMigratable(guest->features[i].name, map) && - STRNEQ(guest->features[i].name, "cmt") && - STRNEQ(guest->features[i].name, "mbm_total") && - STRNEQ(guest->features[i].name, "mbm_local")) { - i++; - } else { - VIR_FREE(guest->features[i].name); - VIR_DELETE_ELEMENT_INPLACE(guest->features, i, guest->nfeatures); - } - } - for (i = 0; !passthrough && i < oldguest->nfeatures; i++) { - if (virCPUDefUpdateFeature(guest, - oldguest->features[i].name, - oldguest->features[i].policy) < 0) - goto cleanup; - } - - ret = 0; - - cleanup: - virCPUDefFree(oldguest); - return ret; -} - - -static int -x86Update(virCPUDefPtr guest, - const virCPUDef *host) -{ - switch ((virCPUMode) guest->mode) { - case VIR_CPU_MODE_CUSTOM: - return x86UpdateCustom(guest, host); - - case VIR_CPU_MODE_HOST_MODEL: - guest->match = VIR_CPU_MATCH_EXACT; - return x86UpdateHostModel(guest, host, false); - - case VIR_CPU_MODE_HOST_PASSTHROUGH: - guest->match = VIR_CPU_MATCH_MINIMUM; - return x86UpdateHostModel(guest, host, true); - - case VIR_CPU_MODE_LAST: - break; - } - - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unexpected CPU mode: %d"), guest->mode); - return -1; -} - - -static int x86HasFeature(const virCPUData *data, const char *name) { @@ -2716,7 +2656,7 @@ struct cpuArchDriver cpuDriverX86 = { #endif .guestData = x86GuestData, .baseline = x86Baseline, - .update = x86Update, + .update = virCPUx86Update, .hasFeature = x86HasFeature, .dataFormat = x86CPUDataFormat, .dataParse = x86CPUDataParse, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3f5df71..5e9a81f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -975,7 +975,7 @@ cpuGetModels; cpuGuestData; cpuHasFeature; cpuNodeData; -cpuUpdate; +virCPUUpdate; # cpu/cpu_x86.h diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index d6462d3..b96f101 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6588,7 +6588,7 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, if (cpu->mode == VIR_CPU_MODE_HOST_MODEL && !migrating && - cpuUpdate(cpu, host) < 0) + virCPUUpdate(def->os.arch, cpu, host) < 0) goto cleanup; if (compareAgainstHost && diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0e30381..3c46a06 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3407,7 +3407,7 @@ qemuDomainDefFormatBuf(virQEMUDriverPtr driver, goto cleanup; } - if (cpuUpdate(def->cpu, caps->host.cpu) < 0) + if (virCPUUpdate(def->os.arch, def->cpu, caps->host.cpu) < 0) goto cleanup; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 83e64b2..d76d0c0 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4487,7 +4487,7 @@ qemuProcessStartValidateGuestCPU(virDomainObjPtr vm, if (cpu->mode == VIR_CPU_MODE_HOST_MODEL && flags & VIR_QEMU_PROCESS_START_NEW && - cpuUpdate(cpu, host) < 0) + virCPUUpdate(vm->def->os.arch, cpu, host) < 0) goto cleanup; cmp = cpuGuestData(host, cpu, &data, &compare_msg); diff --git a/tests/cputest.c b/tests/cputest.c index ee779fb..e6696e9 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -398,7 +398,7 @@ cpuTestUpdate(const void *arg) !(cpu = cpuTestLoadXML(data->arch, data->name))) goto cleanup; - if (cpuUpdate(cpu, host) < 0) + if (virCPUUpdate(host->arch, cpu, host) < 0) goto cleanup; if (virAsprintf(&result, "%s+%s", data->host, data->name) < 0) @@ -622,11 +622,14 @@ mymain(void) host "/" cpu " (" #result ")", \ host, cpu, NULL, 0, NULL, 0, result) +#define DO_TEST_UPDATE_ONLY(arch, host, cpu) \ + DO_TEST(arch, cpuTestUpdate, \ + cpu " on " host, \ + host, cpu, NULL, 0, NULL, 0, 0) \ + #define DO_TEST_UPDATE(arch, host, cpu, result) \ do { \ - DO_TEST(arch, cpuTestUpdate, \ - cpu " on " host, \ - host, cpu, NULL, 0, NULL, 0, 0); \ + DO_TEST_UPDATE_ONLY(arch, host, cpu); \ DO_TEST_COMPARE(arch, host, host "+" cpu, result); \ } while (0) @@ -737,8 +740,9 @@ mymain(void) DO_TEST_UPDATE("x86", "host", "guest", VIR_CPU_COMPARE_SUPERSET); DO_TEST_UPDATE("x86", "host", "host-model", VIR_CPU_COMPARE_IDENTICAL); DO_TEST_UPDATE("x86", "host", "host-model-nofallback", VIR_CPU_COMPARE_IDENTICAL); - DO_TEST_UPDATE("x86", "host", "host-passthrough", VIR_CPU_COMPARE_IDENTICAL); DO_TEST_UPDATE("x86", "host-invtsc", "host-model", VIR_CPU_COMPARE_SUPERSET); + DO_TEST_UPDATE_ONLY("x86", "host", "host-passthrough"); + DO_TEST_UPDATE_ONLY("x86", "host", "host-passthrough-features"); DO_TEST_UPDATE("ppc64", "host", "guest", VIR_CPU_COMPARE_IDENTICAL); DO_TEST_UPDATE("ppc64", "host", "guest-nofallback", VIR_CPU_COMPARE_INCOMPATIBLE); diff --git a/tests/cputestdata/x86-host+host-model-nofallback.xml b/tests/cputestdata/x86-host+host-model-nofallback.xml index bbb68fb..0c3ede0 100644 --- a/tests/cputestdata/x86-host+host-model-nofallback.xml +++ b/tests/cputestdata/x86-host+host-model-nofallback.xml @@ -1,4 +1,4 @@ -<cpu mode='host-model' match='exact'> +<cpu mode='custom' match='exact'> <model fallback='forbid'>Penryn</model> <vendor>Intel</vendor> <topology sockets='1' cores='2' threads='1'/> diff --git a/tests/cputestdata/x86-host+host-model.xml b/tests/cputestdata/x86-host+host-model.xml index c1014e2..a284767 100644 --- a/tests/cputestdata/x86-host+host-model.xml +++ b/tests/cputestdata/x86-host+host-model.xml @@ -1,4 +1,4 @@ -<cpu mode='host-model' match='exact'> +<cpu mode='custom' match='exact'> <model fallback='allow'>Penryn</model> <vendor>Intel</vendor> <feature policy='require' name='dca'/> diff --git a/tests/cputestdata/x86-host+host-passthrough-features.xml b/tests/cputestdata/x86-host+host-passthrough-features.xml new file mode 100644 index 0000000..dc2b775 --- /dev/null +++ b/tests/cputestdata/x86-host+host-passthrough-features.xml @@ -0,0 +1,4 @@ +<cpu mode='host-passthrough'> + <feature policy='disable' name='dca'/> + <feature policy='force' name='vmx'/> +</cpu> diff --git a/tests/cputestdata/x86-host+host-passthrough.xml b/tests/cputestdata/x86-host+host-passthrough.xml index 721fae5..655c7a7 100644 --- a/tests/cputestdata/x86-host+host-passthrough.xml +++ b/tests/cputestdata/x86-host+host-passthrough.xml @@ -1,18 +1 @@ -<cpu mode='host-passthrough' match='minimum'> - <model>Penryn</model> - <vendor>Intel</vendor> - <feature policy='require' name='dca'/> - <feature policy='require' name='xtpr'/> - <feature policy='require' name='tm2'/> - <feature policy='require' name='est'/> - <feature policy='require' name='vmx'/> - <feature policy='require' name='ds_cpl'/> - <feature policy='require' name='monitor'/> - <feature policy='require' name='pbe'/> - <feature policy='require' name='tm'/> - <feature policy='require' name='ht'/> - <feature policy='require' name='ss'/> - <feature policy='require' name='acpi'/> - <feature policy='require' name='ds'/> - <feature policy='require' name='vme'/> -</cpu> +<cpu mode='host-passthrough'/> diff --git a/tests/cputestdata/x86-host+min.xml b/tests/cputestdata/x86-host+min.xml index 6d2d5cd..a284767 100644 --- a/tests/cputestdata/x86-host+min.xml +++ b/tests/cputestdata/x86-host+min.xml @@ -1,17 +1,18 @@ <cpu mode='custom' match='exact'> <model fallback='allow'>Penryn</model> - <feature policy='require' name='vme'/> - <feature policy='require' name='ds'/> - <feature policy='require' name='acpi'/> - <feature policy='require' name='ss'/> - <feature policy='require' name='ht'/> - <feature policy='require' name='tm'/> - <feature policy='require' name='pbe'/> - <feature policy='require' name='monitor'/> - <feature policy='require' name='ds_cpl'/> - <feature policy='require' name='vmx'/> - <feature policy='require' name='est'/> - <feature policy='require' name='tm2'/> - <feature policy='require' name='xtpr'/> + <vendor>Intel</vendor> <feature policy='require' name='dca'/> + <feature policy='require' name='xtpr'/> + <feature policy='require' name='tm2'/> + <feature policy='require' name='est'/> + <feature policy='require' name='vmx'/> + <feature policy='require' name='ds_cpl'/> + <feature policy='require' name='monitor'/> + <feature policy='require' name='pbe'/> + <feature policy='require' name='tm'/> + <feature policy='require' name='ht'/> + <feature policy='require' name='ss'/> + <feature policy='require' name='acpi'/> + <feature policy='require' name='ds'/> + <feature policy='require' name='vme'/> </cpu> diff --git a/tests/cputestdata/x86-host+pentium3.xml b/tests/cputestdata/x86-host+pentium3.xml index a8c15f4..a284767 100644 --- a/tests/cputestdata/x86-host+pentium3.xml +++ b/tests/cputestdata/x86-host+pentium3.xml @@ -1,27 +1,18 @@ <cpu mode='custom' match='exact'> - <model fallback='allow'>pentium3</model> - <feature policy='require' name='apic'/> - <feature policy='require' name='clflush'/> - <feature policy='require' name='ds'/> - <feature policy='require' name='acpi'/> - <feature policy='require' name='sse2'/> - <feature policy='require' name='ss'/> - <feature policy='require' name='ht'/> - <feature policy='require' name='tm'/> - <feature policy='require' name='pbe'/> - <feature policy='require' name='pni'/> - <feature policy='require' name='monitor'/> - <feature policy='require' name='ds_cpl'/> - <feature policy='require' name='vmx'/> - <feature policy='require' name='est'/> - <feature policy='require' name='tm2'/> - <feature policy='require' name='ssse3'/> - <feature policy='require' name='cx16'/> - <feature policy='require' name='xtpr'/> + <model fallback='allow'>Penryn</model> + <vendor>Intel</vendor> <feature policy='require' name='dca'/> - <feature policy='require' name='sse4.1'/> - <feature policy='require' name='syscall'/> - <feature policy='require' name='nx'/> - <feature policy='require' name='lm'/> - <feature policy='require' name='lahf_lm'/> + <feature policy='require' name='xtpr'/> + <feature policy='require' name='tm2'/> + <feature policy='require' name='est'/> + <feature policy='require' name='vmx'/> + <feature policy='require' name='ds_cpl'/> + <feature policy='require' name='monitor'/> + <feature policy='require' name='pbe'/> + <feature policy='require' name='tm'/> + <feature policy='require' name='ht'/> + <feature policy='require' name='ss'/> + <feature policy='require' name='acpi'/> + <feature policy='require' name='ds'/> + <feature policy='require' name='vme'/> </cpu> diff --git a/tests/cputestdata/x86-host-invtsc+host-model.xml b/tests/cputestdata/x86-host-invtsc+host-model.xml index ad1bbf8..998ed23 100644 --- a/tests/cputestdata/x86-host-invtsc+host-model.xml +++ b/tests/cputestdata/x86-host-invtsc+host-model.xml @@ -1,4 +1,4 @@ -<cpu mode='host-model' match='exact'> +<cpu mode='custom' match='exact'> <model fallback='allow'>SandyBridge</model> <vendor>Intel</vendor> <feature policy='require' name='osxsave'/> diff --git a/tests/cputestdata/x86-host-passthrough-features.xml b/tests/cputestdata/x86-host-passthrough-features.xml new file mode 100644 index 0000000..dc2b775 --- /dev/null +++ b/tests/cputestdata/x86-host-passthrough-features.xml @@ -0,0 +1,4 @@ +<cpu mode='host-passthrough'> + <feature policy='disable' name='dca'/> + <feature policy='force' name='vmx'/> +</cpu> -- 2.10.0

Keeping nfeatures_max set to 0 while nfeatures > 0 and some features are already stored in features array is just asking for problems once we want to add a new feature into the array. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu_x86.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index bd26703..f424f72 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1871,10 +1871,12 @@ x86Decode(virCPUDefPtr cpu, if (vendor && VIR_STRDUP(cpu->vendor, vendor->name) < 0) goto cleanup; - cpu->model = cpuModel->model; + VIR_STEAL_PTR(cpu->model, cpuModel->model); + VIR_STEAL_PTR(cpu->features, cpuModel->features); cpu->nfeatures = cpuModel->nfeatures; - cpu->features = cpuModel->features; - VIR_FREE(cpuModel); + cpuModel->nfeatures = 0; + cpu->nfeatures_max = cpuModel->nfeatures_max; + cpuModel->nfeatures_max = 0; ret = 0; -- 2.10.0

The API is supposed to make sure the provided CPU definition does not use a CPU model which is not supported by the hypervisor (if at all possible, of course). Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - adapted to changes in previous patches src/cpu/cpu.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ src/cpu/cpu.h | 14 ++++++++++++ src/cpu/cpu_x86.c | 51 +++++++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 1 + 4 files changed, 125 insertions(+) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index e6f6335..748b6f9 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -809,3 +809,62 @@ cpuGetModels(virArch arch, char ***models) return driver->getModels(models); } + + +/** + * virCPUTranslate: + * + * @arch: CPU architecture + * @cpu: CPU definition to be translated + * @models: NULL-terminated list of allowed CPU models (NULL if all are allowed) + * @nmodels: number of CPU models in @models + * + * Translates @cpu model (if allowed by @cpu->fallback) to a closest CPU model + * from @models list. + * + * The function does nothing (and returns 0) if @cpu does not have to be + * translated. + * + * Returns -1 on error, 0 on success. + */ +int +virCPUTranslate(virArch arch, + virCPUDefPtr cpu, + char **models, + unsigned int nmodels) +{ + struct cpuArchDriver *driver; + + VIR_DEBUG("arch=%s, cpu=%p, model=%s, models=%p, nmodels=%u", + virArchToString(arch), cpu, NULLSTR(cpu->model), models, nmodels); + + if (!(driver = cpuGetSubDriver(arch))) + return -1; + + if (cpu->mode == VIR_CPU_MODE_HOST_MODEL || + cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) + return 0; + + if (cpuModelIsAllowed(cpu->model, (const char **) models, nmodels)) + return 0; + + if (cpu->fallback != VIR_CPU_FALLBACK_ALLOW) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("CPU model %s is not supported by hypervisor"), + cpu->model); + return -1; + } + + if (!driver->translate) { + virReportError(VIR_ERR_NO_SUPPORT, + _("cannot translate CPU model %s to a supported model"), + cpu->model); + return -1; + } + + if (driver->translate(cpu, (const char **) models, nmodels) < 0) + return -1; + + VIR_DEBUG("model=%s", NULLSTR(cpu->model)); + return 0; +} diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index dac7688..6a21bfa 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -103,6 +103,11 @@ typedef virCPUDataPtr typedef int (*cpuArchGetModels) (char ***models); +typedef int +(*virCPUArchTranslate)(virCPUDefPtr cpu, + const char **models, + unsigned int nmodels); + struct cpuArchDriver { const char *name; const virArch *arch; @@ -119,6 +124,7 @@ struct cpuArchDriver { cpuArchDataFormat dataFormat; cpuArchDataParse dataParse; cpuArchGetModels getModels; + virCPUArchTranslate translate; }; @@ -202,6 +208,14 @@ cpuModelIsAllowed(const char *model, int cpuGetModels(virArch arch, char ***models); +int +virCPUTranslate(virArch arch, + virCPUDefPtr cpu, + char **models, + unsigned int nmodels) + ATTRIBUTE_NONNULL(2); + + /* cpuDataFormat and cpuDataParse are implemented for unit tests only and * have no real-life usage */ diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index f424f72..a45427a 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2643,6 +2643,56 @@ x86GetModels(char ***models) } +static int +virCPUx86Translate(virCPUDefPtr cpu, + const char **models, + unsigned int nmodels) +{ + virCPUDefPtr translated = NULL; + virCPUx86MapPtr map; + virCPUx86ModelPtr model = NULL; + size_t i; + int ret = -1; + + if (!(map = virCPUx86GetMap())) + goto cleanup; + + if (!(model = x86ModelFromCPU(cpu, map, -1))) + goto cleanup; + + if (model->vendor && + virCPUx86DataAddCPUID(&model->data, &model->vendor->cpuid) < 0) + goto cleanup; + + if (x86DataAddSignature(&model->data, model->signature) < 0) + goto cleanup; + + if (!(translated = virCPUDefCopyWithoutModel(cpu))) + goto cleanup; + + if (VIR_STRDUP(translated->vendor, cpu->vendor) < 0 || + VIR_STRDUP(translated->vendor_id, cpu->vendor_id) < 0) + goto cleanup; + + if (x86Decode(translated, &model->data, models, nmodels, NULL, 0) < 0) + goto cleanup; + + for (i = 0; i < cpu->nfeatures; i++) { + virCPUFeatureDefPtr f = cpu->features + i; + if (virCPUDefUpdateFeature(translated, f->name, f->policy) < 0) + goto cleanup; + } + + virCPUDefStealModel(cpu, translated); + ret = 0; + + cleanup: + virCPUDefFree(translated); + x86ModelFree(model); + return ret; +} + + struct cpuArchDriver cpuDriverX86 = { .name = "x86", .arch = archs, @@ -2663,4 +2713,5 @@ struct cpuArchDriver cpuDriverX86 = { .dataFormat = x86CPUDataFormat, .dataParse = x86CPUDataParse, .getModels = x86GetModels, + .translate = virCPUx86Translate, }; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 5e9a81f..aa8d390 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -975,6 +975,7 @@ cpuGetModels; cpuGuestData; cpuHasFeature; cpuNodeData; +virCPUTranslate; virCPUUpdate; -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - new patch (separated from 38/41) src/cpu/cpu.c | 10 +++++----- src/cpu/cpu.h | 10 +++++----- src/cpu/cpu_arm.c | 1 - src/cpu/cpu_ppc64.c | 1 - src/cpu/cpu_s390.c | 1 - src/cpu/cpu_x86.c | 6 +++--- src/libvirt_private.syms | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_parse_command.c | 2 +- src/qemu/qemu_process.c | 10 +++++----- src/vmware/vmware_conf.c | 6 +++--- tests/cputest.c | 2 +- 12 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 748b6f9..99c1a4c 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -648,7 +648,7 @@ virCPUUpdate(virArch arch, /** - * cpuHasFeature: + * virCPUDataCheckFeature: * * @data: internal CPU representation * @feature: feature to be checked for @@ -659,8 +659,8 @@ virCPUUpdate(virArch arch, * -1 on error. */ int -cpuHasFeature(const virCPUData *data, - const char *feature) +virCPUDataCheckFeature(const virCPUData *data, + const char *feature) { struct cpuArchDriver *driver; @@ -669,14 +669,14 @@ cpuHasFeature(const virCPUData *data, if ((driver = cpuGetSubDriver(data->arch)) == NULL) return -1; - if (driver->hasFeature == NULL) { + if (!driver->dataCheckFeature) { virReportError(VIR_ERR_NO_SUPPORT, _("cannot check guest CPU data for %s architecture"), virArchToString(data->arch)); return -1; } - return driver->hasFeature(data, feature); + return driver->dataCheckFeature(data, feature); } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 6a21bfa..71fa2da 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -91,8 +91,8 @@ typedef int const virCPUDef *host); typedef int -(*cpuArchHasFeature) (const virCPUData *data, - const char *feature); +(*virCPUArchDataCheckFeature)(const virCPUData *data, + const char *feature); typedef char * (*cpuArchDataFormat)(const virCPUData *data); @@ -120,7 +120,7 @@ struct cpuArchDriver { cpuArchGuestData guestData; cpuArchBaseline baseline; virCPUArchUpdate update; - cpuArchHasFeature hasFeature; + virCPUArchDataCheckFeature dataCheckFeature; cpuArchDataFormat dataFormat; cpuArchDataParse dataParse; cpuArchGetModels getModels; @@ -194,8 +194,8 @@ virCPUUpdate(virArch arch, ATTRIBUTE_NONNULL(2); int -cpuHasFeature(const virCPUData *data, - const char *feature) +virCPUDataCheckFeature(const virCPUData *data, + const char *feature) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index e8ab954..37bb71a 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -131,5 +131,4 @@ struct cpuArchDriver cpuDriverArm = { .guestData = armGuestData, .baseline = armBaseline, .update = virCPUarmUpdate, - .hasFeature = NULL, }; diff --git a/src/cpu/cpu_ppc64.c b/src/cpu/cpu_ppc64.c index 00faa22..6f005e5 100644 --- a/src/cpu/cpu_ppc64.c +++ b/src/cpu/cpu_ppc64.c @@ -910,6 +910,5 @@ struct cpuArchDriver cpuDriverPPC64 = { .guestData = ppc64DriverGuestData, .baseline = ppc64DriverBaseline, .update = virCPUppc64Update, - .hasFeature = NULL, .getModels = ppc64DriverGetModels, }; diff --git a/src/cpu/cpu_s390.c b/src/cpu/cpu_s390.c index 23a7f9d..fb352a0 100644 --- a/src/cpu/cpu_s390.c +++ b/src/cpu/cpu_s390.c @@ -83,5 +83,4 @@ struct cpuArchDriver cpuDriverS390 = { .guestData = NULL, .baseline = NULL, .update = NULL, - .hasFeature = NULL, }; diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index a45427a..ae552ac 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2602,8 +2602,8 @@ virCPUx86Update(virCPUDefPtr guest, static int -x86HasFeature(const virCPUData *data, - const char *name) +virCPUx86DataCheckFeature(const virCPUData *data, + const char *name) { virCPUx86MapPtr map; @@ -2709,7 +2709,7 @@ struct cpuArchDriver cpuDriverX86 = { .guestData = x86GuestData, .baseline = x86Baseline, .update = virCPUx86Update, - .hasFeature = x86HasFeature, + .dataCheckFeature = virCPUx86DataCheckFeature, .dataFormat = x86CPUDataFormat, .dataParse = x86CPUDataParse, .getModels = x86GetModels, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index aa8d390..8575f55 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -973,8 +973,8 @@ cpuDecode; cpuEncode; cpuGetModels; cpuGuestData; -cpuHasFeature; cpuNodeData; +virCPUDataCheckFeature; virCPUTranslate; virCPUUpdate; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index b96f101..1154ac6 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6600,7 +6600,7 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, */ if ((def->os.arch == VIR_ARCH_X86_64 || def->os.arch == VIR_ARCH_I686) && compareAgainstHost) { - int hasSVM = cpuHasFeature(data, "svm"); + int hasSVM = virCPUDataCheckFeature(data, "svm"); if (hasSVM < 0) goto cleanup; *hasHwVirt = hasSVM > 0 ? true : false; diff --git a/src/qemu/qemu_parse_command.c b/src/qemu/qemu_parse_command.c index 82d1621..e3a6a34 100644 --- a/src/qemu/qemu_parse_command.c +++ b/src/qemu/qemu_parse_command.c @@ -1605,7 +1605,7 @@ qemuParseCommandLineCPU(virDomainDefPtr dom, NULL, NULL, NULL, NULL) < 0) goto cleanup; - is_32bit = (cpuHasFeature(cpuData, "lm") != 1); + is_32bit = (virCPUDataCheckFeature(cpuData, "lm") != 1); cpuDataFree(cpuData); } else if (model) { is_32bit = STREQ(model, "qemu32"); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index d76d0c0..72046df 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3702,7 +3702,7 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver, } if (def->features[VIR_DOMAIN_FEATURE_PVSPINLOCK] == VIR_TRISTATE_SWITCH_ON) { - if (!cpuHasFeature(guestcpu, VIR_CPU_x86_KVM_PV_UNHALT)) { + if (!virCPUDataCheckFeature(guestcpu, VIR_CPU_x86_KVM_PV_UNHALT)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("host doesn't support paravirtual spinlocks")); goto cleanup; @@ -3715,7 +3715,7 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver, if (virAsprintf(&cpuFeature, "__kvm_hv_%s", virDomainHypervTypeToString(i)) < 0) goto cleanup; - if (!cpuHasFeature(guestcpu, cpuFeature)) { + if (!virCPUDataCheckFeature(guestcpu, cpuFeature)) { switch ((virDomainHyperv) i) { case VIR_DOMAIN_HYPERV_RELAXED: case VIR_DOMAIN_HYPERV_VAPIC: @@ -3751,7 +3751,7 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver, continue; if (STREQ(feature->name, "invtsc") && - !cpuHasFeature(guestcpu, feature->name)) { + !virCPUDataCheckFeature(guestcpu, feature->name)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("host doesn't support invariant TSC")); goto cleanup; @@ -4495,8 +4495,8 @@ qemuProcessStartValidateGuestCPU(virDomainObjPtr vm, case VIR_CPU_COMPARE_INCOMPATIBLE: if (cpuEncode(host->arch, host, NULL, &hostData, NULL, NULL, NULL, NULL) == 0 && - (!cpuHasFeature(hostData, "hle") || - !cpuHasFeature(hostData, "rtm")) && + (!virCPUDataCheckFeature(hostData, "hle") || + !virCPUDataCheckFeature(hostData, "rtm")) && (STREQ_NULLABLE(cpu->model, "Haswell") || STREQ_NULLABLE(cpu->model, "Broadwell"))) noTSX = true; diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c index 8736976..4222f4e 100644 --- a/src/vmware/vmware_conf.c +++ b/src/vmware/vmware_conf.c @@ -100,9 +100,9 @@ vmwareCapsInit(void) * - Host CPU is x86_64 with virtualization extensions */ if (caps->host.arch == VIR_ARCH_X86_64 || - (cpuHasFeature(data, "lm") && - (cpuHasFeature(data, "vmx") || - cpuHasFeature(data, "svm")))) { + (virCPUDataCheckFeature(data, "lm") && + (virCPUDataCheckFeature(data, "vmx") || + virCPUDataCheckFeature(data, "svm")))) { if ((guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, diff --git a/tests/cputest.c b/tests/cputest.c index e6696e9..ce8f8c0 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -430,7 +430,7 @@ cpuTestHasFeature(const void *arg) NULL, NULL, NULL, NULL) < 0) goto cleanup; - result = cpuHasFeature(hostData, data->name); + result = virCPUDataCheckFeature(hostData, data->name); if (data->result == -1) virResetLastError(); -- 2.10.0

To match our coding style and to provide better debug and error messages. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - new patch (separated from 38/41) src/cpu/cpu.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 99c1a4c..cc7d03c 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -650,7 +650,7 @@ virCPUUpdate(virArch arch, /** * virCPUDataCheckFeature: * - * @data: internal CPU representation + * @data: CPU data * @feature: feature to be checked for * * Checks whether @feature is supported by the CPU described by @data. @@ -664,14 +664,15 @@ virCPUDataCheckFeature(const virCPUData *data, { struct cpuArchDriver *driver; - VIR_DEBUG("data=%p, feature=%s", data, feature); + VIR_DEBUG("arch=%s, data=%p, feature=%s", + virArchToString(data->arch), data, feature); - if ((driver = cpuGetSubDriver(data->arch)) == NULL) + if (!(driver = cpuGetSubDriver(data->arch))) return -1; if (!driver->dataCheckFeature) { virReportError(VIR_ERR_NO_SUPPORT, - _("cannot check guest CPU data for %s architecture"), + _("cannot check guest CPU feature for %s architecture"), virArchToString(data->arch)); return -1; } -- 2.10.0

The function is similar to virCPUDataCheckFeature, but it works directly on CPU definition rather than requiring it to be transformed into CPU data first. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - new patch (separated from 38/41) src/cpu/cpu.c | 36 ++++++++++++++++++++++++++++++++++++ src/cpu/cpu.h | 13 +++++++++++++ src/cpu/cpu_x86.c | 23 +++++++++++++++++++++++ src/libvirt_private.syms | 1 + tests/cputest.c | 6 +++++- 5 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index cc7d03c..2ab61d7 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -648,6 +648,42 @@ virCPUUpdate(virArch arch, /** + * virCPUCheckFeature: + * + * @arch: CPU architecture + * @cpu: CPU definition + * @feature: feature to be checked for + * + * Checks whether @feature is supported by the CPU described by @cpu. + * + * Returns 1 if the feature is supported, 0 if it's not supported, or + * -1 on error. + */ +int +virCPUCheckFeature(virArch arch, + const virCPUDef *cpu, + const char *feature) +{ + struct cpuArchDriver *driver; + + VIR_DEBUG("arch=%s, cpu=%p, feature=%s", + virArchToString(arch), cpu, feature); + + if (!(driver = cpuGetSubDriver(arch))) + return -1; + + if (!driver->checkFeature) { + virReportError(VIR_ERR_NO_SUPPORT, + _("cannot check guest CPU feature for %s architecture"), + virArchToString(arch)); + return -1; + } + + return driver->checkFeature(cpu, feature); +} + + +/** * virCPUDataCheckFeature: * * @data: CPU data diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 71fa2da..f14c2c8 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -91,6 +91,10 @@ typedef int const virCPUDef *host); typedef int +(*virCPUArchCheckFeature)(const virCPUDef *cpu, + const char *feature); + +typedef int (*virCPUArchDataCheckFeature)(const virCPUData *data, const char *feature); @@ -120,6 +124,7 @@ struct cpuArchDriver { cpuArchGuestData guestData; cpuArchBaseline baseline; virCPUArchUpdate update; + virCPUArchCheckFeature checkFeature; virCPUArchDataCheckFeature dataCheckFeature; cpuArchDataFormat dataFormat; cpuArchDataParse dataParse; @@ -193,6 +198,14 @@ virCPUUpdate(virArch arch, const virCPUDef *host) ATTRIBUTE_NONNULL(2); + +int +virCPUCheckFeature(virArch arch, + const virCPUDef *cpu, + const char *feature) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + + int virCPUDataCheckFeature(const virCPUData *data, const char *feature) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index ae552ac..7224d76 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2602,6 +2602,28 @@ virCPUx86Update(virCPUDefPtr guest, static int +virCPUx86CheckFeature(const virCPUDef *cpu, + const char *name) +{ + int ret = -1; + virCPUx86MapPtr map; + virCPUx86ModelPtr model = NULL; + + if (!(map = virCPUx86GetMap())) + return -1; + + if (!(model = x86ModelFromCPU(cpu, map, -1))) + goto cleanup; + + ret = x86FeatureInData(name, &model->data, map); + + cleanup: + x86ModelFree(model); + return ret; +} + + +static int virCPUx86DataCheckFeature(const virCPUData *data, const char *name) { @@ -2709,6 +2731,7 @@ struct cpuArchDriver cpuDriverX86 = { .guestData = x86GuestData, .baseline = x86Baseline, .update = virCPUx86Update, + .checkFeature = virCPUx86CheckFeature, .dataCheckFeature = virCPUx86DataCheckFeature, .dataFormat = x86CPUDataFormat, .dataParse = x86CPUDataParse, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8575f55..c4fd7ae 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -974,6 +974,7 @@ cpuEncode; cpuGetModels; cpuGuestData; cpuNodeData; +virCPUCheckFeature; virCPUDataCheckFeature; virCPUTranslate; virCPUUpdate; diff --git a/tests/cputest.c b/tests/cputest.c index ce8f8c0..72f00b6 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -430,7 +430,11 @@ cpuTestHasFeature(const void *arg) NULL, NULL, NULL, NULL) < 0) goto cleanup; - result = virCPUDataCheckFeature(hostData, data->name); + result = virCPUCheckFeature(host->arch, host, data->name); + + if (data->result == result) + result = virCPUDataCheckFeature(hostData, data->name); + if (data->result == -1) virResetLastError(); -- 2.10.0

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - new patch src/cpu/cpu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 2ab61d7..ba5bf1a 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -95,13 +95,16 @@ cpuGetSubDriverByName(const char *name) * * @host: host CPU definition * @xml: XML description of either guest or host CPU to be compared with @host + * @failIncompatible: return an error instead of VIR_CPU_COMPARE_INCOMPATIBLE * * Compares the CPU described by @xml with @host CPU. * * Returns VIR_CPU_COMPARE_ERROR on error, VIR_CPU_COMPARE_INCOMPATIBLE when * the two CPUs are incompatible, VIR_CPU_COMPARE_IDENTICAL when the two CPUs * are identical, VIR_CPU_COMPARE_SUPERSET when the @xml CPU is a superset of - * the @host CPU. + * the @host CPU. If @failIncompatible is true, the function will return + * VIR_CPU_COMPARE_ERROR (and set VIR_ERR_CPU_INCOMPATIBLE error) when the + * two CPUs are incompatible. */ virCPUCompareResult cpuCompareXML(virCPUDefPtr host, @@ -138,13 +141,16 @@ cpuCompareXML(virCPUDefPtr host, * * @host: host CPU definition * @cpu: either guest or host CPU to be compared with @host + * @failIncompatible: return an error instead of VIR_CPU_COMPARE_INCOMPATIBLE * * Compares the CPU described by @cpu with @host CPU. * * Returns VIR_CPU_COMPARE_ERROR on error, VIR_CPU_COMPARE_INCOMPATIBLE when * the two CPUs are incompatible, VIR_CPU_COMPARE_IDENTICAL when the two CPUs * are identical, VIR_CPU_COMPARE_SUPERSET when the @cpu CPU is a superset of - * the @host CPU. + * the @host CPU. If @failIncompatible is true, the function will return + * VIR_CPU_COMPARE_ERROR (and set VIR_ERR_CPU_INCOMPATIBLE error) when the + * two CPUs are incompatible. */ virCPUCompareResult cpuCompare(virCPUDefPtr host, -- 2.10.0

Both cpuCompare* APIs are renamed to virCPUCompare*. And they should now work for any guest CPU definition, i.e., even for host-passthrough (trivial) and host-model CPUs. The implementation in x86 driver is enhanced to provide a hint about -noTSX Broadwell and Haswell models when appropriate. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - adapted to changes in previous patches - added check for xml == NULL in virCPUCompareXML src/cpu/cpu.c | 42 +++++++++++++++--------- src/cpu/cpu.h | 21 ++++++------ src/cpu/cpu_arm.c | 8 ++--- src/cpu/cpu_ppc64.c | 15 +++++++-- src/cpu/cpu_x86.c | 84 ++++++++++++++++++++++++++++++++++++------------ src/libvirt_private.syms | 4 +-- src/libxl/libxl_driver.c | 14 ++------ src/qemu/qemu_driver.c | 14 ++------ tests/cputest.c | 4 +-- 9 files changed, 126 insertions(+), 80 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index ba5bf1a..995d925 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -91,8 +91,9 @@ cpuGetSubDriverByName(const char *name) /** - * cpuCompareXML: + * virCPUCompareXML: * + * @arch: CPU architecture * @host: host CPU definition * @xml: XML description of either guest or host CPU to be compared with @host * @failIncompatible: return an error instead of VIR_CPU_COMPARE_INCOMPATIBLE @@ -107,25 +108,31 @@ cpuGetSubDriverByName(const char *name) * two CPUs are incompatible. */ virCPUCompareResult -cpuCompareXML(virCPUDefPtr host, - const char *xml, - bool failIncompatible) +virCPUCompareXML(virArch arch, + virCPUDefPtr host, + const char *xml, + bool failIncompatible) { xmlDocPtr doc = NULL; xmlXPathContextPtr ctxt = NULL; virCPUDefPtr cpu = NULL; virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR; - VIR_DEBUG("host=%p, xml=%s", host, NULLSTR(xml)); + VIR_DEBUG("arch=%s, host=%p, xml=%s", + virArchToString(arch), host, NULLSTR(xml)); + + if (!xml) { + virReportError(VIR_ERR_INVALID_ARG, "%s", _("missing CPU definition")); + goto cleanup; + } if (!(doc = virXMLParseStringCtxt(xml, _("(CPU_definition)"), &ctxt))) goto cleanup; - cpu = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_AUTO); - if (cpu == NULL) + if (!(cpu = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_AUTO))) goto cleanup; - ret = cpuCompare(host, cpu, failIncompatible); + ret = virCPUCompare(arch, host, cpu, failIncompatible); cleanup: virCPUDefFree(cpu); @@ -137,8 +144,9 @@ cpuCompareXML(virCPUDefPtr host, /** - * cpuCompare: + * virCPUCompare: * + * @arch: CPU architecture * @host: host CPU definition * @cpu: either guest or host CPU to be compared with @host * @failIncompatible: return an error instead of VIR_CPU_COMPARE_INCOMPATIBLE @@ -153,21 +161,23 @@ cpuCompareXML(virCPUDefPtr host, * two CPUs are incompatible. */ virCPUCompareResult -cpuCompare(virCPUDefPtr host, - virCPUDefPtr cpu, - bool failIncompatible) +virCPUCompare(virArch arch, + virCPUDefPtr host, + virCPUDefPtr cpu, + bool failIncompatible) { struct cpuArchDriver *driver; - VIR_DEBUG("host=%p, cpu=%p", host, cpu); + VIR_DEBUG("arch=%s, host=%p, cpu=%p", + virArchToString(arch), host, cpu); - if ((driver = cpuGetSubDriver(host->arch)) == NULL) + if (!(driver = cpuGetSubDriver(arch))) return VIR_CPU_COMPARE_ERROR; - if (driver->compare == NULL) { + if (!driver->compare) { virReportError(VIR_ERR_NO_SUPPORT, _("cannot compare CPUs of %s architecture"), - virArchToString(host->arch)); + virArchToString(arch)); return VIR_CPU_COMPARE_ERROR; } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index f14c2c8..51bacb7 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -45,7 +45,7 @@ struct _virCPUData { typedef virCPUCompareResult -(*cpuArchCompare) (virCPUDefPtr host, +(*virCPUArchCompare)(virCPUDefPtr host, virCPUDefPtr cpu, bool failIncompatible); @@ -116,7 +116,7 @@ struct cpuArchDriver { const char *name; const virArch *arch; unsigned int narch; - cpuArchCompare compare; + virCPUArchCompare compare; cpuArchDecode decode; cpuArchEncode encode; cpuArchDataFree free; @@ -134,16 +134,17 @@ struct cpuArchDriver { virCPUCompareResult -cpuCompareXML(virCPUDefPtr host, - const char *xml, - bool failIncompatible) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +virCPUCompareXML(virArch arch, + virCPUDefPtr host, + const char *xml, + bool failIncompatible); virCPUCompareResult -cpuCompare (virCPUDefPtr host, - virCPUDefPtr cpu, - bool failIncompatible) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +virCPUCompare(virArch arch, + virCPUDefPtr host, + virCPUDefPtr cpu, + bool failIncompatible) + ATTRIBUTE_NONNULL(3); int cpuDecode (virCPUDefPtr cpu, diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 37bb71a..db603a6 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -112,9 +112,9 @@ armBaseline(virCPUDefPtr *cpus, } static virCPUCompareResult -armCompare(virCPUDefPtr host ATTRIBUTE_UNUSED, - virCPUDefPtr cpu ATTRIBUTE_UNUSED, - bool failMessages ATTRIBUTE_UNUSED) +virCPUarmCompare(virCPUDefPtr host ATTRIBUTE_UNUSED, + virCPUDefPtr cpu ATTRIBUTE_UNUSED, + bool failMessages ATTRIBUTE_UNUSED) { return VIR_CPU_COMPARE_IDENTICAL; } @@ -123,7 +123,7 @@ struct cpuArchDriver cpuDriverArm = { .name = "arm", .arch = archs, .narch = ARRAY_CARDINALITY(archs), - .compare = armCompare, + .compare = virCPUarmCompare, .decode = NULL, .encode = NULL, .free = armDataFree, diff --git a/src/cpu/cpu_ppc64.c b/src/cpu/cpu_ppc64.c index 6f005e5..21ea0e1 100644 --- a/src/cpu/cpu_ppc64.c +++ b/src/cpu/cpu_ppc64.c @@ -634,13 +634,24 @@ ppc64Compute(virCPUDefPtr host, } static virCPUCompareResult -ppc64DriverCompare(virCPUDefPtr host, +virCPUppc64Compare(virCPUDefPtr host, virCPUDefPtr cpu, bool failIncompatible) { virCPUCompareResult ret; char *message = NULL; + if (!host || !host->model) { + if (failIncompatible) { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", + _("unknown host CPU")); + } else { + VIR_WARN("unknown host CPU"); + ret = VIR_CPU_COMPARE_INCOMPATIBLE; + } + return -1; + } + ret = ppc64Compute(host, cpu, NULL, &message); if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) { @@ -902,7 +913,7 @@ struct cpuArchDriver cpuDriverPPC64 = { .name = "ppc64", .arch = archs, .narch = ARRAY_CARDINALITY(archs), - .compare = ppc64DriverCompare, + .compare = virCPUppc64Compare, .decode = ppc64DriverDecode, .encode = NULL, .free = ppc64DriverFree, diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 7224d76..6397dcb 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1057,7 +1057,8 @@ x86ModelFromCPU(const virCPUDef *cpu, policy != -1) return x86ModelNew(); - if (policy == VIR_CPU_FEATURE_REQUIRE || policy == -1) { + if (cpu->model && + (policy == VIR_CPU_FEATURE_REQUIRE || policy == -1)) { if (!(model = x86ModelFind(map, cpu->model))) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown CPU model %s"), cpu->model); @@ -1519,12 +1520,6 @@ x86Compute(virCPUDefPtr host, virArch arch; size_t i; - if (!cpu->model) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("no guest CPU model specified")); - return VIR_CPU_COMPARE_ERROR; - } - if (cpu->arch != VIR_ARCH_NONE) { bool found = false; @@ -1565,7 +1560,7 @@ x86Compute(virCPUDefPtr host, } if (!(map = virCPUx86GetMap()) || - !(host_model = x86ModelFromCPU(host, map, VIR_CPU_FEATURE_REQUIRE)) || + !(host_model = x86ModelFromCPU(host, map, -1)) || !(cpu_force = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_FORCE)) || !(cpu_require = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_REQUIRE)) || !(cpu_optional = x86ModelFromCPU(cpu, map, VIR_CPU_FEATURE_OPTIONAL)) || @@ -1664,25 +1659,68 @@ x86Compute(virCPUDefPtr host, static virCPUCompareResult -x86Compare(virCPUDefPtr host, - virCPUDefPtr cpu, - bool failIncompatible) +virCPUx86Compare(virCPUDefPtr host, + virCPUDefPtr cpu, + bool failIncompatible) { - virCPUCompareResult ret; + virCPUCompareResult ret = VIR_CPU_COMPARE_ERROR; + virCPUx86MapPtr map; + virCPUx86ModelPtr model = NULL; char *message = NULL; + if (!host || !host->model) { + if (failIncompatible) { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", + _("unknown host CPU")); + } else { + VIR_WARN("unknown host CPU"); + ret = VIR_CPU_COMPARE_INCOMPATIBLE; + } + goto cleanup; + } + ret = x86Compute(host, cpu, NULL, &message); - if (failIncompatible && ret == VIR_CPU_COMPARE_INCOMPATIBLE) { - ret = VIR_CPU_COMPARE_ERROR; - if (message) { - virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message); - } else { - virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL); + if (ret == VIR_CPU_COMPARE_INCOMPATIBLE) { + bool noTSX = false; + + if (STREQ_NULLABLE(cpu->model, "Haswell") || + STREQ_NULLABLE(cpu->model, "Broadwell")) { + if (!(map = virCPUx86GetMap())) + goto cleanup; + + if (!(model = x86ModelFromCPU(cpu, map, -1))) + goto cleanup; + + noTSX = !x86FeatureInData("hle", &model->data, map) || + !x86FeatureInData("rtm", &model->data, map); + } + + if (failIncompatible) { + ret = VIR_CPU_COMPARE_ERROR; + if (message) { + if (noTSX) { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, + _("%s; try using '%s-noTSX' CPU model"), + message, cpu->model); + } else { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", message); + } + } else { + if (noTSX) { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, + _("try using '%s-noTSX' CPU model"), + cpu->model); + } else { + virReportError(VIR_ERR_CPU_INCOMPATIBLE, NULL); + } + } } } - VIR_FREE(message); + cleanup: + VIR_FREE(message); + x86ModelFree(model); return ret; } @@ -1693,6 +1731,12 @@ x86GuestData(virCPUDefPtr host, virCPUDataPtr *data, char **message) { + if (!guest->model) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("no guest CPU model specified")); + return VIR_CPU_COMPARE_ERROR; + } + return x86Compute(host, guest, data, message); } @@ -2719,7 +2763,7 @@ struct cpuArchDriver cpuDriverX86 = { .name = "x86", .arch = archs, .narch = ARRAY_CARDINALITY(archs), - .compare = x86Compare, + .compare = virCPUx86Compare, .decode = x86DecodeCPUData, .encode = x86Encode, .free = x86FreeCPUData, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c4fd7ae..0834d50 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -964,8 +964,6 @@ virSecretObjSetValueSize; # cpu/cpu.h cpuBaseline; cpuBaselineXML; -cpuCompare; -cpuCompareXML; cpuDataFormat; cpuDataFree; cpuDataParse; @@ -975,6 +973,8 @@ cpuGetModels; cpuGuestData; cpuNodeData; virCPUCheckFeature; +virCPUCompare; +virCPUCompareXML; virCPUDataCheckFeature; virCPUTranslate; virCPUUpdate; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 04ffaa6..42fa129 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -6369,18 +6369,8 @@ libxlConnectCompareCPU(virConnectPtr conn, cfg = libxlDriverConfigGet(driver); - if (!cfg->caps->host.cpu || - !cfg->caps->host.cpu->model) { - if (failIncompatible) { - virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", - _("cannot get host CPU capabilities")); - } else { - VIR_WARN("cannot get host CPU capabilities"); - ret = VIR_CPU_COMPARE_INCOMPATIBLE; - } - } else { - ret = cpuCompareXML(cfg->caps->host.cpu, xmlDesc, failIncompatible); - } + ret = virCPUCompareXML(cfg->caps->host.arch, cfg->caps->host.cpu, + xmlDesc, failIncompatible); virObjectUnref(cfg); return ret; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ca47b4e..9995265 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12809,18 +12809,8 @@ qemuConnectCompareCPU(virConnectPtr conn, if (!(caps = virQEMUDriverGetCapabilities(driver, false))) goto cleanup; - if (!caps->host.cpu || - !caps->host.cpu->model) { - if (failIncompatible) { - virReportError(VIR_ERR_CPU_INCOMPATIBLE, "%s", - _("cannot get host CPU capabilities")); - } else { - VIR_WARN("cannot get host CPU capabilities"); - ret = VIR_CPU_COMPARE_INCOMPATIBLE; - } - } else { - ret = cpuCompareXML(caps->host.cpu, xmlDesc, failIncompatible); - } + ret = virCPUCompareXML(caps->host.arch, caps->host.cpu, + xmlDesc, failIncompatible); cleanup: virObjectUnref(caps); diff --git a/tests/cputest.c b/tests/cputest.c index 72f00b6..6842d27 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -215,7 +215,7 @@ cpuTestCompare(const void *arg) !(cpu = cpuTestLoadXML(data->arch, data->name))) goto cleanup; - result = cpuCompare(host, cpu, false); + result = virCPUCompare(host->arch, host, cpu, false); if (data->result == VIR_CPU_COMPARE_ERROR) virResetLastError(); @@ -360,7 +360,7 @@ cpuTestBaseline(const void *arg) for (i = 0; i < ncpus; i++) { virCPUCompareResult cmp; - cmp = cpuCompare(cpus[i], baseline, false); + cmp = virCPUCompare(cpus[i]->arch, cpus[i], baseline, false); if (cmp != VIR_CPU_COMPARE_SUPERSET && cmp != VIR_CPU_COMPARE_IDENTICAL) { VIR_TEST_VERBOSE("\nbaseline CPU is incompatible with CPU %zu\n", -- 2.10.0

Storing the updated CPU definition in the live domain definition saves us from having to update it over and over when we need it. Not to mention that we will soon further update the CPU definition according to QEMU once it's started. A highly wanted side effect of this patch, libvirt will pass all CPU features explicitly specified in domain XML to QEMU, even those that are already included in the host model. This patch should fix the following bugs: https://bugzilla.redhat.com/show_bug.cgi?id=1207095 https://bugzilla.redhat.com/show_bug.cgi?id=1339680 https://bugzilla.redhat.com/show_bug.cgi?id=1371039 https://bugzilla.redhat.com/show_bug.cgi?id=1373849 https://bugzilla.redhat.com/show_bug.cgi?id=1375524 Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - added links to bugs fixed in this series - added a hunk from 38/41 touching qemuDomainFormatXML src/qemu/qemu_command.c | 161 +++++++------------ src/qemu/qemu_domain.c | 17 +- src/qemu/qemu_process.c | 178 +++++++++------------ .../qemuxml2argv-cpu-Haswell3.args | 2 +- .../qemuxml2argv-cpu-exact2-nofallback.args | 3 +- .../qemuxml2argvdata/qemuxml2argv-cpu-exact2.args | 3 +- .../qemuxml2argv-cpu-fallback.args | 2 +- .../qemuxml2argv-cpu-host-model-cmt.args | 2 +- .../qemuxml2argv-cpu-host-model-fallback.args | 2 +- .../qemuxml2argv-cpu-minimum2.args | 2 +- .../qemuxml2argvdata/qemuxml2argv-cpu-strict1.args | 3 +- 11 files changed, 152 insertions(+), 223 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1154ac6..6cf46f6 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6559,62 +6559,18 @@ static int qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, const virDomainDef *def, virBufferPtr buf, - virQEMUCapsPtr qemuCaps, - bool *hasHwVirt, - bool migrating) + virQEMUCapsPtr qemuCaps) { int ret = -1; size_t i; - virCPUDefPtr host = NULL; - virCPUDefPtr guest = NULL; - virCPUDefPtr cpu = NULL; - virCPUDefPtr featCpu = NULL; - size_t ncpus = 0; - char **cpus = NULL; - virCPUDataPtr data = NULL; - const char *preferred; virCapsPtr caps = NULL; - bool compareAgainstHost = ((def->virtType == VIR_DOMAIN_VIRT_KVM || - def->cpu->mode != VIR_CPU_MODE_CUSTOM) && - def->cpu->mode != VIR_CPU_MODE_HOST_PASSTHROUGH); + virCPUDefPtr cpu = def->cpu; if (!(caps = virQEMUDriverGetCapabilities(driver, false))) goto cleanup; - host = caps->host.cpu; - - if (!(cpu = virCPUDefCopy(def->cpu))) - goto cleanup; - - if (cpu->mode == VIR_CPU_MODE_HOST_MODEL && - !migrating && - virCPUUpdate(def->os.arch, cpu, host) < 0) - goto cleanup; - - if (compareAgainstHost && - cpuGuestData(host, cpu, &data, NULL) == VIR_CPU_COMPARE_ERROR) - goto cleanup; - - /* Only 'svm' requires --enable-nesting. The nested - * 'vmx' patches now simply hook off the CPU features - */ - if ((def->os.arch == VIR_ARCH_X86_64 || def->os.arch == VIR_ARCH_I686) && - compareAgainstHost) { - int hasSVM = virCPUDataCheckFeature(data, "svm"); - if (hasSVM < 0) - goto cleanup; - *hasHwVirt = hasSVM > 0 ? true : false; - } - - if ((cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) || - ((cpu->mode == VIR_CPU_MODE_HOST_MODEL) && - ARCH_IS_PPC64(def->os.arch))) { - if (def->virtType != VIR_DOMAIN_VIRT_KVM) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("CPU mode '%s' is only supported with kvm"), - virCPUModeTypeToString(cpu->mode)); - goto cleanup; - } + switch ((virCPUMode) cpu->mode) { + case VIR_CPU_MODE_HOST_PASSTHROUGH: virBufferAddLit(buf, "host"); if (def->os.arch == VIR_ARCH_ARMV7L && @@ -6626,69 +6582,55 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, "aarch64 host")); goto cleanup; } - virBufferAddLit(buf, ",aarch64=off"); } + break; - if (ARCH_IS_PPC64(def->os.arch) && - cpu->mode == VIR_CPU_MODE_HOST_MODEL && - def->cpu->model != NULL) { - virBufferAsprintf(buf, ",compat=%s", def->cpu->model); + case VIR_CPU_MODE_HOST_MODEL: + if (ARCH_IS_PPC64(def->os.arch)) { + virBufferAddLit(buf, "host"); + if (cpu->model) + virBufferAsprintf(buf, ",compat=%s", cpu->model); } else { - featCpu = cpu; - } - } else { - if (VIR_ALLOC(guest) < 0) + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected host-model CPU for %s architecture"), + virArchToString(def->os.arch)); goto cleanup; - if (VIR_STRDUP(guest->vendor_id, cpu->vendor_id) < 0) - goto cleanup; - - if (compareAgainstHost) { - guest->arch = host->arch; - if (cpu->match == VIR_CPU_MATCH_MINIMUM) - preferred = host->model; - else - preferred = cpu->model; - - guest->type = VIR_CPU_TYPE_GUEST; - guest->fallback = cpu->fallback; - - if (virQEMUCapsGetCPUDefinitions(qemuCaps, &cpus, &ncpus) < 0) - goto cleanup; - - if (cpuDecode(guest, data, - (const char **)cpus, ncpus, preferred) < 0) - goto cleanup; - } else { - guest->arch = def->os.arch; - if (VIR_STRDUP(guest->model, cpu->model) < 0) - goto cleanup; } - virBufferAdd(buf, guest->model, -1); - if (guest->vendor_id) - virBufferAsprintf(buf, ",vendor=%s", guest->vendor_id); - featCpu = guest; + break; + + case VIR_CPU_MODE_CUSTOM: + virBufferAdd(buf, cpu->model, -1); + break; + + case VIR_CPU_MODE_LAST: + break; } - if (featCpu) { - for (i = 0; i < featCpu->nfeatures; i++) { - char sign; - if (featCpu->features[i].policy == VIR_CPU_FEATURE_DISABLE) - sign = '-'; - else - sign = '+'; + if (cpu->vendor_id) + virBufferAsprintf(buf, ",vendor=%s", cpu->vendor_id); - virBufferAsprintf(buf, ",%c%s", sign, featCpu->features[i].name); + for (i = 0; i < cpu->nfeatures; i++) { + switch ((virCPUFeaturePolicy) cpu->features[i].policy) { + case VIR_CPU_FEATURE_FORCE: + case VIR_CPU_FEATURE_REQUIRE: + virBufferAsprintf(buf, ",+%s", cpu->features[i].name); + break; + + case VIR_CPU_FEATURE_DISABLE: + case VIR_CPU_FEATURE_FORBID: + virBufferAsprintf(buf, ",-%s", cpu->features[i].name); + break; + + case VIR_CPU_FEATURE_OPTIONAL: + case VIR_CPU_FEATURE_LAST: + break; } } ret = 0; cleanup: virObjectUnref(caps); - cpuDataFree(data); - virCPUDefFree(guest); - virCPUDefFree(cpu); - virStringFreeListCount(cpus, ncpus); return ret; } @@ -6696,8 +6638,7 @@ static int qemuBuildCpuCommandLine(virCommandPtr cmd, virQEMUDriverPtr driver, const virDomainDef *def, - virQEMUCapsPtr qemuCaps, - bool migrating) + virQEMUCapsPtr qemuCaps) { virArch hostarch = virArchFromHost(); char *cpu = NULL; @@ -6715,10 +6656,28 @@ qemuBuildCpuCommandLine(virCommandPtr cmd, if (def->cpu && (def->cpu->mode != VIR_CPU_MODE_CUSTOM || def->cpu->model)) { - if (qemuBuildCpuModelArgStr(driver, def, &buf, qemuCaps, - &hasHwVirt, migrating) < 0) + if (qemuBuildCpuModelArgStr(driver, def, &buf, qemuCaps) < 0) goto cleanup; have_cpu = true; + + /* Only 'svm' requires --enable-nesting. The nested 'vmx' patches now + * simply hook off the CPU features. */ + if (ARCH_IS_X86(def->os.arch) && + def->virtType == VIR_DOMAIN_VIRT_KVM) { + virCPUDefPtr cpuDef = NULL; + + if (def->cpu->mode == VIR_CPU_MODE_CUSTOM) + cpuDef = def->cpu; + else if (def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) + cpuDef = virQEMUCapsGetHostModel(qemuCaps); + + if (cpuDef) { + int svm = virCPUCheckFeature(def->os.arch, cpuDef, "svm"); + if (svm < 0) + goto cleanup; + hasHwVirt = svm > 0; + } + } } else { /* * Need to force a 32-bit guest CPU type if @@ -9476,7 +9435,7 @@ qemuBuildCommandLine(virQEMUDriverPtr driver, if (qemuBuildMachineCommandLine(cmd, cfg, def, qemuCaps) < 0) goto error; - if (qemuBuildCpuCommandLine(cmd, driver, def, qemuCaps, !!migrateURI) < 0) + if (qemuBuildCpuCommandLine(cmd, driver, def, qemuCaps) < 0) goto error; if (qemuBuildDomainLoaderCommandLine(cmd, def, qemuCaps) < 0) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 3c46a06..4439068 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3399,14 +3399,8 @@ qemuDomainDefFormatBuf(virQEMUDriverPtr driver, /* Update guest CPU requirements according to host CPU */ if ((flags & VIR_DOMAIN_XML_UPDATE_CPU) && def->cpu && - (def->cpu->mode != VIR_CPU_MODE_CUSTOM || def->cpu->model)) { - if (!caps->host.cpu || - !caps->host.cpu->model) { - virReportError(VIR_ERR_OPERATION_FAILED, - "%s", _("cannot get host CPU capabilities")); - goto cleanup; - } - + (def->cpu->mode != VIR_CPU_MODE_CUSTOM || + def->cpu->model)) { if (virCPUUpdate(def->os.arch, def->cpu, caps->host.cpu) < 0) goto cleanup; } @@ -3542,10 +3536,13 @@ char *qemuDomainFormatXML(virQEMUDriverPtr driver, { virDomainDefPtr def; - if ((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef) + if ((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef) { def = vm->newDef; - else + } else { def = vm->def; + if (virDomainObjIsActive(vm)) + flags &= ~VIR_DOMAIN_XML_UPDATE_CPU; + } return qemuDomainDefFormatXML(driver, def, flags); } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 72046df..9896eaf 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4444,107 +4444,6 @@ qemuProcessStartValidateXML(virQEMUDriverPtr driver, } -static int -qemuProcessStartValidateGuestCPU(virDomainObjPtr vm, - virQEMUCapsPtr qemuCaps, - virCapsPtr caps, - unsigned int flags) -{ - int ret = -1; - virCPUDefPtr host = NULL; - virCPUDefPtr cpu = NULL; - size_t ncpus = 0; - char **cpus = NULL; - bool noTSX = false; - virCPUCompareResult cmp; - virCPUDataPtr data = NULL; - virCPUDataPtr hostData = NULL; - char *compare_msg = NULL; - - if (!vm->def->cpu || - (vm->def->cpu->mode == VIR_CPU_MODE_CUSTOM && - !vm->def->cpu->model)) - return 0; - - if ((vm->def->virtType != VIR_DOMAIN_VIRT_KVM && - vm->def->cpu->mode == VIR_CPU_MODE_CUSTOM) || - vm->def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) - return 0; - - host = caps->host.cpu; - - 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; - } - - if (!(cpu = virCPUDefCopy(vm->def->cpu))) - goto cleanup; - - if (cpu->mode == VIR_CPU_MODE_HOST_MODEL && - flags & VIR_QEMU_PROCESS_START_NEW && - virCPUUpdate(vm->def->os.arch, cpu, host) < 0) - goto cleanup; - - cmp = cpuGuestData(host, cpu, &data, &compare_msg); - switch (cmp) { - case VIR_CPU_COMPARE_INCOMPATIBLE: - if (cpuEncode(host->arch, host, NULL, &hostData, - NULL, NULL, NULL, NULL) == 0 && - (!virCPUDataCheckFeature(hostData, "hle") || - !virCPUDataCheckFeature(hostData, "rtm")) && - (STREQ_NULLABLE(cpu->model, "Haswell") || - STREQ_NULLABLE(cpu->model, "Broadwell"))) - noTSX = true; - - if (compare_msg) { - if (noTSX) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("guest and host CPU are not compatible: " - "%s; try using '%s-noTSX' CPU model"), - compare_msg, cpu->model); - } else { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("guest and host CPU are not compatible: " - "%s"), - compare_msg); - } - } else { - if (noTSX) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("guest CPU is not compatible with host " - "CPU; try using '%s-noTSX' CPU model"), - cpu->model); - } else { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("guest CPU is not compatible with host " - "CPU")); - } - } - /* fall through */ - case VIR_CPU_COMPARE_ERROR: - goto cleanup; - - default: - break; - } - - ret = 0; - - cleanup: - VIR_FREE(compare_msg); - cpuDataFree(data); - cpuDataFree(hostData); - virCPUDefFree(cpu); - virStringFreeListCount(cpus, ncpus); - return ret; -} - - /** * qemuProcessStartValidate: * @vm: domain object @@ -4614,9 +4513,6 @@ qemuProcessStartValidate(virQEMUDriverPtr driver, } } - if (qemuProcessStartValidateGuestCPU(vm, qemuCaps, caps, flags) < 0) - return -1; - return 0; } @@ -5044,6 +4940,76 @@ qemuProcessSetupHotpluggableVcpus(virQEMUDriverPtr driver, } +static int +qemuProcessUpdateGuestCPU(virDomainDefPtr def, + virQEMUCapsPtr qemuCaps, + virCapsPtr caps, + unsigned int flags) +{ + int ret = -1; + size_t nmodels = 0; + char **models = NULL; + + if (!def->cpu) + return 0; + + /* nothing to do if only topology part of CPU def is used */ + if (def->cpu->mode == VIR_CPU_MODE_CUSTOM && !def->cpu->model) + return 0; + + /* Old libvirt added host CPU model to host-model CPUs for migrations, + * while new libvirt just turns host-model into custom mode. We need + * to fix the mode to maintain backward compatibility and to avoid + * the CPU model to be replaced in virCPUUpdate. + */ + if (!(flags & VIR_QEMU_PROCESS_START_NEW) && + ARCH_IS_X86(def->os.arch) && + def->cpu->mode == VIR_CPU_MODE_HOST_MODEL && + def->cpu->model) { + def->cpu->mode = VIR_CPU_MODE_CUSTOM; + } + + if (!virQEMUCapsIsCPUModeSupported(qemuCaps, caps, def->virtType, + def->cpu->mode)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("CPU mode '%s' for %s %s domain on %s host is not " + "supported by hypervisor"), + virCPUModeTypeToString(def->cpu->mode), + virArchToString(def->os.arch), + virDomainVirtTypeToString(def->virtType), + virArchToString(caps->host.arch)); + return -1; + } + + /* nothing to update for host-passthrough */ + if (def->cpu->mode == VIR_CPU_MODE_HOST_PASSTHROUGH) + return 0; + + /* custom CPUs in TCG mode don't need to be compared to host CPU */ + if (def->virtType != VIR_DOMAIN_VIRT_QEMU || + def->cpu->mode != VIR_CPU_MODE_CUSTOM) { + if (virCPUCompare(caps->host.arch, virQEMUCapsGetHostModel(qemuCaps), + def->cpu, true) < 0) + return -1; + } + + if (virCPUUpdate(def->os.arch, def->cpu, + virQEMUCapsGetHostModel(qemuCaps)) < 0) + goto cleanup; + + if (virQEMUCapsGetCPUDefinitions(qemuCaps, &models, &nmodels) < 0 || + virCPUTranslate(def->os.arch, def->cpu, models, nmodels) < 0) + goto cleanup; + + def->cpu->fallback = VIR_CPU_FALLBACK_FORBID; + ret = 0; + + cleanup: + virStringFreeListCount(models, nmodels); + return ret; +} + + /** * qemuProcessPrepareDomain * @@ -5154,6 +5120,10 @@ qemuProcessPrepareDomain(virConnectPtr conn, priv->monStart = 0; priv->gotShutdown = false; + VIR_DEBUG("Updating guest CPU definition"); + if (qemuProcessUpdateGuestCPU(vm->def, priv->qemuCaps, caps, flags) < 0) + goto cleanup; + ret = 0; cleanup: VIR_FREE(nodeset); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-Haswell3.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-Haswell3.args index ef0e68b..2e74a67 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-Haswell3.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-Haswell3.args @@ -8,7 +8,7 @@ QEMU_AUDIO_DRV=none \ -name QEMUGuest1 \ -S \ -M pc \ --cpu Haswell \ +-cpu Haswell,+rtm,+hle \ -m 214 \ -smp 6,sockets=6,cores=1,threads=1 \ -uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.args index 0693e70..628be83 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2-nofallback.args @@ -8,7 +8,8 @@ QEMU_AUDIO_DRV=none \ -name QEMUGuest1 \ -S \ -M pc \ --cpu core2duo,+ds,+ht,+tm,+ds_cpl,+xtpr,+3dnowext,+lahf_lm,-nx \ +-cpu core2duo,+ds,+ht,+tm,+ds_cpl,+xtpr,+3dnowext,+lahf_lm,-nx,-cx16,-tm2,-pbe,\ +-ss,-sse4a,-wdt \ -m 214 \ -smp 6,sockets=6,cores=1,threads=1 \ -uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.args index 0693e70..628be83 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.args @@ -8,7 +8,8 @@ QEMU_AUDIO_DRV=none \ -name QEMUGuest1 \ -S \ -M pc \ --cpu core2duo,+ds,+ht,+tm,+ds_cpl,+xtpr,+3dnowext,+lahf_lm,-nx \ +-cpu core2duo,+ds,+ht,+tm,+ds_cpl,+xtpr,+3dnowext,+lahf_lm,-nx,-cx16,-tm2,-pbe,\ +-ss,-sse4a,-wdt \ -m 214 \ -smp 6,sockets=6,cores=1,threads=1 \ -uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.args index 0352eb7..6afcc58 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-fallback.args @@ -8,7 +8,7 @@ QEMU_AUDIO_DRV=none \ -name QEMUGuest1 \ -S \ -M pc \ --cpu Penryn,-sse4.1 \ +-cpu Penryn,-sse4.1,-sse4.2,-popcnt,-aes \ -m 214 \ -smp 6,sockets=6,cores=1,threads=1 \ -uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-cmt.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-cmt.args index e29daf7..7ae4ac5 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-cmt.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-cmt.args @@ -9,7 +9,7 @@ QEMU_AUDIO_DRV=none \ -S \ -M pc \ -cpu Haswell,+vme,+ds,+acpi,+ss,+ht,+tm,+pbe,+dtes64,+monitor,+ds_cpl,+vmx,\ -+smx,+est,+tm2,+xtpr,+pdcm,+osxsave,+f16c,+rdrand,+pdpe1gb,+abm \ ++smx,+est,+tm2,+xtpr,+pdcm,+osxsave,+f16c,+rdrand,+pdpe1gb,+abm,+lahf_lm \ -m 214 \ -smp 6,sockets=6,cores=1,threads=1 \ -uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.args index 4e53547..26b838e 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-host-model-fallback.args @@ -9,7 +9,7 @@ QEMU_AUDIO_DRV=none \ -S \ -M pc \ -cpu Penryn,+vme,+ds,+acpi,+ss,+ht,+tm,+pbe,+monitor,+ds_cpl,+vmx,+est,+tm2,\ -+xtpr,-sse4.1 \ ++xtpr,-sse4.1,+cx16,+lahf_lm \ -m 214 \ -smp 6,sockets=6,cores=1,threads=1 \ -uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum2.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum2.args index e1b902f..d9821b6 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum2.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum2.args @@ -9,7 +9,7 @@ QEMU_AUDIO_DRV=none \ -S \ -M pc \ -cpu core2duo,+ds,+acpi,+ss,+ht,+tm,+pbe,+ds_cpl,+vmx,+est,+tm2,+cx16,+xtpr,\ -+lahf_lm,-syscall,-nx,-lm \ ++lahf_lm,-syscall,-nx,-lm,-svm \ -m 214 \ -smp 6,sockets=6,cores=1,threads=1 \ -uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ diff --git a/tests/qemuxml2argvdata/qemuxml2argv-cpu-strict1.args b/tests/qemuxml2argvdata/qemuxml2argv-cpu-strict1.args index ad7b1c5..e011095 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-cpu-strict1.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-cpu-strict1.args @@ -8,7 +8,8 @@ QEMU_AUDIO_DRV=none \ -name QEMUGuest1 \ -S \ -M pc \ --cpu core2duo,+ds,+acpi,+ht,+tm,+ds_cpl,+vmx,+est,+xtpr,+3dnowext,+lahf_lm,-nx \ +-cpu core2duo,+ds,+acpi,+ht,+tm,+ds_cpl,+vmx,+est,+xtpr,+3dnowext,+lahf_lm,-nx,\ +-cx16,-tm2,-pbe,-ss,-sse4a,-wdt \ -m 214 \ -smp 6,sockets=6,cores=1,threads=1 \ -uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ -- 2.10.0

On Mon, Sep 19, 2016 at 15:30:53 +0200, Jiri Denemark wrote:
Storing the updated CPU definition in the live domain definition saves us from having to update it over and over when we need it. Not to mention that we will soon further update the CPU definition according to QEMU once it's started.
A highly wanted side effect of this patch, libvirt will pass all CPU features explicitly specified in domain XML to QEMU, even those that are already included in the host model.
This patch should fix the following bugs: https://bugzilla.redhat.com/show_bug.cgi?id=1207095 https://bugzilla.redhat.com/show_bug.cgi?id=1339680 https://bugzilla.redhat.com/show_bug.cgi?id=1371039 https://bugzilla.redhat.com/show_bug.cgi?id=1373849 https://bugzilla.redhat.com/show_bug.cgi?id=1375524
And one more: https://bugzilla.redhat.com/show_bug.cgi?id=1377913 Jirka

It really doesn't belong to the generic CPU driver. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Version 2: - no change src/cpu/cpu_x86.c | 16 ++-------------- src/qemu/qemu_capabilities.c | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 6397dcb..64f1c47 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2559,22 +2559,10 @@ x86UpdateHostModel(virCPUDefPtr guest, /* Remove non-migratable features by default */ updated->type = VIR_CPU_TYPE_GUEST; updated->mode = VIR_CPU_MODE_CUSTOM; - if (virCPUDefCopyModel(updated, host, true) < 0) + if (virCPUDefCopyModelFilter(updated, host, true, + x86FeatureIsMigratable, map) < 0) goto cleanup; - i = 0; - while (i < updated->nfeatures) { - if (x86FeatureIsMigratable(updated->features[i].name, map) && - STRNEQ(updated->features[i].name, "cmt") && - STRNEQ(updated->features[i].name, "mbm_total") && - STRNEQ(updated->features[i].name, "mbm_local")) { - i++; - } else { - VIR_FREE(updated->features[i].name); - VIR_DELETE_ELEMENT_INPLACE(updated->features, i, updated->nfeatures); - } - } - if (guest->vendor_id) { VIR_FREE(updated->vendor_id); if (VIR_STRDUP(updated->vendor_id, guest->vendor_id) < 0) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 985b585..4d859c4 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2947,6 +2947,19 @@ int virQEMUCapsProbeQMP(virQEMUCapsPtr qemuCaps, } +static bool +virQEMUCapsCPUFilterFeatures(const char *name, + void *opaque ATTRIBUTE_UNUSED) +{ + if (STREQ(name, "cmt") || + STREQ(name, "mbm_total") || + STREQ(name, "mbm_local")) + return false; + + return true; +} + + void virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps, virCapsHostPtr host) @@ -2965,7 +2978,8 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps, cpu->mode = VIR_CPU_MODE_CUSTOM; cpu->match = VIR_CPU_MATCH_EXACT; - if (virCPUDefCopyModel(cpu, host->cpu, true) < 0) + if (virCPUDefCopyModelFilter(cpu, host->cpu, true, + virQEMUCapsCPUFilterFeatures, NULL) < 0) goto error; } -- 2.10.0

On 09/19/2016 09:30 AM, Jiri Denemark wrote:
Version 2: - review comments addressed; see individual patches for details
This patch series does several things:
- fixes tests to avoid relying on bugs in our code - adds support for advertising supported CPU modes and models in domain capabilities - starts adding better and higher level APIs to our cpu driver (the old low level APIs will be removed once this process is over) - prepares qemu driver for asking QEMU what a host CPU looks like and what CPU models can be run on it - makes QEMU CPU command line builder build command line and nothing else
The added part of domain capabilities XML looks like this:
<cpu> <mode name='host-passthrough' supported='yes'/> <mode name='host-model' supported='yes'> <model fallback='allow'>Broadwell</model> <vendor>Intel</vendor> <feature policy='disable' name='aes'/> <feature policy='require' name='vmx'/> </mode> <mode name='custom' supported='yes'> <model usable='no'>Broadwell</model> <model usable='yes'>Broadwell-noTSX</model> ... </mode> </cpu>
and host-passthrough is only advertised as supported for KVM domains, host-model is only supported when guest architecture is compatible with host and overall it should just work the way one would expect (in contrast to the current state of the code).
[...] ACK series, John
participants (2)
-
Jiri Denemark
-
John Ferlan