Currently we hardcode the QEMU machine types. We should really just parse the output of 'qemu -M ?' so the lists don't get out of sync. xenner doesn't support '-M ?', so we still need to hardcode that. The horrible (const char *const *) is removed in a subsequent patch. * src/qemu_conf.c: kill the arch_info*machines tables, retain the hardcoded xenner machine type, add qemudProbeMachineTypes() to run and parse 'qemu -M ?' and use it in qemudCapsInitGuest() --- src/qemu_conf.c | 201 ++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 154 insertions(+), 47 deletions(-) diff --git a/src/qemu_conf.c b/src/qemu_conf.c index 4bd511a..bdbeff2 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -222,31 +222,6 @@ int qemudLoadDriverConfig(struct qemud_driver *driver, return 0; } -/* The list of possible machine types for various architectures, - as supported by QEMU - taken from 'qemu -M ?' for each arch */ -static const char *const arch_info_hvm_x86_machines[] = { - "pc", "isapc" -}; -static const char *const arch_info_hvm_arm_machines[] = { - "versatilepb","integratorcp","versatileab","realview", - "akita","spitz","borzoi","terrier","sx1-v1","sx1", - "cheetah","n800","n810","lm3s811evb","lm3s6965evb", - "connex","verdex","mainstone","musicpal","tosa", -}; -static const char *const arch_info_hvm_mips_machines[] = { - "mips" -}; -static const char *const arch_info_hvm_sparc_machines[] = { - "sun4m" -}; -static const char *const arch_info_hvm_ppc_machines[] = { - "g3beige", "mac99", "prep" -}; - -static const char *const arch_info_xen_x86_machines[] = { - "xenner" -}; - struct qemu_feature_flags { const char *name; const int default_on; @@ -256,8 +231,7 @@ struct qemu_feature_flags { struct qemu_arch_info { const char *arch; int wordsize; - const char *const *machines; - int nmachines; + const char *machine; const char *binary; const char *altbinary; const struct qemu_feature_flags *flags; @@ -279,29 +253,135 @@ static const struct qemu_feature_flags const arch_info_x86_64_flags [] = { /* 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", "/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", NULL, arch_info_x86_64_flags, 2 }, - { "arm", 32, arch_info_hvm_arm_machines, 20, - "/usr/bin/qemu-system-arm", NULL, NULL, 0 }, - { "mips", 32, arch_info_hvm_mips_machines, 1, - "/usr/bin/qemu-system-mips", NULL, NULL, 0 }, - { "mipsel", 32, arch_info_hvm_mips_machines, 1, - "/usr/bin/qemu-system-mipsel", NULL, NULL, 0 }, - { "sparc", 32, arch_info_hvm_sparc_machines, 1, - "/usr/bin/qemu-system-sparc", NULL, NULL, 0 }, - { "ppc", 32, arch_info_hvm_ppc_machines, 3, - "/usr/bin/qemu-system-ppc", NULL, NULL, 0 }, + { "i686", 32, NULL, "/usr/bin/qemu", + "/usr/bin/qemu-system-x86_64", arch_info_i686_flags, 4 }, + { "x86_64", 64, NULL, "/usr/bin/qemu-system-x86_64", + NULL, arch_info_x86_64_flags, 2 }, + { "arm", 32, NULL, "/usr/bin/qemu-system-arm", NULL, NULL, 0 }, + { "mips", 32, NULL, "/usr/bin/qemu-system-mips", NULL, NULL, 0 }, + { "mipsel", 32, NULL, "/usr/bin/qemu-system-mipsel", NULL, NULL, 0 }, + { "sparc", 32, NULL, "/usr/bin/qemu-system-sparc", NULL, NULL, 0 }, + { "ppc", 32, NULL, "/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", NULL, arch_info_i686_flags, 4 }, - { "x86_64", 64, arch_info_xen_x86_machines, 1, - "/usr/bin/xenner", NULL, arch_info_x86_64_flags, 2 }, + { "i686", 32, "xenner", "/usr/bin/xenner", NULL, arch_info_i686_flags, 4 }, + { "x86_64", 64, "xenner", "/usr/bin/xenner", NULL, arch_info_x86_64_flags, 2 }, }; + +/* Format is: + * <machine> <desc> [(default)] + */ +static int +qemudParseMachineTypesStr(const char *output, + char ***machines, + int *nmachines) +{ + const char *p = output; + const char *next; + char **list = NULL; + int i, nitems = 0; + + do { + const char *t; + char *machine; + + if ((next = strchr(p, '\n'))) + ++next; + + if (STRPREFIX(p, "Supported machines are:")) + continue; + + if (!(t = strchr(p, ' ')) || (next && t >= next)) + continue; + + if (!(machine = strndup(p, t - p))) + goto error; + + if (VIR_REALLOC_N(list, nitems + 1) < 0) { + VIR_FREE(machine); + goto error; + } + + p = t; + if (!(t = strstr(p, "(default)")) || (next && t >= next)) { + list[nitems++] = machine; + } else { + /* put the default first in the list */ + memmove(list + 1, list, sizeof(*list) * nitems); + list[0] = machine; + nitems++; + } + } while ((p = next)); + + *machines = list; + *nmachines = nitems; + + return 0; + +error: + for (i = 0; i < nitems; i++) + VIR_FREE(list[i]); + VIR_FREE(list); + return -1; +} + +static int +qemudProbeMachineTypes(const char *binary, + char ***machines, + int *nmachines) +{ + const char *const qemuarg[] = { binary, "-M", "?", NULL }; + const char *const qemuenv[] = { "LC_ALL=C", NULL }; + char *output; + 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, &output); + if (len < 0) { + virReportSystemError(NULL, errno, "%s", + _("Unable to read 'qemu -M ?' output")); + goto cleanup; + } + + if (qemudParseMachineTypesStr(output, machines, nmachines) < 0) + goto cleanup2; + + ret = 0; + +cleanup2: + VIR_FREE(output); +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 int qemudCapsInitGuest(virCapsPtr caps, const char *hostmachine, @@ -313,6 +393,8 @@ qemudCapsInitGuest(virCapsPtr caps, int haskqemu = 0; const char *kvmbin = NULL; const char *binary = NULL; + char **machines = NULL; + int nmachines = 0; /* Check for existance of base emulator, or alternate base * which can be used with magic cpu choice @@ -351,6 +433,23 @@ qemudCapsInitGuest(virCapsPtr caps, if (!binary) return 0; + if (info->machine) { + char *machine; + + if (!(machine = strdup(info->machine))) + return -1; + + if (VIR_ALLOC_N(machines, nmachines) < 0) { + VIR_FREE(machine); + return -1; + } + + machines[0] = machine; + nmachines = 1; + + } else if (qemudProbeMachineTypes(binary, &machines, &nmachines) < 0) + return -1; + /* We register kvm as the base emulator too, since we can * just give -no-kvm to disable acceleration if required */ if ((guest = virCapabilitiesAddGuest(caps, @@ -359,9 +458,17 @@ qemudCapsInitGuest(virCapsPtr caps, info->wordsize, binary, NULL, - info->nmachines, - info->machines)) == NULL) + nmachines, + (const char *const *)machines)) == NULL) { + for (i = 0; i < nmachines; i++) + VIR_FREE(machines[i]); + VIR_FREE(machines); return -1; + } + + for (i = 0; i < nmachines; i++) + VIR_FREE(machines[i]); + VIR_FREE(machines); if (hvm) { if (virCapabilitiesAddGuestDomain(guest, -- 1.6.2.5 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list