From fba9c200834d8d31ed34e632470563a0074fe528 Mon Sep 17 00:00:00 2001 Message-ID: From: Jiri Denemark Date: Thu, 21 May 2026 17:55:28 +0200 Subject: [PATCH] qemu_capabilities: Cache expanded CPU When probing host model CPU we already expand it to get a list of all CPU features. Let's store the expanded CPU definition in virQEMUCaps and copy it to domain capabilities when requested by the VIR_CONNECT_GET_DOMAIN_CAPABILITIES_EXPAND_CPU_FEATURES flag instead of expanding the CPU over and over on each request. Signed-off-by: Jiri Denemark Reviewed-by: Peter Krempa (cherry picked from commit 312000a739aebaa9de655bb1f6a539326ea8783d) https://redhat.atlassian.net/browse/RHEL-177364 Signed-off-by: Jiri Denemark --- src/qemu/qemu_capabilities.c | 39 ++++++++++++++++++++++++++---------- src/qemu/qemu_capabilities.h | 3 +++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 2e8f220abc..555723cafb 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -788,6 +788,9 @@ struct _virQEMUCapsHostCPUData { unsigned int physAddrSize; /* Host CPU definition reported in domain capabilities. */ virCPUDef *reported; + /* Expanded host CPU definition with features that are implicitly enabled + * by the selected CPU model. */ + virCPUDef *expanded; /* Migratable host CPU definition used for updating guest CPU. */ virCPUDef *migratable; /* CPU definition with features detected by libvirt using virCPUGetHost @@ -1962,6 +1965,9 @@ virQEMUCapsHostCPUDataCopy(virQEMUCapsHostCPUData *dst, if (src->reported) dst->reported = virCPUDefCopy(src->reported); + if (src->expanded) + dst->expanded = virCPUDefCopy(src->expanded); + if (src->migratable) dst->migratable = virCPUDefCopy(src->migratable); @@ -1975,6 +1981,7 @@ virQEMUCapsHostCPUDataClear(virQEMUCapsHostCPUData *cpuData) { qemuMonitorCPUModelInfoFree(cpuData->info); virCPUDefFree(cpuData->reported); + virCPUDefFree(cpuData->expanded); virCPUDefFree(cpuData->migratable); virCPUDefFree(cpuData->full); @@ -2301,6 +2308,9 @@ virQEMUCapsGetHostModel(virQEMUCaps *qemuCaps, /* 'full' is non-NULL only if we have data from both QEMU and * virCPUGetHost */ return cpuData->full ? cpuData->full : cpuData->reported; + + case VIR_QEMU_CAPS_HOST_CPU_EXPANDED: + return cpuData->expanded; } return NULL; @@ -2312,6 +2322,7 @@ virQEMUCapsSetHostModel(virQEMUCaps *qemuCaps, virDomainVirtType type, unsigned int physAddrSize, virCPUDef *reported, + virCPUDef *expanded, virCPUDef *migratable, virCPUDef *full) { @@ -2320,6 +2331,7 @@ virQEMUCapsSetHostModel(virQEMUCaps *qemuCaps, cpuData = &virQEMUCapsGetAccel(qemuCaps, type)->hostCPU; cpuData->physAddrSize = physAddrSize; cpuData->reported = reported; + cpuData->expanded = expanded; cpuData->migratable = migratable; cpuData->full = full; } @@ -4123,16 +4135,18 @@ virQEMUCapsInitHostCPUModel(virQEMUCaps *qemuCaps, virCPUDefCopyModelFilter(cpu, hostCPU, true, virQEMUCapsCPUFilterFeatures, &qemuCaps->arch); - } else if (virQEMUCapsTypeIsAccelerated(type) && - virCPUGetHostIsSupported(qemuCaps->arch)) { + } + + cpuExpanded = virCPUDefCopy(cpu); + if (virCPUExpandFeatures(qemuCaps->arch, cpuExpanded) < 0) + goto error; + + if (rc == 0 && + virQEMUCapsTypeIsAccelerated(type) && + virCPUGetHostIsSupported(qemuCaps->arch)) { if (!(fullCPU = virQEMUCapsProbeHostCPU(qemuCaps->arch, NULL))) goto error; - cpuExpanded = virCPUDefCopy(cpu); - - if (virCPUExpandFeatures(qemuCaps->arch, cpuExpanded) < 0) - goto error; - for (i = 0; i < cpuExpanded->nfeatures; i++) { if (cpuExpanded->features[i].policy == VIR_CPU_FEATURE_REQUIRE) virCPUDefUpdateFeature(fullCPU, cpuExpanded->features[i].name, @@ -4171,6 +4185,7 @@ virQEMUCapsInitHostCPUModel(virQEMUCaps *qemuCaps, virQEMUCapsSetHostModel(qemuCaps, type, physAddrSize, g_steal_pointer(&cpu), + g_steal_pointer(&cpuExpanded), g_steal_pointer(&migCPU), g_steal_pointer(&fullCPU)); @@ -6587,9 +6602,14 @@ virQEMUCapsFillDomainCPUHostModel(virQEMUCaps *qemuCaps, virDomainCaps *domCaps, unsigned int flags) { - virQEMUCapsHostCPUType cpuType = VIR_QEMU_CAPS_HOST_CPU_REPORTED; + virQEMUCapsHostCPUType cpuType; virCPUDef *cpu; + if (flags & VIR_CONNECT_GET_DOMAIN_CAPABILITIES_EXPAND_CPU_FEATURES) + cpuType = VIR_QEMU_CAPS_HOST_CPU_EXPANDED; + else + cpuType = VIR_QEMU_CAPS_HOST_CPU_REPORTED; + cpu = virCPUDefCopy(virQEMUCapsGetHostModel(qemuCaps, domCaps->virttype, cpuType)); @@ -6600,9 +6620,6 @@ virQEMUCapsFillDomainCPUHostModel(virQEMUCaps *qemuCaps, cpu, VIR_CPU_FEATURE_DISABLE); } - if (flags & VIR_CONNECT_GET_DOMAIN_CAPABILITIES_EXPAND_CPU_FEATURES) - virCPUExpandFeatures(domCaps->arch, cpu); - virCPUDefSortFeatures(cpu); domCaps->cpu.hostModel = cpu; } diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index bc3ecbb89f..8822bf120b 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -788,6 +788,9 @@ typedef enum { * combined with features reported by QEMU. This is used for backward * compatible comparison between a guest CPU and a host CPU. */ VIR_QEMU_CAPS_HOST_CPU_FULL, + /* Expanded host CPU definition with features that are implicitly enabled + * by the selected CPU model. */ + VIR_QEMU_CAPS_HOST_CPU_EXPANDED, } virQEMUCapsHostCPUType; virCPUDef *virQEMUCapsGetHostModel(virQEMUCaps *qemuCaps, -- 2.54.0