[libvirt] PATCH: Be more flexible in emulator choice on x86 archs

Daniel P. Berrange berrange at redhat.com
Mon Mar 16 18:03:59 UTC 2009


Currently we are pretty strict about what emulator binary we allow for
QEMU guests on x86 arches. In particular, for arch+domain type combos:

 - i686+qemu must use 'qemu' binary
 - x86_64+qemu must use 'qemu-system-x86_64' binary
 - kvm must use 'qemu-kvm' or 'kvm' binaries
 - i686+kvm on x86_64 host is not allowed

These restrictions are overkill because

 - i686+qemu could use 'qemu-system-x86_64' if '-cpu qemu32' is added
 - i686+qemu could use 'qemu-kvm' if '-cpu qemu32 -no-kvm' is added
 - x86_64+qemu could use 'qemu-kvm' if '-no-kvm' is added
 - i686+kvm on x86_64 host can be used if '-cpu qemu32' is added

This patch makes QEMU driver more flexible in this way when setting up
its capabilities information. It also makes it aware of the -no-kvm
and -cpu flag, using them where required by the os type + arch + emulator
combinations specified in the guest XML.

This should finally remove the confusion where a user in virt-manager
selectrs 'i686' and then wonders why we've disallowed choice of 'kvm'.
It also fixes 'virsh version' when only qemu-kvm is installed.

The matrix should now work thus:

1. qemu, qemu-system-x86_64, qemu-kvm all available

     qemu+i686   => qemu
     qemu+x86_64 => qemu-system-x86_64
     kvm+i686    => qemu-kvm -cpu qemu32
     kvm+x86_64  => qemu-kvm

2. qemu, qemu-kvm available

     qemu+i686   => qemu
     qemu+x86_64 => qemu-kvm -no-kvm
     kvm+i686    => qemu-kvm -cpu qemu32
     kvm+x86_64  => qemu-kvm

3. qemu-system-x86_64, qemu-kvm available

     qemu+i686   => qemu-system-x86_64 -cpu qemu32
     qemu+x86_64 => qemu-system-x86_64
     kvm+i686    => qemu-kvm -cpu qemu32
     kvm+x86_64  => qemu-kvm

4. qemu-kvm available

     qemu+i686   => qemu-kvm -no-kvm -cpu qemu32
     qemu+x86_64 => qemu-kvm -no-kvm
     kvm+i686    => qemu-kvm -cpu qemu32
     kvm+x86_64  => qemu-kvm


The only real remaining problem is that we don't cope with scenario
where the KVM enabled binary is called 'qemu-system-x64_64' instead
of 'qemu-kvm' or 'kvm'.

Regards,
Daniel

Index: src/qemu_conf.c
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_conf.c,v
retrieving revision 1.138
diff -u -p -r1.138 qemu_conf.c
--- src/qemu_conf.c	16 Mar 2009 13:54:26 -0000	1.138
+++ src/qemu_conf.c	16 Mar 2009 17:53:20 -0000
@@ -211,6 +211,7 @@ struct qemu_arch_info {
     const char *const *machines;
     int nmachines;
     const char *binary;
+    const char *altbinary;
     const struct qemu_feature_flags *flags;
     int nflags;
 };
