3e5111
From b2196db320485b642d6654279ebb6b75eeafd3e9 Mon Sep 17 00:00:00 2001
3e5111
Message-Id: <b2196db320485b642d6654279ebb6b75eeafd3e9@dist-git>
3e5111
From: Jiri Denemark <jdenemar@redhat.com>
3e5111
Date: Tue, 11 Apr 2017 20:46:05 +0200
3e5111
Subject: [PATCH] qemu: Use more data for comparing CPUs
3e5111
3e5111
With QEMU older than 2.9.0 libvirt uses CPUID instruction to determine
3e5111
what CPU features are supported on the host. This was later used when
3e5111
checking compatibility of guest CPUs. Since QEMU 2.9.0 we ask QEMU for
3e5111
the host CPU data. But the two methods we use usually provide disjoint
3e5111
sets of CPU features because QEMU/KVM does not support all features
3e5111
provided by the host CPU and on the other hand it can enable some
3e5111
feature even if the host CPU does not support them.
3e5111
3e5111
So if there is a domain which requires a CPU features disabled by
3e5111
QEMU/KVM, libvirt will refuse to start it with QEMU > 2.9.0 as its guest
3e5111
CPU is incompatible with the host CPU data we got from QEMU. But such
3e5111
domain would happily start on older QEMU (of course, the features would
3e5111
be missing the guest CPU). To fix this regression, we need to combine
3e5111
both CPU feature sets when checking guest CPU compatibility.
3e5111
3e5111
https://bugzilla.redhat.com/show_bug.cgi?id=1439933
3e5111
3e5111
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
3e5111
(cherry picked from commit 5b4a6adb5ca24a6cb91cdc55c31506fb278d3a91)
3e5111
3e5111
https://bugzilla.redhat.com/show_bug.cgi?id=1444421
3e5111
3e5111
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
3e5111
---
3e5111
 src/qemu/qemu_capabilities.c | 35 +++++++++++++++++++++++++++++++++--
3e5111
 src/qemu/qemu_capabilities.h |  4 ++++
3e5111
 src/qemu/qemu_process.c      |  2 +-
3e5111
 3 files changed, 38 insertions(+), 3 deletions(-)
3e5111
3e5111
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
3e5111
index ec773971e..49de506ed 100644
3e5111
--- a/src/qemu/qemu_capabilities.c
3e5111
+++ b/src/qemu/qemu_capabilities.c
3e5111
@@ -387,6 +387,10 @@ struct _virQEMUCapsHostCPUData {
3e5111
     virCPUDefPtr reported;
3e5111
     /* Migratable host CPU definition used for updating guest CPU. */
3e5111
     virCPUDefPtr migratable;
3e5111
+    /* CPU definition with features detected by libvirt using virCPUGetHost
3e5111
+     * combined with features reported by QEMU. This is used for backward
3e5111
+     * compatible comparison between a guest CPU and a host CPU. */
3e5111
+    virCPUDefPtr full;
3e5111
 };
3e5111
 
3e5111
 /*
3e5111
@@ -2112,6 +2116,10 @@ virQEMUCapsHostCPUDataCopy(virQEMUCapsHostCPUDataPtr dst,
3e5111
         !(dst->migratable = virCPUDefCopy(src->migratable)))
3e5111
         return -1;
3e5111
 
3e5111
+    if (src->full &&
3e5111
+        !(dst->full = virCPUDefCopy(src->full)))
3e5111
+        return -1;
3e5111
+
3e5111
     return 0;
3e5111
 }
3e5111
 
3e5111
@@ -2122,6 +2130,7 @@ virQEMUCapsHostCPUDataClear(virQEMUCapsHostCPUDataPtr cpuData)
3e5111
     qemuMonitorCPUModelInfoFree(cpuData->info);
3e5111
     virCPUDefFree(cpuData->reported);
3e5111
     virCPUDefFree(cpuData->migratable);
3e5111
+    virCPUDefFree(cpuData->full);
3e5111
 
3e5111
     memset(cpuData, 0, sizeof(*cpuData));
3e5111
 }
3e5111
@@ -2463,6 +2472,11 @@ virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps,
3e5111
 
3e5111
     case VIR_QEMU_CAPS_HOST_CPU_MIGRATABLE:
3e5111
         return cpuData->migratable;
3e5111
+
3e5111
+    case VIR_QEMU_CAPS_HOST_CPU_FULL:
3e5111
+        /* 'full' is non-NULL only if we have data from both QEMU and
3e5111
+         * virCPUGetHost */
3e5111
+        return cpuData->full ? cpuData->full : cpuData->reported;
3e5111
     }
3e5111
 
3e5111
     return NULL;
