[libvirt] [PATCH 11/41] qemu: Separate guest CPU validation from command line creation

Jiri Denemark jdenemar at redhat.com
Fri Aug 12 13:33:05 UTC 2016


qemu_command.c should deal with translating our domain definition into a
QEMU command line and nothing else.

Signed-off-by: Jiri Denemark <jdenemar at 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




More information about the libvir-list mailing list