[libvirt] [PATCH 00/41] Enhance guest CPU configuration code

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>Broadwell</model> <model>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). Big thanks for any comments and review in advance and... Enjoy my PTO :-) Jiri Denemark (41): 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 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 virCPUDefMoveModel 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: Rework cpuHasFeature 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 | 19 + src/conf/domain_capabilities.c | 209 ++++++++++ src/conf/domain_capabilities.h | 47 +++ src/cpu/cpu.c | 247 ++++++++--- 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/qemu/qemu_capabilities.c | 387 ++++++++++++----- src/qemu/qemu_capabilities.h | 24 +- src/qemu/qemu_capspriv.h | 13 +- src/qemu/qemu_command.c | 216 +++------- src/qemu/qemu_domain.c | 32 +- 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 | 126 ++++-- tests/testutilsqemu.h | 11 +- tools/virsh-host.c | 10 +- 79 files changed, 2455 insertions(+), 1119 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.9.2

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> --- 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 5a7733c..a424af0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -18229,14 +18229,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 bc1f93d..f9075ba 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5766,11 +5766,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.9.2

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> --- docs/formatdomaincaps.html.in | 44 ++++++ docs/schemas/domaincaps.rng | 43 ++++++ src/conf/domain_capabilities.c | 150 +++++++++++++++++++++ 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, 347 insertions(+) diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in index d5a8414..15a13c1 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 + guest CPU. + </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..c07f995 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->count; i++) + VIR_FREE(cpuModels->models[i].name); + + VIR_FREE(cpuModels->models); +} + + virDomainCapsPtr virDomainCapsNew(const char *path, const char *machine, @@ -100,6 +124,86 @@ 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->alloc = nmodels; + + return cpuModels; + + error: + virObjectUnref(cpuModels); + return NULL; +} + + +virDomainCapsCPUModelsPtr +virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old) +{ + virDomainCapsCPUModelsPtr cpuModels; + size_t i; + + if (!(cpuModels = virDomainCapsCPUModelsNew(old->count))) + return NULL; + + for (i = 0; i < old->count; 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->alloc, + cpuModels->count, 1) < 0) + return -1; + + cpuModels->models[cpuModels->count++].name = *name; + *name = NULL; + 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 +338,51 @@ virDomainCapsOSFormat(virBufferPtr buf, } static void +virDomainCapsCPUCustomFormat(virBufferPtr buf, + virDomainCapsCPUModelsPtr custom) +{ + size_t i; + + virBufferAdjustIndent(buf, 2); + + for (i = 0; i < custom->count; 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->count) { + 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 +482,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..509c306 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 alloc; + size_t count; + 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 419c33d..f91ce17 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -152,6 +152,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.9.2

On 08/12/2016 09:32 AM, Jiri Denemark wrote:
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> --- docs/formatdomaincaps.html.in | 44 ++++++ docs/schemas/domaincaps.rng | 43 ++++++ src/conf/domain_capabilities.c | 150 +++++++++++++++++++++ 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, 347 insertions(+)
[...]
diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 1676f0e..c07f995 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c
[...]
+ +int +virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels, + char **name) +{ + if (VIR_RESIZE_N(cpuModels->models, cpuModels->alloc, + cpuModels->count, 1) < 0) + return -1; + + cpuModels->models[cpuModels->count++].name = *name; + *name = NULL;
Similar to VIR_STEAL_PTR with the added count++ twist...
+ 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 +338,51 @@ virDomainCapsOSFormat(virBufferPtr buf, }
static void
[...]
diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 492a9cf..509c306 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 alloc; + size_t count;
Easier for me to read/see "->nmodels_max" and "->nmodels"... Not sure how pervasive it is to change... Not a requirement, your call...
+ virDomainCapsCPUModelPtr models; +}; + +typedef struct _virDomainCapsCPU virDomainCapsCPU; +typedef virDomainCapsCPU *virDomainCapsCPUPtr; +struct _virDomainCapsCPU { + bool hostPassthrough; + bool hostModel; + virDomainCapsCPUModelsPtr custom; +}; +
[...]

On Mon, Aug 29, 2016 at 12:31:44 -0400, John Ferlan wrote:
+int +virDomainCapsCPUModelsAddSteal(virDomainCapsCPUModelsPtr cpuModels, + char **name) +{ + if (VIR_RESIZE_N(cpuModels->models, cpuModels->alloc, + cpuModels->count, 1) < 0) + return -1; + + cpuModels->models[cpuModels->count++].name = *name; + *name = NULL;
Similar to VIR_STEAL_PTR with the added count++ twist...
Right, I changed it to use VIR_STEAL_PTR. ...
diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 492a9cf..509c306 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 alloc; + size_t count;
Easier for me to read/see "->nmodels_max" and "->nmodels"... Not sure how pervasive it is to change... Not a requirement, your call...
Yeah, nmodels{,_max} is more common in our code base. Fixed. Jirka

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> --- 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 43e3ea7..1dcc970 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -373,8 +373,7 @@ struct _virQEMUCaps { virArch arch; - size_t ncpuDefinitions; - char **cpuDefinitions; + virDomainCapsCPUModelsPtr cpuDefinitions; size_t nmachineTypes; struct virQEMUCapsMachineType *machineTypes; @@ -612,7 +611,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; @@ -634,9 +636,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 @@ -647,14 +646,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. @@ -666,11 +667,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++; @@ -691,19 +694,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 @@ -2033,11 +2033,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; } @@ -2076,9 +2074,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); @@ -2216,28 +2212,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->count) < 0) + return -1; + + for (i = 0; i < qemuCaps->cpuDefinitions->count; 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->count; + return 0; + + error: + virStringFreeListCount(models, i); + return -1; } @@ -2534,16 +2560,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 { @@ -2889,17 +2929,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); @@ -3053,9 +3095,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->count; i++) { + virDomainCapsCPUModelPtr cpu = qemuCaps->cpuDefinitions->models + i; + virBufferEscapeString(&buf, "<cpu name='%s'/>\n", cpu->name); + } } for (i = 0; i < qemuCaps->nmachineTypes; i++) { @@ -3171,10 +3215,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 d249e2e..0767a87 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -418,10 +418,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 55df23d..3f542bc 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6459,9 +6459,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; @@ -6615,6 +6616,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 83e1272..4687660 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3317,7 +3317,7 @@ qemuMonitorMachineInfoFree(qemuMonitorMachineInfoPtr machine) int qemuMonitorGetCPUDefinitions(qemuMonitorPtr mon, - char ***cpus) + qemuMonitorCPUDefInfoPtr **cpus) { VIR_DEBUG("cpus=%p", cpus); @@ -3327,6 +3327,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 591d3ed..9e431ed 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -844,8 +844,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 d455adf..39ff24a 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4855,14 +4855,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; @@ -4898,13 +4899,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", @@ -4912,7 +4918,7 @@ int qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, goto cleanup; } - if (VIR_STRDUP(cpulist[i], tmp) < 0) + if (VIR_STRDUP(cpu->name, tmp) < 0) goto cleanup; } @@ -4921,7 +4927,11 @@ int qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, cpulist = NULL; cleanup: - virStringFreeList(cpulist); + if (ret < 0 && 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 174f0ef..feb061f 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -346,7 +346,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 544b569..dab447b 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 ad0693f..a457c69 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.9.2

On 08/12/2016 09:32 AM, Jiri Denemark wrote:
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> --- 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(-)
[..]
-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->count) < 0) + return -1; +
So if we don't have names, we don't get models and the following loop will only add to models if we've allocated it because we have names, right? Thus could there be an optimization to set/return ->count if !names prior to this check? e.g. if (!names) { *count = qemuCaps->cpuDefinitions->count; return 0; } This works, but it's tough to read.
+ for (i = 0; i < qemuCaps->cpuDefinitions->count; 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->count; + return 0; + + error: + virStringFreeListCount(models, i); + return -1; }
[...]
--- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4855,14 +4855,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;
@@ -4898,13 +4899,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", @@ -4912,7 +4918,7 @@ int qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, goto cleanup; }
- if (VIR_STRDUP(cpulist[i], tmp) < 0) + if (VIR_STRDUP(cpu->name, tmp) < 0) goto cleanup; }
@@ -4921,7 +4927,11 @@ int qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, cpulist = NULL;
cleanup: - virStringFreeList(cpulist); + if (ret < 0 && cpulist) {
I think "ret < 0" is superfluous... Coverity whines too
+ for (i = 0; i < n; i++) + qemuMonitorCPUDefInfoFree(cpulist[i]); + VIR_FREE(cpulist); + } virJSONValueFree(cmd); virJSONValueFree(reply); return ret;
[...]

On Mon, Aug 29, 2016 at 12:32:34 -0400, John Ferlan wrote: ...
-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->count) < 0) + return -1; +
So if we don't have names, we don't get models and the following loop will only add to models if we've allocated it because we have names, right?
Thus could there be an optimization to set/return ->count if !names prior to this check? e.g.
It could, but only for a limited time. In the future the for loop will do a bit of filtering and thus we will have to go through it to compute @count.
if (!names) { *count = qemuCaps->cpuDefinitions->count; return 0; }
This works, but it's tough to read.
+ for (i = 0; i < qemuCaps->cpuDefinitions->count; 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->count; + return 0; + + error: + virStringFreeListCount(models, i); + return -1; } ... @@ -4921,7 +4927,11 @@ int qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, cpulist = NULL;
cleanup: - virStringFreeList(cpulist); + if (ret < 0 && cpulist) {
I think "ret < 0" is superfluous... Coverity whines too
Right. Fixed. Jirka

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tests/qemuxml2argvtest.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index a457c69..38f2025 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; @@ -547,11 +547,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.9.2

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tests/qemuxml2argvtest.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 38f2025..7ff9deb 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.9.2

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- tests/qemuxml2argvtest.c | 109 ++++++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 7ff9deb..4ec0990 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; } @@ -549,7 +534,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.9.2

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> --- tests/qemuxml2argvtest.c | 104 ++++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 4ec0990..82926db 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.9.2

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> --- tests/qemuxml2argvtest.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 82926db..9e9db6e 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]; @@ -530,9 +542,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.9.2

qemuCaps->arch should match the guest architecture from domain XML. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- 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 1dcc970..58a96d4 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2188,6 +2188,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 9e9db6e..f9ed6f5 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.9.2

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> --- tests/testutilsqemu.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- tests/testutilsqemu.h | 8 ++++++-- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index 11dd20e..9b66101 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; caps->host.cpu = cpuDefault; @@ -440,15 +451,45 @@ 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); + virCPUDefFree(cpuPower8); 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; + else if (ARCH_IS_PPC64(arch)) + cpu = cpuPower8; + } + + 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..6d35116f 100644 --- a/tests/testutilsqemu.h +++ b/tests/testutilsqemu.h @@ -19,8 +19,12 @@ virQEMUCapsPtr qemuTestParseCapabilities(const char *capsFile); extern virCPUDefPtr cpuDefault; extern virCPUDefPtr cpuHaswell; -void testQemuCapsSetCPU(virCapsPtr caps, - virCPUDefPtr hostCPU); +extern virCPUDefPtr cpuPower8; + +void qemuTestSetHostArch(virCapsPtr caps, + virArch arch); +void qemuTestSetHostCPU(virCapsPtr caps, + virCPUDefPtr cpu); int qemuTestDriverInit(virQEMUDriver *driver); void qemuTestDriverFree(virQEMUDriver *driver); -- 2.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- tests/testutilsqemu.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- tests/testutilsqemu.h | 8 ++++++-- 2 files changed, 52 insertions(+), 7 deletions(-)
diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index 11dd20e..9b66101 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -16,6 +16,7 @@
virCPUDefPtr cpuDefault; virCPUDefPtr cpuHaswell; +virCPUDefPtr cpuPower8;
^^ Nothing in the commit message that indicates that we're also adding a power8 type. Thus it would seem that this could be two commits - I would think adding the cpuPower8Data [1] Also, should each of these should be initialized to NULL?
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;
caps->host.cpu = cpuDefault;
Should this change to a qemuTestSetHostCPU(caps, NULL) to work properly on power8?
@@ -440,15 +451,45 @@ 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); + virCPUDefFree(cpuPower8);
[1] Since we can get to cleanup without ever initializing any of these... ACK 1-10 - just be sure to check/consider thoughts left in 2, 3, and here. Of course we're post freeze now, so I guess there's a bit more waiting to do anyway. John
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; + else if (ARCH_IS_PPC64(arch)) + cpu = cpuPower8; + } + + 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..6d35116f 100644 --- a/tests/testutilsqemu.h +++ b/tests/testutilsqemu.h @@ -19,8 +19,12 @@ virQEMUCapsPtr qemuTestParseCapabilities(const char *capsFile);
extern virCPUDefPtr cpuDefault; extern virCPUDefPtr cpuHaswell; -void testQemuCapsSetCPU(virCapsPtr caps, - virCPUDefPtr hostCPU); +extern virCPUDefPtr cpuPower8; + +void qemuTestSetHostArch(virCapsPtr caps, + virArch arch); +void qemuTestSetHostCPU(virCapsPtr caps, + virCPUDefPtr cpu);
int qemuTestDriverInit(virQEMUDriver *driver); void qemuTestDriverFree(virQEMUDriver *driver);