@@ -231,24 +232,24 @@ static const struct qemu_feature_flags c
 /* The archicture tables for supported QEMU archs */
 static const struct qemu_arch_info const arch_info_hvm[] = {
     {  "i686", 32, arch_info_hvm_x86_machines, 2,
-       "/usr/bin/qemu", arch_info_i686_flags, 4 },
+       "/usr/bin/qemu", "/usr/bin/qemu-system-x86_64", arch_info_i686_flags, 4 },
     {  "x86_64", 64, arch_info_hvm_x86_machines, 2,
-       "/usr/bin/qemu-system-x86_64", arch_info_x86_64_flags, 2 },
+       "/usr/bin/qemu-system-x86_64", NULL, arch_info_x86_64_flags, 2 },
     {  "mips", 32, arch_info_hvm_mips_machines, 1,
-       "/usr/bin/qemu-system-mips", NULL, 0 },
+       "/usr/bin/qemu-system-mips", NULL, NULL, 0 },
     {  "mipsel", 32, arch_info_hvm_mips_machines, 1,
-       "/usr/bin/qemu-system-mipsel", NULL, 0 },
+       "/usr/bin/qemu-system-mipsel", NULL, NULL, 0 },
     {  "sparc", 32, arch_info_hvm_sparc_machines, 1,
-       "/usr/bin/qemu-system-sparc", NULL, 0 },
+       "/usr/bin/qemu-system-sparc", NULL, NULL, 0 },
     {  "ppc", 32, arch_info_hvm_ppc_machines, 3,
-       "/usr/bin/qemu-system-ppc", NULL, 0 },
+       "/usr/bin/qemu-system-ppc", NULL, NULL, 0 },
 };
 
 static const struct qemu_arch_info const arch_info_xen[] = {
     {  "i686", 32, arch_info_xen_x86_machines, 1,
-       "/usr/bin/xenner", arch_info_i686_flags, 4 },
+       "/usr/bin/xenner", NULL, arch_info_i686_flags, 4 },
     {  "x86_64", 64, arch_info_xen_x86_machines, 1,
-       "/usr/bin/xenner", arch_info_x86_64_flags, 2 },
+       "/usr/bin/xenner", NULL, arch_info_x86_64_flags, 2 },
 };
 
 static int
