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