[libvirt] [PATCH v15] support offline migration

li guang lig.fnst at cn.fujitsu.com
Mon Dec 10 01:31:58 UTC 2012


在 2012-12-07五的 16:01 +0100,Jiri Denemark写道:
> On Wed, Nov 21, 2012 at 16:28:49 +0800, liguang wrote:
> ...
> > diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> > index d52ec59..53171df 100644
> > --- a/src/qemu/qemu_migration.c
> > +++ b/src/qemu/qemu_migration.c
> > @@ -2675,7 +2702,9 @@ static int doPeer2PeerMigrate3(struct qemud_driver *driver,
> >               uri, &uri_out, flags, dname, resource, dom_xml);
> >          qemuDomainObjExitRemoteWithDriver(driver, vm);
> >      }
> > +
> >      VIR_FREE(dom_xml);
> > +
> >      if (ret == -1)
> >          goto cleanup;
> >  
> 
> I wonder why you keep changing the code that I agreed with in the previous
> version. Similar thing happened from v13 to v14. This change would break p2p
> migration (which was handled correctly in v14).
> 
> Anyway, I combined the good pieces of code from v13, v14, and v15, added some
> fixes and a code to give reasonable error messages when libvirt client and
> source and destination libvirt daemons do not all come from the same release.
> 
> The following is the diff to you patch, which may serve as my review comments.
> I'll send a combined v16 patch shortly.

Thank you so much!
you cut my changes for p2p & tunnel,
but, that's fine.