On Mon, Aug 29, 2016 at 12:45:03 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- tests/testutilsqemu.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- tests/testutilsqemu.h | 8 ++++++-- 2 files changed, 52 insertions(+), 7 deletions(-)
diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index 11dd20e..9b66101 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -16,6 +16,7 @@
virCPUDefPtr cpuDefault; virCPUDefPtr cpuHaswell; +virCPUDefPtr cpuPower8;
^^ Nothing in the commit message that indicates that we're also adding a power8 type.
Thus it would seem that this could be two commits - I would think adding the cpuPower8Data
Yes, I separated it to a new patch.
[1] Also, should each of these should be initialized to NULL?
They are zero-initialized since they are static.
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;
caps->host.cpu = cpuDefault;
Should this change to a qemuTestSetHostCPU(caps, NULL) to work properly on power8?
It doesn't change much since caps is initialized a few lines earlier as if (!(caps = virCapabilitiesNew(VIR_ARCH_X86_64, false, false))) return NULL; But using qemuTestSetHostCPU() to initialize the CPU is cleaner. Fixed. ...
ACK 1-10 - just be sure to check/consider thoughts left in 2, 3, and here. Of course we're post freeze now, so I guess there's a bit more waiting to do anyway.
You probably haven't noticed it, but this kind of sparse review with accumulated ACKs scattered in random places of random replies is quite hard to work with. Either an "ACK series" reply to a cover letter or separate and standalone replies to each patch with review comments and a conclusion (ack, nack, conditional ack) makes it a lot easier for the author to process the review. Jirka

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> --- 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 3f542bc..823b58d 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6445,9 +6445,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 || @@ -6459,15 +6456,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; @@ -6476,53 +6464,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 @@ -6547,7 +6491,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 " @@ -6566,7 +6510,6 @@ qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, } else { featCpu = cpu; } - } else { if (VIR_ALLOC(guest) < 0) goto cleanup; @@ -6582,6 +6525,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; @@ -6611,9 +6558,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 7481626..4d709fc 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4390,6 +4390,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 @@ -4459,6 +4561,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 f9ed6f5..2b94ff0 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1394,13 +1394,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); @@ -1947,14 +1947,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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- 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/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index f9ed6f5..2b94ff0 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1394,13 +1394,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);
Adding this to the previous patch seems to work, but...
DO_TEST("encrypted-disk", NONE); DO_TEST("encrypted-disk-usage", NONE); @@ -1947,14 +1947,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);
Adding this one causes failure... Perhaps due to the: + if (cpu) + caps->host.arch = cpu->arch; in previous patch? or perhaps some shortly subsequent patch... It's not so much an objection to the patch, but by simply adding those API's in patch 10 I guess I would have expected them to just work, but trial and error proves otherwise. Of course reading future patches perhaps sheds even more light (or black magic, voodoo) ;-).
DO_TEST("kvm-pit-device", QEMU_CAPS_KVM_PIT_TICK_POLICY); DO_TEST("kvm-pit-delay", QEMU_CAPS_NO_KVM_PIT);

On Mon, Aug 29, 2016 at 15:21:43 -0400, John Ferlan wrote: ...
- 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);
Adding this one causes failure... Perhaps due to the:
+ if (cpu) + caps->host.arch = cpu->arch;
in previous patch? or perhaps some shortly subsequent patch...
It's not so much an objection to the patch, but by simply adding those API's in patch 10 I guess I would have expected them to just work, but trial and error proves otherwise. Of course reading future patches perhaps sheds even more light (or black magic, voodoo) ;-).
The test suite was heavily relying on bugs in our code, which means both need to be fixed at the same time, otherwise the tests would just break. Jirka

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> --- .../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 2b94ff0..ecdab3c 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.9.2

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> --- tests/qemuxml2argvtest.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index ecdab3c..59be0ea 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1513,10 +1513,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", @@ -1879,6 +1883,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); @@ -1961,8 +1966,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.9.2

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> --- .../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 9b66101..1f0db16 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.9.2

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> --- 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 58a96d4..aeea3a3 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -428,6 +428,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 @@ -441,12 +464,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; } @@ -807,7 +826,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 @@ -829,14 +847,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 */ @@ -852,7 +863,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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- 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 58a96d4..aeea3a3 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -428,6 +428,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 @@ -441,12 +464,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; } @@ -807,7 +826,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 @@ -829,14 +847,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 */ @@ -852,7 +863,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) {
Noted by Coverity in this module - existing I think as well, it's just that the change piqued Coverity's interest in analyzing things... At the top of this function we have a: /* Ignore binary if extracting version info fails */ if (binary) { if (!(qemubinCaps = virQEMUCapsCacheLookup(cache, binary))) { virResetLastError(); ... Then there's the replace if condition w/ virQEMUCapsGuestIsNative followed by a: ret = virQEMUCapsInitGuestFromBinary(caps, binary, qemubinCaps, kvmbin, kvmbinCaps, guestarch); where it's noted that virQEMUCapsInitGuestFromBinary will dereference qemubinCaps in the call to virQEMUCapsGetMachineTypesCaps and it's possible that qemubinCaps is NULL if "binary" is set. The analysis doesn't go into the virQEMUCapsGuestIsNative condition. It's also notable that if !binary is checked in virQEMUCapsInitGuestFromBinary, so this is somewhat of an "edge" condition. Whether this is even possible - I'm not even sure!

On Mon, Aug 29, 2016 at 17:56:29 -0400, John Ferlan wrote: ...
@@ -852,7 +863,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) {
Noted by Coverity in this module - existing I think as well, it's just that the change piqued Coverity's interest in analyzing things...
At the top of this function we have a:
/* Ignore binary if extracting version info fails */ if (binary) { if (!(qemubinCaps = virQEMUCapsCacheLookup(cache, binary))) { virResetLastError(); ...
Then there's the replace if condition w/ virQEMUCapsGuestIsNative followed by a:
ret = virQEMUCapsInitGuestFromBinary(caps, binary, qemubinCaps, kvmbin, kvmbinCaps, guestarch);
where it's noted that virQEMUCapsInitGuestFromBinary will dereference qemubinCaps in the call to virQEMUCapsGetMachineTypesCaps and it's possible that qemubinCaps is NULL if "binary" is set. The analysis doesn't go into the virQEMUCapsGuestIsNative condition. It's also notable that if !binary is checked in virQEMUCapsInitGuestFromBinary, so this is somewhat of an "edge" condition.
That's impossible, see if (binary) { if (!(qemubinCaps = virQEMUCapsCacheLookup(cache, binary))) { virResetLastError(); VIR_FREE(binary); } } Jirka

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- 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 aeea3a3..7a7ddb8 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4194,6 +4194,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 && 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) @@ -4400,7 +4420,8 @@ virQEMUCapsFillDomainFeatureGICCaps(virQEMUCapsPtr qemuCaps, int -virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps, +virQEMUCapsFillDomainCaps(virCapsPtr caps, + virDomainCapsPtr domCaps, virQEMUCapsPtr qemuCaps, virFirmwarePtr *firmwares, size_t nfirmwares) @@ -4423,6 +4444,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 0767a87..9fd38d9 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -494,7 +494,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 a424af0..7e4f4e7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -18497,6 +18497,7 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, virDomainCapsPtr domCaps = NULL; int arch = virArchFromHost(); /* virArch */ virQEMUDriverConfigPtr cfg = NULL; + virCapsPtr caps = NULL; virCheckFlags(0, ret); @@ -18505,6 +18506,9 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn, cfg = virQEMUDriverGetConfig(driver); + if (!(caps = virQEMUDriverGetCapabilities(driver, false))) + goto cleanup; + if (qemuHostdevHostSupportsPassthroughLegacy() || qemuHostdevHostSupportsPassthroughVFIO()) virttype = VIR_DOMAIN_VIRT_KVM; @@ -18576,13 +18580,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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- 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 aeea3a3..7a7ddb8 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4194,6 +4194,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))
^^^^ Can caps be NULL?
+ domCaps->cpu.hostPassthrough = true; + + if (qemuCaps->cpuDefinitions && caps && caps->host.cpu)
^^^^ Since you check here So far as this patch it doesn't seem so and if I check at the end the two callers to virQEMUCapsFillDomainCaps have failure paths for !caps prior to the calls. Perhaps adding a NONNULL to the prototype will just help clear things up.
+ domCaps->cpu.hostModel = virQEMUCapsGuestIsNative(caps->host.arch, + qemuCaps->arch); + + domCaps->cpu.custom = virObjectRef(qemuCaps->cpuDefinitions); + + return 0; +} + +
[...]

On Mon, Aug 29, 2016 at 17:59:02 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- 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 aeea3a3..7a7ddb8 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4194,6 +4194,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))
^^^^ Can caps be NULL?
+ domCaps->cpu.hostPassthrough = true; + + if (qemuCaps->cpuDefinitions && caps && caps->host.cpu)
^^^^ Since you check here
No, caps cannot be NULL and the code will go away completely in patch 28 in this series. I fixed it anyway. Jirka

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> --- 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 57f0c0e..7ac2812 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1127,9 +1127,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) { + vshPrint(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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- 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/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 57f0c0e..7ac2812 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -1127,9 +1127,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) { + vshPrint(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]); + }
I seem to recall some recent work around the -q[uiet] switch - is that something that this code needs to be concerned with? (as silly as that seems while I'm typing it!)
} VIR_FREE(models);