3e5111
@@ -2473,12 +2487,14 @@ static void
3e5111
 virQEMUCapsSetHostModel(virQEMUCapsPtr qemuCaps,
3e5111
                         virDomainVirtType type,
3e5111
                         virCPUDefPtr reported,
3e5111
-                        virCPUDefPtr migratable)
3e5111
+                        virCPUDefPtr migratable,
3e5111
+                        virCPUDefPtr full)
3e5111
 {
3e5111
     virQEMUCapsHostCPUDataPtr cpuData = virQEMUCapsGetHostCPUData(qemuCaps, type);
3e5111
 
3e5111
     cpuData->reported = reported;
3e5111
     cpuData->migratable = migratable;
3e5111
+    cpuData->full = full;
3e5111
 }
3e5111
 
3e5111
 
3e5111
@@ -3350,6 +3366,8 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
3e5111
     virCPUDefPtr cpu = NULL;
3e5111
     virCPUDefPtr migCPU = NULL;
3e5111
     virCPUDefPtr hostCPU = NULL;
3e5111
+    virCPUDefPtr fullCPU = NULL;
3e5111
+    size_t i;
3e5111
     int rc;
3e5111
 
3e5111
     if (!caps || !virQEMUCapsGuestIsNative(caps->host.arch, qemuCaps->arch))
3e5111
@@ -3369,6 +3387,18 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
3e5111
                                      virQEMUCapsCPUFilterFeatures,
3e5111
                                      qemuCaps) < 0)
3e5111
             goto error;
3e5111
+    } else if (type == VIR_DOMAIN_VIRT_KVM &&
3e5111
+               virCPUGetHostIsSupported(qemuCaps->arch)) {
3e5111
+        if (!(fullCPU = virCPUGetHost(qemuCaps->arch, VIR_CPU_TYPE_GUEST,
3e5111
+                                      NULL, NULL, 0)))
3e5111
+            goto error;
3e5111
+
3e5111
+        for (i = 0; i < cpu->nfeatures; i++) {
3e5111
+            if (cpu->features[i].policy == VIR_CPU_FEATURE_REQUIRE &&
3e5111
+                virCPUDefUpdateFeature(fullCPU, cpu->features[i].name,
3e5111
+                                       VIR_CPU_FEATURE_REQUIRE) < 0)
3e5111
+                goto error;
3e5111
+        }
3e5111
     }
3e5111
 
3e5111
     if (!(migCPU = virQEMUCapsNewHostCPUModel()))
3e5111
@@ -3384,7 +3414,7 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
3e5111
             goto error;
3e5111
     }
3e5111
 
3e5111
-    virQEMUCapsSetHostModel(qemuCaps, type, cpu, migCPU);
3e5111
+    virQEMUCapsSetHostModel(qemuCaps, type, cpu, migCPU, fullCPU);
3e5111
 
3e5111
  cleanup:
3e5111
     virCPUDefFree(hostCPU);
3e5111
@@ -3393,6 +3423,7 @@ virQEMUCapsInitHostCPUModel(virQEMUCapsPtr qemuCaps,
3e5111
  error:
3e5111
     virCPUDefFree(cpu);
3e5111
     virCPUDefFree(migCPU);
3e5111
+    virCPUDefFree(fullCPU);
3e5111
     virResetLastError();
3e5111
     goto cleanup;
3e5111
 }
3e5111
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
3e5111
index 16fe044cc..644b8e27b 100644
3e5111
--- a/src/qemu/qemu_capabilities.h
3e5111
+++ b/src/qemu/qemu_capabilities.h
3e5111
@@ -456,6 +456,10 @@ typedef enum {
3e5111
     VIR_QEMU_CAPS_HOST_CPU_REPORTED,
3e5111
     /* Migratable host CPU definition used for updating guest CPU. */
3e5111
     VIR_QEMU_CAPS_HOST_CPU_MIGRATABLE,
3e5111
+    /* CPU definition with features detected by libvirt using virCPUGetHost
3e5111
+     * combined with features reported by QEMU. This is used for backward
3e5111
+     * compatible comparison between a guest CPU and a host CPU. */
3e5111
+    VIR_QEMU_CAPS_HOST_CPU_FULL,
3e5111
 } virQEMUCapsHostCPUType;
3e5111
 
3e5111
 virCPUDefPtr virQEMUCapsGetHostModel(virQEMUCapsPtr qemuCaps,
3e5111
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
3e5111
index c81389ef2..a33ec87e6 100644
3e5111
--- a/src/qemu/qemu_process.c
3e5111
+++ b/src/qemu/qemu_process.c
3e5111
@@ -5307,7 +5307,7 @@ qemuProcessUpdateGuestCPU(virDomainDefPtr def,
3e5111
     if (def->cpu->check == VIR_CPU_CHECK_PARTIAL &&
3e5111
         virCPUCompare(caps->host.arch,
3e5111
                       virQEMUCapsGetHostModel(qemuCaps, def->virtType,
3e5111
-                                              VIR_QEMU_CAPS_HOST_CPU_REPORTED),
3e5111
+                                              VIR_QEMU_CAPS_HOST_CPU_FULL),
3e5111
                       def->cpu, true) < 0)
3e5111
         return -1;
3e5111
 
3e5111
-- 
3e5111
2.12.2
3e5111