On Tue, Jul 23, 2013 at 05:19:03PM +0100, Daniel P. Berrange wrote:
> On Tue, Jul 23, 2013 at 06:11:35PM +0200, Jiri Denemark wrote:
> > Since QEMU and kvm may filter some host CPU features or add efficiently
> > emulated features, asking QEMU binary for host CPU data provides
> > better results when we later use the data for building guest CPUs.
> > ---
> >  src/qemu/qemu_capabilities.c | 44 
> > +++++++++++++++++++++++++++++++++++++++++++-
> >  src/qemu/qemu_capabilities.h |  2 ++
> >  2 files changed, 45 insertions(+), 1 deletion(-)
> > 
> > diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
> > index 9440396..d46a059 100644
> > --- a/src/qemu/qemu_capabilities.c
> > +++ b/src/qemu/qemu_capabilities.c
> > @@ -253,6 +253,7 @@ struct _virQEMUCaps {
> >  
> >      size_t ncpuDefinitions;
> >      char **cpuDefinitions;
> > +    virCPUDefPtr hostCPU;
> >  
> >      size_t nmachineTypes;
> >      char **machineTypes;
> > @@ -1757,6 +1758,9 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr 
> > qemuCaps)
> >              goto error;
> >      }
> >  
> > +    if (!(ret->hostCPU = virCPUDefCopy(qemuCaps->hostCPU)))
> > +        goto error;
> > +
> >      if (VIR_ALLOC_N(ret->machineTypes, qemuCaps->nmachineTypes) < 0)
> >          goto error;
> >      if (VIR_ALLOC_N(ret->machineAliases, qemuCaps->nmachineTypes) < 0)
> > @@ -1796,6 +1800,7 @@ void virQEMUCapsDispose(void *obj)
> >          VIR_FREE(qemuCaps->cpuDefinitions[i]);
> >      }
> >      VIR_FREE(qemuCaps->cpuDefinitions);
> > +    virCPUDefFree(qemuCaps->hostCPU);
> >  
> >      virBitmapFree(qemuCaps->flags);
> >  
> > @@ -2485,7 +2490,6 @@ virQEMUCapsInitQMPCommandNew(const char *binary,
> >                                 "-no-user-config",
> >                                 "-nodefaults",
> >                                 "-nographic",
> > -                               "-M", "none",
> >                                 "-qmp", monitor,
> >                                 "-pidfile", pidfile,
> >                                 "-daemonize",
> > @@ -2617,6 +2621,7 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps,
> >  
> >      cmd = virQEMUCapsInitQMPCommandNew(qemuCaps->binary, monarg, pidfile,
> >                                         runUid, runGid);
> > +    virCommandAddArgList(cmd, "-M", "none", NULL);
> >  
> >      if ((ret = virQEMUCapsInitQMPCommandRun(cmd, qemuCaps->binary, pidfile,
> >                                              &config, &mon, &pid)) < 0) {
> > @@ -2679,6 +2684,37 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps,
> >      if (virQEMUCapsProbeQMPCommandLine(qemuCaps, mon) < 0)
> >          goto cleanup;
> >  
> > +    if ((qemuCaps->arch == VIR_ARCH_I686 ||
> > +         qemuCaps->arch == VIR_ARCH_X86_64) &&
> > +        (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM) ||
> > +         virQEMUCapsGet(qemuCaps, QEMU_CAPS_ENABLE_KVM)) &&
> > +        virQEMUCapsGet(qemuCaps, QEMU_CAPS_CPU_HOST) &&
> > +        qemuCaps->nmachineTypes) {
> > +        virQEMUCapsInitQMPCommandAbort(&cmd, &mon, &pid, pidfile);
> > +
> > +        VIR_DEBUG("Checking host CPU data provided by %s", 
> > qemuCaps->binary);
> > +        cmd = virQEMUCapsInitQMPCommandNew(qemuCaps->binary, monarg, 
> > pidfile,
> > +                                           runUid, runGid);
> > +        virCommandAddArgList(cmd, "-cpu", "host", NULL);
> > +        /* -cpu host gives the same CPU for all machine types so we just
> > +         * use the first one when probing
> > +         */
> > +        virCommandAddArg(cmd, "-machine");
> > +        virCommandAddArgFormat(cmd, "%s,accel=kvm",
> > +                               qemuCaps->machineTypes[0]);
> > +
> > +        if (virQEMUCapsInitQMPCommandRun(cmd, qemuCaps->binary, pidfile,
> > +                                         &config, &mon, &pid) < 0)
> > +            goto cleanup;
> > +
> > +        qemuCaps->hostCPU = qemuMonitorGetCPU(mon, qemuCaps->arch);
> > +        if (qemuCaps->hostCPU) {
> > +            char *cpu = virCPUDefFormat(qemuCaps->hostCPU, 0);
> > +            VIR_DEBUG("Host CPU reported by %s: %s", qemuCaps->binary, 
> > cpu);
> > +            VIR_FREE(cpu);
> > +        }
> > +    }
> 
> 
> This code is causing us to invoke the QEMU binary multiple times,
> which is something we worked really hard to get away from. I really,
> really don't like this as an approach. QEMU needs to be able to
> give us the data we need here without multiple invocations.
> 
> eg, by allowing the monitor command to specify 'kvm' vs 'qemu'
> when asking for data, so you can interrogate it without having
> to re-launch it with different accel=XXX args.

The specific information libvirt requires here depend on KVM being
initialized, and QEMU code/interfaces currently assume that: 1) there's
only 1 machine being initialized, and it is initialized very early; 2)
there's only one accelerator being initialized, and it is initialized
very early.

I have no idea how long it will take for QEMU to provide a QMP interface
for late/multiple initialization of machines/accelerators. In the
meantime, the way libvirt queries for host CPU capabilities without
taking QEMU and kernel capabilities into account is a serious bug we
need to solve.

Maybe if we are lucky we can find a workaround in the meantime that
won't require running QEMU multiple times, but I am not sure. Maybe it
will be a hack that will be worse than simply running QEMU twice.

-- 
Eduardo

Reply via email to