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 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list