From 26cfb1a3cd39d731099ee7d5d1c47b3730ebde16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 3 Aug 2018 13:29:26 +0100 Subject: [PATCH] qemu: ensure default machine types don't change if QEMU changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is increasingly likely that some distro is going to change the default "x86" machine type in QEMU from "pc" to "q35". This will certainly break existing applications which write their XML on the assumption that it is using a "pc" machine by default. For example they'll lack a IDE CDROM and get PCIe instead of PCI which changes the topology radically. Libvirt promises to isolate applications from hypervisor changes that may cause incompatibilities, so we must ensure that we always use the "pc" machine type if it is available. Only use QEMU's own reported default machine type if "pc" does not exist. This issue is not x86-only, other arches are liable to change their default machine, while some arches don't report any default at all causing libvirt to pick the first machine in the list. Thus to guarantee stability to applications, declare a preferred default machine for all architectures we currently support with QEMU. Note this change assumes there will always be a "pc" alias as long as a versioned "pc-XXX" machine type exists. If QEMU were to ship a "pc-XXX" machine type but not provide the "pc" alias, it is too hard to decide which to default so. Versioned machine types are supposed to be considered opaque strings, so we can't apply any sensible ordering ourselves and QEMU isn't reporting the list of machines in any sensible ordering itself. Reviewed-by: Andrea Bolognani Signed-off-by: Daniel P. Berrangé --- src/qemu/qemu_capabilities.c | 80 ++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 0fb800589a..619a2c99cf 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2233,6 +2233,61 @@ virQEMUCapsProbeQMPDevices(virQEMUCapsPtr qemuCaps, } +/* Historically QEMU x86 targets defaulted to 'pc' machine type but + * in future x86_64 might switch to 'q35'. Such a change is considered + * an ABI break from libvirt's POV. Other QEMU targets may not declare + * a default machine at all, causing libvirt to use the first reported + * machine in the list. + * + * Here we record a preferred default machine for all arches, so + * that we're not vulnerable to changes in QEMU defaults or machine + * list ordering. + */ +static const char *preferredMachines[VIR_ARCH_LAST] = +{ + [VIR_ARCH_ALPHA] = "clipper", + [VIR_ARCH_ARMV6L] = NULL, /* No QEMU impl */ + [VIR_ARCH_ARMV7L] = "integratorcp", + [VIR_ARCH_ARMV7B] = "integratorcp", + + [VIR_ARCH_AARCH64] = "integratorcp", + [VIR_ARCH_CRIS] = "axis-dev88", + [VIR_ARCH_I686] = "pc", + [VIR_ARCH_ITANIUM] = NULL, /* doesn't exist in QEMU any more */ + [VIR_ARCH_LM32] = "lm32-evr", + + [VIR_ARCH_M68K] = "mcf5208evb", + [VIR_ARCH_MICROBLAZE] = "petalogix-s3adsp1800", + [VIR_ARCH_MICROBLAZEEL] = "petalogix-s3adsp1800", + [VIR_ARCH_MIPS] = "malta", + [VIR_ARCH_MIPSEL] = "malta", + + [VIR_ARCH_MIPS64] = "malta", + [VIR_ARCH_MIPS64EL] = "malta", + [VIR_ARCH_OR32] = "or1k-sim", + [VIR_ARCH_PARISC] = NULL, /* No QEMU impl */ + [VIR_ARCH_PARISC64] = NULL, /* No QEMU impl */ + + [VIR_ARCH_PPC] = "g3beige", + [VIR_ARCH_PPCLE] = "g3beige", + [VIR_ARCH_PPC64] = "pseries", + [VIR_ARCH_PPC64LE] = "pseries", + [VIR_ARCH_PPCEMB] = "bamboo", + + [VIR_ARCH_S390] = NULL, /* No QEMU impl*/ + [VIR_ARCH_S390X] = "s390-ccw-virtio", + [VIR_ARCH_SH4] = "shix", + [VIR_ARCH_SH4EB] = "shix", + [VIR_ARCH_SPARC] = "SS-5", + + [VIR_ARCH_SPARC64] = "sun4u", + [VIR_ARCH_UNICORE32] = "puv3", + [VIR_ARCH_X86_64] = "pc", + [VIR_ARCH_XTENSA] = "sim", + [VIR_ARCH_XTENSAEB] = "sim", +}; + + static int virQEMUCapsProbeQMPMachineTypes(virQEMUCapsPtr qemuCaps, qemuMonitorPtr mon) @@ -2241,7 +2296,9 @@ virQEMUCapsProbeQMPMachineTypes(virQEMUCapsPtr qemuCaps, int nmachines = 0; int ret = -1; size_t i; - size_t defIdx = 0; + ssize_t defIdx = -1; + ssize_t preferredIdx = -1; + const char *preferredMachine = preferredMachines[qemuCaps->arch]; if ((nmachines = qemuMonitorGetMachines(mon, &machines)) < 0) return -1; @@ -2263,12 +2320,29 @@ virQEMUCapsProbeQMPMachineTypes(virQEMUCapsPtr qemuCaps, mach->maxCpus = machines[i]->maxCpus; mach->hotplugCpus = machines[i]->hotplugCpus; + if (preferredMachine && + (STREQ_NULLABLE(mach->alias, preferredMachine) || + STREQ(mach->name, preferredMachine))) { + preferredIdx = qemuCaps->nmachineTypes - 1; + } + if (machines[i]->isDefault) defIdx = qemuCaps->nmachineTypes - 1; } - if (defIdx) - virQEMUCapsSetDefaultMachine(qemuCaps, defIdx); + /* + * We'll prefer to use our own historical default machine + * to avoid mgmt apps seeing semantics changes when QEMU + * alters its defaults. + * + * Our preferred machine might have been compiled out of + * QEMU at build time though, so we still fallback to honouring + * QEMU's reported default in that case + */ + if (preferredIdx == -1) + preferredIdx = defIdx; + if (preferredIdx != -1) + virQEMUCapsSetDefaultMachine(qemuCaps, preferredIdx); ret = 0; -- GitLab