7a3408
From d890a1ebfea47603a67def4658166f061a801313 Mon Sep 17 00:00:00 2001
7a3408
Message-Id: <d890a1ebfea47603a67def4658166f061a801313@dist-git>
7a3408
From: Andrea Bolognani <abologna@redhat.com>
7a3408
Date: Wed, 16 Sep 2015 11:07:42 +0200
7a3408
Subject: [PATCH] qemu: Fix using guest architecture as lookup key
7a3408
7a3408
When looking for a QEMU binary suitable for running ppc64le guests
7a3408
we have to take into account the fact that we use the QEMU target
7a3408
as key for the hash, so direct comparison is not good enough.
7a3408
7a3408
Factor out the logic from virQEMUCapsFindBinaryForArch() to a new
7a3408
virQEMUCapsFindTarget() function and use that both when looking
7a3408
for QEMU binaries available on the system and when looking up
7a3408
QEMU capabilities later.
7a3408
7a3408
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1260753
7a3408
(cherry picked from commit eb36666d22d52ecf0a1755dd0a8a45de982e00fb)
7a3408
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
7a3408
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
7a3408
---
7a3408
 src/qemu/qemu_capabilities.c | 107 +++++++++++++++++++++++++++++--------------
7a3408
 1 file changed, 72 insertions(+), 35 deletions(-)
7a3408
7a3408
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
7a3408
index faebeac..5b21307 100644
7a3408
--- a/src/qemu/qemu_capabilities.c
7a3408
+++ b/src/qemu/qemu_capabilities.c
7a3408
@@ -381,6 +381,28 @@ static const char *virQEMUCapsArchToString(virArch arch)
7a3408
     return virArchToString(arch);
7a3408
 }
7a3408
 
7a3408
+/* Given a host and guest architectures, find a suitable QEMU target.
7a3408
+ *
7a3408
+ * This is meant to be used as a second attempt if qemu-system-$guestarch
7a3408
+ * can't be found, eg. on a x86_64 host you want to use qemu-system-i386,
7a3408
+ * if available, instead of qemu-system-x86_64 to run i686 guests */
7a3408
+static virArch
7a3408
+virQEMUCapsFindTarget(virArch hostarch,
7a3408
+                      virArch guestarch)
7a3408
+{
7a3408
+    /* Both ppc64 and ppc64le guests can use the ppc64 target */
7a3408
+    if (ARCH_IS_PPC64(guestarch))
7a3408
+        guestarch = VIR_ARCH_PPC64;
7a3408
+
7a3408
+    /* armv7l guests on aarch64 hosts can use the aarch64 target
7a3408
+     * i686 guests on x86_64 hosts can use the x86_64 target */
7a3408
+    if ((guestarch == VIR_ARCH_ARMV7L && hostarch == VIR_ARCH_AARCH64) ||
7a3408
+        (guestarch == VIR_ARCH_I686 && hostarch == VIR_ARCH_X86_64)) {
7a3408
+        return hostarch;
7a3408
+    }
7a3408
+
7a3408
+    return guestarch;
7a3408
+}
7a3408
 
7a3408
 static virCommandPtr
7a3408
 virQEMUCapsProbeCommand(const char *qemu,
7a3408
@@ -685,51 +707,55 @@ virQEMUCapsProbeCPUModels(virQEMUCapsPtr qemuCaps, uid_t runUid, gid_t runGid)
7a3408
     return ret;
7a3408
 }
7a3408
 
7a3408
+static char *
7a3408
+virQEMUCapsFindBinary(const char *format,
7a3408
+                      const char *archstr)
7a3408
+{
7a3408
+    char *ret = NULL;
7a3408
+    char *binary = NULL;
7a3408
+
7a3408
+    if (virAsprintf(&binary, format, archstr) < 0)
7a3408
+        goto out;
7a3408
+
7a3408
+    ret = virFindFileInPath(binary);
7a3408
+    VIR_FREE(binary);
7a3408
+    if (ret && virFileIsExecutable(ret))
7a3408
+        goto out;
7a3408
+
7a3408
+    VIR_FREE(ret);
7a3408
+
7a3408
+ out:
7a3408
+    return ret;
7a3408
+}
7a3408
 
7a3408
 static char *
7a3408
 virQEMUCapsFindBinaryForArch(virArch hostarch,
7a3408
                              virArch guestarch)