On Mon, Aug 29, 2016 at 17:59:21 -0400, John Ferlan wrote: ...
@@ -1127,9 +1127,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) { + vshPrint(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]); + }
I seem to recall some recent work around the -q[uiet] switch - is that something that this code needs to be concerned with? (as silly as that seems while I'm typing it!)
Not silly at all. I replaced vshPrint with vshPrintExtra. Jirka

cpuGetSubDriver already reports a useful error. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- 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.9.2

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> --- 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 c07f995..6f9f7e7 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -169,6 +169,33 @@ virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old) } +virDomainCapsCPUModelsPtr +virDomainCapsCPUModelsFilter(virDomainCapsCPUModelsPtr old, + char **models) +{ + virDomainCapsCPUModelsPtr cpuModels; + size_t i; + + if (!(cpuModels = virDomainCapsCPUModelsNew(0))) + return NULL; + + for (i = 0; i < old->count; 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 509c306..29b18bb 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, + 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 f91ce17..80c112a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -155,6 +155,7 @@ virDomainAuditVcpu; virDomainCapsCPUModelsAdd; virDomainCapsCPUModelsAddSteal; virDomainCapsCPUModelsCopy; +virDomainCapsCPUModelsFilter; virDomainCapsCPUModelsNew; virDomainCapsEnumClear; virDomainCapsEnumSet; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 7a7ddb8..123aae5 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4198,6 +4198,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)) @@ -4207,7 +4209,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, + 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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- 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 c07f995..6f9f7e7 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -169,6 +169,33 @@ virDomainCapsCPUModelsCopy(virDomainCapsCPUModelsPtr old) }
+virDomainCapsCPUModelsPtr +virDomainCapsCPUModelsFilter(virDomainCapsCPUModelsPtr old, + char **models) +{ + virDomainCapsCPUModelsPtr cpuModels; + size_t i; + + if (!(cpuModels = virDomainCapsCPUModelsNew(0))) + return NULL; + + for (i = 0; i < old->count; i++) { + if (models && !virStringArrayHasString(models, old->models[i].name))
My Coverity environment had a build failure here: conf/domain_capabilities.c: In function 'virDomainCapsCPUModelsFilter': conf/domain_capabilities.c:183:48: error: passing argument 1 of 'virStringArrayHasString' from incompatible pointer type [-Werror=incompatible-pointer-types] if (models && !virStringArrayHasString(models, old->models[i].name)) ^~~~~~ In file included from conf/domain_capabilities.c:28:0: ./util/virstring.h:47:6: note: expected 'const char **' but argument is of type 'char **' bool virStringArrayHasString(const char **strings, const char *needle); ^~~~~~~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors Makefile:8092: recipe for target 'conf/libvirt_conf_la-domain_capabilities.lo' failed Which a handily place (const char **) resolved. I seem to recall a discussion on something similar recently upstream...
+ 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 509c306..29b18bb 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, + 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 f91ce17..80c112a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -155,6 +155,7 @@ virDomainAuditVcpu; virDomainCapsCPUModelsAdd; virDomainCapsCPUModelsAddSteal; virDomainCapsCPUModelsCopy; +virDomainCapsCPUModelsFilter; virDomainCapsCPUModelsNew; virDomainCapsEnumClear; virDomainCapsEnumSet; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 7a7ddb8..123aae5 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4198,6 +4198,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)) @@ -4207,7 +4209,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) {
if cpuGetModels returns 0, then models is empty so is there any point in making the call?
+ filtered = virDomainCapsCPUModelsFilter(qemuCaps->cpuDefinitions, + models); + virStringFreeList(models); + } + domCaps->cpu.custom = filtered;
return 0; }
[...]

On Mon, Aug 29, 2016 at 18:01:21 -0400, John Ferlan wrote: ...
My Coverity environment had a build failure here:
conf/domain_capabilities.c: In function 'virDomainCapsCPUModelsFilter': conf/domain_capabilities.c:183:48: error: passing argument 1 of 'virStringArrayHasString' from incompatible pointer type [-Werror=incompatible-pointer-types] if (models && !virStringArrayHasString(models, old->models[i].name)) ^~~~~~ In file included from conf/domain_capabilities.c:28:0: ./util/virstring.h:47:6: note: expected 'const char **' but argument is of type 'char **' bool virStringArrayHasString(const char **strings, const char *needle); ^~~~~~~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors Makefile:8092: recipe for target 'conf/libvirt_conf_la-domain_capabilities.lo' failed
Yeah, my compiler doesn't like this either. It's caused by a recent change to virStringArrayHasString. Fixed.
@@ -4207,7 +4209,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) {
if cpuGetModels returns 0, then models is empty so is there any point in making the call?
Yeah, currently there's no reason to call it if models is empty, but it will change in the future :-) That's what happens when splitting the changes into several patches once a complete functionality has been implemented. Jirka

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> --- docs/formatdomaincaps.html.in | 10 ++-- docs/schemas/domaincaps.rng | 7 +++ src/conf/domain_capabilities.c | 50 +++++++++++++----- 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, 229 insertions(+), 174 deletions(-) diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in index 15a13c1..49ccbfc 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> says + 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 6f9f7e7..c9e3a28 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->count; 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->alloc, cpuModels->count, 1) < 0) return -1; - cpuModels->models[cpuModels->count++].name = *name; + cpuModels->models[cpuModels->count].usable = usable; + cpuModels->models[cpuModels->count].name = *name; + cpuModels->count++; *name = NULL; return 0; } @@ -213,14 +222,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; @@ -366,18 +376,21 @@ virDomainCapsOSFormat(virBufferPtr buf, static void virDomainCapsCPUCustomFormat(virBufferPtr buf, - virDomainCapsCPUModelsPtr custom) + virDomainCapsCPUModelsPtr custom, + virDomainCapsCPUUsable usable) { size_t i; - - virBufferAdjustIndent(buf, 2); + const char *usableStr = virDomainCapsCPUUsableTypeToString(usable); for (i = 0; i < custom->count; i++) { - virBufferAsprintf(buf, "<model>%s</model>\n", - custom->models[i].name); - } + virDomainCapsCPUModelPtr model = custom->models + i; - virBufferAdjustIndent(buf, -2); + if (model->usable != usable) + continue; + + virBufferAsprintf(buf, "<model usable='%s'>%s</model>\n", + usableStr, model->name); + } } static void @@ -399,7 +412,16 @@ virDomainCapsCPUFormat(virBufferPtr buf, virCPUModeTypeToString(VIR_CPU_MODE_CUSTOM)); if (cpu->custom && cpu->custom->count) { virBufferAddLit(buf, "supported='yes'>\n"); - virDomainCapsCPUCustomFormat(buf, cpu->custom); + virBufferAdjustIndent(buf, 2); + + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_YES); + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_NO); + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN); + + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</mode>\n"); } else { virBufferAddLit(buf, "supported='no'/>\n"); diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 29b18bb..7498f89 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, 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 80c112a..53d4e7f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -157,6 +157,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 123aae5..232ae1f 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -665,7 +665,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)); @@ -713,7 +714,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)); @@ -2244,7 +2246,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; } @@ -2593,7 +2596,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; } @@ -2960,7 +2964,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..1d58e57 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='yes'>Model3</model> + <model usable='no'>Model2</model> + <model usable='unknown'>Model1</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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- docs/formatdomaincaps.html.in | 10 ++-- docs/schemas/domaincaps.rng | 7 +++ src/conf/domain_capabilities.c | 50 +++++++++++++----- 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, 229 insertions(+), 174 deletions(-)
So 11-19 with at least some adjustments have an ACK from me. Since you're fixing issues the point I noted in patch 11 is probably something that patches 10-12 resolve, so no big deal. The coverity issue in 15 would be nice to resolve, but since it already exists afaict it's doable afterwards. My note from patch 19 probably needs to be handled as I imagine it'll be an "issue" on "some" platform with "some" compiler. I'll hold off on an ACK for this one. I'm going to stop here for today and pick it up again tomorrow. I do have some notations below. I have some questions, but perhaps they'll be answered in future changes. John
diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in index 15a13c1..49ccbfc 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> says
s/says/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>
Why is this not optional? Hmm... Seems to be output only - still an odd construct though. Not sure I have a better idea (yet).
<text/> </element> </zeroOrMore> diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index 6f9f7e7..c9e3a28 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->count; 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->alloc, cpuModels->count, 1) < 0) return -1;
- cpuModels->models[cpuModels->count++].name = *name; + cpuModels->models[cpuModels->count].usable = usable; + cpuModels->models[cpuModels->count].name = *name; + cpuModels->count++; *name = NULL; return 0; } @@ -213,14 +222,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; @@ -366,18 +376,21 @@ virDomainCapsOSFormat(virBufferPtr buf,
static void virDomainCapsCPUCustomFormat(virBufferPtr buf, - virDomainCapsCPUModelsPtr custom) + virDomainCapsCPUModelsPtr custom, + virDomainCapsCPUUsable usable) { size_t i; - - virBufferAdjustIndent(buf, 2); + const char *usableStr = virDomainCapsCPUUsableTypeToString(usable);
for (i = 0; i < custom->count; i++) { - virBufferAsprintf(buf, "<model>%s</model>\n", - custom->models[i].name); - } + virDomainCapsCPUModelPtr model = custom->models + i;
- virBufferAdjustIndent(buf, -2); + if (model->usable != usable) + continue; + + virBufferAsprintf(buf, "<model usable='%s'>%s</model>\n", + usableStr, model->name); + } }
static void @@ -399,7 +412,16 @@ virDomainCapsCPUFormat(virBufferPtr buf, virCPUModeTypeToString(VIR_CPU_MODE_CUSTOM)); if (cpu->custom && cpu->custom->count) { virBufferAddLit(buf, "supported='yes'>\n"); - virDomainCapsCPUCustomFormat(buf, cpu->custom); + virBufferAdjustIndent(buf, 2); + + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_YES); + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_NO); + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN);
So we're listing all the usable ones first, followed by the unusable, followed by the unknown. Hence the full.xml output change. In any case, that seem like something that would be documentable - the sorting algorithm... It wasn't listed in the cover letter either (the usable attribute isn't there). I guess it just seems inefficient to run through the custom list 3 times just so we can print out in a specific/sorted order. Not sure what printing "unknown" really buys us - seems to be ignorable to me at least at this point in the review process.
+ + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</mode>\n"); } else { virBufferAddLit(buf, "supported='no'/>\n"); diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h index 29b18bb..7498f89 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, 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 80c112a..53d4e7f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -157,6 +157,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 123aae5..232ae1f 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -665,7 +665,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));
@@ -713,7 +714,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));
@@ -2244,7 +2246,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; }
@@ -2593,7 +2596,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; }
@@ -2960,7 +2964,8 @@ virQEMUCapsLoadCache(virQEMUCapsPtr qemuCaps, const char *filename, }
if (virDomainCapsCPUModelsAddSteal(qemuCaps->cpuDefinitions, - &str) < 0) + &str, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0)]
So we can go from 'yes' or 'no' to 'unknown' (for at least a short period of time). I guess I would have expected to "read" and use the cached data like other places... Leads me to wonder why it's being saved. Can it be possible to go from 'yes' to 'no' if we go through unknown? Guess it's just not clear what the dynamics of the conversion are and when is (should be) expected.
goto cleanup; } } diff --git a/tests/domaincapsschemadata/full.xml b/tests/domaincapsschemadata/full.xml index 80fd1f0..1d58e57 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='yes'>Model3</model> + <model usable='no'>Model2</model> + <model usable='unknown'>Model1</model>
Sort by yes, no, unknown...
</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;

On Mon, Aug 29, 2016 at 19:21:24 -0400, John Ferlan wrote: ...
@@ -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> says
s/says/indicates/
Fixed.
+ 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>
Why is this not optional? Hmm... Seems to be output only - still an odd construct though. Not sure I have a better idea (yet).
Exactly, it's output only and we always format it so there's no reason for the attribute to be optional. ...
@@ -399,7 +412,16 @@ virDomainCapsCPUFormat(virBufferPtr buf, virCPUModeTypeToString(VIR_CPU_MODE_CUSTOM)); if (cpu->custom && cpu->custom->count) { virBufferAddLit(buf, "supported='yes'>\n"); - virDomainCapsCPUCustomFormat(buf, cpu->custom); + virBufferAdjustIndent(buf, 2); + + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_YES); + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_NO); + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN);
So we're listing all the usable ones first, followed by the unusable, followed by the unknown. Hence the full.xml output change.
Hmm, it really seems pretty stupid to group them by usable value, doesn't it? I just fixed the code so that the CPU models are printed in a single loop no matter whether they're usable or not.
In any case, that seem like something that would be documentable - the sorting algorithm... It wasn't listed in the cover letter either (the usable attribute isn't there).
Hmm, you're right, I missed this in the cover letter.
I guess it just seems inefficient to run through the custom list 3 times just so we can print out in a specific/sorted order. Not sure what printing "unknown" really buys us - seems to be ignorable to me at least at this point in the review process.
For any hypervisor that doesn't give us the usability data, all CPUs will have usable='unknown'. Or were you thinking about why don't we just skip this attribute if it's value is unknown? If so, I think it's better to be explicit. ...
@@ -2960,7 +2964,8 @@ virQEMUCapsLoadCache(virQEMUCapsPtr qemuCaps, const char *filename, }
if (virDomainCapsCPUModelsAddSteal(qemuCaps->cpuDefinitions, - &str) < 0) + &str, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0)]
So we can go from 'yes' or 'no' to 'unknown' (for at least a short period of time). I guess I would have expected to "read" and use the cached data like other places... Leads me to wonder why it's being saved. Can it be possible to go from 'yes' to 'no' if we go through unknown? Guess it's just not clear what the dynamics of the conversion are and when is (should be) expected.
There's no code in QEMU driver which would set the value to anything but 'unknown' yet. There's no conversion involved. This is just a preparation for a later patch that would really ask QEMU for this stuff. Jirka

