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

Nikola Ciprich extmaillist at linuxbox.cz
Fri Mar 20 07:23:46 UTC 2009


Hi Dan,
I'd like to ask about qemu-0.10.0: it already contains KVM support,
BUT in contrary to std kvm userspace package, KVM support needs to be enabled
by switch (while in kvm shipped userspace it's enabled by default and can by disabled by switch).
How can I enable it when I want to use new qemu + with KVM enabled from libvirt?
thanks a lot in advance...
BR
nik

On Mon, Mar 16, 2009 at 06:03:59PM +0000, Daniel P. Berrange wrote:
> 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 at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list
> 

-- 
-------------------------------------
Nikola CIPRICH
LinuxBox.cz, s.r.o.
28. rijna 168, 709 01 Ostrava

tel.:   +420 596 603 142
fax:    +420 596 621 273
mobil:  +420 777 093 799
www.linuxbox.cz

mobil servis: +420 737 238 656
email servis: servis at linuxbox.cz
-------------------------------------




More information about the libvir-list mailing list