7a3408
 {
7a3408
-    char *ret;
7a3408
+    char *ret = NULL;
7a3408
     const char *archstr;
7a3408
-    char *binary;
7a3408
+    virArch target;
7a3408
 
7a3408
-    if (ARCH_IS_PPC64(guestarch))
7a3408
-        archstr = virQEMUCapsArchToString(VIR_ARCH_PPC64);
7a3408
-    else
7a3408
-        archstr = virQEMUCapsArchToString(guestarch);
7a3408
+    /* First attempt: try the guest architecture as it is */
7a3408
+    archstr = virQEMUCapsArchToString(guestarch);
7a3408
+    if ((ret = virQEMUCapsFindBinary("qemu-system-%s", archstr)) != NULL)
7a3408
+        goto out;
7a3408
 
7a3408
-    if (virAsprintf(&binary, "qemu-system-%s", archstr) < 0)
7a3408
-        return NULL;
7a3408
-
7a3408
-    ret = virFindFileInPath(binary);
7a3408
-    VIR_FREE(binary);
7a3408
-    if (ret && !virFileIsExecutable(ret))
7a3408
-        VIR_FREE(ret);
7a3408
-
7a3408
-    if (guestarch == VIR_ARCH_ARMV7L &&
7a3408
-        !ret &&
7a3408
-        hostarch == VIR_ARCH_AARCH64) {
7a3408
-        ret = virFindFileInPath("qemu-system-aarch64");
7a3408
-        if (ret && !virFileIsExecutable(ret))
7a3408
-            VIR_FREE(ret);
7a3408
-    }
7a3408
-
7a3408
-    if (guestarch == VIR_ARCH_I686 &&
7a3408
-        !ret &&
7a3408
-        hostarch == VIR_ARCH_X86_64) {
7a3408
-        ret = virFindFileInPath("qemu-system-x86_64");
7a3408
-        if (ret && !virFileIsExecutable(ret))
7a3408
-            VIR_FREE(ret);
7a3408
+    /* Second attempt: try looking up by target instead */
7a3408
+    target = virQEMUCapsFindTarget(hostarch, guestarch);
7a3408
+    if (target != guestarch) {
7a3408
+        archstr = virQEMUCapsArchToString(target);
7a3408
+        if ((ret = virQEMUCapsFindBinary("qemu-system-%s", archstr)) != NULL)
7a3408
+            goto out;
7a3408
     }
7a3408
 
7a3408
-    if (guestarch == VIR_ARCH_I686 &&
7a3408
-        !ret) {
7a3408
-        ret = virFindFileInPath("qemu");
7a3408
-        if (ret && !virFileIsExecutable(ret))
7a3408
-            VIR_FREE(ret);
7a3408
+    /* Third attempt, i686 only: try 'qemu' */
7a3408
+    if (guestarch == VIR_ARCH_I686) {
7a3408
+        if ((ret = virQEMUCapsFindBinary("%s", "qemu")) != NULL)
7a3408
+            goto out;
7a3408
     }
7a3408
 
7a3408
+ out:
7a3408
     return ret;
7a3408
 }
7a3408
 
7a3408
@@ -3773,13 +3799,24 @@ virQEMUCapsCacheLookupByArch(virQEMUCapsCachePtr cache,
7a3408
                              virArch arch)
7a3408
 {
7a3408
     virQEMUCapsPtr ret = NULL;
7a3408
+    virArch target;
7a3408
     struct virQEMUCapsSearchData data = { .arch = arch };
7a3408
 
7a3408
     virMutexLock(&cache->lock);
7a3408
     ret = virHashSearch(cache->binaries, virQEMUCapsCompareArch, &data);
7a3408
+    if (!ret) {
7a3408
+        /* If the first attempt at finding capabilities has failed, try
7a3408
+         * again using the QEMU target as lookup key instead */
7a3408
+        target = virQEMUCapsFindTarget(virArchFromHost(), data.arch);
7a3408
+        if (target != data.arch) {
7a3408
+            data.arch = target;
7a3408
+            ret = virHashSearch(cache->binaries, virQEMUCapsCompareArch, &data);
7a3408
+        }
7a3408
+    }
7a3408
+    virObjectRef(ret);
7a3408
+    virMutexUnlock(&cache->lock);
7a3408
+
7a3408
     VIR_DEBUG("Returning caps %p for arch %s", ret, virArchToString(arch));
7a3408
-    virObjectRef(ret);
7a3408
-    virMutexUnlock(&cache->lock);
7a3408
 
7a3408
     return ret;
7a3408
 }
7a3408
-- 
7a3408
2.5.3
7a3408