[...]
@@ -399,7 +412,16 @@ virDomainCapsCPUFormat(virBufferPtr buf, virCPUModeTypeToString(VIR_CPU_MODE_CUSTOM)); if (cpu->custom && cpu->custom->count) { virBufferAddLit(buf, "supported='yes'>\n"); - virDomainCapsCPUCustomFormat(buf, cpu->custom); + virBufferAdjustIndent(buf, 2); + + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_YES); + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_NO); + virDomainCapsCPUCustomFormat(buf, cpu->custom, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN);
So we're listing all the usable ones first, followed by the unusable, followed by the unknown. Hence the full.xml output change.
Hmm, it really seems pretty stupid to group them by usable value, doesn't it? I just fixed the code so that the CPU models are printed in a single loop no matter whether they're usable or not.
In any case, that seem like something that would be documentable - the sorting algorithm... It wasn't listed in the cover letter either (the usable attribute isn't there).
Hmm, you're right, I missed this in the cover letter.
I guess it just seems inefficient to run through the custom list 3 times just so we can print out in a specific/sorted order. Not sure what printing "unknown" really buys us - seems to be ignorable to me at least at this point in the review process.
For any hypervisor that doesn't give us the usability data, all CPUs will have usable='unknown'. Or were you thinking about why don't we just skip this attribute if it's value is unknown? If so, I think it's better to be explicit.
...
I suppose I was more grousing about the 3 times through, but then starting thinking is it worth it to print unknown, but since this is output only so I can agree it's fine to be explicit. Sorry if taking the route of ACK'ing every 10 or so patches is/was hard to work with - it's a large series and was not possible for me to review in one sitting, so I tried to break it up into more manageable chunks. In particular, this one I reviewed after 7PM (considering I typically am up/online by 6AM - that's a long day). It was mostly a workflow thing for me and I've seen other reviews take a similar approach with larger series. I should have also replied to the cover letter, but forgot. In any case, I think you've answered my issues so (more explicit) ACK for this one with the noted changes. John
@@ -2960,7 +2964,8 @@ virQEMUCapsLoadCache(virQEMUCapsPtr qemuCaps, const char *filename, }
if (virDomainCapsCPUModelsAddSteal(qemuCaps->cpuDefinitions, - &str) < 0) + &str, + VIR_DOMCAPS_CPU_USABLE_UNKNOWN) < 0)]
So we can go from 'yes' or 'no' to 'unknown' (for at least a short period of time). I guess I would have expected to "read" and use the cached data like other places... Leads me to wonder why it's being saved. Can it be possible to go from 'yes' to 'no' if we go through unknown? Guess it's just not clear what the dynamics of the conversion are and when is (should be) expected.
There's no code in QEMU driver which would set the value to anything but 'unknown' yet. There's no conversion involved. This is just a preparation for a later patch that would really ask QEMU for this stuff.
Jirka

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- 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 052f28c..c06f700 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 @@ -4377,125 +4378,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 @@ -5440,10 +5322,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 --> @@ -5527,11 +5405,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.9.2

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 25 +++++++++++++++---------- src/qemu/qemu_capabilities.h | 6 ++++-- src/qemu/qemu_capspriv.h | 3 ++- src/qemu/qemu_domain.c | 13 ++++++++----- src/qemu/qemu_driver.c | 9 ++++++--- src/qemu/qemu_process.c | 14 +++++++++++--- tests/qemucapsprobe.c | 2 +- 7 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 232ae1f..8f55fcc 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -837,7 +837,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); } @@ -877,7 +877,7 @@ virQEMUCapsInitGuest(virCapsPtr caps, if (!kvmbin) continue; - if (!(kvmbinCaps = virQEMUCapsCacheLookup(cache, kvmbin))) { + if (!(kvmbinCaps = virQEMUCapsCacheLookup(caps, cache, kvmbin))) { virResetLastError(); VIR_FREE(kvmbin); continue; @@ -1986,7 +1986,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; @@ -3783,7 +3783,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, @@ -3861,13 +3862,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); } @@ -3960,7 +3962,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; @@ -3980,7 +3984,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) { @@ -4000,11 +4004,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 9fd38d9..df49809 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -445,9 +445,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 efc46f9..9ba7cbd 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2285,7 +2285,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; @@ -2442,7 +2443,7 @@ qemuDomainChrDefDropDefaultPath(virDomainChrDefPtr chr, static int qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, const virDomainDef *def, - virCapsPtr caps ATTRIBUTE_UNUSED, + virCapsPtr caps, unsigned int parseFlags, void *opaque) { @@ -2451,7 +2452,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 && @@ -2628,7 +2630,7 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, static int qemuDomainDefAssignAddresses(virDomainDef *def, - virCapsPtr caps ATTRIBUTE_UNUSED, + virCapsPtr caps, unsigned int parseFlags ATTRIBUTE_UNUSED, void *opaque) { @@ -2637,7 +2639,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 7e4f4e7..695da14 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8270,7 +8270,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) { @@ -15634,7 +15635,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) @@ -18533,7 +18535,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 4d709fc..ae94c21 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3246,6 +3246,7 @@ qemuProcessReconnect(void *opaque) int ret; unsigned int stopFlags = 0; bool jobStarted = false; + virCapsPtr caps = NULL; VIR_FREE(data); @@ -3256,6 +3257,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; @@ -3325,7 +3329,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; @@ -3422,6 +3427,7 @@ qemuProcessReconnect(void *opaque) virDomainObjEndAPI(&obj); virObjectUnref(conn); virObjectUnref(cfg); + virObjectUnref(caps); virNWFilterUnlockFilterUpdates(); return; @@ -4609,7 +4615,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; @@ -6043,7 +6050,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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 25 +++++++++++++++---------- src/qemu/qemu_capabilities.h | 6 ++++-- src/qemu/qemu_capspriv.h | 3 ++- src/qemu/qemu_domain.c | 13 ++++++++----- src/qemu/qemu_driver.c | 9 ++++++--- src/qemu/qemu_process.c | 14 +++++++++++--- tests/qemucapsprobe.c | 2 +- 7 files changed, 47 insertions(+), 25 deletions(-)
OK I lied slightly... 21 ACK ... build breaks here - probably because of new function qemuDomainDefValidate... luckily caps is passed as ATTRIBUTE_UNUSED, so it seems to be easily handled... John
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 232ae1f..8f55fcc 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -837,7 +837,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); } @@ -877,7 +877,7 @@ virQEMUCapsInitGuest(virCapsPtr caps, if (!kvmbin) continue;
- if (!(kvmbinCaps = virQEMUCapsCacheLookup(cache, kvmbin))) { + if (!(kvmbinCaps = virQEMUCapsCacheLookup(caps, cache, kvmbin))) { virResetLastError(); VIR_FREE(kvmbin); continue; @@ -1986,7 +1986,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; @@ -3783,7 +3783,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, @@ -3861,13 +3862,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); }
@@ -3960,7 +3962,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;
@@ -3980,7 +3984,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) { @@ -4000,11 +4004,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 9fd38d9..df49809 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -445,9 +445,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 efc46f9..9ba7cbd 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2285,7 +2285,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;
@@ -2442,7 +2443,7 @@ qemuDomainChrDefDropDefaultPath(virDomainChrDefPtr chr, static int qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, const virDomainDef *def, - virCapsPtr caps ATTRIBUTE_UNUSED, + virCapsPtr caps, unsigned int parseFlags, void *opaque) { @@ -2451,7 +2452,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 && @@ -2628,7 +2630,7 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
static int qemuDomainDefAssignAddresses(virDomainDef *def, - virCapsPtr caps ATTRIBUTE_UNUSED, + virCapsPtr caps, unsigned int parseFlags ATTRIBUTE_UNUSED, void *opaque) { @@ -2637,7 +2639,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 7e4f4e7..695da14 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8270,7 +8270,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) { @@ -15634,7 +15635,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) @@ -18533,7 +18535,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 4d709fc..ae94c21 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3246,6 +3246,7 @@ qemuProcessReconnect(void *opaque) int ret; unsigned int stopFlags = 0; bool jobStarted = false; + virCapsPtr caps = NULL;
VIR_FREE(data);
@@ -3256,6 +3257,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; @@ -3325,7 +3329,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; @@ -3422,6 +3427,7 @@ qemuProcessReconnect(void *opaque) virDomainObjEndAPI(&obj); virObjectUnref(conn); virObjectUnref(cfg); + virObjectUnref(caps); virNWFilterUnlockFilterUpdates(); return;
@@ -4609,7 +4615,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; @@ -6043,7 +6050,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;

On Mon, Aug 29, 2016 at 19:31:22 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 25 +++++++++++++++---------- src/qemu/qemu_capabilities.h | 6 ++++-- src/qemu/qemu_capspriv.h | 3 ++- src/qemu/qemu_domain.c | 13 ++++++++----- src/qemu/qemu_driver.c | 9 ++++++--- src/qemu/qemu_process.c | 14 +++++++++++--- tests/qemucapsprobe.c | 2 +- 7 files changed, 47 insertions(+), 25 deletions(-)
OK I lied slightly... 21 ACK ...
build breaks here - probably because of new function qemuDomainDefValidate... luckily caps is passed as ATTRIBUTE_UNUSED, so it seems to be easily handled...
Right, it was an easy fix. Jirka

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> --- 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 53d4e7f..26f5bc8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -66,6 +66,7 @@ virCapabilitiesSetNetPrefix; virCPUDefAddFeature; virCPUDefCopy; virCPUDefCopyModel; +virCPUDefCopyWithoutModel; virCPUDefFormat; virCPUDefFormatBuf; virCPUDefFree; -- 2.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- src/conf/cpu_conf.c | 16 +++++++++++++++- src/conf/cpu_conf.h | 3 +++ src/libvirt_private.syms | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) '
suggestion - how about "virCPUDefSparseCopy" ? Especially since nothing that requires a VIR_STRDUP is copied (e.g. vendor, vendor_id, features).
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 53d4e7f..26f5bc8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -66,6 +66,7 @@ virCapabilitiesSetNetPrefix; virCPUDefAddFeature; virCPUDefCopy; virCPUDefCopyModel; +virCPUDefCopyWithoutModel; virCPUDefFormat; virCPUDefFormatBuf; virCPUDefFree;

On Tue, Aug 30, 2016 at 10:23:10 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- src/conf/cpu_conf.c | 16 +++++++++++++++- src/conf/cpu_conf.h | 3 +++ src/libvirt_private.syms | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) '
suggestion - how about "virCPUDefSparseCopy" ? Especially since nothing that requires a VIR_STRDUP is copied (e.g. vendor, vendor_id, features).
The API copies everything but the CPU model stuff (which can be copied separately with virCPUDefCopyModel). I think virCPUDefCopyWithoutModel is more explicit about what it does than virCPUDefSparseCopy or something similarly generic. Jirka

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> --- 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..13f3da3 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -115,6 +115,23 @@ virCPUDefCopyModel(virCPUDefPtr dst, } +void +virCPUDefMoveModel(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..d866a89 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 +virCPUDefMoveModel(virCPUDefPtr dst, + virCPUDefPtr src); + virCPUDefPtr virCPUDefCopy(const virCPUDef *cpu); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 26f5bc8..1cfebd5 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -71,6 +71,7 @@ virCPUDefFormat; virCPUDefFormatBuf; virCPUDefFree; virCPUDefFreeModel; +virCPUDefMoveModel; virCPUDefParseXML; virCPUDefUpdateFeature; virCPUModeTypeToString; -- 2.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- src/conf/cpu_conf.c | 17 +++++++++++++++++ src/conf/cpu_conf.h | 4 ++++ src/libvirt_private.syms | 1 + 3 files changed, 22 insertions(+)
Less "Move" and more "Take"... virCPUDefStealModel is a suggestion - of course it's more than ->model, but close enough I think.
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index c6e847a..13f3da3 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -115,6 +115,23 @@ virCPUDefCopyModel(virCPUDefPtr dst, }
+void +virCPUDefMoveModel(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..d866a89 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 +virCPUDefMoveModel(virCPUDefPtr dst, + virCPUDefPtr src); + virCPUDefPtr virCPUDefCopy(const virCPUDef *cpu);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 26f5bc8..1cfebd5 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -71,6 +71,7 @@ virCPUDefFormat; virCPUDefFormatBuf; virCPUDefFree; virCPUDefFreeModel; +virCPUDefMoveModel; virCPUDefParseXML; virCPUDefUpdateFeature; virCPUModeTypeToString;

On Tue, Aug 30, 2016 at 10:24:07 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- src/conf/cpu_conf.c | 17 +++++++++++++++++ src/conf/cpu_conf.h | 4 ++++ src/libvirt_private.syms | 1 + 3 files changed, 22 insertions(+)
Less "Move" and more "Take"... virCPUDefStealModel is a suggestion - of
Ok, works for me. Changed.
course it's more than ->model, but close enough I think.
It's documented that it's more than just ->model. And actually all *Model APIs work on more than just ->model. Jirka

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> --- src/conf/cpu_conf.c | 31 ++++++++++++++++++++++++------- src/conf/cpu_conf.h | 12 ++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 13f3da3..b74c48b 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 ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) +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 d866a89..9d2d9b6 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -123,6 +123,18 @@ 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 ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) +virCPUDefCopyModelFilter(virCPUDefPtr dst, + const virCPUDef *src, + bool resetPolicy, + virCPUDefFeatureFilter filter, + void *opaque); void virCPUDefMoveModel(virCPUDefPtr dst, virCPUDefPtr src); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1cfebd5..3a33956 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -66,6 +66,7 @@ virCapabilitiesSetNetPrefix; virCPUDefAddFeature; virCPUDefCopy; virCPUDefCopyModel; +virCPUDefCopyModelFilter; virCPUDefCopyWithoutModel; virCPUDefFormat; virCPUDefFormatBuf; -- 2.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- src/conf/cpu_conf.c | 31 ++++++++++++++++++++++++------- src/conf/cpu_conf.h | 12 ++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 13f3da3..b74c48b 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 ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
Any particular advantage to putting the NONNULL in both the .h file and here? I see virCPUDefCopyModel is similar.
+virCPUDefCopyModelFilter(virCPUDefPtr dst, + const virCPUDef *src, + bool resetPolicy, + virCPUDefFeatureFilter filter, + void *opaque) +{
[...]

On Tue, Aug 30, 2016 at 10:25:10 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- src/conf/cpu_conf.c | 31 ++++++++++++++++++++++++------- src/conf/cpu_conf.h | 12 ++++++++++++ src/libvirt_private.syms | 1 + 3 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 13f3da3..b74c48b 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 ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
Any particular advantage to putting the NONNULL in both the .h file and here? I see virCPUDefCopyModel is similar.
Copy & paste I guess. Fixed. Jirka

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> --- src/qemu/qemu_capabilities.c | 63 +++++++++++++++++++++++++++++++++++++------- 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, 76 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 8f55fcc..97dc877 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -374,6 +374,7 @@ struct _virQEMUCaps { virArch arch; virDomainCapsCPUModelsPtr cpuDefinitions; + virCPUDefPtr cpuModel; size_t nmachineTypes; struct virQEMUCapsMachineType *machineTypes; @@ -2052,6 +2053,10 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps) goto error; } + if (qemuCaps->cpuModel && + !(ret->cpuModel = virCPUDefCopy(qemuCaps->cpuModel))) + goto error; + if (VIR_ALLOC_N(ret->machineTypes, qemuCaps->nmachineTypes) < 0) goto error; ret->nmachineTypes = qemuCaps->nmachineTypes; @@ -2821,6 +2826,37 @@ 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->cpuModel = cpu; + return; + + error: + virCPUDefFree(cpu); + qemuCaps->cpuModel = NULL; +} + + /* * Parsing a doc that looks like * @@ -2839,8 +2875,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; @@ -3068,6 +3107,8 @@ virQEMUCapsLoadCache(virQEMUCapsPtr qemuCaps, const char *filename, } VIR_FREE(nodes); + virQEMUCapsInitHostCPUModel(qemuCaps, &caps->host); + ret = 0; cleanup: VIR_FREE(str); @@ -3256,7 +3297,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; @@ -3298,8 +3341,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(); @@ -3783,7 +3826,7 @@ virQEMUCapsLogProbeFailure(const char *binary) virQEMUCapsPtr -virQEMUCapsNewForBinaryInternal(virCapsPtr caps ATTRIBUTE_UNUSED, +virQEMUCapsNewForBinaryInternal(virCapsPtr caps, const char *binary, const char *libDir, const char *cacheDir, @@ -3823,7 +3866,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) { @@ -3849,16 +3892,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 59be0ea..e801424 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 1f0db16..e2b4db4 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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- src/qemu/qemu_capabilities.c | 63 +++++++++++++++++++++++++++++++++++++------- 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, 76 insertions(+), 21 deletions(-)
I personally think this should be closer to patch 22 where the caps gets introduced into virQEMUCapsNewForBinaryInternal, but it's not a review requirement...
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 8f55fcc..97dc877 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -374,6 +374,7 @@ struct _virQEMUCaps { virArch arch;
virDomainCapsCPUModelsPtr cpuDefinitions; + virCPUDefPtr cpuModel;
hostCpuModel ? IOW: Some way to make it more clear to a casual reader and perhaps easier to find via cscope Also I note that this isn't being written out to the cache (e.g. no change to virQEMUCapsFormatCache), so probably need to "note" that some how. Furthermore, perhaps this should be moved after the gic stuff and the note made that anything "after" this point isn't written out, rather it's refetched during Load
size_t nmachineTypes; struct virQEMUCapsMachineType *machineTypes; @@ -2052,6 +2053,10 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps) goto error; }
+ if (qemuCaps->cpuModel && + !(ret->cpuModel = virCPUDefCopy(qemuCaps->cpuModel)) + goto error; + if (VIR_ALLOC_N(ret->machineTypes, qemuCaps->nmachineTypes) < 0) goto error; ret->nmachineTypes = qemuCaps->nmachineTypes; @@ -2821,6 +2826,37 @@ 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->cpuModel = cpu;
This is leaked - eg. no virCPUDefFree in virQEMUCapsDispose Since this is a void function it is possible to have a failure (above) thus having qemuCaps->cpuModel be NULL... Store that knowledge away as it becomes important later in patch 40 as processing will call virQEMUCapsGetHostModel which returns this field.
+ return; + + error: + virCPUDefFree(cpu); + qemuCaps->cpuModel = NULL;
Should we virResetLastError() since we don't care about the failure in the two callers?
+} + + /* * Parsing a doc that looks like *
[...]

On Tue, Aug 30, 2016 at 10:27:44 -0400, John Ferlan wrote: ...
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 8f55fcc..97dc877 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -374,6 +374,7 @@ struct _virQEMUCaps { virArch arch;
virDomainCapsCPUModelsPtr cpuDefinitions; + virCPUDefPtr cpuModel;
hostCpuModel ?
IOW: Some way to make it more clear to a casual reader and perhaps easier to find via cscope
Also I note that this isn't being written out to the cache (e.g. no change to virQEMUCapsFormatCache), so probably need to "note" that some how. Furthermore, perhaps this should be moved after the gic stuff and the note made that anything "after" this point isn't written out, rather it's refetched during Load
Makes sense, all of it. Fixed. ...
+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->cpuModel = cpu;
This is leaked - eg. no virCPUDefFree in virQEMUCapsDispose
Oops. Fixed.
Since this is a void function it is possible to have a failure (above) thus having qemuCaps->cpuModel be NULL... Store that knowledge away as it becomes important later in patch 40 as processing will call virQEMUCapsGetHostModel which returns this field.
Not only that. The host->cpu->model is not guaranteed to be set (e.g., it's not set on AArch64) and thus qemuCaps->hostCPUModel can be NULL even if there's no failure.
+ return; + + error: + virCPUDefFree(cpu); + qemuCaps->cpuModel = NULL;
Should we virResetLastError() since we don't care about the failure in the two callers?
I guess so. Fixed. Jirka

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> --- 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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- src/cpu/cpu_arm.c | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-)
I see cpuNodeData and cpuDecode are generally used together, but not so in tests/cputest.c, which doesn't test arm anyway, so seemingly not a problem... Just making a note...
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,

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> --- 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 49ccbfc..34eb777 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> says 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 c9e3a28..34379e9 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -404,9 +404,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 7498f89..36693d7 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 97dc877..5197180 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4260,9 +4260,7 @@ virQEMUCapsFillDomainCPUCaps(virCapsPtr caps, virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch)) domCaps->cpu.hostPassthrough = true; - if (qemuCaps->cpuDefinitions && caps && caps->host.cpu) - domCaps->cpu.hostModel = virQEMUCapsGuestIsNative(caps->host.arch, - qemuCaps->arch); + domCaps->cpu.hostModel = virCPUDefCopy(qemuCaps->cpuModel); if (qemuCaps->cpuDefinitions && cpuGetModels(domCaps->arch, &models) >= 0) { diff --git a/tests/domaincapsschemadata/full.xml b/tests/domaincapsschemadata/full.xml index 1d58e57..5853151 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='yes'>Model3</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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- 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(-)
Hmmm... I guess we are displaying the cpuModel data - it just wasn't "obvious" previously...
diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in index 49ccbfc..34eb777 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> says that the CPU a guest will see
s/says/indicates
+ should match this CPU definition. + </dd>
Should this make a reference to http://libvirt.org/formatdomain.html#elementsCPU since that's the allow/forbid and 'host-model' for the domain description? Too bad there weren't any easily crafted 'forbid' examples for test...
<dt><code>custom</code></dt> <dd>
[...]

On Tue, Aug 30, 2016 at 10:49:25 -0400, John Ferlan wrote: ...
- <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> says that the CPU a guest will see
s/says/indicates
Fixed.
+ should match this CPU definition. + </dd>
Should this make a reference to
http://libvirt.org/formatdomain.html#elementsCPU
since that's the allow/forbid and 'host-model' for the domain description?
Yes, but it should go to the patch that first introduced the <cpu> element in domain capabilities XML. I'll add it there.
Too bad there weren't any easily crafted 'forbid' examples for test...
There's still some work to be done to get there. We'll be asking QEMU what it thinks the host CPU is and then we can finally start to report host-model CPUs which will match what guests will get. So stay tuned :-) Jirka

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- 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 5197180..670f944 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2295,6 +2295,13 @@ virQEMUCapsGetCPUDefinitions(virQEMUCapsPtr qemuCaps, } +virCPUDefPtr +virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps) +{ + return qemuCaps->cpuModel; +} + + int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps, size_t *nmachines, virCapsGuestMachinePtr **machines) diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index df49809..1203073 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -424,6 +424,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.9.2

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 55 ++++++++++++++++++++++++++++++++++---------- src/qemu/qemu_capabilities.h | 4 ++++ 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 670f944..f70a36c 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2302,6 +2302,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->cpuModel; + + case VIR_CPU_MODE_CUSTOM: + return qemuCaps->cpuDefinitions && + qemuCaps->cpuDefinitions->count > 0; + + case VIR_CPU_MODE_LAST: + break; + } + + return false; +} + + int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps, size_t *nmachines, virCapsGuestMachinePtr **machines) @@ -4260,22 +4286,27 @@ 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->cpuModel); + if (virQEMUCapsIsCPUModeSupported(qemuCaps, caps, domCaps->virttype, + VIR_CPU_MODE_HOST_MODEL)) + domCaps->cpu.hostModel = virCPUDefCopy(qemuCaps->cpuModel); - if (qemuCaps->cpuDefinitions && - cpuGetModels(domCaps->arch, &models) >= 0) { - filtered = virDomainCapsCPUModelsFilter(qemuCaps->cpuDefinitions, - models); - virStringFreeList(models); + if (virQEMUCapsIsCPUModeSupported(qemuCaps, caps, domCaps->virttype, + VIR_CPU_MODE_CUSTOM)) { + virDomainCapsCPUModelsPtr filtered = NULL; + char **models = NULL; + + if (qemuCaps->cpuDefinitions && + cpuGetModels(domCaps->arch, &models) >= 0) { + filtered = virDomainCapsCPUModelsFilter(qemuCaps->cpuDefinitions, + 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 1203073..2ea5849 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -425,6 +425,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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 55 ++++++++++++++++++++++++++++++++++---------- src/qemu/qemu_capabilities.h | 4 ++++ 2 files changed, 47 insertions(+), 12 deletions(-)
So another 10 down almost 75% done! Let's consider ACK's again... Still not sure about patch 20 w/r/t to the need for "unknown" printing, the sorting by yes, no, and unknown, and whether LoadCache should "read" what's been printed and validate against the current (if that matters). As for 21-30, if there's no reply then an ACK can be implied. A couple of replies (23, 24) make suggestions for function name changes - your choice on those. Two (25, 27) I've just left some thoughts - they don't really require changes. Patch 22 will need an adjustment for an ACK, but the build would fail anyway, so it's obvious. Patch 26 needs an adjust to fix a leak for an ACK, your choice on renaming cpuModel, and I think the virResetLastError should be called. I've seen "future" patches where returning NULL may come into play... Patch 28 - your call on the domain page reference That just leaves this one with one innocuous adjustment shown below. Not required for an ACK John
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 670f944..f70a36c 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2302,6 +2302,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->cpuModel; + + case VIR_CPU_MODE_CUSTOM: + return qemuCaps->cpuDefinitions && + qemuCaps->cpuDefinitions->count > 0; + + case VIR_CPU_MODE_LAST: + break; + } + + return false; +} + + int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps, size_t *nmachines, virCapsGuestMachinePtr **machines) @@ -4260,22 +4286,27 @@ 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->cpuModel); + if (virQEMUCapsIsCPUModeSupported(qemuCaps, caps, domCaps->virttype, + VIR_CPU_MODE_HOST_MODEL)) + domCaps->cpu.hostModel = virCPUDefCopy(qemuCaps->cpuModel);
- if (qemuCaps->cpuDefinitions && - cpuGetModels(domCaps->arch, &models) >= 0) { - filtered = virDomainCapsCPUModelsFilter(qemuCaps->cpuDefinitions, - models); - virStringFreeList(models); + if (virQEMUCapsIsCPUModeSupported(qemuCaps, caps, domCaps->virttype, + VIR_CPU_MODE_CUSTOM)) { + virDomainCapsCPUModelsPtr filtered = NULL; + char **models = NULL; + + if (qemuCaps->cpuDefinitions &&
Redundant check for MODE_CUSTOM when ModeSupported is true
+ cpuGetModels(domCaps->arch, &models) >= 0) { + filtered = virDomainCapsCPUModelsFilter(qemuCaps->cpuDefinitions, + 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 1203073..2ea5849 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -425,6 +425,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,

On Tue, Aug 30, 2016 at 11:08:44 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 55 ++++++++++++++++++++++++++++++++++---------- src/qemu/qemu_capabilities.h | 4 ++++ 2 files changed, 47 insertions(+), 12 deletions(-)
So another 10 down almost 75% done! Let's consider ACK's again...
Still not sure about patch 20 w/r/t to the need for "unknown" printing, the sorting by yes, no, and unknown, and whether LoadCache should "read" what's been printed and validate against the current (if that matters).
As for 21-30, if there's no reply then an ACK can be implied. A couple of replies (23, 24) make suggestions for function name changes - your choice on those. Two (25, 27) I've just left some thoughts - they don't really require changes.
Patch 22 will need an adjustment for an ACK, but the build would fail anyway, so it's obvious.
Patch 26 needs an adjust to fix a leak for an ACK, your choice on renaming cpuModel, and I think the virResetLastError should be called. I've seen "future" patches where returning NULL may come into play...
Patch 28 - your call on the domain page reference
That just leaves this one with one innocuous adjustment shown below. Not required for an ACK
Heh, this summary doesn't really clarify the situation and it's not entirely obvious which patches are ACKed which patches are ACKed once I make the suggested changes, and which patches need additional review of the changes. We'll see if it changes after I process all review comments. ...
+ if (virQEMUCapsIsCPUModeSupported(qemuCaps, caps, domCaps->virttype, + VIR_CPU_MODE_CUSTOM)) { + virDomainCapsCPUModelsPtr filtered = NULL; + char **models = NULL; + + if (qemuCaps->cpuDefinitions &&
Redundant check for MODE_CUSTOM when ModeSupported is true
Right. Fixed. Jirka

On 09/15/2016 07:30 AM, Jiri Denemark wrote:
On Tue, Aug 30, 2016 at 11:08:44 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_capabilities.c | 55 ++++++++++++++++++++++++++++++++++---------- src/qemu/qemu_capabilities.h | 4 ++++ 2 files changed, 47 insertions(+), 12 deletions(-)
So another 10 down almost 75% done! Let's consider ACK's again...
Still not sure about patch 20 w/r/t to the need for "unknown" printing, the sorting by yes, no, and unknown, and whether LoadCache should "read" what's been printed and validate against the current (if that matters).
As for 21-30, if there's no reply then an ACK can be implied. A couple of replies (23, 24) make suggestions for function name changes - your choice on those. Two (25, 27) I've just left some thoughts - they don't really require changes.
Patch 22 will need an adjustment for an ACK, but the build would fail anyway, so it's obvious.
Patch 26 needs an adjust to fix a leak for an ACK, your choice on renaming cpuModel, and I think the virResetLastError should be called. I've seen "future" patches where returning NULL may come into play...
Patch 28 - your call on the domain page reference
That just leaves this one with one innocuous adjustment shown below. Not required for an ACK
Heh, this summary doesn't really clarify the situation and it's not entirely obvious which patches are ACKed which patches are ACKed once I make the suggested changes, and which patches need additional review of the changes. We'll see if it changes after I process all review comments.
...
I was clear to me even reading it days later.
From 21-30, if I didn't comment, then ACK.
If I did comment or suggest, then your choice on making the changes, but still it's an implied ACK with the caveat of 22 which had a build failure and 26 which had a leak and I would assume you would fix I think you've addressed those so perhaps to be more explicit ACK 21-30 (and I already ACK'd 20 separately) John I trust that you'd make the changes and I didn't want to see PATCH v2 00/41 (or some *larger* number!)
+ if (virQEMUCapsIsCPUModeSupported(qemuCaps, caps, domCaps->virttype, + VIR_CPU_MODE_CUSTOM)) { + virDomainCapsCPUModelsPtr filtered = NULL; + char **models = NULL; + + if (qemuCaps->cpuDefinitions &&
Redundant check for MODE_CUSTOM when ModeSupported is true
Right. Fixed.
Jirka

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- 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 670b02e..914352d 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.9.2

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> --- src/cpu/cpu_x86.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 914352d..dcf9c25 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,26 @@ 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; + + case VIR_CPU_FEATURE_OPTIONAL: + case VIR_CPU_FEATURE_LAST: + break; + } + } else if (x86DataAdd(&model->data, &feature->data) < 0) { goto error; + } } return model; -- 2.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- src/cpu/cpu_x86.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-)
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 914352d..dcf9c25 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) ||
[1]
+ (policy != -1 && fpol != policy)) continue;
if (!(feature = x86FeatureFind(map, cpu->features[i].name))) { @@ -1054,8 +1070,26 @@ 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; + + case VIR_CPU_FEATURE_OPTIONAL:
[1] Coverity happlily points out that OPTIONAL is a DEAD_CODE path especially due to the prior check and continue; I see no other sane way around it other than a comment before the case: /* 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;

On Tue, Aug 30, 2016 at 17:52:24 -0400, John Ferlan wrote: ...
+ case VIR_CPU_FEATURE_DISABLE: + case VIR_CPU_FEATURE_FORBID: + x86DataSubtract(&model->data, &feature->data); + break; + + case VIR_CPU_FEATURE_OPTIONAL:
[1] Coverity happlily points out that OPTIONAL is a DEAD_CODE path especially due to the prior check and continue;
I see no other sane way around it other than a comment before the case:
/* coverity[dead_error_condition] */ case VIR_CPU_FEATURE_OPTIONAL:
Easy enough. Fixed. Jirka

Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- 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 dcf9c25..ed9b010 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2652,8 +2652,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.9.2

