In qemu-0.11 there is a 'pc-0.10' machine type which allows you to run guests with a machine which is compatible with the pc machine in qemu-0.10 - e.g. using the original PCI class for virtio-blk and virtio-console and disabling MSI support in virtio-net. The idea here is that we don't want to surprise guests by changing the hardware when qemu is updated. I've just posted some patches for qemu-0.11 which allows libvirt to canonicalize the 'pc' machine alias to the latest machine version. This patches makes us use that so that when a guest is configured to use the 'pc' machine type, we resolve that to 'pc-0.11' machine and save that in the guest XML. See also: https://fedoraproject.org/wiki/Features/KVM_Stable_Guest_ABI * src/qemu_conf.c: add qemudCanonicalizeMachine() to parse the output of 'qemu -M ?' * src/qemu_driver.c: canonicalize the machine type in qemudDomainDefine() --- src/qemu_conf.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/qemu_conf.h | 3 + src/qemu_driver.c | 3 + 3 files changed, 120 insertions(+), 0 deletions(-) diff --git a/src/qemu_conf.c b/src/qemu_conf.c index 4043d70..3f4edfa 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -470,6 +470,120 @@ virCapsPtr qemudCapsInit(void) { return NULL; } +/* Format is: + * <machine> <desc> [(alias of <machine>)] + */ +static int +qemudParseMachineTypesStr(const char *machines ATTRIBUTE_UNUSED, + const char *machine ATTRIBUTE_UNUSED, + char **canonical) +{ + const char *p = machines; + + *canonical = NULL; + + do { + const char *eol; + char *s; + + if (!(eol = strchr(p, '\n'))) + return -1; /* eof file without finding @machine */ + + if (!STRPREFIX(p, machine)) { + p = eol + 1; + continue; /* doesn't match @machine */ + } + + p += strlen(machine); + + if (*p != ' ') { + p = eol + 1; + continue; /* not a complete match of @machine */ + } + + do { + p++; + } while (*p == ' '); + + p = strstr(p, "(alias of "); + if (!p || p > eol) + return 0; /* not an alias, name is canonical */ + + *canonical = strndup(p + strlen("(alias of "), eol - p); + + s = strchr(*canonical, ')'); + if (!s) { + VIR_FREE(*canonical); + *canonical = NULL; + return -1; /* output is screwed up */ + } + + *s = '\0'; + break; + } while (1); + + return 0; +} + +int +qemudCanonicalizeMachine(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainDefPtr def) +{ + const char *const qemuarg[] = { def->emulator, "-M", "?", NULL }; + const char *const qemuenv[] = { "LC_ALL=C", NULL }; + char *machines, *canonical; + enum { MAX_MACHINES_OUTPUT_SIZE = 1024*4 }; + pid_t child; + int newstdout = -1, len; + int ret = -1, status; + + if (virExec(NULL, qemuarg, qemuenv, NULL, + &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0) + return -1; + + len = virFileReadLimFD(newstdout, MAX_MACHINES_OUTPUT_SIZE, &machines); + if (len < 0) { + virReportSystemError(NULL, errno, "%s", + _("Unable to read 'qemu -M ?' output")); + goto cleanup; + } + + if (qemudParseMachineTypesStr(machines, def->os.machine, &canonical) < 0) + goto cleanup2; + + if (canonical) { + VIR_FREE(def->os.machine); + def->os.machine = canonical; + } + + ret = 0; + +cleanup2: + VIR_FREE(machines); +cleanup: + if (close(newstdout) < 0) + ret = -1; + +rewait: + if (waitpid(child, &status, 0) != child) { + if (errno == EINTR) + goto rewait; + + VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"), + WEXITSTATUS(status), (unsigned long)child); + ret = -1; + } + /* Check & log unexpected exit status, but don't fail, + * as there's really no need to throw an error if we did + * actually read a valid version number above */ + if (WEXITSTATUS(status) != 0) { + VIR_WARN(_("Unexpected exit status '%d', qemu probably failed"), + WEXITSTATUS(status)); + } + + return ret; +} + static unsigned int qemudComputeCmdFlags(const char *help, unsigned int version, unsigned int is_kvm, diff --git a/src/qemu_conf.h b/src/qemu_conf.h index fbf2ab9..b668669 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -123,6 +123,9 @@ int qemudExtractVersionInfo (const char *qemu, unsigned int *version, unsigned int *flags); +int qemudCanonicalizeMachine (virConnectPtr conn, + virDomainDefPtr def); + int qemudParseHelpStr (const char *str, unsigned int *flags, unsigned int *version, diff --git a/src/qemu_driver.c b/src/qemu_driver.c index d2db1a2..98f8e95 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -4102,6 +4102,9 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) { } } + if (qemudCanonicalizeMachine(conn, def) < 0) + goto cleanup; + if (!(vm = virDomainAssignDef(conn, &driver->domains, def))) { -- 1.6.2.5 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list