[libvirt] [PATCH V3] implement offline migration

Daniel P. Berrange berrange at redhat.com
Tue Aug 28 06:20:24 UTC 2012


On Tue, Aug 28, 2012 at 01:38:32PM +0800, liguang wrote:
> Signed-off-by: liguang <lig.fnst at cn.fujitsu.com>

Please provide a full description of what this patch is supposed
to be doing and why you've implemented it this way. I struggle
to understand what on earth this patch is doing with the streams
APIs, nor why we need a new public API for this.

Daniel

> ---
>  daemon/remote.c              |   46 +++++++++++++++++++++++++++
>  docs/hvsupport.pl            |    2 +
>  include/libvirt/libvirt.h.in |    6 +++
>  python/generator.py          |    1 +
>  src/driver.h                 |    5 +++
>  src/libvirt.c                |   22 +++++++++++++
>  src/libvirt_public.syms      |    1 +
>  src/remote/remote_driver.c   |   70 ++++++++++++++++++++++++++++++++++++++++++
>  src/remote/remote_protocol.x |   10 +++++-
>  tools/virsh-domain.c         |   69 +++++++++++++++++++++++++++++++++++++++++
>  10 files changed, 231 insertions(+), 1 deletions(-)
> 
> diff --git a/daemon/remote.c b/daemon/remote.c
> index 24928f4..c47a580 100644
> --- a/daemon/remote.c
> +++ b/daemon/remote.c
> @@ -21,6 +21,9 @@
>   */
>  
>  #include <config.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
>  
>  #include "virterror_internal.h"
>  
> @@ -48,6 +51,7 @@
>  #include "virdbus.h"
>  #include "remote_protocol.h"
>  #include "qemu_protocol.h"
> +#include "fdstream.h"
>  
>  
>  #define VIR_FROM_THIS VIR_FROM_RPC
> @@ -1768,6 +1772,48 @@ no_memory:
>      goto cleanup;
>  }
>  
> +static int remoteDispatchDomainMigrateOffline(
> +    virNetServerPtr server ATTRIBUTE_UNUSED,
> +    virNetServerClientPtr client,
> +    virNetMessagePtr msg ATTRIBUTE_UNUSED,
> +    virNetMessageErrorPtr rerr,
> +    remote_domain_migrate_offline_args *args,
> +    remote_domain_migrate_offline_ret *ret ATTRIBUTE_UNUSED)
> +{
> +    int rv = -1;
> +    virStreamPtr st = NULL;
> +    daemonClientStreamPtr stream = NULL;
> +    daemonClientPrivatePtr priv =
> +        virNetServerClientGetPrivateData(client);
> +
> +    if (!priv->conn) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
> +        goto cleanup;
> +    }
> +
> +    st = virStreamNew(priv->conn, VIR_STREAM_NONBLOCK);
> +
> +    if (!(stream = daemonCreateClientStream(client, st, remoteProgram, &msg->header)))
> +        goto cleanup;
> +
> +    if (virFDStreamCreateFile(st,
> +                            args->name,
> +                            0, 0,
> +                            O_WRONLY, 0) < 0)
> +        goto cleanup;
> +
> +
> +    if (daemonAddClientStream(client, stream, false) < 0)
> +        goto cleanup;
> +
> +    rv = 0;
> +
> +cleanup:
> +    if (rv < 0)
> +        virNetMessageSaveError(rerr);
> +    return rv;
> +}
> +
>  static int
>  remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED,
>                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
> diff --git a/docs/hvsupport.pl b/docs/hvsupport.pl
> index 4871739..47fc505 100755
> --- a/docs/hvsupport.pl
> +++ b/docs/hvsupport.pl
> @@ -128,6 +128,8 @@ $apis{virDomainMigratePrepareTunnel3} = "0.9.2";
>  $apis{virDomainMigratePerform3} = "0.9.2";
>  $apis{virDomainMigrateFinish3} = "0.9.2";
>  $apis{virDomainMigrateConfirm3} = "0.9.2";
> +$apis{virDomainMigrateOffline} = "0.10.1";
> +
>  
>  
>  
> diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
> index cfe5047..7c9cf3c 100644
> --- a/include/libvirt/libvirt.h.in
> +++ b/include/libvirt/libvirt.h.in
> @@ -995,6 +995,7 @@ typedef enum {
>                                                 * whole migration process; this will be used automatically
>                                                 * when supported */
>      VIR_MIGRATE_UNSAFE            = (1 << 9), /* force migration even if it is considered unsafe */
> +    VIR_MIGRATE_OFFLINE           = (1 << 10), /* offline migration */
>  } virDomainMigrateFlags;
>  
>  /* Domain migration. */
> @@ -1030,6 +1031,11 @@ int virDomainMigrateGetMaxSpeed(virDomainPtr domain,
>                                  unsigned long *bandwidth,
>                                  unsigned int flags);
>  
> +int
> +virDomainMigrateOffline(virConnectPtr dconn,
> +                        char *file);
> +
> +
>  /**
>   * VIR_NODEINFO_MAXCPUS:
>   * @nodeinfo: virNodeInfo instance
> diff --git a/python/generator.py b/python/generator.py
> index 7beb361..a1b1203 100755
> --- a/python/generator.py
> +++ b/python/generator.py
> @@ -427,6 +427,7 @@ skip_impl = (
>      'virDomainGetDiskErrors',
>      'virConnectUnregisterCloseCallback',
>      'virConnectRegisterCloseCallback',
> +	'virDomainMigrateOffline',
>  )
>  
>  qemu_skip_impl = (
> diff --git a/src/driver.h b/src/driver.h
> index e88ab28..9041005 100644
> --- a/src/driver.h
> +++ b/src/driver.h
> @@ -881,6 +881,10 @@ typedef char *
>                                 int type,
>                                 const char *uri,
>                                 unsigned int flags);
> +typedef int
> +    (*virDrvDomainMigrateOffline)(virConnectPtr dconn,
> +                                  const char *file);
> +
>  
>  /**
>   * _virDriver:
> @@ -1068,6 +1072,7 @@ struct _virDriver {
>      virDrvDomainGetDiskErrors           domainGetDiskErrors;
>      virDrvDomainSetMetadata             domainSetMetadata;
>      virDrvDomainGetMetadata             domainGetMetadata;
> +    virDrvDomainMigrateOffline          domainMigrateOffline;
>  };
>  
>  typedef int
> diff --git a/src/libvirt.c b/src/libvirt.c
> index b034ed6..2878384 100644
> --- a/src/libvirt.c
> +++ b/src/libvirt.c
> @@ -5001,6 +5001,28 @@ virDomainMigratePeer2Peer (virDomainPtr domain,
>      }
>  }
>  
> +/**
> + * virDomainMigrateOffline:
> + * @dconn: target connection handler
> + * @file: the file to push to target
> + *
> + * to handle offline migration
> + * Returns -1 if error, else 0
> + */
> +int
> +virDomainMigrateOffline(virConnectPtr dconn,
> +                        char *file)
> +{
> +    VIR_DEBUG("dconn=%p, file=%s", dconn, NULLSTR(file));
> +
> +    if (!VIR_IS_CONNECT (dconn)) {
> +        virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__);
> +        virDispatchError(NULL);
> +        return -1;
> +    }
> +
> +    return dconn->driver->domainMigrateOffline(dconn, file);
> +}
>  
>  /*
>   * In normal migration, the libvirt client co-ordinates communication
> diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
> index 92ae95a..e6a7de7 100644
> --- a/src/libvirt_public.syms
> +++ b/src/libvirt_public.syms
> @@ -550,6 +550,7 @@ LIBVIRT_0.10.0 {
>          virConnectRegisterCloseCallback;
>          virConnectUnregisterCloseCallback;
>          virDomainGetSecurityLabelList;
> +	virDomainMigrateOffline;
>          virDomainPinEmulator;
>          virDomainGetEmulatorPinInfo;
>  } LIBVIRT_0.9.13;
> diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
> index cf1f079..0952783 100644
> --- a/src/remote/remote_driver.c
> +++ b/src/remote/remote_driver.c
> @@ -22,8 +22,12 @@
>   */
>  
>  #include <config.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
>  
>  #include <unistd.h>
> +#include <stdio.h>
>  #include <assert.h>
>  
>  #include "virnetclient.h"
> @@ -5247,6 +5251,71 @@ done:
>      return rv;
>  }
>  
> +static int
> +doRemoteReadFile(virStreamPtr st ATTRIBUTE_UNUSED,
> +                 char *buf, size_t nbytes, void *opaque)
> +{
> +    int *fd = opaque;
> +
> +    return read(*fd, buf, nbytes);
> +}
> +
> +static int
> +remoteDomainMigrateOffline(virConnectPtr dconn,
> +                           const char *name)
> +{
> +    int rv = -1, fd = -1;
> +    virStreamPtr st = virStreamNew(dconn, 0);
> +    remote_domain_migrate_offline_args args;
> +    remote_domain_migrate_offline_ret ret;
> +    struct private_data *priv = dconn->privateData;
> +    virNetClientStreamPtr netst = NULL;
> +
> +    remoteDriverLock(priv);
> +
> +    args.name = (char *)name;
> +    memset(&ret, 0, sizeof(ret));
> +
> +    if (!(netst = virNetClientStreamNew(priv->remoteProgram, REMOTE_PROC_DOMAIN_MIGRATE_OFFLINE, priv->counter)))
> +        goto done;
> +    if (virNetClientAddStream(priv->client, netst) < 0) {
> +        virObjectUnref(netst);
> +        goto done;
> +    }
> +    st->driver = &remoteStreamDrv;
> +    st->privateData = netst;
> +
> +    if ((fd = open(name, O_RDONLY)) < 0)
> +        goto done;
> +    if (fd == -1)
> +        goto done;
> +
> +    if (call (dconn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_OFFLINE,
> +              (xdrproc_t) xdr_remote_domain_migrate_offline_args, (char *) &args,
> +              (xdrproc_t) xdr_remote_domain_migrate_offline_ret, (char *) &ret) == -1) {
> +        virNetClientRemoveStream(priv->client, netst);
> +        virObjectUnref(netst);
> +        st->driver = NULL;
> +        st->privateData = NULL;
> +        goto done;
> +    }
> +
> +    remoteDriverUnlock(priv);
> +
> +    if (virStreamSendAll(st, doRemoteReadFile, &fd) < 0)
> +        goto done;
> +    if (virStreamFinish(st) < 0)
> +        goto done;
> +    if (VIR_CLOSE(fd) < 0)
> +        goto done;
> +
> +    rv = 0;
> +
> +done:
> +    return rv;
> +}
> +
> +
>  static void
>  remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event)
>  {
> @@ -5491,6 +5560,7 @@ static virDriver remote_driver = {
>      .domainEventDeregister = remoteDomainEventDeregister, /* 0.5.0 */
>      .domainMigratePrepare2 = remoteDomainMigratePrepare2, /* 0.5.0 */
>      .domainMigrateFinish2 = remoteDomainMigrateFinish2, /* 0.5.0 */
> +    .domainMigrateOffline = remoteDomainMigrateOffline, /* 0.10.1 */
>      .nodeDeviceDettach = remoteNodeDeviceDettach, /* 0.6.1 */
>      .nodeDeviceReAttach = remoteNodeDeviceReAttach, /* 0.6.1 */
>      .nodeDeviceReset = remoteNodeDeviceReset, /* 0.6.1 */
> diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
> index 085d5d9..c845737 100644
> --- a/src/remote/remote_protocol.x
> +++ b/src/remote/remote_protocol.x
> @@ -2558,6 +2558,13 @@ struct remote_connect_list_all_domains_ret {
>      unsigned int ret;
>  };
>  
> +struct remote_domain_migrate_offline_args {
> +    remote_nonnull_string name;
> +};
> +
> +struct remote_domain_migrate_offline_ret {
> +    int retval;
> +};
>  
>  /*----- Protocol. -----*/
>  
> @@ -2888,7 +2895,8 @@ enum remote_procedure {
>      REMOTE_PROC_DOMAIN_GET_HOSTNAME = 277, /* autogen autogen */
>      REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL_LIST = 278, /* skipgen skipgen priority:high */
>      REMOTE_PROC_DOMAIN_PIN_EMULATOR = 279, /* skipgen skipgen */
> -    REMOTE_PROC_DOMAIN_GET_EMULATOR_PIN_INFO = 280 /* skipgen skipgen */
> +    REMOTE_PROC_DOMAIN_GET_EMULATOR_PIN_INFO = 280, /* skipgen skipgen */
> +    REMOTE_PROC_DOMAIN_MIGRATE_OFFLINE = 281 /* skipgen skipgen priority:low*/
>  
>      /*
>       * Notice how the entries are grouped in sets of 10 ?
> diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
> index dbcaa25..70f7694 100644
> --- a/tools/virsh-domain.c
> +++ b/tools/virsh-domain.c
> @@ -6698,9 +6698,66 @@ static const vshCmdOptDef opts_migrate[] = {
>      {"dname", VSH_OT_DATA, 0, N_("rename to new name during migration (if supported)")},
>      {"timeout", VSH_OT_INT, 0, N_("force guest to suspend if live migration exceeds timeout (in seconds)")},
>      {"xml", VSH_OT_STRING, 0, N_("filename containing updated XML for the target")},
> +    {"offline", VSH_OT_BOOL, 0, N_("migration when there's no domain active")},
>      {NULL, 0, 0, NULL}
>  };
>  
> +static int
> +push_file(char dst[] ATTRIBUTE_UNUSED, char *file, virConnectPtr dconn)
> +{
> +    int ret = -1;
> +
> +    ret = virDomainMigrateOffline(dconn, file);
> +
> +    return ret;
> +}
> +
> +static void
> +vshMigrateOffline(vshControl *ctl, char *file, char dst[])
> +{
> +    xmlDocPtr xml = NULL;
> +    xmlXPathContextPtr ctxt = NULL;
> +    xmlNodePtr *disks = NULL;
> +    virConnectPtr dconn = NULL;
> +    int i = 0, ret = 0;
> +    char *src[] = {NULL};
> +
> +    if (!vshConnectionUsability(ctl, ctl->conn))
> +        return;
> +
> +    xml = virXMLParseFileCtxt(file, &ctxt);
> +    if (!xml) {
> +        vshError(NULL, "%s", _("Fail to get domain information from"));
> +        goto cleanup;
> +    }
> +
> +    ret = virXPathNodeSet("./devices/disk", ctxt, &disks);
> +    if (ret < 0) {
> +        vshError(NULL, "%s", _("Fail to get disk node"));
> +        goto cleanup;
> +    }
> +
> +    dconn = virConnectOpen(dst);
> +    if (!dconn)
> +        goto cleanup;
> +    vshPrint(ctl, "pushing %s to %s\n", file, dst);
> +    if (push_file(dst, file, dconn) < 0)
> +        goto cleanup;
> +    for (i = 0 ; i < ret ; i++) {
> +        ctxt->node = disks[i];
> +        src[i] = virXPathString("string(./source/@file"
> +                                "|./source/@dir"
> +                                "|./source/@name)", ctxt);
> +        vshPrint(ctl, "pushing %s to %s\n", src[i], dst);
> +        if (push_file(dst, src[i], dconn) < 0)
> +            break;
> +    }
> +
> +cleanup:
> +    xmlXPathFreeContext(ctxt);
> +    xmlFreeDoc(xml);
> +}
> +
>  static void
>  doMigrate(void *opaque)
>  {
> @@ -6767,12 +6824,24 @@ doMigrate(void *opaque)
>      if (vshCommandOptBool(cmd, "unsafe"))
>          flags |= VIR_MIGRATE_UNSAFE;
>  
> +    if (vshCommandOptBool(cmd, "offline")) {
> +        flags |= VIR_MIGRATE_OFFLINE;
> +        if (xmlfile == NULL)
> +            vshError(ctl, _("please specify xmlfile for offline migration"));
> +    }
> +
>      if (xmlfile &&
>          virFileReadAll(xmlfile, 8192, &xml) < 0) {
>          vshError(ctl, _("file '%s' doesn't exist"), xmlfile);
>          goto out;
>      }
>  
> +    if (flags & VIR_MIGRATE_OFFLINE) {
> +        vshMigrateOffline(ctl, (char *)xmlfile, (char *)desturi);
> +        goto out;
> +    }
> +
> +
>      if ((flags & VIR_MIGRATE_PEER2PEER) ||
>          vshCommandOptBool(cmd, "direct")) {
>          /* For peer2peer migration or direct migration we only expect one URI
> -- 
> 1.7.2.5
> 
> --
> libvir-list mailing list
> libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list

-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list