The function checks CPUID data for a given feature. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- 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 ed9b010..e4bde79 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) @@ -2525,15 +2546,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; @@ -2645,23 +2663,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.9.2

The reworked API is now called virCPUUpdate and it should change the provided CPU definition into a one which can be consumed by 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> --- po/POTFILES.in | 1 + src/cpu/cpu.c | 59 ++++-- 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, 227 insertions(+), 245 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..f3eb211 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"), + _("cannot update guest CPU for %s architecture"), virArchToString(host->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..f4bb51d 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) ATTRIBUTE_NONNULL(3); int cpuHasFeature(const virCPUData *data, diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index a3aed6b..49da36e 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; + + virCPUDefMoveModel(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 e4bde79..746c804 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1121,40 +1121,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) @@ -2532,23 +2498,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; + } + + virCPUDefMoveModel(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) @@ -2558,107 +2586,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) { @@ -2715,7 +2655,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 3a33956..ef04ce4 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -971,7 +971,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 823b58d..ce04c76 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6461,7 +6461,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 9ba7cbd..d8c589e 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3275,7 +3275,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 ae94c21..662a46a 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4440,7 +4440,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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
The reworked API is now called virCPUUpdate and it should change the provided CPU definition into a one which can be consumed by QEMU command
s/by/by the/
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> --- po/POTFILES.in | 1 + src/cpu/cpu.c | 59 ++++-- 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, 227 insertions(+), 245 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..f3eb211 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -579,38 +579,71 @@ cpuBaseline(virCPUDefPtr *cpus,
/** - * cpuUpdate: + * virCPUUpdate:
In a way I'd expect a "virCPUUpdate" API to go in src/util/... somewhere. Not a problem to keep it here, but I guess when I see vir prefixed functions I think src/util/...
* - * @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)
Still not 100% clear whether if eventually (patch 40) it's possible to enter here with 'host == NULL'... Keeping in mind from patch 26 that virQEMUCapsInitHostCPUModel could have qemuCaps->cpuModel = NULL, thus the virQEMUCapsGetHostModel could then return a NULL from qemuProcessUpdateGuestCPU which calls this function. However, that possibility is gated by whether virQEMUCapsIsCPUModeSupported succeeds or not. Since you've added NULLSTR and host ? checks, I'm partially assuming it's possible to get here with host == NULL. The intro comments here don't help me determine that though. I'm lost in the terminology between old/new that's described in patch 40. If your belief is things are going to be OK, then I'm fine with that, but I figured I'd at least point out what I saw and what got confusing eventually. Hopefully it's understandable.
{ 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));
The Coverity build throws up here... According to cpu.h, arg 3 is NONNULL; however, as I pointed out above that could change. So at the very least cpu.h needs to change to remove the NONNULL(3).
- 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"), + _("cannot update guest CPU for %s architecture"), virArchToString(host->arch));'
Should this just be 'arch' ? if not, if host == NULL, then this will core.
return -1; }
- return driver->update(guest, host); + if (driver->update(guest, host) < 0)
Seems as though all implemented ->update functions will return an error if 'host' is NULL, so that's good I guess. Whether it's expected is something you can answer!
+ 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..f4bb51d 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);
Why the name change? I see upcoming patches also use the new nomenclature, although I'll assume not all driver functions will change. Is that the goal for the future?
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) ATTRIBUTE_NONNULL(3);
Remove the ATTRIBUTE_NONNULL(3) as noted above or even go back to the earlier void function and allow it to error...
int cpuHasFeature(const virCPUData *data,
[...]

On Tue, Aug 30, 2016 at 17:53:56 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
The reworked API is now called virCPUUpdate and it should change the provided CPU definition into a one which can be consumed by QEMU command
s/by/by the/
Fixed. ...
/** - * cpuUpdate: + * virCPUUpdate:
In a way I'd expect a "virCPUUpdate" API to go in src/util/... somewhere. Not a problem to keep it here, but I guess when I see vir prefixed functions I think src/util/...
Not really, I think the vir prefix is just used when someone refactors an old code. AFAIK the goal (not enforced in any way) was to eventually use the prefix for all functions. Anyway, see virQEMUCaps* is good example of such functions/types that are not in src/util. ...
+virCPUUpdate(virArch arch, + virCPUDefPtr guest, + const virCPUDef *host)
Still not 100% clear whether if eventually (patch 40) it's possible to enter here with 'host == NULL'... Keeping in mind from patch 26 that virQEMUCapsInitHostCPUModel could have qemuCaps->cpuModel = NULL, thus the virQEMUCapsGetHostModel could then return a NULL from qemuProcessUpdateGuestCPU which calls this function. However, that possibility is gated by whether virQEMUCapsIsCPUModeSupported succeeds or not. Since you've added NULLSTR and host ? checks, I'm partially assuming it's possible to get here with host == NULL. The intro comments here don't help me determine that though.
Yes, it is possible to enter virCPUUpdate with host == NULL. virQEMUCapsIsCPUModeSupported checks hostCPUModel only for VIR_CPU_MODE_HOST_MODEL, but virCPUUpdate is called for all CPU definitions. It may seem we do not call virCPUUpdate if hostCPUModel is NULL since the code is still not in its final shape after this patch (until patch 40 is applied).
I'm lost in the terminology between old/new that's described in patch 40. If your belief is things are going to be OK, then I'm fine with that, but I figured I'd at least point out what I saw and what got confusing eventually. Hopefully it's understandable.
{ 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));
The Coverity build throws up here... According to cpu.h, arg 3 is NONNULL; however, as I pointed out above that could change.
So at the very least cpu.h needs to change to remove the NONNULL(3).
Yes, fixed. ...
+ if (!driver->update) { virReportError(VIR_ERR_NO_SUPPORT, - _("cannot update guest CPU data for %s architecture"), + _("cannot update guest CPU for %s architecture"), virArchToString(host->arch));'
Should this just be 'arch' ? if not, if host == NULL, then this will core.
Oops, yes, I forgot to change this one when adding an explicit arch parameter.
return -1; }
- return driver->update(guest, host); + if (driver->update(guest, host) < 0)
Seems as though all implemented ->update functions will return an error if 'host' is NULL, so that's good I guess. Whether it's expected is something you can answer!
It depends on the guest CPU definition, sometimes host == NULL is OK, sometimes it is not. And the update functions detect whether they need host CPU model for updating the CPU and report an error.
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 422818e..f4bb51d 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);
Why the name change? I see upcoming patches also use the new nomenclature, although I'll assume not all driver functions will change. Is that the goal for the future?
I think I mentioned it somewhere in the cover letter or maybe I just wanted to do that, but the goal is to completely rework all APIs provided by the cpu driver. Some of them will just change their names to virCPU*, some of them will be completely removed, and several new APIs will be added. So the new name also serves as a way to distinguish reworked/new APIs from those that still needs to be rewritten or removed.
@@ -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) ATTRIBUTE_NONNULL(3);
Remove the ATTRIBUTE_NONNULL(3) as noted above or even go back to the
Done. Jirka

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> --- 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 746c804..c867f83 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1870,10 +1870,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.9.2

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> --- 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 f3eb211..e215304 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 f4bb51d..b8036b2 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 c867f83..69b081d 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2642,6 +2642,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; + } + + virCPUDefMoveModel(cpu, translated); + ret = 0; + + cleanup: + virCPUDefFree(translated); + x86ModelFree(model); + return ret; +} + + struct cpuArchDriver cpuDriverX86 = { .name = "x86", .arch = archs, @@ -2662,4 +2712,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 ef04ce4..1f50499 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -971,6 +971,7 @@ cpuGetModels; cpuGuestData; cpuHasFeature; cpuNodeData; +virCPUTranslate; virCPUUpdate; -- 2.9.2

The function is renamed to virCPUDataCheckFeature and another function (virCPUCheckFeature) which works on CPU definition rather than raw CPU data is introduced. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu.c | 55 ++++++++++++++++++++++++++++++++++++------- src/cpu/cpu.h | 23 ++++++++++++++---- src/cpu/cpu_arm.c | 1 - src/cpu/cpu_ppc64.c | 1 - src/cpu/cpu_s390.c | 1 - src/cpu/cpu_x86.c | 30 ++++++++++++++++++++--- src/libvirt_private.syms | 3 ++- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_domain.c | 7 ++++-- src/qemu/qemu_parse_command.c | 2 +- src/qemu/qemu_process.c | 10 ++++---- src/vmware/vmware_conf.c | 6 ++--- tests/cputest.c | 6 ++++- 13 files changed, 113 insertions(+), 34 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index e215304..d6b0372 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -648,9 +648,45 @@ virCPUUpdate(virArch arch, /** - * cpuHasFeature: + * virCPUCheckFeature: * - * @data: internal CPU representation + * @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 * @feature: feature to be checked for * * Checks whether @feature is supported by the CPU described by @data. @@ -659,24 +695,25 @@ virCPUUpdate(virArch arch, * -1 on error. */ int -cpuHasFeature(const virCPUData *data, - const char *feature) +virCPUDataCheckFeature(const virCPUData *data, + const char *feature) { 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->hasFeature == NULL) { + 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; } - return driver->hasFeature(data, feature); + return driver->dataCheckFeature(data, feature); } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index b8036b2..77ccb38 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -91,8 +91,12 @@ typedef int const virCPUDef *host); typedef int -(*cpuArchHasFeature) (const virCPUData *data, - const char *feature); +(*virCPUArchCheckFeature)(const virCPUDef *cpu, + const char *feature); + +typedef int +(*virCPUArchDataCheckFeature)(const virCPUData *data, + const char *feature); typedef char * (*cpuArchDataFormat)(const virCPUData *data); @@ -120,7 +124,8 @@ struct cpuArchDriver { cpuArchGuestData guestData; cpuArchBaseline baseline; virCPUArchUpdate update; - cpuArchHasFeature hasFeature; + virCPUArchCheckFeature checkFeature; + virCPUArchDataCheckFeature dataCheckFeature; cpuArchDataFormat dataFormat; cpuArchDataParse dataParse; cpuArchGetModels getModels; @@ -193,9 +198,17 @@ virCPUUpdate(virArch arch, const virCPUDef *host) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + int -cpuHasFeature(const virCPUData *data, - const char *feature) +virCPUCheckFeature(virArch arch, + const virCPUDef *cpu, + const char *feature) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + + +int +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 49da36e..3b68d83 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 69b081d..782c917 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2601,8 +2601,30 @@ virCPUx86Update(virCPUDefPtr guest, static int -x86HasFeature(const virCPUData *data, - const char *name) +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) { virCPUx86MapPtr map; @@ -2612,6 +2634,7 @@ x86HasFeature(const virCPUData *data, return x86FeatureInData(name, &data->data.x86, map); } + static int x86GetModels(char ***models) { @@ -2708,7 +2731,8 @@ struct cpuArchDriver cpuDriverX86 = { .guestData = x86GuestData, .baseline = x86Baseline, .update = virCPUx86Update, - .hasFeature = x86HasFeature, + .checkFeature = virCPUx86CheckFeature, + .dataCheckFeature = virCPUx86DataCheckFeature, .dataFormat = x86CPUDataFormat, .dataParse = x86CPUDataParse, .getModels = x86GetModels, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1f50499..15aac81 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -969,8 +969,9 @@ cpuDecode; cpuEncode; cpuGetModels; cpuGuestData; -cpuHasFeature; cpuNodeData; +virCPUCheckFeature; +virCPUDataCheckFeature; virCPUTranslate; virCPUUpdate; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index ce04c76..985b628 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6473,7 +6473,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_domain.c b/src/qemu/qemu_domain.c index d8c589e..decbdd0 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3402,10 +3402,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_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 662a46a..d4269db 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3694,7 +3694,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; @@ -3707,7 +3707,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: @@ -3743,7 +3743,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; @@ -4448,8 +4448,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..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 = cpuHasFeature(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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
The function is renamed to virCPUDataCheckFeature and another function (virCPUCheckFeature) which works on CPU definition rather than raw CPU data is introduced.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu.c | 55 ++++++++++++++++++++++++++++++++++++------- src/cpu/cpu.h | 23 ++++++++++++++---- src/cpu/cpu_arm.c | 1 - src/cpu/cpu_ppc64.c | 1 - src/cpu/cpu_s390.c | 1 - src/cpu/cpu_x86.c | 30 ++++++++++++++++++++--- src/libvirt_private.syms | 3 ++- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_domain.c | 7 ++++-- src/qemu/qemu_parse_command.c | 2 +- src/qemu/qemu_process.c | 10 ++++---- src/vmware/vmware_conf.c | 6 ++--- tests/cputest.c | 6 ++++- 13 files changed, 113 insertions(+), 34 deletions(-)
Multiple things going on - too bad they couldn't be split... Still not clear why cputest changes, but it's been a long road to get this far so I'm tired. [...]

On Tue, Aug 30, 2016 at 17:56:05 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
The function is renamed to virCPUDataCheckFeature and another function (virCPUCheckFeature) which works on CPU definition rather than raw CPU data is introduced.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu.c | 55 ++++++++++++++++++++++++++++++++++++------- src/cpu/cpu.h | 23 ++++++++++++++---- src/cpu/cpu_arm.c | 1 - src/cpu/cpu_ppc64.c | 1 - src/cpu/cpu_s390.c | 1 - src/cpu/cpu_x86.c | 30 ++++++++++++++++++++--- src/libvirt_private.syms | 3 ++- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_domain.c | 7 ++++-- src/qemu/qemu_parse_command.c | 2 +- src/qemu/qemu_process.c | 10 ++++---- src/vmware/vmware_conf.c | 6 ++--- tests/cputest.c | 6 ++++- 13 files changed, 113 insertions(+), 34 deletions(-)
Multiple things going on - too bad they couldn't be split... Still not
Hmm, looking at the patch now, it seems it could be split in two and one hunk looks like it should go to an earlier patch. I'll look at this.
clear why cputest changes, but it's been a long road to get this far so I'm tired.
The cputest was changed to test both functions. Jirka

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> --- src/cpu/cpu.c | 37 ++++++++++++--------- 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/qemu/qemu_driver.c | 14 ++------ tests/cputest.c | 4 +-- 8 files changed, 119 insertions(+), 68 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index d6b0372..4ea192c 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 * @@ -104,25 +105,26 @@ cpuGetSubDriverByName(const char *name) * the @host CPU. */ 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 (!(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); @@ -134,8 +136,9 @@ cpuCompareXML(virCPUDefPtr host, /** - * cpuCompare: + * virCPUCompare: * + * @arch: CPU architecture * @host: host CPU definition * @cpu: either guest or host CPU to be compared with @host * @@ -147,21 +150,23 @@ cpuCompareXML(virCPUDefPtr host, * the @host CPU. */ 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 77ccb38..0e81e91 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 3b68d83..2cef5bc 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 782c917..e0987c4 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); @@ -1518,12 +1519,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; @@ -1564,7 +1559,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)) || @@ -1663,25 +1658,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; } @@ -1692,6 +1730,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 15aac81..5ed90d5 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -960,8 +960,6 @@ virSecretObjSetValueSize; # cpu/cpu.h cpuBaseline; cpuBaselineXML; -cpuCompare; -cpuCompareXML; cpuDataFormat; cpuDataFree; cpuDataParse; @@ -971,6 +969,8 @@ cpuGetModels; cpuGuestData; cpuNodeData; virCPUCheckFeature; +virCPUCompare; +virCPUCompareXML; virCPUDataCheckFeature; virCPUTranslate; virCPUUpdate; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 695da14..f035ea1 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -12702,18 +12702,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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
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> --- src/cpu/cpu.c | 37 ++++++++++++--------- 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/qemu/qemu_driver.c | 14 ++------ tests/cputest.c | 4 +-- 8 files changed, 119 insertions(+), 68 deletions(-)
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index d6b0372..4ea192c 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
Existing, @failIncompatible description is missing
* @@ -104,25 +105,26 @@ cpuGetSubDriverByName(const char *name) * the @host CPU. */ 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));
The prototype changed such that 'host' and 'xml' could be passed as NULL without a compiler complaint (ok a static analysis complaint). Was that by design?
if (!(doc = virXMLParseStringCtxt(xml, _("(CPU_definition)"), &ctxt)))
Having xml as NULL probably doesn't work well here.
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);
Allowing host to be NULL will cause failure in PPC and X86 which perhaps is expected.
cleanup: virCPUDefFree(cpu); @@ -134,8 +136,9 @@ cpuCompareXML(virCPUDefPtr host,
/** - * cpuCompare: + * virCPUCompare: * + * @arch: CPU architecture * @host: host CPU definition * @cpu: either guest or host CPU to be compared with @host * @@ -147,21 +150,23 @@ cpuCompareXML(virCPUDefPtr host, * the @host CPU. */ 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 77ccb38..0e81e91 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);
Was removing NONNULL by design? I think it needs to be replaced for xml at least.
+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 3b68d83..2cef5bc 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 782c917..e0987c4 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)) {
Shall I assume this related to the compare patch? or a fix as a result? I assume it's related to changes in x86Compute and x86GuestData, but it wasn't really clear from the commit message.
if (!(model = x86ModelFind(map, cpu->model))) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown CPU model %s"), cpu->model);
[...]

On Tue, Aug 30, 2016 at 17:57:01 -0400, John Ferlan wrote: ...
- * cpuCompareXML: + * virCPUCompareXML: * + * @arch: CPU architecture * @host: host CPU definition * @xml: XML description of either guest or host CPU to be compared with @host
Existing, @failIncompatible description is missing
I added a separate patch to fix this.
* @@ -104,25 +105,26 @@ cpuGetSubDriverByName(const char *name) * the @host CPU. */ 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));
The prototype changed such that 'host' and 'xml' could be passed as NULL without a compiler complaint (ok a static analysis complaint). Was that by design?
host == NULL is definitely allowed by design, since we want to be able to successfully compare CPUs on ARM where we are not able to detect the host CPU model. I'm not exactly sure about the xml argument, but since NULLSTR(xml) was already here I figured this is a good place to return an error for xml == NULL rather than forcing all callers to do this check. However I apparently didn't implement the check :-)
if (!(doc = virXMLParseStringCtxt(xml, _("(CPU_definition)"), &ctxt)))
Having xml as NULL probably doesn't work well here.
I added an explicit check for xml == NULL.
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);
Allowing host to be NULL will cause failure in PPC and X86 which perhaps is expected.
Yes, although it will partially change in the future. ...
virCPUCompareResult -cpuCompareXML(virCPUDefPtr host, - const char *xml, - bool failIncompatible) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
Was removing NONNULL by design? I think it needs to be replaced for xml at least.
Yup, it was done by design. ...
@@ -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)) {
Shall I assume this related to the compare patch? or a fix as a result? I assume it's related to changes in x86Compute and x86GuestData, but it wasn't really clear from the commit message.
Yes, it's related to this patch and required to do what commit message says: "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." Thanks to this x86ModelFromCPU() may now be called for CPU definitions without a model, e.g., CPUs with host-model mode. Jirka

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. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_command.c | 161 +++++++------------ src/qemu/qemu_domain.c | 10 +- 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, 147 insertions(+), 221 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 985b628..ebeeebe 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6432,62 +6432,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 && @@ -6499,69 +6455,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; } @@ -6569,8 +6511,7 @@ static int qemuBuildCpuCommandLine(virCommandPtr cmd, virQEMUDriverPtr driver, const virDomainDef *def, - virQEMUCapsPtr qemuCaps, - bool migrating) + virQEMUCapsPtr qemuCaps) { virArch hostarch = virArchFromHost(); char *cpu = NULL; @@ -6588,10 +6529,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 @@ -9331,7 +9290,7 @@ qemuBuildCommandLine(virQEMUDriverPtr driver, if (qemuBuildMachineCommandLine(cmd, 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 decbdd0..0b052ce 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3267,14 +3267,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; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index d4269db..943704f 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4397,107 +4397,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 @@ -4567,9 +4466,6 @@ qemuProcessStartValidate(virQEMUDriverPtr driver, } } - if (qemuProcessStartValidateGuestCPU(vm, qemuCaps, caps, flags) < 0) - return -1; - return 0; } @@ -4825,6 +4721,76 @@ qemuProcessSetupIOThreads(virDomainObjPtr vm) } +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 * @@ -4935,6 +4901,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.9.2

On 08/12/2016 09:33 AM, 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.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_command.c | 161 +++++++------------ src/qemu/qemu_domain.c | 10 +- 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, 147 insertions(+), 221 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 985b628..ebeeebe 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6432,62 +6432,18 @@ static int qemuBuildCpuModelArgStr(virQEMUDriverPtr driver, const virDomainDef *def, virBufferPtr buf, - virQEMUCapsPtr qemuCaps, - bool *hasHwVirt, - bool migrating) + virQEMUCapsPtr qemuCaps)
This is a nice reduction! So much more understandable.
{
[...]
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index decbdd0..0b052ce 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3267,14 +3267,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)) {
It would seem this could be related to an earlier patch - that is the cpuUpdate patch... It can stay here, but it just feels like it could move.
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 d4269db..943704f 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4397,107 +4397,6 @@ qemuProcessStartValidateXML(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)) {
So this will fail for mode == VIR_CPU_MODE_HOST_MODEL if ->cpuModel wasn't filled in, but it's just not clear enough to me (after 40 patches) whether the following checks could return NULL for the GetHostModel. IIRC none of the failures are cores, just reported errors, which is good and I supposed would be expected by this point in time!
+ 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), ^^^^^^^^^^^^^^^^^^^^^^^ This could legally be NULL and thus cause failures in the various compare function callbacks.
+ def->cpu, true) < 0) + return -1; + } + + if (virCPUUpdate(def->os.arch, def->cpu, + virQEMUCapsGetHostModel(qemuCaps)) < 0)
Same here for update callbacks
+ 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; +} + +
[...]