@@ -257,43 +258,62 @@ qemudCapsInitGuest(virCapsPtr caps,
                    const struct qemu_arch_info *info,
                    int hvm) {
     virCapsGuestPtr guest;
-    int i, haskvm, hasbase, samearch;
+    int i;
+    int hasbase = 0;
+    int hasaltbase = 0;
+    int haskvm = 0;
+    int haskqemu = 0;
     const char *kvmbin = NULL;
 
-    /* Check for existance of base emulator */
+    /* Check for existance of base emulator, or alternate base
+     * which can be used with magic cpu choice
+     */
     hasbase = (access(info->binary, X_OK) == 0);
+    hasaltbase = (access(info->altbinary, X_OK) == 0);
 
-    samearch = STREQ(info->arch, hostmachine);
-    if (samearch) {
+    /* Can use acceleration for KVM/KQEMU if
+     *  - host & guest arches match
+     * Or
+     *  - hostarch is x86_64 and guest arch is i686
+     * The latter simply needs "-cpu qemu32"
+     */
+    if (STREQ(info->arch, hostmachine) ||
+        (STREQ(hostmachine, "x86_64") && STREQ(info->arch, "i686"))) {
         const char *const kvmbins[] = { "/usr/bin/qemu-kvm", /* Fedora */
                                         "/usr/bin/kvm" }; /* Upstream .spec */
 
         for (i = 0; i < ARRAY_CARDINALITY(kvmbins); ++i) {
-            if ((haskvm = (access(kvmbins[i], X_OK) == 0))) {
+            if (access(kvmbins[i], X_OK) == 0 &&
+                access("/dev/kvm", F_OK) == 0) {
+                haskvm = 1;
                 kvmbin = kvmbins[i];
                 break;
             }
         }
-    } else {
-        haskvm = 0;
+
+        if (access("/dev/kqemu", F_OK) == 0)
+            haskqemu = 1;
     }
 
-    if (!hasbase && !haskvm)
+
+    if (!hasbase && !hasaltbase && !haskvm)
         return 0;
 
+    /* We register kvm as the base emulator too, since we can
+     * just give -no-kvm to disable acceleration if required */
     if ((guest = virCapabilitiesAddGuest(caps,
                                          hvm ? "hvm" : "xen",
                                          info->arch,
                                          info->wordsize,
-                                         info->binary,
+                                         (hasbase ? info->binary :
+                                          (hasaltbase ? info->altbinary : kvmbin)),
                                          NULL,
                                          info->nmachines,
                                          info->machines)) == NULL)
         return -1;
 
     if (hvm) {
-        if (hasbase &&
-            virCapabilitiesAddGuestDomain(guest,
+        if (virCapabilitiesAddGuestDomain(guest,
                                           "qemu",
                                           NULL,
                                           NULL,
@@ -301,27 +321,23 @@ qemudCapsInitGuest(virCapsPtr caps,
                                           NULL) == NULL)
             return -1;
 
-        /* If guest & host match, then we can accelerate */
-        if (samearch) {
-            if (access("/dev/kqemu", F_OK) == 0 &&
-                virCapabilitiesAddGuestDomain(guest,
-                                              "kqemu",
-                                              NULL,
-                                              NULL,
-                                              0,
-                                              NULL) == NULL)
-                return -1;
+        if (haskqemu &&
+            virCapabilitiesAddGuestDomain(guest,
+                                          "kqemu",
+                                          NULL,
+                                          NULL,
+                                          0,
+                                          NULL) == NULL)
+            return -1;
 
-            if (access("/dev/kvm", F_OK) == 0 &&
-                haskvm &&
-                virCapabilitiesAddGuestDomain(guest,
-                                              "kvm",
-                                              kvmbin,
-                                              NULL,
-                                              0,
-                                              NULL) == NULL)
-                return -1;
-        }
+        if (haskvm &&
+            virCapabilitiesAddGuestDomain(guest,
+                                          "kvm",
+                                          kvmbin,
+                                          NULL,
+                                          0,
+                                          NULL) == NULL)
+            return -1;
     } else {
         if (virCapabilitiesAddGuestDomain(guest,
                                           "kvm",
@@ -363,12 +379,14 @@ virCapsPtr qemudCapsInit(void) {
     if (virCapsInitNUMA(caps) < 0)
         goto no_memory;
 
+    /* First the pure HVM guests */
     for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_hvm) ; i++)
         if (qemudCapsInitGuest(caps,
                                utsname.machine,
                                &arch_info_hvm[i], 1) < 0)
             goto no_memory;
 
+    /* Then possibly the Xen paravirt guests (ie Xenner */
     if (access("/usr/bin/xenner", X_OK) == 0 &&
         access("/dev/kvm", F_OK) == 0) {
         for (i = 0 ; i < ARRAY_CARDINALITY(arch_info_xen) ; i++)
@@ -430,6 +448,8 @@ int qemudExtractVersionInfo(const char *
 
     if (strstr(help, "-no-kqemu"))
         flags |= QEMUD_CMD_FLAG_KQEMU;
+    if (strstr(help, "-no-kvm"))
+        flags |= QEMUD_CMD_FLAG_KVM;
     if (strstr(help, "-no-reboot"))
         flags |= QEMUD_CMD_FLAG_NO_REBOOT;
     if (strstr(help, "-name"))
@@ -749,6 +769,7 @@ int qemudBuildCommandLine(virConnectPtr 
     char boot[VIR_DOMAIN_BOOT_LAST];
     struct utsname ut;
     int disableKQEMU = 0;
+    int disableKVM = 0;
     int qargc = 0, qarga = 0;
     const char **qargv = NULL;
     int qenvc = 0, qenva = 0;
@@ -757,6 +778,7 @@ int qemudBuildCommandLine(virConnectPtr 
     char uuid[VIR_UUID_STRING_BUFLEN];
     char domid[50];
     char *pidfile;
+    const char *cpu = NULL;
 
     uname_normalize(&ut);
 
@@ -789,9 +811,16 @@ int qemudBuildCommandLine(virConnectPtr 
         }
     }
 
+    emulator = vm->def->emulator;
+    if (!emulator)
+        emulator = virDomainDefDefaultEmulator(conn, vm->def, driver->caps);
+    if (!emulator)
+        return -1;
+
+
     /* Need to explicitly disable KQEMU if
      * 1. Arch matches host arch
-     * 2. Guest is 'qemu'
+     * 2. Guest domain is 'qemu'
      * 3. The qemu binary has the -no-kqemu flag
      */
     if ((qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU) &&
@@ -799,6 +828,34 @@ int qemudBuildCommandLine(virConnectPtr 
         vm->def->virtType == VIR_DOMAIN_VIRT_QEMU)
         disableKQEMU = 1;
 
+    /* Need to explicitly disable KVM if
+     * 1. Arch matches host arch
+     * 2. Guest domain is 'qemu'
+     * 3. The qemu binary has the -no-kvm flag
+     */
+    if ((qemuCmdFlags & QEMUD_CMD_FLAG_KVM) &&
+        STREQ(ut.machine, vm->def->os.arch) &&
+        vm->def->virtType == VIR_DOMAIN_VIRT_QEMU)
+        disableKVM = 1;
+
+    /*
+     * Need to force a 32-bit guest CPU type if
+     *
+     *  1. guest OS is i686
+     *  2. host OS is x86_64
+     *  3. emulator is qemu-kvm or kvm
+     *
+     * Or
+     *
+     *  1. guest OS is i686
+     *  2. emulator is qemu-system-x86_64
+     */
+    if (STREQ(vm->def->os.arch, "i686") &&
+        ((STREQ(ut.machine, "x86_64") &&
+          strstr(emulator, "kvm")) ||
+         strstr(emulator, "x86_64")))
+        cpu = "qemu32";
+
 #define ADD_ARG_SPACE                                                   \
     do { \
         if (qargc == qarga) {                                           \
@@ -887,12 +944,6 @@ int qemudBuildCommandLine(virConnectPtr 
     ADD_ENV_COPY("LOGNAME");
     ADD_ENV_COPY("TMPDIR");
 
-    emulator = vm->def->emulator;
-    if (!emulator)
-        emulator = virDomainDefDefaultEmulator(conn, vm->def, driver->caps);
-    if (!emulator)
-        return -1;
-
     ADD_ARG_LIT(emulator);
     ADD_ARG_LIT("-S");
 
@@ -904,9 +955,15 @@ int qemudBuildCommandLine(virConnectPtr 
         ADD_ARG_LIT("-M");
         ADD_ARG_LIT(vm->def->os.machine);
     }
+    if (cpu) {
+        ADD_ARG_LIT("-cpu");
+        ADD_ARG_LIT(cpu);
+    }
 
     if (disableKQEMU)
         ADD_ARG_LIT("-no-kqemu");
+    if (disableKVM)
+        ADD_ARG_LIT("-no-kvm");
     ADD_ARG_LIT("-m");
     ADD_ARG_LIT(memory);
     ADD_ARG_LIT("-smp");
Index: src/qemu_conf.h
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_conf.h,v
retrieving revision 1.58
diff -u -p -r1.58 qemu_conf.h
--- src/qemu_conf.h	16 Mar 2009 13:54:26 -0000	1.58
+++ src/qemu_conf.h	16 Mar 2009 17:53:20 -0000
@@ -55,6 +55,7 @@ enum qemud_cmd_flags {
     QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP  = (1 << 10), /* New migration syntax after merge to QEMU with TCP transport */
     QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC = (1 << 11), /* New migration syntax after merge to QEMU with EXEC transport */
     QEMUD_CMD_FLAG_DRIVE_CACHE_V2    = (1 << 12), /* Is the cache= flag wanting new v2 values */
+    QEMUD_CMD_FLAG_KVM               = (1 << 13), /* Whether KVM is compiled in */
 };
 
 /* Main driver state */
Index: src/qemu_driver.c
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_driver.c,v
retrieving revision 1.218
diff -u -p -r1.218 qemu_driver.c
--- src/qemu_driver.c	16 Mar 2009 17:16:04 -0000	1.218
+++ src/qemu_driver.c	16 Mar 2009 17:53:20 -0000
@@ -1733,6 +1733,7 @@ qemudMonitorCommand(const virDomainObjPt
 static int qemudProbe(void)
 {
     if ((virFileExists("/usr/bin/qemu")) ||
+        (virFileExists("/usr/bin/qemu-system-x86_64")) ||
         (virFileExists("/usr/bin/qemu-kvm")) ||
         (virFileExists("/usr/bin/kvm")) ||
         (virFileExists("/usr/bin/xenner")))
@@ -1749,10 +1750,10 @@ static virDrvOpenStatus qemudOpen(virCon
     if (qemu_driver == NULL)
         goto decline;
 
-    if (!qemudProbe())
-        goto decline;
-
     if (conn->uri == NULL) {
+        if (!qemudProbe())
+            goto decline;
+
         conn->uri = xmlParseURI(uid ? "qemu:///session" : "qemu:///system");
         if (!conn->uri) {
             virReportOOMError(conn);


-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list