[libvirt] [PATCH] Canonicalize qemu machine types

Daniel P. Berrange berrange at redhat.com
Wed Jul 22 10:39:52 UTC 2009


On Tue, Jul 21, 2009 at 04:01:37PM +0100, Mark McLoughlin wrote:
> 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.

We currently also list "valid" machine types in the capabilities
XML for each driver. I use quotes, because this list is currently
dubiously hardcoded. I'm thinking it might be better to do the
parsing of -M ? output as part of the capaiblities intiialization
code. The canonicalize method would then just need to query the 
existing capabilities data & could even be  done in the domain XML
parser code instead of qemu driver.


> ---
>  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);


Need to check for NULL here.

> +
> +        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


Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list