On Tue, Aug 30, 2016 at 17:58:56 -0400, John Ferlan wrote: ...
@@ -3267,14 +3267,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)) {
It would seem this could be related to an earlier patch - that is the cpuUpdate patch... It can stay here, but it just feels like it could move.
Perhaps it could, although the old code was very fragile and sometimes I had to postpone some changes to avoid breaking tests. I'm not sure if it was this case or not, but I wanted to change only the virCPUUpdate APIs in that patch and keep unnecessary changes in callers for a later patch.
if (virCPUUpdate(def->os.arch, def->cpu, caps->host.cpu) < 0) goto cleanup; }
...
+ if (!virQEMUCapsIsCPUModeSupported(qemuCaps, caps, def->virtType, + def->cpu->mode)) {
So this will fail for mode == VIR_CPU_MODE_HOST_MODEL if ->cpuModel wasn't filled in, but it's just not clear enough to me (after 40 patches) whether the following checks could return NULL for the GetHostModel. IIRC none of the failures are cores, just reported errors, which is good and I supposed would be expected by this point in time!
Not knowing the host CPU model is a normal and expected situation (ARM never sets it and even on x86 we may be unable to detect the host CPU in some cases) and the code should be able to deal with it by reporting an error only when we really need the host CPU model (e.g., for host-model CPUs, minimum match CPUs, optional features, etc.).
+ 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), ^^^^^^^^^^^^^^^^^^^^^^^ This could legally be NULL and thus cause failures in the various compare function callbacks.
Indeed.
+ def->cpu, true) < 0) + return -1; + } + + if (virCPUUpdate(def->os.arch, def->cpu, + virQEMUCapsGetHostModel(qemuCaps)) < 0)
Same here for update callbacks
Right. Jirka