> 
> diff --git a/src/libvirt.c b/src/libvirt.c
> index 6144a17..f48ae53 100644
> --- a/src/libvirt.c
> +++ b/src/libvirt.c
> @@ -4830,9 +4830,13 @@ virDomainMigrateVersion3(virDomainPtr domain,
>          uri = uri_out; /* Did domainMigratePrepare3 change URI? */
>  
>      if (flags & VIR_MIGRATE_OFFLINE) {
> +        VIR_DEBUG("Offline migration, skipping Perform phase");
> +        VIR_FREE(cookieout);
> +        cookieoutlen = 0;
>          cancelled = 0;
>          goto finish;
>      }
> +
>      /* Perform the migration.  The driver isn't supposed to return
>       * until the migration is complete. The src VM should remain
>       * running, but in paused state until the destination can
> @@ -5203,6 +5207,23 @@ virDomainMigrate(virDomainPtr domain,
>          goto error;
>      }
>  
> +    if (flags & VIR_MIGRATE_OFFLINE) {
> +        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
> +                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
> +            virLibConnError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
> +                            _("offline migration is not supported by "
> +                              "the source host"));
> +            goto error;
> +        }
> +        if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
> +                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
> +            virLibConnError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
> +                            _("offline migration is not supported by "
> +                              "the destination host"));
> +            goto error;
> +        }
> +    }
> +
>      if (flags & VIR_MIGRATE_PEER2PEER) {
>          if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
>                                       VIR_DRV_FEATURE_MIGRATION_P2P)) {
> @@ -5408,6 +5429,23 @@ virDomainMigrate2(virDomainPtr domain,
>          goto error;
>      }
>  
> +    if (flags & VIR_MIGRATE_OFFLINE) {
> +        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
> +                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
> +            virLibConnError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
> +                            _("offline migration is not supported by "
> +                              "the source host"));
> +            goto error;
> +        }
> +        if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
> +                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
> +            virLibConnError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
> +                            _("offline migration is not supported by "
> +                              "the destination host"));
> +            goto error;
> +        }
> +    }
> +
>      if (flags & VIR_MIGRATE_PEER2PEER) {
>          if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
>                                       VIR_DRV_FEATURE_MIGRATION_P2P)) {
> @@ -5585,6 +5623,15 @@ virDomainMigrateToURI(virDomainPtr domain,
>  
>      virCheckNonNullArgGoto(duri, error);
>  
> +    if (flags & VIR_MIGRATE_OFFLINE &&
> +        !VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
> +                                  VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
> +        virLibConnError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
> +                        _("offline migration is not supported by "
> +                          "the source host"));
> +        goto error;
> +    }
> +
>      if (flags & VIR_MIGRATE_PEER2PEER) {
>          if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
>                                       VIR_DRV_FEATURE_MIGRATION_P2P)) {
> diff --git a/src/libvirt_internal.h b/src/libvirt_internal.h
> index 2eda156..595d2db 100644
> --- a/src/libvirt_internal.h
> +++ b/src/libvirt_internal.h
> @@ -105,6 +105,11 @@ enum {
>       * Support for VIR_DOMAIN_XML_MIGRATABLE flag in domainGetXMLDesc
>       */
>      VIR_DRV_FEATURE_XML_MIGRATABLE = 11,
> +
> +    /*
> +     * Support for offline migration.
> +     */
> +    VIR_DRV_FEATURE_MIGRATION_OFFLINE = 12,
>  };
>  
> 
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 12ca3d2..d449579 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -1208,6 +1208,7 @@ qemuSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
>      case VIR_DRV_FEATURE_FD_PASSING:
>      case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
>      case VIR_DRV_FEATURE_XML_MIGRATABLE:
> +    case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
>          return 1;
>      default:
>          return 0;
> @@ -9911,7 +9912,7 @@ qemuDomainMigrateBegin3(virDomainPtr domain,
>       */
>      if (!(flags & VIR_MIGRATE_OFFLINE) &&
>          qemuDomainCheckEjectableMedia(driver, vm, asyncJob) < 0)
> -            goto endjob;
> +        goto endjob;
>  
>      if (!(xml = qemuMigrationBegin(driver, vm, xmlin, dname,
>                                     cookieout, cookieoutlen,
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index 95ff392..0ca7dd4 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -1445,19 +1445,23 @@ char *qemuMigrationBegin(virQEMUDriverPtr driver,
>      if (flags & VIR_MIGRATE_OFFLINE) {
>          if (flags & (VIR_MIGRATE_NON_SHARED_DISK |
>                       VIR_MIGRATE_NON_SHARED_INC)) {
> -            virReportError(VIR_ERR_OPERATION_INVALID,
> -                           "%s",
> +            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
>                             _("offline migration cannot handle "
>                               "non-shared storage"));
>              goto cleanup;
>          }
>          if (!(flags & VIR_MIGRATE_PERSIST_DEST)) {
> -            virReportError(VIR_ERR_OPERATION_INVALID,
> -                           "%s",
> +            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
>                             _("offline migration must be specified with "
>                               "the persistent flag set"));
>              goto cleanup;
>          }
> +        if (flags & VIR_MIGRATE_TUNNELLED) {
> +            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> +                           _("tunnelled offline migration does not "
> +                             "make sense"));
> +            goto cleanup;
> +        }
>      }
>  
>      if (xmlin) {
> @@ -1531,10 +1535,33 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
>      bool tunnel = !!st;
>      char *origname = NULL;
>      char *xmlout = NULL;
> +    unsigned int cookieFlags;
>  
>      if (virTimeMillisNow(&now) < 0)
>          return -1;
>  
> +    if (flags & VIR_MIGRATE_OFFLINE) {
> +        if (flags & (VIR_MIGRATE_NON_SHARED_DISK |
> +                     VIR_MIGRATE_NON_SHARED_INC)) {
> +            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> +                           _("offline migration cannot handle "
> +                             "non-shared storage"));
> +            goto cleanup;
> +        }
> +        if (!(flags & VIR_MIGRATE_PERSIST_DEST)) {
> +            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> +                           _("offline migration must be specified with "
> +                             "the persistent flag set"));
> +            goto cleanup;
> +        }
> +        if (tunnel) {
> +            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> +                           _("tunnelled offline migration does not "
> +                             "make sense"));
> +            goto cleanup;
> +        }
> +    }
> +
>      if (!(def = virDomainDefParseString(driver->caps, dom_xml,
>                                          QEMU_EXPECTED_VIRT_TYPES,
>                                          VIR_DOMAIN_XML_INACTIVE)))
> @@ -1618,6 +1645,9 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
>      /* Domain starts inactive, even if the domain XML had an id field. */
>      vm->def->id = -1;
>  
> +    if (flags & VIR_MIGRATE_OFFLINE)
> +        goto done;
> +
>      if (tunnel &&
>          (pipe(dataFD) < 0 || virSetCloseExec(dataFD[1]) < 0)) {
>          virReportSystemError(errno, "%s",
> @@ -1628,18 +1658,15 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
>      /* Start the QEMU daemon, with the same command-line arguments plus
>       * -incoming $migrateFrom
>       */
> -    if (!(flags & VIR_MIGRATE_OFFLINE)) {
> -        if (qemuProcessStart(dconn, driver, vm, migrateFrom, dataFD[0],
> -                             NULL, NULL,
> -                             VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START,
> -                             VIR_QEMU_PROCESS_START_PAUSED |
> -                             VIR_QEMU_PROCESS_START_AUTODESROY) < 0) {
> -            virDomainAuditStart(vm, "migrated", false);
> -            /* Note that we don't set an error here because qemuProcessStart
> -             * should have already done that.
> -             */
> -            goto endjob;
> -        }
> +    if (qemuProcessStart(dconn, driver, vm, migrateFrom, dataFD[0], NULL, NULL,
> +                         VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_START,
> +                         VIR_QEMU_PROCESS_START_PAUSED |
> +                         VIR_QEMU_PROCESS_START_AUTODESROY) < 0) {
> +        virDomainAuditStart(vm, "migrated", false);
> +        /* Note that we don't set an error here because qemuProcessStart
> +         * should have already done that.
> +         */
> +        goto endjob;
>      }
>  
>      if (tunnel) {
> @@ -1647,8 +1674,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
>              virReportSystemError(errno, "%s",
>                                   _("cannot pass pipe for tunnelled migration"));
>              virDomainAuditStart(vm, "migrated", false);
> -            if (!(flags & VIR_MIGRATE_OFFLINE))
> -                qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
> +            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
>              goto endjob;
>          }
>          dataFD[1] = -1; /* 'st' owns the FD now & will close it */
> @@ -1663,24 +1689,30 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
>          VIR_DEBUG("Received no lockstate");
>      }
>  
> -    if (!(flags & VIR_MIGRATE_OFFLINE)) {
> -        if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen,
> -                                    QEMU_MIGRATION_COOKIE_GRAPHICS) < 0) {
> -            /* We could tear down the whole guest here, but
> -             * cookie data is (so far) non-critical, so that
> -             * seems a little harsh. We'll just warn for now.
> -             */
> -            VIR_WARN("Unable to encode migration cookie");
> -        }
> +done:
> +    if (flags & VIR_MIGRATE_OFFLINE)
> +        cookieFlags = 0;
> +    else
> +        cookieFlags = QEMU_MIGRATION_COOKIE_GRAPHICS;
> +
> +    if (qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen,
> +                                cookieFlags) < 0) {
> +        /* We could tear down the whole guest here, but
> +         * cookie data is (so far) non-critical, so that
> +         * seems a little harsh. We'll just warn for now.
> +         */
> +        VIR_WARN("Unable to encode migration cookie");
>      }
>  
>      if (qemuDomainCleanupAdd(vm, qemuMigrationPrepareCleanup) < 0)
>          goto endjob;
>  
> -    virDomainAuditStart(vm, "migrated", true);
> -    event = virDomainEventNewFromObj(vm,
> -                                     VIR_DOMAIN_EVENT_STARTED,
> -                                     VIR_DOMAIN_EVENT_STARTED_MIGRATED);
> +    if (!(flags & VIR_MIGRATE_OFFLINE)) {
> +        virDomainAuditStart(vm, "migrated", true);
> +        event = virDomainEventNewFromObj(vm,
> +                                         VIR_DOMAIN_EVENT_STARTED,
> +                                         VIR_DOMAIN_EVENT_STARTED_MIGRATED);
> +    }
>  
>      /* We keep the job active across API calls until the finish() call.
>       * This prevents any other APIs being invoked while incoming
> @@ -2702,12 +2734,18 @@ static int doPeer2PeerMigrate3(virQEMUDriverPtr driver,
>               uri, &uri_out, flags, dname, resource, dom_xml);
>          qemuDomainObjExitRemoteWithDriver(driver, vm);
>      }
> -
>      VIR_FREE(dom_xml);
> -
>      if (ret == -1)
>          goto cleanup;
>  
> +    if (flags & VIR_MIGRATE_OFFLINE) {
> +        VIR_DEBUG("Offline migration, skipping Perform phase");
> +        VIR_FREE(cookieout);
> +        cookieoutlen = 0;
> +        cancelled = 0;
> +        goto finish;
> +    }
> +
>      if (!(flags & VIR_MIGRATE_TUNNELLED) &&
>          (uri_out == NULL)) {
>          virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> @@ -2846,6 +2884,7 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver,
>      virConnectPtr dconn = NULL;
>      bool p2p;
>      virErrorPtr orig_err = NULL;
> +    bool offline;
>  
>      VIR_DEBUG("driver=%p, sconn=%p, vm=%p, xmlin=%s, dconnuri=%s, "
>                "uri=%s, flags=%lx, dname=%s, resource=%lu",
> @@ -2878,6 +2917,9 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver,
>           */
>      *v3proto = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
>                                          VIR_DRV_FEATURE_MIGRATION_V3);
> +    if (flags & VIR_MIGRATE_OFFLINE)
> +        offline = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
> +                                           VIR_DRV_FEATURE_MIGRATION_OFFLINE);
>      qemuDomainObjExitRemoteWithDriver(driver, vm);
>  
>      if (!p2p) {
> @@ -2886,6 +2928,13 @@ static int doPeer2PeerMigrate(virQEMUDriverPtr driver,
>          goto cleanup;
>      }
>  
> +    if (flags & VIR_MIGRATE_OFFLINE && !offline) {
> +        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
> +                       _("offline migration is not supported by "
> +                         "the destination host"));
> +        goto cleanup;
> +    }
> +
>      /* domain may have been stopped while we were talking to remote daemon */
>      if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
>          virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> @@ -3320,9 +3369,11 @@ qemuMigrationFinish(virQEMUDriverPtr driver,
>                   * to restart during confirm() step, so we kill it off now.
>                   */
>                  if (v3proto) {
> -                    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED,
> -                                    VIR_QEMU_PROCESS_STOP_MIGRATED);
> -                    virDomainAuditStop(vm, "failed");
> +                    if (!(flags & VIR_MIGRATE_OFFLINE)) {
> +                        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED,
> +                                        VIR_QEMU_PROCESS_STOP_MIGRATED);
> +                        virDomainAuditStop(vm, "failed");
> +                    }
>                      if (newVM)
>                          vm->persistent = 0;
>                  }
> @@ -3395,16 +3446,15 @@ qemuMigrationFinish(virQEMUDriverPtr driver,
>              }
>          }
>  
> -        if (virDomainObjIsActive(vm)) {
> -            if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
> -                VIR_WARN("Failed to save status on vm %s", vm->def->name);
> -                goto endjob;
> -            }
> +        if (virDomainObjIsActive(vm) &&
> +            virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
> +            VIR_WARN("Failed to save status on vm %s", vm->def->name);
> +            goto endjob;
>          }
>  
>          /* Guest is successfully running, so cancel previous auto destroy */
>          qemuProcessAutoDestroyRemove(driver, vm);
> -    } else {
> +    } else if (!(flags & VIR_MIGRATE_OFFLINE)) {
>          qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED,
>                          VIR_QEMU_PROCESS_STOP_MIGRATED);
>          virDomainAuditStop(vm, "failed");

-- 
regards!
li guang





More information about the libvir-list mailing list