[libvirt] [PATCH 2/2] qemu: Emit compatible XML when migrating a domain

Eric Blake eblake at redhat.com
Fri May 4 23:28:39 UTC 2012


On 05/04/2012 04:40 PM, Jiri Denemark wrote:
> When we added the default USB controller into domain XML, we efficiently
> broke migration to older versions of libvirt that didn't support USB
> controllers at all (0.9.4 and earlier) even for domains that doesn't use

s/doesn't/don't/

> anything that the older libvirt can't provide. We still want to present
> the default USB controller in any XML seen by a user/app but we can
> safely remove it from the domain XML used during migration. If we are
> migrating to a new enough libvirt, it will add the controller XML back,
> while older libvirt won't be confused with it although it will still
> tell qemu to create the controller.
> 
> Similar approach can be used in the future whenever we find out we
> always enabled some kind of device without properly advertising it in
> domain XML.

Memballoon would be such a device, if we care about migration to even
older libvirt.

> ---
>  src/qemu/qemu_domain.c    |   60 ++++++++++++++++++++++++++++++++++++++++----
>  src/qemu/qemu_domain.h    |   10 +++++--
>  src/qemu/qemu_driver.c    |   21 +++++++++------
>  src/qemu/qemu_migration.c |   10 ++++---
>  src/qemu/qemu_process.c   |    8 +++---
>  5 files changed, 83 insertions(+), 26 deletions(-)
> 
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index b105644..3752ddf 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -1227,11 +1227,14 @@ int
>  qemuDomainDefFormatBuf(struct qemud_driver *driver,
>                         virDomainDefPtr def,
>                         unsigned int flags,
> +                       bool compatible,
>                         virBuffer *buf)

Rather than adding a new 'compatible' flag and having to adjust _every_
caller, could we instead add a new VIR_DOMAIN_XML_INTERNAL flag to be
or'd in to flags only for the callers that care?  On the other hand,
we'd have to filter that flag back out before calling into domain_conf,
so I guess this approach is as good as any.

>  {
>      int ret = -1;
>      virCPUDefPtr cpu = NULL;
>      virCPUDefPtr def_cpu = def->cpu;
> +    virDomainControllerDefPtr *controllers = NULL;
> +    int ncontrollers = 0;
>  
>      /* Update guest CPU requirements according to host CPU */
>      if ((flags & VIR_DOMAIN_XML_UPDATE_CPU) &&
> @@ -1249,21 +1252,64 @@ qemuDomainDefFormatBuf(struct qemud_driver *driver,
>          def->cpu = cpu;
>      }
>  
> +    if (compatible) {
> +        int i;
> +        virDomainControllerDefPtr usb = NULL;
> +
> +        /* If only the default USB controller is present, we can remove it
> +         * and make the XML compatible with older versions of libvirt which
> +         * didn't support USB controllers in the XML but always added the
> +         * default one to qemu anyway.
> +         */
> +        for (i = 0; i < def->ncontrollers; i++) {
> +            if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
> +                if (usb) {
> +                    usb = NULL;
> +                    break;
> +                }
> +                usb = def->controllers[i];
> +            }
> +        }
> +        if (usb && usb->idx == 0 && usb->model == -1) {

Just like memballoon, if we ever want to explicitly represent an XML
with no usb controller, we will have to provide <controller type='usb'
mode='none'>; but there, the model would not be -1, so this would
properly be migrated.

> +            VIR_DEBUG("Removing default USB controller from domain '%s'"
> +                      " for migration compatibility", def->name);
> +            controllers = def->controllers;
> +            ncontrollers = def->ncontrollers;
> +            if (VIR_ALLOC_N(def->controllers, ncontrollers - 1) < 0) {
> +                controllers = NULL;
> +                virReportOOMError();
> +                goto cleanup;
> +            }
> +
> +            def->ncontrollers = 0;
> +            for (i = 0; i < ncontrollers; i++) {
> +                if (controllers[i] != usb)
> +                    def->controllers[def->ncontrollers++] = controllers[i];
> +            }
> +        }
> +    }
> +
>      ret = virDomainDefFormatInternal(def, flags, buf);
>  
>  cleanup:
>      def->cpu = def_cpu;
>      virCPUDefFree(cpu);
> +    if (controllers) {
> +        VIR_FREE(def->controllers);
> +        def->controllers = controllers;
> +        def->ncontrollers = ncontrollers;
> +    }

This looks like it will correctly trim _only_ the default usb controller
from modern xml, and restore it after the migration has been prepared.
On the receiving side, modern libvirt will know to reconstruct the
default usb controller.

> +++ b/src/qemu/qemu_driver.c
> @@ -2630,9 +2630,9 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
>              virDomainDefFree(def);
>              goto endjob;
>          }
> -        xml = qemuDomainDefFormatLive(driver, def, true);
> +        xml = qemuDomainDefFormatLive(driver, def, true, true);
>      } else {
> -        xml = qemuDomainDefFormatLive(driver, vm->def, true);
> +        xml = qemuDomainDefFormatLive(driver, vm->def, true, true);

Good - save is indeed a migration case, since you can save on one
machine and load on another.

> @@ -10406,7 +10408,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
>      } else {
>          /* Easiest way to clone inactive portion of vm->def is via
>           * conversion in and back out of xml.  */
> -        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true)) ||
> +        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, false)) ||

I also agree with this one - although reverting to a snapshot is like
loading a saved image, we don't currently migrate snapshots so they are
only useful within the same host, so the revert should never be by an
older libvirt that didn't recognize the usb controller.


> @@ -433,6 +433,7 @@ qemuMigrationCookieXMLFormat(struct qemud_driver *driver,
>                                     mig->persistent,
>                                     VIR_DOMAIN_XML_INACTIVE |
>                                     VIR_DOMAIN_XML_SECURE,
> +                                   true,
>                                     buf) < 0)

And of course, the main driver for this patch is migration.

It looks to me like you passed the correct 'compatible' flag in all the
callers, and that this does allow for cross-migration from newer to
older xml.

ACK.

-- 
Eric Blake   eblake at redhat.com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 620 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20120504/b7ec45f7/attachment-0001.sig>


More information about the libvir-list mailing list