It really doesn't belong to the generic CPU driver. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- 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 e0987c4..237fa40 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2558,22 +2558,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 f70a36c..187d4c1 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2859,6 +2859,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) @@ -2877,7 +2890,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.9.2

On 08/12/2016 09:33 AM, Jiri Denemark wrote:
It really doesn't belong to the generic CPU driver.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu_x86.c | 16 ++-------------- src/qemu/qemu_capabilities.c | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 15 deletions(-)
Hmm... interesting is this something that the online perf add more stats will need to also adjust, see (8/8): http://www.redhat.com/archives/libvir-list/2016-August/msg00209.html It doesn't seem so, but since I recognized the acronyms I figured I'd check... So here we are again at a summary - if I didn't comment on something consider it an implicit ACK. There's a couple of reviews that are simple and ACK'able - I think they're obvious. However, there's also a couple where I'm just looking for information. I have no reason to not ACK, just wanted some clarity. I don't necessarily need to see a whole new series. I think it just the interaction noted in patch 40, 35, and 26 (update and compare callbacks). John
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index e0987c4..237fa40 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -2558,22 +2558,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 f70a36c..187d4c1 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2859,6 +2859,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) @@ -2877,7 +2890,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; }

On Tue, Aug 30, 2016 at 18:06:36 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
It really doesn't belong to the generic CPU driver.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu_x86.c | 16 ++-------------- src/qemu/qemu_capabilities.c | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 15 deletions(-)
Hmm... interesting is this something that the online perf add more stats will need to also adjust, see (8/8):
http://www.redhat.com/archives/libvir-list/2016-August/msg00209.html
It doesn't seem so, but since I recognized the acronyms I figured I'd check...
The support for perf events is advertised by CMT CPU feature (and a few others), but otherwise the parts of our code dealing with CPU features and perf events are unrelated. There's no need to adjust anything in the perf events code.
So here we are again at a summary - if I didn't comment on something consider it an implicit ACK.
There's a couple of reviews that are simple and ACK'able - I think they're obvious.
However, there's also a couple where I'm just looking for information. I have no reason to not ACK, just wanted some clarity. I don't necessarily need to see a whole new series. I think it just the interaction noted in patch 40, 35, and 26 (update and compare callbacks).
So after my replies to your comments, do you want me to resend any patches from the series? I think the best option is to resend them all and mark all unchanged patches so that reviewers do not need to look at them again, but it's going to be a series of 45 patches. Anyway, thanks for the review, I can imagine going through so many patches to the ugly CPU code was not easy. But I think the code is going to get better thanks to the patches :-) Jirka

On 09/16/2016 09:03 AM, Jiri Denemark wrote:
On Tue, Aug 30, 2016 at 18:06:36 -0400, John Ferlan wrote:
On 08/12/2016 09:33 AM, Jiri Denemark wrote:
It really doesn't belong to the generic CPU driver.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/cpu/cpu_x86.c | 16 ++-------------- src/qemu/qemu_capabilities.c | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 15 deletions(-)
Hmm... interesting is this something that the online perf add more stats will need to also adjust, see (8/8):
http://www.redhat.com/archives/libvir-list/2016-August/msg00209.html
It doesn't seem so, but since I recognized the acronyms I figured I'd check...
The support for perf events is advertised by CMT CPU feature (and a few others), but otherwise the parts of our code dealing with CPU features and perf events are unrelated. There's no need to adjust anything in the perf events code.
So here we are again at a summary - if I didn't comment on something consider it an implicit ACK.
There's a couple of reviews that are simple and ACK'able - I think they're obvious.
However, there's also a couple where I'm just looking for information. I have no reason to not ACK, just wanted some clarity. I don't necessarily need to see a whole new series. I think it just the interaction noted in patch 40, 35, and 26 (update and compare callbacks).
So after my replies to your comments, do you want me to resend any patches from the series? I think the best option is to resend them all and mark all unchanged patches so that reviewers do not need to look at them again, but it's going to be a series of 45 patches.
Not sure I look forward to the idea of looking at and trying to put 45 patches into short term memory. But I also think process wise it's what is should be done. Then again I think there were certainly quite a few at the beginning (up through perhaps 19) were OK. It was at 20 where that Format algorithm (sorting by yes, no, unknown) got me side tracked. Then starting at 26 is where I kept shuttling back and forth between things. Part of me says - let's push and move on in order to make progress. If you wait for another few days it's that much longer to fix any weird compiler or testing issues on other platforms that invariably creep up when large series are pushed. How's that for non-committal... I'm 85% on the push side though as I believe you've dealt with my comments and questions. John
Anyway, thanks for the review, I can imagine going through so many patches to the ugly CPU code was not easy. But I think the code is going to get better thanks to the patches :-)
Jirka

On Fri, Aug 12, 2016 at 15:32:54 +0200, Jiri Denemark wrote:
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>Broadwell</model> <model>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).
Big thanks for any comments and review in advance and...
Gentle ping. Jirka
participants (2)
-
Jiri Denemark
-
John Ferlan