[libvirt] [PATCH V2 00/13] libxl: add basic support for migration

V2 of https://www.redhat.com/archives/libvir-list/2014-March/msg00156.html New in this version: not much. I rebased on the hostdev passthrough changes and added a few 'begin phase' checks to fail early if the domain is not migratable. See 13/13 for details. Based on an earlier patch from Chunyan Liu https://www.redhat.com/archives/libvir-list/2013-September/msg00667.html This patch series adds basic migration support to the libxl driver. Follow-up patches can improve pre-migration checks and add support for additional migration flags. Patches 1-12 are almost exclusively code motion, moving functions from the main driver module into the libxl_domain and libxl_conf modules. Patch 13 contains the actual migration impl. Jim Fehlig (13): libxl: move libxlDomainEventQueue to libxl_domain libxl: move libxlDomainManagedSavePath to libxl_domain libxl: move libxlSaveImageOpen to libxl_domain libxl: move libxlVmCleanup{,Job} to libxl_domain libxl: move libxlDomEventsRegister to libxl_domain libxl: move libxlDomainAutoCoreDump to libxl_domain libxl: move libxlDoNodeGetInfo to libxl_conf libxl: move libxlDomainSetVcpuAffinities to libxl_domain libxl: move libxlFreeMem to libxl_domain libxl: move libxlVmStart to libxl_domain libxl: include a pointer to the driver in libxlDomainObjPrivate libxl: move domain event handler to libxl_domain libxl: add migration support po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/libxl/libxl_conf.c | 36 ++ src/libxl/libxl_conf.h | 10 + src/libxl/libxl_domain.c | 705 +++++++++++++++++++++++++++++++ src/libxl/libxl_domain.h | 51 ++- src/libxl/libxl_driver.c | 988 +++++++++++--------------------------------- src/libxl/libxl_migration.c | 598 +++++++++++++++++++++++++++ src/libxl/libxl_migration.h | 78 ++++ 9 files changed, 1716 insertions(+), 754 deletions(-) create mode 100644 src/libxl/libxl_migration.c create mode 100644 src/libxl/libxl_migration.h -- 1.8.1.4

Move libxlDomainEventQueue from libxl_driver to libxl_domain for use by other libxl modules. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_domain.c | 6 ++++++ src/libxl/libxl_domain.h | 4 ++++ src/libxl/libxl_driver.c | 6 ------ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 274fb6c..e5a5720 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -548,3 +548,9 @@ cleanup: VIR_FREE(log_file); return ret; } + +void +libxlDomainEventQueue(libxlDriverPrivatePtr driver, virObjectEventPtr event) +{ + virObjectEventStateQueue(driver->domainEventState, event); +} diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index 0a29d38..dd57e57 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -91,4 +91,8 @@ libxlDomainObjEndJob(libxlDriverPrivatePtr driver, virDomainObjPtr obj) ATTRIBUTE_RETURN_CHECK; +void +libxlDomainEventQueue(libxlDriverPrivatePtr driver, + virObjectEventPtr event); + #endif /* LIBXL_DOMAIN_H */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index ae7342a..1c4d61b 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -102,12 +102,6 @@ libxlDomObjFromDomain(virDomainPtr dom) return vm; } -static void -libxlDomainEventQueue(libxlDriverPrivatePtr driver, virObjectEventPtr event) -{ - virObjectEventStateQueue(driver->domainEventState, event); -} - static int libxlAutostartDomain(virDomainObjPtr vm, void *opaque) -- 1.8.1.4

Move libxlDomainManagedSavePath from libxl_driver to libxl_domain for use by other libxl modules. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_domain.c | 10 ++++++++++ src/libxl/libxl_domain.h | 4 ++++ src/libxl/libxl_driver.c | 10 ---------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index e5a5720..04f26f8 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -554,3 +554,13 @@ libxlDomainEventQueue(libxlDriverPrivatePtr driver, virObjectEventPtr event) { virObjectEventStateQueue(driver->domainEventState, event); } + +char * +libxlDomainManagedSavePath(libxlDriverPrivatePtr driver, virDomainObjPtr vm) { + char *ret; + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + + ignore_value(virAsprintf(&ret, "%s/%s.save", cfg->saveDir, vm->def->name)); + virObjectUnref(cfg); + return ret; +} diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index dd57e57..5558009 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -95,4 +95,8 @@ void libxlDomainEventQueue(libxlDriverPrivatePtr driver, virObjectEventPtr event); +char * +libxlDomainManagedSavePath(libxlDriverPrivatePtr driver, + virDomainObjPtr vm); + #endif /* LIBXL_DOMAIN_H */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 1c4d61b..db7e954 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -164,16 +164,6 @@ cleanup: return ret; } -static char * -libxlDomainManagedSavePath(libxlDriverPrivatePtr driver, virDomainObjPtr vm) { - char *ret; - libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); - - ignore_value(virAsprintf(&ret, "%s/%s.save", cfg->saveDir, vm->def->name)); - virObjectUnref(cfg); - return ret; -} - /* * This internal function expects the driver lock to already be held on * entry. -- 1.8.1.4

Move libxlSaveImageOpen from libxl_driver to libxl_domain for use by other libxl modules. For consistency, rename to libxlDomainSaveImageOpen. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_domain.c | 76 +++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_domain.h | 8 +++++ src/libxl/libxl_driver.c | 80 +++--------------------------------------------- 3 files changed, 88 insertions(+), 76 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 04f26f8..eaa4d10 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -23,6 +23,8 @@ #include <config.h> +#include <fcntl.h> + #include "libxl_domain.h" #include "viralloc.h" @@ -564,3 +566,77 @@ libxlDomainManagedSavePath(libxlDriverPrivatePtr driver, virDomainObjPtr vm) { virObjectUnref(cfg); return ret; } + +/* + * Open a saved image file and initialize domain definition from the header. + * + * Returns the opened fd on success, -1 on failure. + */ +int +libxlDomainSaveImageOpen(libxlDriverPrivatePtr driver, + libxlDriverConfigPtr cfg, + const char *from, + virDomainDefPtr *ret_def, + libxlSavefileHeaderPtr ret_hdr) +{ + int fd; + virDomainDefPtr def = NULL; + libxlSavefileHeader hdr; + char *xml = NULL; + + if ((fd = virFileOpenAs(from, O_RDONLY, 0, -1, -1, 0)) < 0) { + virReportSystemError(-fd, + _("Failed to open domain image file '%s'"), from); + goto error; + } + + if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { + virReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("failed to read libxl header")); + goto error; + } + + if (memcmp(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic))) { + virReportError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect")); + goto error; + } + + if (hdr.version > LIBXL_SAVE_VERSION) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("image version is not supported (%d > %d)"), + hdr.version, LIBXL_SAVE_VERSION); + goto error; + } + + if (hdr.xmlLen <= 0) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("invalid XML length: %d"), hdr.xmlLen); + goto error; + } + + if (VIR_ALLOC_N(xml, hdr.xmlLen) < 0) + goto error; + + if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML")); + goto error; + } + + if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt, + 1 << VIR_DOMAIN_VIRT_XEN, + VIR_DOMAIN_XML_INACTIVE))) + goto error; + + VIR_FREE(xml); + + *ret_def = def; + *ret_hdr = hdr; + + return fd; + +error: + VIR_FREE(xml); + virDomainDefFree(def); + VIR_FORCE_CLOSE(fd); + return -1; +} diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index 5558009..3c1f5c0 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -99,4 +99,12 @@ char * libxlDomainManagedSavePath(libxlDriverPrivatePtr driver, virDomainObjPtr vm); +int +libxlDomainSaveImageOpen(libxlDriverPrivatePtr driver, + libxlDriverConfigPtr cfg, + const char *from, + virDomainDefPtr *ret_def, + libxlSavefileHeaderPtr ret_hdr) + ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5); + #endif /* LIBXL_DOMAIN_H */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index db7e954..c621f43 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -164,78 +164,6 @@ cleanup: return ret; } -/* - * This internal function expects the driver lock to already be held on - * entry. - */ -static int ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) -libxlSaveImageOpen(libxlDriverPrivatePtr driver, - libxlDriverConfigPtr cfg, - const char *from, - virDomainDefPtr *ret_def, - libxlSavefileHeaderPtr ret_hdr) -{ - int fd; - virDomainDefPtr def = NULL; - libxlSavefileHeader hdr; - char *xml = NULL; - - if ((fd = virFileOpenAs(from, O_RDONLY, 0, -1, -1, 0)) < 0) { - virReportSystemError(-fd, - _("Failed to open domain image file '%s'"), from); - goto error; - } - - if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { - virReportError(VIR_ERR_OPERATION_FAILED, - "%s", _("failed to read libxl header")); - goto error; - } - - if (memcmp(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic))) { - virReportError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect")); - goto error; - } - - if (hdr.version > LIBXL_SAVE_VERSION) { - virReportError(VIR_ERR_OPERATION_FAILED, - _("image version is not supported (%d > %d)"), - hdr.version, LIBXL_SAVE_VERSION); - goto error; - } - - if (hdr.xmlLen <= 0) { - virReportError(VIR_ERR_OPERATION_FAILED, - _("invalid XML length: %d"), hdr.xmlLen); - goto error; - } - - if (VIR_ALLOC_N(xml, hdr.xmlLen) < 0) - goto error; - - if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) { - virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML")); - goto error; - } - - if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt, - 1 << VIR_DOMAIN_VIRT_XEN, - VIR_DOMAIN_XML_INACTIVE))) - goto error; - - VIR_FREE(xml); - - *ret_def = def; - *ret_hdr = hdr; - - return fd; - -error: - VIR_FREE(xml); - virDomainDefFree(def); - VIR_FORCE_CLOSE(fd); - return -1; -} /* * Core dump domain to default dump path. @@ -708,9 +636,9 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, if (virFileExists(managed_save_path)) { - managed_save_fd = libxlSaveImageOpen(driver, cfg, - managed_save_path, - &def, &hdr); + managed_save_fd = libxlDomainSaveImageOpen(driver, cfg, + managed_save_path, + &def, &hdr); if (managed_save_fd < 0) goto endjob; @@ -2133,7 +2061,7 @@ libxlDomainRestoreFlags(virConnectPtr conn, const char *from, return -1; } - fd = libxlSaveImageOpen(driver, cfg, from, &def, &hdr); + fd = libxlDomainSaveImageOpen(driver, cfg, from, &def, &hdr); if (fd < 0) goto cleanup_unlock; -- 1.8.1.4

Move libxlVmCleanup and libxlVmCleanupJob from libxl_driver to libxl_domain for use by other libxl modules. For consistency, rename to libxlDomainCleanup and libxlDomainCleanupJob. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_domain.c | 91 ++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_domain.h | 10 +++++ src/libxl/libxl_driver.c | 102 +++-------------------------------------------- 3 files changed, 107 insertions(+), 96 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index eaa4d10..39577ef 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -28,6 +28,7 @@ #include "libxl_domain.h" #include "viralloc.h" +#include "viratomic.h" #include "virfile.h" #include "virerror.h" #include "virlog.h" @@ -640,3 +641,93 @@ error: VIR_FORCE_CLOSE(fd); return -1; } + +/* + * Cleanup function for domain that has reached shutoff state. + * + * virDomainObjPtr must be locked on invocation + */ +void +libxlDomainCleanup(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + virDomainShutoffReason reason) +{ + libxlDomainObjPrivatePtr priv = vm->privateData; + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + int vnc_port; + char *file; + size_t i; + virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr; + + virHostdevReAttachDomainDevices(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def, VIR_HOSTDEV_SP_PCI, NULL); + + vm->def->id = -1; + + if (priv->deathW) { + libxl_evdisable_domain_death(priv->ctx, priv->deathW); + priv->deathW = NULL; + } + + if (vm->persistent) + virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason); + + if (virAtomicIntDecAndTest(&driver->nactive) && driver->inhibitCallback) + driver->inhibitCallback(false, driver->inhibitOpaque); + + if ((vm->def->ngraphics == 1) && + vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && + vm->def->graphics[0]->data.vnc.autoport) { + vnc_port = vm->def->graphics[0]->data.vnc.port; + if (vnc_port >= LIBXL_VNC_PORT_MIN) { + if (virPortAllocatorRelease(driver->reservedVNCPorts, + vnc_port) < 0) + VIR_DEBUG("Could not mark port %d as unused", vnc_port); + } + } + + /* Remove any cputune settings */ + if (vm->def->cputune.nvcpupin) { + for (i = 0; i < vm->def->cputune.nvcpupin; ++i) { + virBitmapFree(vm->def->cputune.vcpupin[i]->cpumask); + VIR_FREE(vm->def->cputune.vcpupin[i]); + } + VIR_FREE(vm->def->cputune.vcpupin); + vm->def->cputune.nvcpupin = 0; + } + + if (virAsprintf(&file, "%s/%s.xml", cfg->stateDir, vm->def->name) > 0) { + if (unlink(file) < 0 && errno != ENOENT && errno != ENOTDIR) + VIR_DEBUG("Failed to remove domain XML for %s", vm->def->name); + VIR_FREE(file); + } + + if (vm->newDef) { + virDomainDefFree(vm->def); + vm->def = vm->newDef; + vm->def->id = -1; + vm->newDef = NULL; + } + + virObjectUnref(cfg); +} + +/* + * Cleanup function for domain that has reached shutoff state. + * Executed in the context of a job. + * + * virDomainObjPtr should be locked on invocation + * Returns true if references remain on virDomainObjPtr, false otherwise. + */ +bool +libxlDomainCleanupJob(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + virDomainShutoffReason reason) +{ + if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_DESTROY) < 0) + return true; + + libxlDomainCleanup(driver, vm, reason); + + return libxlDomainObjEndJob(driver, vm); +} diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index 3c1f5c0..949e1c2 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -107,4 +107,14 @@ libxlDomainSaveImageOpen(libxlDriverPrivatePtr driver, libxlSavefileHeaderPtr ret_hdr) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5); +void +libxlDomainCleanup(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + virDomainShutoffReason reason); + +bool +libxlDomainCleanupJob(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + virDomainShutoffReason reason); + #endif /* LIBXL_DOMAIN_H */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index c621f43..3b3c878 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -210,96 +210,6 @@ cleanup: } /* - * Cleanup function for domain that has reached shutoff state. - * - * virDomainObjPtr should be locked on invocation - */ -static void -libxlVmCleanup(libxlDriverPrivatePtr driver, - virDomainObjPtr vm, - virDomainShutoffReason reason) -{ - libxlDomainObjPrivatePtr priv = vm->privateData; - libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); - int vnc_port; - char *file; - size_t i; - virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr; - - virHostdevReAttachDomainDevices(hostdev_mgr, LIBXL_DRIVER_NAME, - vm->def, VIR_HOSTDEV_SP_PCI, NULL); - - vm->def->id = -1; - - if (priv->deathW) { - libxl_evdisable_domain_death(priv->ctx, priv->deathW); - priv->deathW = NULL; - } - - if (vm->persistent) - virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason); - - if (virAtomicIntDecAndTest(&driver->nactive) && driver->inhibitCallback) - driver->inhibitCallback(false, driver->inhibitOpaque); - - if ((vm->def->ngraphics == 1) && - vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && - vm->def->graphics[0]->data.vnc.autoport) { - vnc_port = vm->def->graphics[0]->data.vnc.port; - if (vnc_port >= LIBXL_VNC_PORT_MIN) { - if (virPortAllocatorRelease(driver->reservedVNCPorts, - vnc_port) < 0) - VIR_DEBUG("Could not mark port %d as unused", vnc_port); - } - } - - /* Remove any cputune settings */ - if (vm->def->cputune.nvcpupin) { - for (i = 0; i < vm->def->cputune.nvcpupin; ++i) { - virBitmapFree(vm->def->cputune.vcpupin[i]->cpumask); - VIR_FREE(vm->def->cputune.vcpupin[i]); - } - VIR_FREE(vm->def->cputune.vcpupin); - vm->def->cputune.nvcpupin = 0; - } - - if (virAsprintf(&file, "%s/%s.xml", cfg->stateDir, vm->def->name) > 0) { - if (unlink(file) < 0 && errno != ENOENT && errno != ENOTDIR) - VIR_DEBUG("Failed to remove domain XML for %s", vm->def->name); - VIR_FREE(file); - } - - if (vm->newDef) { - virDomainDefFree(vm->def); - vm->def = vm->newDef; - vm->def->id = -1; - vm->newDef = NULL; - } - - virObjectUnref(cfg); -} - -/* - * Cleanup function for domain that has reached shutoff state. - * Executed in the context of a job. - * - * virDomainObjPtr should be locked on invocation - * Returns true if references remain on virDomainObjPtr, false otherwise. - */ -static bool -libxlVmCleanupJob(libxlDriverPrivatePtr driver, - virDomainObjPtr vm, - virDomainShutoffReason reason) -{ - if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_DESTROY) < 0) - return true; - - libxlVmCleanup(driver, vm, reason); - - return libxlDomainObjEndJob(driver, vm); -} - -/* * Handle previously registered event notification from libxenlight. * * Note: Xen 4.3 removed the const from the event handler signature. @@ -397,7 +307,7 @@ destroy: dom_event = NULL; } libxl_domain_destroy(ctx, vm->def->id, NULL); - if (libxlVmCleanupJob(driver, vm, reason)) { + if (libxlDomainCleanupJob(driver, vm, reason)) { if (!vm->persistent) { virDomainObjListRemove(driver->domains, vm); vm = NULL; @@ -411,7 +321,7 @@ restart: dom_event = NULL; } libxl_domain_destroy(ctx, vm->def->id, NULL); - libxlVmCleanupJob(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN); + libxlDomainCleanupJob(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN); libxlVmStart(driver, vm, 0, -1); cleanup: @@ -832,7 +742,7 @@ libxlReconnectDomain(virDomainObjPtr vm, return 0; out: - libxlVmCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_UNKNOWN); + libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_UNKNOWN); if (!vm->persistent) virDomainObjListRemoveLocked(driver->domains, vm); else @@ -1629,7 +1539,7 @@ libxlDomainDestroyFlags(virDomainPtr dom, goto cleanup; } - if (libxlVmCleanupJob(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED)) { + if (libxlDomainCleanupJob(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED)) { if (!vm->persistent) { virDomainObjListRemove(driver->domains, vm); vm = NULL; @@ -1971,7 +1881,7 @@ libxlDoDomainSave(libxlDriverPrivatePtr driver, virDomainObjPtr vm, goto cleanup; } - libxlVmCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED); + libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED); vm->hasManagedSave = true; ret = 0; @@ -2164,7 +2074,7 @@ libxlDomainCoreDump(virDomainPtr dom, const char *to, unsigned int flags) goto unpause; } - libxlVmCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED); + libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED); event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, VIR_DOMAIN_EVENT_STOPPED_CRASHED); if (!vm->persistent) -- 1.8.1.4

Move libxlDomEventsRegister from libxl_driver to libxl_domain for use by other libxl modules. For consistency, rename to libxlDomainEventsRegister. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_domain.c | 24 ++++++++++++++++++++++++ src/libxl/libxl_domain.h | 4 +++- src/libxl/libxl_driver.c | 30 +++--------------------------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 39577ef..3608fbb 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -731,3 +731,27 @@ libxlDomainCleanupJob(libxlDriverPrivatePtr driver, return libxlDomainObjEndJob(driver, vm); } + +/* + * Register for domain events emitted by libxl. + */ +int +libxlDomainEventsRegister(virDomainObjPtr vm) +{ + libxlDomainObjPrivatePtr priv = vm->privateData; + + libxl_event_register_callbacks(priv->ctx, &ev_hooks, vm); + + /* Always enable domain death events */ + if (libxl_evenable_domain_death(priv->ctx, vm->def->id, 0, &priv->deathW)) + goto error; + + return 0; + +error: + if (priv->deathW) { + libxl_evdisable_domain_death(priv->ctx, priv->deathW); + priv->deathW = NULL; + } + return -1; +} diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index 949e1c2..1ac9174 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -75,7 +75,7 @@ struct _libxlDomainObjPrivate { extern virDomainXMLPrivateDataCallbacks libxlDomainXMLPrivateDataCallbacks; extern virDomainDefParserConfig libxlDomainDefParserConfig; - +extern const struct libxl_event_hooks ev_hooks; int libxlDomainObjPrivateInitCtx(virDomainObjPtr vm); @@ -116,5 +116,7 @@ bool libxlDomainCleanupJob(libxlDriverPrivatePtr driver, virDomainObjPtr vm, virDomainShutoffReason reason); +int +libxlDomainEventsRegister(virDomainObjPtr vm); #endif /* LIBXL_DOMAIN_H */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 3b3c878..ed1d6b2 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -382,36 +382,12 @@ error: libxl_event_free(priv->ctx, (libxl_event *)event); } -static const struct libxl_event_hooks ev_hooks = { +const struct libxl_event_hooks ev_hooks = { .event_occurs_mask = LIBXL_EVENTMASK_ALL, .event_occurs = libxlEventHandler, .disaster = NULL, }; -/* - * Register for domain events emitted by libxl. - */ -static int -libxlDomEventsRegister(virDomainObjPtr vm) -{ - libxlDomainObjPrivatePtr priv = vm->privateData; - - libxl_event_register_callbacks(priv->ctx, &ev_hooks, vm); - - /* Always enable domain death events */ - if (libxl_evenable_domain_death(priv->ctx, vm->def->id, 0, &priv->deathW)) - goto error; - - return 0; - -error: - if (priv->deathW) { - libxl_evdisable_domain_death(priv->ctx, priv->deathW); - priv->deathW = NULL; - } - return -1; -} - static int libxlDomainSetVcpuAffinities(libxlDriverPrivatePtr driver, virDomainObjPtr vm) { @@ -629,7 +605,7 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, * be cleaned up if there are any subsequent failures. */ vm->def->id = domid; - if (libxlDomEventsRegister(vm) < 0) + if (libxlDomainEventsRegister(vm) < 0) goto cleanup_dom; if ((dom_xml = virDomainDefFormat(vm->def, 0)) == NULL) @@ -737,7 +713,7 @@ libxlReconnectDomain(virDomainObjPtr vm, driver->inhibitCallback(true, driver->inhibitOpaque); /* Re-register domain death et. al. events */ - libxlDomEventsRegister(vm); + libxlDomainEventsRegister(vm); virObjectUnlock(vm); return 0; -- 1.8.1.4

Move libxlDomainAutoCoreDump from libxl_driver to libxl_domain for use by other libxl modules. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_domain.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_domain.h | 4 ++++ src/libxl/libxl_driver.c | 44 -------------------------------------------- 3 files changed, 48 insertions(+), 44 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 3608fbb..dceba9f 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -755,3 +755,47 @@ error: } return -1; } + +/* + * Core dump domain to default dump path. + * + * virDomainObjPtr must be locked on invocation + */ +int +libxlDomainAutoCoreDump(libxlDriverPrivatePtr driver, + virDomainObjPtr vm) +{ + libxlDomainObjPrivatePtr priv = vm->privateData; + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + time_t curtime = time(NULL); + char timestr[100]; + struct tm time_info; + char *dumpfile = NULL; + int ret = -1; + + localtime_r(&curtime, &time_info); + strftime(timestr, sizeof(timestr), "%Y-%m-%d-%H:%M:%S", &time_info); + + if (virAsprintf(&dumpfile, "%s/%s-%s", + cfg->autoDumpDir, + vm->def->name, + timestr) < 0) + goto cleanup; + + if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) + goto cleanup; + + /* Unlock virDomainObj while dumping core */ + virObjectUnlock(vm); + libxl_domain_core_dump(priv->ctx, vm->def->id, dumpfile, NULL); + virObjectLock(vm); + + ignore_value(libxlDomainObjEndJob(driver, vm)); + ret = 0; + +cleanup: + VIR_FREE(dumpfile); + virObjectUnref(cfg); + + return ret; +} diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index 1ac9174..a50efd3 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -119,4 +119,8 @@ libxlDomainCleanupJob(libxlDriverPrivatePtr driver, int libxlDomainEventsRegister(virDomainObjPtr vm); +int +libxlDomainAutoCoreDump(libxlDriverPrivatePtr driver, + virDomainObjPtr vm); + #endif /* LIBXL_DOMAIN_H */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index ed1d6b2..033d678c 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -166,50 +166,6 @@ cleanup: /* - * Core dump domain to default dump path. - * - * virDomainObjPtr must be locked on invocation - */ -static int -libxlDomainAutoCoreDump(libxlDriverPrivatePtr driver, - virDomainObjPtr vm) -{ - libxlDomainObjPrivatePtr priv = vm->privateData; - libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); - time_t curtime = time(NULL); - char timestr[100]; - struct tm time_info; - char *dumpfile = NULL; - int ret = -1; - - localtime_r(&curtime, &time_info); - strftime(timestr, sizeof(timestr), "%Y-%m-%d-%H:%M:%S", &time_info); - - if (virAsprintf(&dumpfile, "%s/%s-%s", - cfg->autoDumpDir, - vm->def->name, - timestr) < 0) - goto cleanup; - - if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) - goto cleanup; - - /* Unlock virDomainObj while dumping core */ - virObjectUnlock(vm); - libxl_domain_core_dump(priv->ctx, vm->def->id, dumpfile, NULL); - virObjectLock(vm); - - ignore_value(libxlDomainObjEndJob(driver, vm)); - ret = 0; - -cleanup: - VIR_FREE(dumpfile); - virObjectUnref(cfg); - - return ret; -} - -/* * Handle previously registered event notification from libxenlight. * * Note: Xen 4.3 removed the const from the event handler signature. -- 1.8.1.4

Move libxlDoNodeGetInfo from libxl_driver to libxl_conf for use by other libxl modules. For consistency, rename to libxlDriverNodeGetInfo. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_conf.c | 36 ++++++++++++++++++++++++++++++++++++ src/libxl/libxl_conf.h | 4 ++++ src/libxl/libxl_driver.c | 41 ++--------------------------------------- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 8ba3ce3..f6a63e6 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -1207,6 +1207,42 @@ error: return -1; } +int +libxlDriverNodeGetInfo(libxlDriverPrivatePtr driver, virNodeInfoPtr info) +{ + libxl_physinfo phy_info; + virArch hostarch = virArchFromHost(); + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + int ret = -1; + + if (libxl_get_physinfo(cfg->ctx, &phy_info)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("libxl_get_physinfo_info failed")); + goto cleanup; + } + + if (virStrcpyStatic(info->model, virArchToString(hostarch)) == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("machine type %s too big for destination"), + virArchToString(hostarch)); + goto cleanup; + } + + info->memory = phy_info.total_pages * (cfg->verInfo->pagesize / 1024); + info->cpus = phy_info.nr_cpus; + info->nodes = phy_info.nr_nodes; + info->cores = phy_info.cores_per_socket; + info->threads = phy_info.threads_per_core; + info->sockets = 1; + info->mhz = phy_info.cpu_khz / 1000; + + ret = 0; + +cleanup: + virObjectUnref(cfg); + return ret; +} + virCapsPtr libxlMakeCapabilities(libxl_ctx *ctx) { diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index 4f6f7ce..5a340b9 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -138,6 +138,10 @@ libxlDriverConfigNew(void); libxlDriverConfigPtr libxlDriverConfigGet(libxlDriverPrivatePtr driver); +int +libxlDriverNodeGetInfo(libxlDriverPrivatePtr driver, + virNodeInfoPtr info); + virCapsPtr libxlMakeCapabilities(libxl_ctx *ctx); diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 033d678c..36e3e25 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -128,43 +128,6 @@ cleanup: return ret; } -static int -libxlDoNodeGetInfo(libxlDriverPrivatePtr driver, virNodeInfoPtr info) -{ - libxl_physinfo phy_info; - virArch hostarch = virArchFromHost(); - libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); - int ret = -1; - - if (libxl_get_physinfo(cfg->ctx, &phy_info)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("libxl_get_physinfo_info failed")); - goto cleanup; - } - - if (virStrcpyStatic(info->model, virArchToString(hostarch)) == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("machine type %s too big for destination"), - virArchToString(hostarch)); - goto cleanup; - } - - info->memory = phy_info.total_pages * (cfg->verInfo->pagesize / 1024); - info->cpus = phy_info.nr_cpus; - info->nodes = phy_info.nr_nodes; - info->cores = phy_info.cores_per_socket; - info->threads = phy_info.threads_per_core; - info->sockets = 1; - info->mhz = phy_info.cpu_khz / 1000; - - ret = 0; - -cleanup: - virObjectUnref(cfg); - return ret; -} - - /* * Handle previously registered event notification from libxenlight. * @@ -358,7 +321,7 @@ libxlDomainSetVcpuAffinities(libxlDriverPrivatePtr driver, virDomainObjPtr vm) size_t i; int ret = -1; - if (libxlDoNodeGetInfo(driver, &nodeinfo) < 0) + if (libxlDriverNodeGetInfo(driver, &nodeinfo) < 0) goto cleanup; cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo)); @@ -1061,7 +1024,7 @@ libxlNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) if (virNodeGetInfoEnsureACL(conn) < 0) return -1; - return libxlDoNodeGetInfo(conn->privateData, info); + return libxlDriverNodeGetInfo(conn->privateData, info); } static char * -- 1.8.1.4

Move libxlDomainSetVcpuAffinities from libxl_driver to libxl_domain for use by other libxl modules. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_domain.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_domain.h | 4 ++++ src/libxl/libxl_driver.c | 54 ------------------------------------------------ 3 files changed, 58 insertions(+), 54 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index dceba9f..afe891f 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -799,3 +799,57 @@ cleanup: return ret; } + +int +libxlDomainSetVcpuAffinities(libxlDriverPrivatePtr driver, virDomainObjPtr vm) +{ + libxlDomainObjPrivatePtr priv = vm->privateData; + virDomainDefPtr def = vm->def; + libxl_bitmap map; + virBitmapPtr cpumask = NULL; + uint8_t *cpumap = NULL; + virNodeInfo nodeinfo; + size_t cpumaplen; + int vcpu; + size_t i; + int ret = -1; + + if (libxlDriverNodeGetInfo(driver, &nodeinfo) < 0) + goto cleanup; + + cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo)); + + for (vcpu = 0; vcpu < def->cputune.nvcpupin; ++vcpu) { + if (vcpu != def->cputune.vcpupin[vcpu]->vcpuid) + continue; + + if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) + goto cleanup; + + cpumask = def->cputune.vcpupin[vcpu]->cpumask; + + for (i = 0; i < virBitmapSize(cpumask); ++i) { + bool bit; + ignore_value(virBitmapGetBit(cpumask, i, &bit)); + if (bit) + VIR_USE_CPU(cpumap, i); + } + + map.size = cpumaplen; + map.map = cpumap; + + if (libxl_set_vcpuaffinity(priv->ctx, def->id, vcpu, &map) != 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to pin vcpu '%d' with libxenlight"), vcpu); + goto cleanup; + } + + VIR_FREE(cpumap); + } + + ret = 0; + +cleanup: + VIR_FREE(cpumap); + return ret; +} diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index a50efd3..775a91c 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -123,4 +123,8 @@ int libxlDomainAutoCoreDump(libxlDriverPrivatePtr driver, virDomainObjPtr vm); +int +libxlDomainSetVcpuAffinities(libxlDriverPrivatePtr driver, + virDomainObjPtr vm); + #endif /* LIBXL_DOMAIN_H */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 36e3e25..80b9e93 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -308,60 +308,6 @@ const struct libxl_event_hooks ev_hooks = { }; static int -libxlDomainSetVcpuAffinities(libxlDriverPrivatePtr driver, virDomainObjPtr vm) -{ - libxlDomainObjPrivatePtr priv = vm->privateData; - virDomainDefPtr def = vm->def; - libxl_bitmap map; - virBitmapPtr cpumask = NULL; - uint8_t *cpumap = NULL; - virNodeInfo nodeinfo; - size_t cpumaplen; - int vcpu; - size_t i; - int ret = -1; - - if (libxlDriverNodeGetInfo(driver, &nodeinfo) < 0) - goto cleanup; - - cpumaplen = VIR_CPU_MAPLEN(VIR_NODEINFO_MAXCPUS(nodeinfo)); - - for (vcpu = 0; vcpu < def->cputune.nvcpupin; ++vcpu) { - if (vcpu != def->cputune.vcpupin[vcpu]->vcpuid) - continue; - - if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) - goto cleanup; - - cpumask = def->cputune.vcpupin[vcpu]->cpumask; - - for (i = 0; i < virBitmapSize(cpumask); ++i) { - bool bit; - ignore_value(virBitmapGetBit(cpumask, i, &bit)); - if (bit) - VIR_USE_CPU(cpumap, i); - } - - map.size = cpumaplen; - map.map = cpumap; - - if (libxl_set_vcpuaffinity(priv->ctx, def->id, vcpu, &map) != 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to pin vcpu '%d' with libxenlight"), vcpu); - goto cleanup; - } - - VIR_FREE(cpumap); - } - - ret = 0; - -cleanup: - VIR_FREE(cpumap); - return ret; -} - -static int libxlFreeMem(libxlDomainObjPrivatePtr priv, libxl_domain_config *d_config) { uint32_t needed_mem; -- 1.8.1.4

Move libxlFreeMem from libxl_driver to libxl_domain for use by other libxl modules. For consistency, rename to libxlDomainFreeMem. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_domain.c | 39 +++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_domain.h | 4 ++++ src/libxl/libxl_driver.c | 41 +---------------------------------------- 3 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index afe891f..3163c2a 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -853,3 +853,42 @@ cleanup: VIR_FREE(cpumap); return ret; } + +int +libxlDomainFreeMem(libxlDomainObjPrivatePtr priv, libxl_domain_config *d_config) +{ + uint32_t needed_mem; + uint32_t free_mem; + size_t i; + int ret = -1; + int tries = 3; + int wait_secs = 10; + + if ((ret = libxl_domain_need_memory(priv->ctx, &d_config->b_info, + &needed_mem)) >= 0) { + for (i = 0; i < tries; ++i) { + if ((ret = libxl_get_free_memory(priv->ctx, &free_mem)) < 0) + break; + + if (free_mem >= needed_mem) { + ret = 0; + break; + } + + if ((ret = libxl_set_memory_target(priv->ctx, 0, + free_mem - needed_mem, + /* relative */ 1, 0)) < 0) + break; + + ret = libxl_wait_for_free_memory(priv->ctx, 0, needed_mem, + wait_secs); + if (ret == 0 || ret != ERROR_NOMEM) + break; + + if ((ret = libxl_wait_for_memory_target(priv->ctx, 0, 1)) < 0) + break; + } + } + + return ret; +} diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index 775a91c..7dacb36 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -127,4 +127,8 @@ int libxlDomainSetVcpuAffinities(libxlDriverPrivatePtr driver, virDomainObjPtr vm); +int +libxlDomainFreeMem(libxlDomainObjPrivatePtr priv, + libxl_domain_config *d_config); + #endif /* LIBXL_DOMAIN_H */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 80b9e93..add08d2 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -307,45 +307,6 @@ const struct libxl_event_hooks ev_hooks = { .disaster = NULL, }; -static int -libxlFreeMem(libxlDomainObjPrivatePtr priv, libxl_domain_config *d_config) -{ - uint32_t needed_mem; - uint32_t free_mem; - size_t i; - int ret = -1; - int tries = 3; - int wait_secs = 10; - - if ((ret = libxl_domain_need_memory(priv->ctx, &d_config->b_info, - &needed_mem)) >= 0) { - for (i = 0; i < tries; ++i) { - if ((ret = libxl_get_free_memory(priv->ctx, &free_mem)) < 0) - break; - - if (free_mem >= needed_mem) { - ret = 0; - break; - } - - if ((ret = libxl_set_memory_target(priv->ctx, 0, - free_mem - needed_mem, - /* relative */ 1, 0)) < 0) - break; - - ret = libxl_wait_for_free_memory(priv->ctx, 0, needed_mem, - wait_secs); - if (ret == 0 || ret != ERROR_NOMEM) - break; - - if ((ret = libxl_wait_for_memory_target(priv->ctx, 0, 1)) < 0) - break; - } - } - - return ret; -} - /* * Start a domain through libxenlight. * @@ -425,7 +386,7 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, if (libxlBuildDomainConfig(driver, vm, &d_config) < 0) goto endjob; - if (cfg->autoballoon && libxlFreeMem(priv, &d_config) < 0) { + if (cfg->autoballoon && libxlDomainFreeMem(priv, &d_config) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, _("libxenlight failed to get free memory for domain '%s'"), d_config.c_info.name); -- 1.8.1.4

Move libxlVmStart from libxl_driver to libxl_domain for use by other libxl modules. For consistency, rename to libxlDomainStart. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_domain.c | 181 +++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_domain.h | 6 ++ src/libxl/libxl_driver.c | 196 ++--------------------------------------------- 3 files changed, 192 insertions(+), 191 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 3163c2a..c5b18a1 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -892,3 +892,184 @@ libxlDomainFreeMem(libxlDomainObjPrivatePtr priv, libxl_domain_config *d_config) return ret; } + +/* + * Start a domain through libxenlight. + * + * virDomainObjPtr must be locked on invocation + */ +int +libxlDomainStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, + bool start_paused, int restore_fd) +{ + libxl_domain_config d_config; + virDomainDefPtr def = NULL; + virObjectEventPtr event = NULL; + libxlSavefileHeader hdr; + int ret = -1; + uint32_t domid = 0; + char *dom_xml = NULL; + char *managed_save_path = NULL; + int managed_save_fd = -1; + libxlDomainObjPrivatePtr priv = vm->privateData; + libxlDriverConfigPtr cfg; +#ifdef LIBXL_HAVE_DOMAIN_CREATE_RESTORE_PARAMS + libxl_domain_restore_params params; +#endif + virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr; + + if (libxlDomainObjPrivateInitCtx(vm) < 0) + return ret; + + if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) + return ret; + + cfg = libxlDriverConfigGet(driver); + /* If there is a managed saved state restore it instead of starting + * from scratch. The old state is removed once the restoring succeeded. */ + if (restore_fd < 0) { + managed_save_path = libxlDomainManagedSavePath(driver, vm); + if (managed_save_path == NULL) + goto endjob; + + if (virFileExists(managed_save_path)) { + + managed_save_fd = libxlDomainSaveImageOpen(driver, cfg, + managed_save_path, + &def, &hdr); + if (managed_save_fd < 0) + goto endjob; + + restore_fd = managed_save_fd; + + if (STRNEQ(vm->def->name, def->name) || + memcmp(vm->def->uuid, def->uuid, VIR_UUID_BUFLEN)) { + char vm_uuidstr[VIR_UUID_STRING_BUFLEN]; + char def_uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(vm->def->uuid, vm_uuidstr); + virUUIDFormat(def->uuid, def_uuidstr); + virReportError(VIR_ERR_OPERATION_FAILED, + _("cannot restore domain '%s' uuid %s from a file" + " which belongs to domain '%s' uuid %s"), + vm->def->name, vm_uuidstr, def->name, def_uuidstr); + goto endjob; + } + + virDomainObjAssignDef(vm, def, true, NULL); + def = NULL; + + if (unlink(managed_save_path) < 0) + VIR_WARN("Failed to remove the managed state %s", + managed_save_path); + + vm->hasManagedSave = false; + } + VIR_FREE(managed_save_path); + } + + libxl_domain_config_init(&d_config); + + if (libxlBuildDomainConfig(driver, vm, &d_config) < 0) + goto endjob; + + if (cfg->autoballoon && libxlDomainFreeMem(priv, &d_config) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("libxenlight failed to get free memory for domain '%s'"), + d_config.c_info.name); + goto endjob; + } + + if (virHostdevPrepareDomainDevices(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def, VIR_HOSTDEV_SP_PCI) < 0) + goto endjob; + + /* Unlock virDomainObj while creating the domain */ + virObjectUnlock(vm); + if (restore_fd < 0) { + ret = libxl_domain_create_new(priv->ctx, &d_config, + &domid, NULL, NULL); + } else { +#ifdef LIBXL_HAVE_DOMAIN_CREATE_RESTORE_PARAMS + params.checkpointed_stream = 0; + ret = libxl_domain_create_restore(priv->ctx, &d_config, &domid, + restore_fd, ¶ms, NULL, NULL); +#else + ret = libxl_domain_create_restore(priv->ctx, &d_config, &domid, + restore_fd, NULL, NULL); +#endif + } + virObjectLock(vm); + + if (ret) { + if (restore_fd < 0) + virReportError(VIR_ERR_INTERNAL_ERROR, + _("libxenlight failed to create new domain '%s'"), + d_config.c_info.name); + else + virReportError(VIR_ERR_INTERNAL_ERROR, + _("libxenlight failed to restore domain '%s'"), + d_config.c_info.name); + goto endjob; + } + + /* + * The domain has been successfully created with libxl, so it should + * be cleaned up if there are any subsequent failures. + */ + vm->def->id = domid; + if (libxlDomainEventsRegister(vm) < 0) + goto cleanup_dom; + + if ((dom_xml = virDomainDefFormat(vm->def, 0)) == NULL) + goto cleanup_dom; + + if (libxl_userdata_store(priv->ctx, domid, "libvirt-xml", + (uint8_t *)dom_xml, strlen(dom_xml) + 1)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("libxenlight failed to store userdata")); + goto cleanup_dom; + } + + if (libxlDomainSetVcpuAffinities(driver, vm) < 0) + goto cleanup_dom; + + if (!start_paused) { + libxl_domain_unpause(priv->ctx, domid); + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED); + } else { + virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER); + } + + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) + goto cleanup_dom; + + if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) + driver->inhibitCallback(true, driver->inhibitOpaque); + + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED, + restore_fd < 0 ? + VIR_DOMAIN_EVENT_STARTED_BOOTED : + VIR_DOMAIN_EVENT_STARTED_RESTORED); + if (event) + libxlDomainEventQueue(driver, event); + + ret = 0; + goto endjob; + +cleanup_dom: + libxl_domain_destroy(priv->ctx, domid, NULL); + vm->def->id = -1; + virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED); + +endjob: + if (!libxlDomainObjEndJob(driver, vm)) + vm = NULL; + + libxl_domain_config_dispose(&d_config); + VIR_FREE(dom_xml); + VIR_FREE(managed_save_path); + virDomainDefFree(def); + VIR_FORCE_CLOSE(managed_save_fd); + virObjectUnref(cfg); + return ret; +} diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index 7dacb36..4b5767a 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -131,4 +131,10 @@ int libxlDomainFreeMem(libxlDomainObjPrivatePtr priv, libxl_domain_config *d_config); +int +libxlDomainStart(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + bool start_paused, + int restore_fd); + #endif /* LIBXL_DOMAIN_H */ diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index add08d2..af7317b 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -77,10 +77,6 @@ static int libxlDomainManagedSaveLoad(virDomainObjPtr vm, void *opaque); -static int -libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, - bool start_paused, int restore_fd); - /* Function definitions */ static virDomainObjPtr @@ -114,7 +110,7 @@ libxlAutostartDomain(virDomainObjPtr vm, virResetLastError(); if (vm->autostart && !virDomainObjIsActive(vm) && - libxlVmStart(driver, vm, false, -1) < 0) { + libxlDomainStart(driver, vm, false, -1) < 0) { err = virGetLastError(); VIR_ERROR(_("Failed to autostart VM '%s': %s"), vm->def->name, @@ -241,7 +237,7 @@ restart: } libxl_domain_destroy(ctx, vm->def->id, NULL); libxlDomainCleanupJob(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN); - libxlVmStart(driver, vm, 0, -1); + libxlDomainStart(driver, vm, 0, -1); cleanup: if (vm) @@ -308,188 +304,6 @@ const struct libxl_event_hooks ev_hooks = { }; /* - * Start a domain through libxenlight. - * - * virDomainObjPtr should be locked on invocation - */ -static int -libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, - bool start_paused, int restore_fd) -{ - libxl_domain_config d_config; - virDomainDefPtr def = NULL; - virObjectEventPtr event = NULL; - libxlSavefileHeader hdr; - int ret = -1; - uint32_t domid = 0; - char *dom_xml = NULL; - char *managed_save_path = NULL; - int managed_save_fd = -1; - libxlDomainObjPrivatePtr priv = vm->privateData; - libxlDriverConfigPtr cfg; -#ifdef LIBXL_HAVE_DOMAIN_CREATE_RESTORE_PARAMS - libxl_domain_restore_params params; -#endif - virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr; - - if (libxlDomainObjPrivateInitCtx(vm) < 0) - return ret; - - if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) - return ret; - - cfg = libxlDriverConfigGet(driver); - /* If there is a managed saved state restore it instead of starting - * from scratch. The old state is removed once the restoring succeeded. */ - if (restore_fd < 0) { - managed_save_path = libxlDomainManagedSavePath(driver, vm); - if (managed_save_path == NULL) - goto endjob; - - if (virFileExists(managed_save_path)) { - - managed_save_fd = libxlDomainSaveImageOpen(driver, cfg, - managed_save_path, - &def, &hdr); - if (managed_save_fd < 0) - goto endjob; - - restore_fd = managed_save_fd; - - if (STRNEQ(vm->def->name, def->name) || - memcmp(vm->def->uuid, def->uuid, VIR_UUID_BUFLEN)) { - char vm_uuidstr[VIR_UUID_STRING_BUFLEN]; - char def_uuidstr[VIR_UUID_STRING_BUFLEN]; - virUUIDFormat(vm->def->uuid, vm_uuidstr); - virUUIDFormat(def->uuid, def_uuidstr); - virReportError(VIR_ERR_OPERATION_FAILED, - _("cannot restore domain '%s' uuid %s from a file" - " which belongs to domain '%s' uuid %s"), - vm->def->name, vm_uuidstr, def->name, def_uuidstr); - goto endjob; - } - - virDomainObjAssignDef(vm, def, true, NULL); - def = NULL; - - if (unlink(managed_save_path) < 0) - VIR_WARN("Failed to remove the managed state %s", - managed_save_path); - - vm->hasManagedSave = false; - } - VIR_FREE(managed_save_path); - } - - libxl_domain_config_init(&d_config); - - if (libxlBuildDomainConfig(driver, vm, &d_config) < 0) - goto endjob; - - if (cfg->autoballoon && libxlDomainFreeMem(priv, &d_config) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("libxenlight failed to get free memory for domain '%s'"), - d_config.c_info.name); - goto endjob; - } - - if (virHostdevPrepareDomainDevices(hostdev_mgr, LIBXL_DRIVER_NAME, - vm->def, VIR_HOSTDEV_SP_PCI) < 0) - goto endjob; - - /* Unlock virDomainObj while creating the domain */ - virObjectUnlock(vm); - if (restore_fd < 0) { - ret = libxl_domain_create_new(priv->ctx, &d_config, - &domid, NULL, NULL); - } else { -#ifdef LIBXL_HAVE_DOMAIN_CREATE_RESTORE_PARAMS - params.checkpointed_stream = 0; - ret = libxl_domain_create_restore(priv->ctx, &d_config, &domid, - restore_fd, ¶ms, NULL, NULL); -#else - ret = libxl_domain_create_restore(priv->ctx, &d_config, &domid, - restore_fd, NULL, NULL); -#endif - } - virObjectLock(vm); - - if (ret) { - if (restore_fd < 0) - virReportError(VIR_ERR_INTERNAL_ERROR, - _("libxenlight failed to create new domain '%s'"), - d_config.c_info.name); - else - virReportError(VIR_ERR_INTERNAL_ERROR, - _("libxenlight failed to restore domain '%s'"), - d_config.c_info.name); - goto endjob; - } - - /* - * The domain has been successfully created with libxl, so it should - * be cleaned up if there are any subsequent failures. - */ - vm->def->id = domid; - if (libxlDomainEventsRegister(vm) < 0) - goto cleanup_dom; - - if ((dom_xml = virDomainDefFormat(vm->def, 0)) == NULL) - goto cleanup_dom; - - if (libxl_userdata_store(priv->ctx, domid, "libvirt-xml", - (uint8_t *)dom_xml, strlen(dom_xml) + 1)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("libxenlight failed to store userdata")); - goto cleanup_dom; - } - - if (libxlDomainSetVcpuAffinities(driver, vm) < 0) - goto cleanup_dom; - - if (!start_paused) { - libxl_domain_unpause(priv->ctx, domid); - virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED); - } else { - virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER); - } - - if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) - goto cleanup_dom; - - if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) - driver->inhibitCallback(true, driver->inhibitOpaque); - - event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED, - restore_fd < 0 ? - VIR_DOMAIN_EVENT_STARTED_BOOTED : - VIR_DOMAIN_EVENT_STARTED_RESTORED); - if (event) - libxlDomainEventQueue(driver, event); - - ret = 0; - goto endjob; - -cleanup_dom: - libxl_domain_destroy(priv->ctx, domid, NULL); - vm->def->id = -1; - virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED); - -endjob: - if (!libxlDomainObjEndJob(driver, vm)) - vm = NULL; - - libxl_domain_config_dispose(&d_config); - VIR_FREE(dom_xml); - VIR_FREE(managed_save_path); - virDomainDefFree(def); - VIR_FORCE_CLOSE(managed_save_fd); - virObjectUnref(cfg); - return ret; -} - - -/* * Reconnect to running domains that were previously started/created * with libxenlight driver. */ @@ -1009,7 +823,7 @@ libxlDomainCreateXML(virConnectPtr conn, const char *xml, goto cleanup; def = NULL; - if (libxlVmStart(driver, vm, (flags & VIR_DOMAIN_START_PAUSED) != 0, + if (libxlDomainStart(driver, vm, (flags & VIR_DOMAIN_START_PAUSED) != 0, -1) < 0) { virDomainObjListRemove(driver->domains, vm); vm = NULL; @@ -1789,7 +1603,7 @@ libxlDomainRestoreFlags(virConnectPtr conn, const char *from, def = NULL; - ret = libxlVmStart(driver, vm, (flags & VIR_DOMAIN_SAVE_PAUSED) != 0, fd); + ret = libxlDomainStart(driver, vm, (flags & VIR_DOMAIN_SAVE_PAUSED) != 0, fd); if (ret < 0 && !vm->persistent) { virDomainObjListRemove(driver->domains, vm); vm = NULL; @@ -2677,7 +2491,7 @@ libxlDomainCreateWithFlags(virDomainPtr dom, goto cleanup; } - ret = libxlVmStart(driver, vm, (flags & VIR_DOMAIN_START_PAUSED) != 0, -1); + ret = libxlDomainStart(driver, vm, (flags & VIR_DOMAIN_START_PAUSED) != 0, -1); cleanup: if (vm) -- 1.8.1.4

Include a pointer to the libxl driver in libxlDomainObjPrivate object so it can be used in the domain event handler and shutdown thread. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_domain.c | 5 +++-- src/libxl/libxl_domain.h | 4 +++- src/libxl/libxl_driver.c | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index c5b18a1..606469e 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -736,10 +736,11 @@ libxlDomainCleanupJob(libxlDriverPrivatePtr driver, * Register for domain events emitted by libxl. */ int -libxlDomainEventsRegister(virDomainObjPtr vm) +libxlDomainEventsRegister(libxlDriverPrivatePtr driver, virDomainObjPtr vm) { libxlDomainObjPrivatePtr priv = vm->privateData; + priv->driver = driver; libxl_event_register_callbacks(priv->ctx, &ev_hooks, vm); /* Always enable domain death events */ @@ -1017,7 +1018,7 @@ libxlDomainStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, * be cleaned up if there are any subsequent failures. */ vm->def->id = domid; - if (libxlDomainEventsRegister(vm) < 0) + if (libxlDomainEventsRegister(driver, vm) < 0) goto cleanup_dom; if ((dom_xml = virDomainDefFormat(vm->def, 0)) == NULL) diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index 4b5767a..979ce2a 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -68,6 +68,7 @@ struct _libxlDomainObjPrivate { /* console */ virChrdevsPtr devs; libxl_evgen_domain_death *deathW; + libxlDriverPrivatePtr driver; struct libxlDomainJobObj job; }; @@ -117,7 +118,8 @@ libxlDomainCleanupJob(libxlDriverPrivatePtr driver, virDomainObjPtr vm, virDomainShutoffReason reason); int -libxlDomainEventsRegister(virDomainObjPtr vm); +libxlDomainEventsRegister(libxlDriverPrivatePtr driver, + virDomainObjPtr vm); int libxlDomainAutoCoreDump(libxlDriverPrivatePtr driver, diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index af7317b..8a34821 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -148,11 +148,11 @@ struct libxlShutdownThreadInfo static void libxlDomainShutdownThread(void *opaque) { - libxlDriverPrivatePtr driver = libxl_driver; struct libxlShutdownThreadInfo *shutdown_info = opaque; virDomainObjPtr vm = shutdown_info->vm; libxlDomainObjPrivatePtr priv = vm->privateData; libxl_event *ev = shutdown_info->event; + libxlDriverPrivatePtr driver = priv->driver; libxl_ctx *ctx = priv->ctx; virObjectEventPtr dom_event = NULL; libxl_shutdown_reason xl_reason = ev->u.domain_shutdown.shutdown_reason; @@ -353,7 +353,7 @@ libxlReconnectDomain(virDomainObjPtr vm, driver->inhibitCallback(true, driver->inhibitOpaque); /* Re-register domain death et. al. events */ - libxlDomainEventsRegister(vm); + libxlDomainEventsRegister(driver, vm); virObjectUnlock(vm); return 0; -- 1.8.1.4

Move the domain event handler and shutdown thread out of the main driver module and into libxl_domain module Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- src/libxl/libxl_domain.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_driver.c | 179 ----------------------------------------------- 2 files changed, 179 insertions(+), 179 deletions(-) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 606469e..d9637b0 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -498,6 +498,185 @@ virDomainDefParserConfig libxlDomainDefParserConfig = { .devicesPostParseCallback = libxlDomainDeviceDefPostParse, }; + +struct libxlShutdownThreadInfo +{ + virDomainObjPtr vm; + libxl_event *event; +}; + + +static void +libxlDomainShutdownThread(void *opaque) +{ + struct libxlShutdownThreadInfo *shutdown_info = opaque; + virDomainObjPtr vm = shutdown_info->vm; + libxlDomainObjPrivatePtr priv = vm->privateData; + libxl_event *ev = shutdown_info->event; + libxlDriverPrivatePtr driver = priv->driver; + libxl_ctx *ctx = priv->ctx; + virObjectEventPtr dom_event = NULL; + libxl_shutdown_reason xl_reason = ev->u.domain_shutdown.shutdown_reason; + virDomainShutoffReason reason = VIR_DOMAIN_SHUTOFF_SHUTDOWN; + + virObjectLock(vm); + + if (xl_reason == LIBXL_SHUTDOWN_REASON_POWEROFF) { + dom_event = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN); + switch ((enum virDomainLifecycleAction) vm->def->onPoweroff) { + case VIR_DOMAIN_LIFECYCLE_DESTROY: + reason = VIR_DOMAIN_SHUTOFF_SHUTDOWN; + goto destroy; + case VIR_DOMAIN_LIFECYCLE_RESTART: + case VIR_DOMAIN_LIFECYCLE_RESTART_RENAME: + goto restart; + case VIR_DOMAIN_LIFECYCLE_PRESERVE: + case VIR_DOMAIN_LIFECYCLE_LAST: + goto cleanup; + } + } else if (xl_reason == LIBXL_SHUTDOWN_REASON_CRASH) { + dom_event = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_CRASHED); + switch ((enum virDomainLifecycleCrashAction) vm->def->onCrash) { + case VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY: + reason = VIR_DOMAIN_SHUTOFF_CRASHED; + goto destroy; + case VIR_DOMAIN_LIFECYCLE_CRASH_RESTART: + case VIR_DOMAIN_LIFECYCLE_CRASH_RESTART_RENAME: + goto restart; + case VIR_DOMAIN_LIFECYCLE_CRASH_PRESERVE: + case VIR_DOMAIN_LIFECYCLE_CRASH_LAST: + goto cleanup; + case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_DESTROY: + libxlDomainAutoCoreDump(driver, vm); + goto destroy; + case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_RESTART: + libxlDomainAutoCoreDump(driver, vm); + goto restart; + } + } else if (xl_reason == LIBXL_SHUTDOWN_REASON_REBOOT) { + dom_event = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN); + switch ((enum virDomainLifecycleAction) vm->def->onReboot) { + case VIR_DOMAIN_LIFECYCLE_DESTROY: + reason = VIR_DOMAIN_SHUTOFF_SHUTDOWN; + goto destroy; + case VIR_DOMAIN_LIFECYCLE_RESTART: + case VIR_DOMAIN_LIFECYCLE_RESTART_RENAME: + goto restart; + case VIR_DOMAIN_LIFECYCLE_PRESERVE: + case VIR_DOMAIN_LIFECYCLE_LAST: + goto cleanup; + } + } else { + VIR_INFO("Unhandled shutdown_reason %d", xl_reason); + goto cleanup; + } + +destroy: + if (dom_event) { + libxlDomainEventQueue(driver, dom_event); + dom_event = NULL; + } + libxl_domain_destroy(ctx, vm->def->id, NULL); + if (libxlDomainCleanupJob(driver, vm, reason)) { + if (!vm->persistent) { + virDomainObjListRemove(driver->domains, vm); + vm = NULL; + } + } + goto cleanup; + +restart: + if (dom_event) { + libxlDomainEventQueue(driver, dom_event); + dom_event = NULL; + } + libxl_domain_destroy(ctx, vm->def->id, NULL); + libxlDomainCleanupJob(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN); + libxlDomainStart(driver, vm, 0, -1); + +cleanup: + if (vm) + virObjectUnlock(vm); + if (dom_event) + libxlDomainEventQueue(driver, dom_event); + libxl_event_free(ctx, ev); + VIR_FREE(shutdown_info); +} + +/* + * Handle previously registered domain event notification from libxenlight. + * + * Note: Xen 4.3 removed the const from the event handler signature. + * Detect which signature to use based on + * LIBXL_HAVE_NONCONST_EVENT_OCCURS_EVENT_ARG. + */ +#ifdef LIBXL_HAVE_NONCONST_EVENT_OCCURS_EVENT_ARG +# define VIR_LIBXL_EVENT_CONST /* empty */ +#else +# define VIR_LIBXL_EVENT_CONST const +#endif + +static void +libxlEventHandler(void *data, VIR_LIBXL_EVENT_CONST libxl_event *event) +{ + virDomainObjPtr vm = data; + libxlDomainObjPrivatePtr priv = vm->privateData; + libxl_shutdown_reason xl_reason = event->u.domain_shutdown.shutdown_reason; + struct libxlShutdownThreadInfo *shutdown_info; + virThread thread; + + if (event->type != LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN) { + VIR_INFO("Unhandled event type %d", event->type); + goto error; + } + + /* + * Similar to the xl implementation, ignore SUSPEND. Any actions needed + * after calling libxl_domain_suspend() are handled by it's callers. + */ + if (xl_reason == LIBXL_SHUTDOWN_REASON_SUSPEND) + goto error; + + /* + * Start a thread to handle shutdown. We don't want to be tying up + * libxl's event machinery by doing a potentially lengthy shutdown. + */ + if (VIR_ALLOC(shutdown_info) < 0) + goto error; + + shutdown_info->vm = data; + shutdown_info->event = (libxl_event *)event; + if (virThreadCreate(&thread, false, libxlDomainShutdownThread, + shutdown_info) < 0) { + /* + * Not much we can do on error here except log it. + */ + VIR_ERROR(_("Failed to create thread to handle domain shutdown")); + goto error; + } + + /* + * libxl_event freed in shutdown thread + */ + return; + +error: + /* Cast away any const */ + libxl_event_free(priv->ctx, (libxl_event *)event); +} + +const struct libxl_event_hooks ev_hooks = { + .event_occurs_mask = LIBXL_EVENTMASK_ALL, + .event_occurs = libxlEventHandler, + .disaster = NULL, +}; + static const libxl_childproc_hooks libxl_child_hooks = { #ifdef LIBXL_HAVE_SIGCHLD_OWNER_SELECTIVE_REAP .chldowner = libxl_sigchld_owner_libxl_always_selective_reap, diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 8a34821..3306dc1 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -125,185 +125,6 @@ cleanup: } /* - * Handle previously registered event notification from libxenlight. - * - * Note: Xen 4.3 removed the const from the event handler signature. - * Detect which signature to use based on - * LIBXL_HAVE_NONCONST_EVENT_OCCURS_EVENT_ARG. - */ - -#ifdef LIBXL_HAVE_NONCONST_EVENT_OCCURS_EVENT_ARG -# define VIR_LIBXL_EVENT_CONST /* empty */ -#else -# define VIR_LIBXL_EVENT_CONST const -#endif - -struct libxlShutdownThreadInfo -{ - virDomainObjPtr vm; - libxl_event *event; -}; - - -static void -libxlDomainShutdownThread(void *opaque) -{ - struct libxlShutdownThreadInfo *shutdown_info = opaque; - virDomainObjPtr vm = shutdown_info->vm; - libxlDomainObjPrivatePtr priv = vm->privateData; - libxl_event *ev = shutdown_info->event; - libxlDriverPrivatePtr driver = priv->driver; - libxl_ctx *ctx = priv->ctx; - virObjectEventPtr dom_event = NULL; - libxl_shutdown_reason xl_reason = ev->u.domain_shutdown.shutdown_reason; - virDomainShutoffReason reason = VIR_DOMAIN_SHUTOFF_SHUTDOWN; - - virObjectLock(vm); - - if (xl_reason == LIBXL_SHUTDOWN_REASON_POWEROFF) { - dom_event = virDomainEventLifecycleNewFromObj(vm, - VIR_DOMAIN_EVENT_STOPPED, - VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN); - switch ((enum virDomainLifecycleAction) vm->def->onPoweroff) { - case VIR_DOMAIN_LIFECYCLE_DESTROY: - reason = VIR_DOMAIN_SHUTOFF_SHUTDOWN; - goto destroy; - case VIR_DOMAIN_LIFECYCLE_RESTART: - case VIR_DOMAIN_LIFECYCLE_RESTART_RENAME: - goto restart; - case VIR_DOMAIN_LIFECYCLE_PRESERVE: - case VIR_DOMAIN_LIFECYCLE_LAST: - goto cleanup; - } - } else if (xl_reason == LIBXL_SHUTDOWN_REASON_CRASH) { - dom_event = virDomainEventLifecycleNewFromObj(vm, - VIR_DOMAIN_EVENT_STOPPED, - VIR_DOMAIN_EVENT_STOPPED_CRASHED); - switch ((enum virDomainLifecycleCrashAction) vm->def->onCrash) { - case VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY: - reason = VIR_DOMAIN_SHUTOFF_CRASHED; - goto destroy; - case VIR_DOMAIN_LIFECYCLE_CRASH_RESTART: - case VIR_DOMAIN_LIFECYCLE_CRASH_RESTART_RENAME: - goto restart; - case VIR_DOMAIN_LIFECYCLE_CRASH_PRESERVE: - case VIR_DOMAIN_LIFECYCLE_CRASH_LAST: - goto cleanup; - case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_DESTROY: - libxlDomainAutoCoreDump(driver, vm); - goto destroy; - case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_RESTART: - libxlDomainAutoCoreDump(driver, vm); - goto restart; - } - } else if (xl_reason == LIBXL_SHUTDOWN_REASON_REBOOT) { - dom_event = virDomainEventLifecycleNewFromObj(vm, - VIR_DOMAIN_EVENT_STOPPED, - VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN); - switch ((enum virDomainLifecycleAction) vm->def->onReboot) { - case VIR_DOMAIN_LIFECYCLE_DESTROY: - reason = VIR_DOMAIN_SHUTOFF_SHUTDOWN; - goto destroy; - case VIR_DOMAIN_LIFECYCLE_RESTART: - case VIR_DOMAIN_LIFECYCLE_RESTART_RENAME: - goto restart; - case VIR_DOMAIN_LIFECYCLE_PRESERVE: - case VIR_DOMAIN_LIFECYCLE_LAST: - goto cleanup; - } - } else { - VIR_INFO("Unhandled shutdown_reason %d", xl_reason); - goto cleanup; - } - -destroy: - if (dom_event) { - libxlDomainEventQueue(driver, dom_event); - dom_event = NULL; - } - libxl_domain_destroy(ctx, vm->def->id, NULL); - if (libxlDomainCleanupJob(driver, vm, reason)) { - if (!vm->persistent) { - virDomainObjListRemove(driver->domains, vm); - vm = NULL; - } - } - goto cleanup; - -restart: - if (dom_event) { - libxlDomainEventQueue(driver, dom_event); - dom_event = NULL; - } - libxl_domain_destroy(ctx, vm->def->id, NULL); - libxlDomainCleanupJob(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN); - libxlDomainStart(driver, vm, 0, -1); - -cleanup: - if (vm) - virObjectUnlock(vm); - if (dom_event) - libxlDomainEventQueue(driver, dom_event); - libxl_event_free(ctx, ev); - VIR_FREE(shutdown_info); -} - -static void -libxlEventHandler(void *data, VIR_LIBXL_EVENT_CONST libxl_event *event) -{ - virDomainObjPtr vm = data; - libxlDomainObjPrivatePtr priv = vm->privateData; - libxl_shutdown_reason xl_reason = event->u.domain_shutdown.shutdown_reason; - struct libxlShutdownThreadInfo *shutdown_info; - virThread thread; - - if (event->type != LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN) { - VIR_INFO("Unhandled event type %d", event->type); - goto error; - } - - /* - * Similar to the xl implementation, ignore SUSPEND. Any actions needed - * after calling libxl_domain_suspend() are handled by it's callers. - */ - if (xl_reason == LIBXL_SHUTDOWN_REASON_SUSPEND) - goto error; - - /* - * Start a thread to handle shutdown. We don't want to be tying up - * libxl's event machinery by doing a potentially lengthy shutdown. - */ - if (VIR_ALLOC(shutdown_info) < 0) - goto error; - - shutdown_info->vm = data; - shutdown_info->event = (libxl_event *)event; - if (virThreadCreate(&thread, false, libxlDomainShutdownThread, - shutdown_info) < 0) { - /* - * Not much we can do on error here except log it. - */ - VIR_ERROR(_("Failed to create thread to handle domain shutdown")); - goto error; - } - - /* - * libxl_event freed in shutdown thread - */ - return; - -error: - /* Cast away any const */ - libxl_event_free(priv->ctx, (libxl_event *)event); -} - -const struct libxl_event_hooks ev_hooks = { - .event_occurs_mask = LIBXL_EVENTMASK_ALL, - .event_occurs = libxlEventHandler, - .disaster = NULL, -}; - -/* * Reconnect to running domains that were previously started/created * with libxenlight driver. */ -- 1.8.1.4

This patch adds initial migration support to the libxl driver, using the VIR_DRV_FEATURE_MIGRATION_PARAMS family of migration functions. Signed-off-by: Jim Fehlig <jfehlig@suse.com> --- V2: - Now that the libxl driver supports hostdev passthrough, ensure domain has no hostdevs before migration - Fail early in libxlDomainMigrateBegin3Params if domain is inactive - Change name of local variable in libxlDoMigrateSend from 'live' to 'xl_flags'. po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/libxl/libxl_conf.h | 6 + src/libxl/libxl_domain.h | 1 + src/libxl/libxl_driver.c | 225 +++++++++++++++++ src/libxl/libxl_migration.c | 598 ++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_migration.h | 78 ++++++ 7 files changed, 911 insertions(+), 1 deletion(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index efac7b2..e90960c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -74,6 +74,7 @@ src/lxc/lxc_process.c src/libxl/libxl_domain.c src/libxl/libxl_driver.c src/libxl/libxl_conf.c +src/libxl/libxl_migration.c src/network/bridge_driver.c src/network/bridge_driver_linux.c src/node_device/node_device_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index d4d7b2b..74ee083 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -698,7 +698,8 @@ XENAPI_DRIVER_SOURCES = \ LIBXL_DRIVER_SOURCES = \ libxl/libxl_conf.c libxl/libxl_conf.h \ libxl/libxl_domain.c libxl/libxl_domain.h \ - libxl/libxl_driver.c libxl/libxl_driver.h + libxl/libxl_driver.c libxl/libxl_driver.h \ + libxl/libxl_migration.c libxl/libxl_migration.h UML_DRIVER_SOURCES = \ uml/uml_conf.c uml/uml_conf.h \ diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index 5a340b9..cf57d64 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -43,6 +43,9 @@ # define LIBXL_VNC_PORT_MIN 5900 # define LIBXL_VNC_PORT_MAX 65535 +# define LIBXL_MIGRATION_PORT_MIN 49152 +# define LIBXL_MIGRATION_PORT_MAX 49216 + # define LIBXL_CONFIG_DIR SYSCONFDIR "/libvirt/libxl" # define LIBXL_AUTOSTART_DIR LIBXL_CONFIG_DIR "/autostart" # define LIBXL_STATE_DIR LOCALSTATEDIR "/run/libvirt/libxl" @@ -115,6 +118,9 @@ struct _libxlDriverPrivate { /* Immutable pointer, self-locking APIs */ virPortAllocatorPtr reservedVNCPorts; + /* Immutable pointer, self-locking APIs */ + virPortAllocatorPtr migrationPorts; + /* Immutable pointer, lockless APIs*/ virSysinfoDefPtr hostsysinfo; }; diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index 979ce2a..9d48049 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -69,6 +69,7 @@ struct _libxlDomainObjPrivate { virChrdevsPtr devs; libxl_evgen_domain_death *deathW; libxlDriverPrivatePtr driver; + unsigned short migrationPort; struct libxlDomainJobObj job; }; diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 3306dc1..6fc5266 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -45,6 +45,7 @@ #include "libxl_domain.h" #include "libxl_driver.h" #include "libxl_conf.h" +#include "libxl_migration.h" #include "xen_xm.h" #include "xen_sxpr.h" #include "virtypedparam.h" @@ -205,6 +206,7 @@ libxlStateCleanup(void) virObjectUnref(libxl_driver->xmlopt); virObjectUnref(libxl_driver->domains); virObjectUnref(libxl_driver->reservedVNCPorts); + virObjectUnref(libxl_driver->migrationPorts); virObjectEventStateFree(libxl_driver->domainEventState); virSysinfoDefFree(libxl_driver->hostsysinfo); @@ -287,6 +289,13 @@ libxlStateInitialize(bool privileged, LIBXL_VNC_PORT_MAX))) goto error; + /* Allocate bitmap for migration port reservation */ + if (!(libxl_driver->migrationPorts = + virPortAllocatorNew(_("migration"), + LIBXL_MIGRATION_PORT_MIN, + LIBXL_MIGRATION_PORT_MAX))) + goto error; + if (!(libxl_driver->domains = virDomainObjListNew())) goto error; @@ -4132,6 +4141,7 @@ libxlConnectSupportsFeature(virConnectPtr conn, int feature) switch (feature) { case VIR_DRV_FEATURE_TYPED_PARAM_STRING: + case VIR_DRV_FEATURE_MIGRATION_PARAMS: return 1; default: return 0; @@ -4313,6 +4323,216 @@ cleanup: return ret; } +static char * +libxlDomainMigrateBegin3Params(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags) +{ + const char *xmlin = NULL; + const char *dname = NULL; + virDomainObjPtr vm = NULL; + + virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL); + if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0) + return NULL; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_XML, + &xmlin) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0) + return NULL; + + if (!(vm = libxlDomObjFromDomain(domain))) + return NULL; + + if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, vm->def) < 0) { + virObjectUnlock(vm); + return NULL; + } + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + virObjectUnlock(vm); + return NULL; + } + + return libxlDomainMigrationBegin(domain->conn, vm, xmlin); +} + +static int +libxlDomainMigratePrepare3Params(virConnectPtr dconn, + virTypedParameterPtr params, + int nparams, + const char *cookiein ATTRIBUTE_UNUSED, + int cookieinlen ATTRIBUTE_UNUSED, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + char **uri_out, + unsigned int flags) +{ + libxlDriverPrivatePtr driver = dconn->privateData; + virDomainDefPtr def = NULL; + const char *dom_xml = NULL; + const char *dname = NULL; + const char *uri_in = NULL; + + virCheckFlags(LIBXL_MIGRATION_FLAGS, -1); + if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0) + goto error; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_XML, + &dom_xml) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_URI, + &uri_in) < 0) + + goto error; + + if (!(def = libxlDomainMigrationPrepareDef(driver, dom_xml, dname))) + goto error; + + if (virDomainMigratePrepare3ParamsEnsureACL(dconn, def) < 0) + goto error; + + if (libxlDomainMigrationPrepare(dconn, def, uri_in, uri_out) < 0) + goto error; + + return 0; + +error: + virDomainDefFree(def); + return -1; +} + +static int +libxlDomainMigratePerform3Params(virDomainPtr dom, + const char *dconnuri, + virTypedParameterPtr params, + int nparams, + const char *cookiein ATTRIBUTE_UNUSED, + int cookieinlen ATTRIBUTE_UNUSED, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags) +{ + libxlDriverPrivatePtr driver = dom->conn->privateData; + virDomainObjPtr vm = NULL; + const char *dom_xml = NULL; + const char *dname = NULL; + const char *uri = NULL; + int ret = -1; + + virCheckFlags(LIBXL_MIGRATION_FLAGS, -1); + if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_XML, + &dom_xml) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_URI, + &uri) < 0) + + goto cleanup; + + if (!(vm = libxlDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainMigratePerform3ParamsEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (libxlDomainMigrationPerform(driver, vm, dom_xml, dconnuri, + uri, dname, flags) < 0) + goto cleanup; + + ret = 0; + +cleanup: + if (vm) + virObjectUnlock(vm); + return ret; +} + +static virDomainPtr +libxlDomainMigrateFinish3Params(virConnectPtr dconn, + virTypedParameterPtr params, + int nparams, + const char *cookiein ATTRIBUTE_UNUSED, + int cookieinlen ATTRIBUTE_UNUSED, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags, + int cancelled) +{ + libxlDriverPrivatePtr driver = dconn->privateData; + virDomainObjPtr vm = NULL; + const char *dname = NULL; + + virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL); + if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0) + return NULL; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0) + return NULL; + + if (!dname || + !(vm = virDomainObjListFindByName(driver->domains, dname))) { + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching name '%s'"), + NULLSTR(dname)); + return NULL; + } + + if (virDomainMigrateFinish3ParamsEnsureACL(dconn, vm->def) < 0) { + virObjectUnlock(vm); + return NULL; + } + + return libxlDomainMigrationFinish(dconn, vm, flags, cancelled); +} + +static int +libxlDomainMigrateConfirm3Params(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + const char *cookiein ATTRIBUTE_UNUSED, + int cookieinlen ATTRIBUTE_UNUSED, + unsigned int flags, + int cancelled) +{ + libxlDriverPrivatePtr driver = domain->conn->privateData; + virDomainObjPtr vm = NULL; + + virCheckFlags(LIBXL_MIGRATION_FLAGS, -1); + if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0) + return -1; + + if (!(vm = libxlDomObjFromDomain(domain))) + return -1; + + if (virDomainMigrateConfirm3ParamsEnsureACL(domain->conn, vm->def) < 0) { + virObjectUnlock(vm); + return -1; + } + + return libxlDomainMigrationConfirm(driver, vm, flags, cancelled); +} + static virDriver libxlDriver = { .no = VIR_DRV_LIBXL, @@ -4403,6 +4623,11 @@ static virDriver libxlDriver = { .nodeDeviceDetachFlags = libxlNodeDeviceDetachFlags, /* 1.2.3 */ .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.2.3 */ .nodeDeviceReset = libxlNodeDeviceReset, /* 1.2.3 */ + .domainMigrateBegin3Params = libxlDomainMigrateBegin3Params, /* 1.2.3 */ + .domainMigratePrepare3Params = libxlDomainMigratePrepare3Params, /* 1.2.3 */ + .domainMigratePerform3Params = libxlDomainMigratePerform3Params, /* 1.2.3 */ + .domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.3 */ + .domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.3 */ }; static virStateDriver libxlStateDriver = { diff --git a/src/libxl/libxl_migration.c b/src/libxl/libxl_migration.c new file mode 100644 index 0000000..01023db --- /dev/null +++ b/src/libxl/libxl_migration.c @@ -0,0 +1,598 @@ +/* + * libxl_migration.c: methods for handling migration with libxenlight + * + * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Jim Fehlig <jfehlig@suse.com> + * Chunyan Liu <cyliu@suse.com> + */ + +#include <config.h> + +#include "internal.h" +#include "virlog.h" +#include "virerror.h" +#include "virconf.h" +#include "datatypes.h" +#include "virfile.h" +#include "viralloc.h" +#include "viruuid.h" +#include "vircommand.h" +#include "virstring.h" +#include "rpc/virnetsocket.h" +#include "libxl_domain.h" +#include "libxl_driver.h" +#include "libxl_conf.h" +#include "libxl_migration.h" + +#define VIR_FROM_THIS VIR_FROM_LIBXL + +typedef struct _libxlMigrateReceiveArgs { + virConnectPtr conn; + virDomainObjPtr vm; + + /* for freeing listen sockets */ + virNetSocketPtr *socks; + size_t nsocks; +} libxlMigrateReceiveArgs; + +static const char libxlMigrateReceiverReady[] = + "libvirt libxl migration receiver ready, send binary domain data"; +static const char libxlMigrateReceiverFinish[] = + "domain received, ready to unpause"; + + +static int +libxlCheckMessageBanner(int fd, const char *banner, int banner_sz) +{ + char buf[banner_sz]; + int ret = 0; + + do { + ret = saferead(fd, buf, banner_sz); + } while (ret == -1 && errno == EAGAIN); + + if (ret != banner_sz || memcmp(buf, banner, banner_sz)) { + return -1; + } + + return 0; +} + +static void +libxlDoMigrateReceive(virNetSocketPtr sock, + int events ATTRIBUTE_UNUSED, + void *opaque) +{ + libxlMigrateReceiveArgs *data = opaque; + virConnectPtr conn = data->conn; + virDomainObjPtr vm = data->vm; + virNetSocketPtr *socks = data->socks; + size_t nsocks = data->nsocks; + libxlDriverPrivatePtr driver = conn->privateData; + virNetSocketPtr client_sock; + int recv_fd; + int len; + size_t i; + int ret; + + virNetSocketAccept(sock, &client_sock); + if (client_sock == NULL) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Fail to accept migration connection")); + goto cleanup; + } + VIR_DEBUG("Accepted migration\n"); + recv_fd = virNetSocketDupFD(client_sock, true); + virObjectUnref(client_sock); + + len = sizeof(libxlMigrateReceiverReady); + if (safewrite(recv_fd, libxlMigrateReceiverReady, len) != len) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to write libxlMigrateReceiverReady")); + goto cleanup; + } + + virObjectLock(vm); + ret = libxlDomainStart(driver, vm, false, recv_fd); + virObjectUnlock(vm); + + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to restore domain with libxenlight")); + if (!vm->persistent) { + virDomainObjListRemove(driver->domains, vm); + vm = NULL; + } + goto cleanup; + } + + len = sizeof(libxlMigrateReceiverFinish); + if (safewrite(recv_fd, libxlMigrateReceiverFinish, len) != len) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to write libxlMigrateReceiverFinish")); + } + + /* Remove all listen socks from event handler, and close them. */ + if (nsocks) { + for (i = 0; i < nsocks; i++) { + virNetSocketUpdateIOCallback(socks[i], 0); + virNetSocketRemoveIOCallback(socks[i]); + virNetSocketClose(socks[i]); + virObjectUnref(socks[i]); + } + VIR_FREE(socks); + } + +cleanup: + VIR_FORCE_CLOSE(recv_fd); + VIR_FREE(opaque); + return; +} + +static int +libxlDoMigrateSend(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + unsigned long flags, + int sockfd) +{ + libxlDomainObjPrivatePtr priv; + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + virObjectEventPtr event = NULL; + int xl_flags = 0; + int ret = -1; + + if (flags & VIR_MIGRATE_LIVE) + xl_flags = LIBXL_SUSPEND_LIVE; + + priv = vm->privateData; + + /* read fixed message from dest (ready to receive) */ + if (libxlCheckMessageBanner(sockfd, libxlMigrateReceiverReady, + sizeof(libxlMigrateReceiverReady))) + goto cleanup; + + if (libxl_domain_suspend(priv->ctx, vm->def->id, sockfd, xl_flags, NULL) != 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to save domain '%d' with libxenlight"), + vm->def->id); + goto cleanup; + } + + /* read fixed message from dest (receive completed) */ + if (libxlCheckMessageBanner(sockfd, libxlMigrateReceiverFinish, + sizeof(libxlMigrateReceiverFinish))) { + if (libxl_domain_resume(priv->ctx, vm->def->id, 0, 0) != 0) { + VIR_DEBUG("Failed to resume domain '%d' with libxenlight", + vm->def->id); + virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_MIGRATION); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED); + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) + goto cleanup; + } + goto cleanup; + } + + ret = 0; + +cleanup: + if (event) + libxlDomainEventQueue(driver, event); + virObjectUnref(cfg); + return ret; +} + +static bool +libxlDomainMigrationIsAllowed(virDomainDefPtr def) +{ + /* Migration is not allowed if definition contains any hostdevs */ + if (def->nhostdevs > 0) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("domain has assigned host devices")); + return false; + } + + return true; +} + +char * +libxlDomainMigrationBegin(virConnectPtr conn, + virDomainObjPtr vm, + const char *xmlin) +{ + libxlDriverPrivatePtr driver = conn->privateData; + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + virDomainDefPtr tmpdef = NULL; + virDomainDefPtr def; + char *xml = NULL; + + if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) + goto cleanup; + + if (xmlin) { + if (!(tmpdef = virDomainDefParseString(xmlin, cfg->caps, + driver->xmlopt, + 1 << VIR_DOMAIN_VIRT_XEN, + VIR_DOMAIN_XML_INACTIVE))) + goto endjob; + + def = tmpdef; + } else { + def = vm->def; + } + + if (!libxlDomainMigrationIsAllowed(def)) + goto endjob; + + xml = virDomainDefFormat(def, VIR_DOMAIN_XML_SECURE); + +cleanup: + if (vm) + virObjectUnlock(vm); + + virDomainDefFree(tmpdef); + virObjectUnref(cfg); + return xml; + +endjob: + if (!libxlDomainObjEndJob(driver, vm)) + vm = NULL; + goto cleanup; +} + +virDomainDefPtr +libxlDomainMigrationPrepareDef(libxlDriverPrivatePtr driver, + const char *dom_xml, + const char *dname) +{ + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + virDomainDefPtr def; + char *name = NULL; + + if (!dom_xml) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("no domain XML passed")); + return NULL; + } + + if (!(def = virDomainDefParseString(dom_xml, cfg->caps, driver->xmlopt, + 1 << VIR_DOMAIN_VIRT_XEN, + VIR_DOMAIN_XML_INACTIVE))) + goto cleanup; + + if (dname) { + name = def->name; + if (VIR_STRDUP(def->name, dname) < 0) { + virDomainDefFree(def); + def = NULL; + } + } + +cleanup: + virObjectUnref(cfg); + VIR_FREE(name); + return def; +} + +int +libxlDomainMigrationPrepare(virConnectPtr dconn, + virDomainDefPtr def, + const char *uri_in, + char **uri_out) +{ + libxlDriverPrivatePtr driver = dconn->privateData; + virDomainObjPtr vm = NULL; + char *hostname = NULL; + unsigned short port; + char portstr[100]; + virURIPtr uri = NULL; + virNetSocketPtr *socks = NULL; + size_t nsocks = 0; + int nsocks_listen = 0; + libxlMigrateReceiveArgs *args; + size_t i; + int ret = -1; + + if (!(vm = virDomainObjListAdd(driver->domains, def, + driver->xmlopt, + VIR_DOMAIN_OBJ_LIST_ADD_LIVE | + VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, + NULL))) + goto cleanup; + + /* Create socket connection to receive migration data */ + if (!uri_in) { + if ((hostname = virGetHostname()) == NULL) + goto cleanup; + + if (STRPREFIX(hostname, "localhost")) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("hostname on destination resolved to localhost," + " but migration requires an FQDN")); + goto cleanup; + } + + if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) + goto cleanup; + + if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0) + goto cleanup; + } else { + if (!(STRPREFIX(uri_in, "tcp://"))) { + /* not full URI, add prefix tcp:// */ + char *tmp; + if (virAsprintf(&tmp, "tcp://%s", uri_in) < 0) + goto cleanup; + uri = virURIParse(tmp); + VIR_FREE(tmp); + } else { + uri = virURIParse(uri_in); + } + + if (uri == NULL) { + virReportError(VIR_ERR_INVALID_ARG, + _("unable to parse URI: %s"), + uri_in); + goto cleanup; + } + + if (uri->server == NULL) { + virReportError(VIR_ERR_INVALID_ARG, + _("missing host in migration URI: %s"), + uri_in); + goto cleanup; + } else { + hostname = uri->server; + } + + if (uri->port == 0) { + if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) + goto cleanup; + + } else { + port = uri->port; + } + + if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0) + goto cleanup; + } + + snprintf(portstr, sizeof(portstr), "%d", port); + + if (virNetSocketNewListenTCP(hostname, portstr, &socks, &nsocks) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Fail to create socket for incoming migration")); + goto cleanup; + } + + if (VIR_ALLOC(args) < 0) + goto cleanup; + + args->conn = dconn; + args->vm = vm; + args->socks = socks; + args->nsocks = nsocks; + + for (i = 0; i < nsocks; i++) { + if (virNetSocketSetBlocking(socks[i], true) < 0) + continue; + if (virNetSocketListen(socks[i], 1) < 0) + continue; + + if (virNetSocketAddIOCallback(socks[i], + 0, + libxlDoMigrateReceive, + args, + NULL) < 0) { + continue; + } + + virNetSocketUpdateIOCallback(socks[i], VIR_EVENT_HANDLE_READABLE); + nsocks_listen++; + } + + if (!nsocks_listen) + goto cleanup; + + ret = 0; + goto done; + +cleanup: + if (nsocks) { + for (i = 0; i < nsocks; i++) { + virNetSocketClose(socks[i]); + virObjectUnref(socks[i]); + } + VIR_FREE(socks); + } + +done: + virURIFree(uri); + if (vm) + virObjectUnlock(vm); + return ret; +} + +int +libxlDomainMigrationPerform(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + const char *dom_xml ATTRIBUTE_UNUSED, + const char *dconnuri ATTRIBUTE_UNUSED, + const char *uri_str, + const char *dname ATTRIBUTE_UNUSED, + unsigned int flags) +{ + char *hostname = NULL; + unsigned short port = 0; + char portstr[100]; + virURIPtr uri = NULL; + virNetSocketPtr sock; + int sockfd = -1; + int saved_errno = EINVAL; + int ret = -1; + + /* parse dst host:port from uri */ + uri = virURIParse(uri_str); + if (uri == NULL || uri->server == NULL || uri->port == 0) + goto cleanup; + + hostname = uri->server; + port = uri->port; + snprintf(portstr, sizeof(portstr), "%d", port); + + /* socket connect to dst host:port */ + if (virNetSocketNewConnectTCP(hostname, portstr, &sock) < 0) { + virReportSystemError(saved_errno, + _("unable to connect to '%s:%s'"), + hostname, portstr); + goto cleanup; + } + + if (virNetSocketSetBlocking(sock, true) < 0) { + virObjectUnref(sock); + goto cleanup; + } + + sockfd = virNetSocketDupFD(sock, true); + virObjectUnref(sock); + + /* suspend vm and send saved data to dst through socket fd */ + virObjectUnlock(vm); + ret = libxlDoMigrateSend(driver, vm, flags, sockfd); + virObjectLock(vm); + +cleanup: + VIR_FORCE_CLOSE(sockfd); + virURIFree(uri); + return ret; +} + +virDomainPtr +libxlDomainMigrationFinish(virConnectPtr dconn, + virDomainObjPtr vm, + unsigned int flags, + int cancelled) +{ + libxlDriverPrivatePtr driver = dconn->privateData; + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + libxlDomainObjPrivatePtr priv = vm->privateData; + virObjectEventPtr event = NULL; + virDomainPtr dom = NULL; + + virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort); + priv->migrationPort = 0; + + if (cancelled) + goto cleanup; + + if (!(flags & VIR_MIGRATE_PAUSED)) { + if (libxl_domain_unpause(priv->ctx, vm->def->id) != 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to unpause domain")); + goto cleanup; + } + + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_MIGRATED); + event = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_RESUMED, + VIR_DOMAIN_EVENT_RESUMED_MIGRATED); + } else { + virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER); + event = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_SUSPENDED_PAUSED); + } + + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) + goto cleanup; + + dom = virGetDomain(dconn, vm->def->name, vm->def->uuid); + + if (dom == NULL) { + libxl_domain_destroy(priv->ctx, vm->def->id, NULL); + libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_FAILED); + libxlDomainEventQueue(driver, event); + } + +cleanup: + if (event) + libxlDomainEventQueue(driver, event); + if (vm) + virObjectUnlock(vm); + virObjectUnref(cfg); + return dom; +} + +int +libxlDomainMigrationConfirm(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + unsigned int flags, + int cancelled) +{ + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + libxlDomainObjPrivatePtr priv = vm->privateData; + virObjectEventPtr event = NULL; + int ret = -1; + + if (cancelled) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("migration failed, attempting to resume on source host")); + if (libxl_domain_resume(priv->ctx, vm->def->id, 1, 0) == 0) { + ret = 0; + } else { + VIR_DEBUG("Unable to resume domain '%s' after failed migration", + vm->def->name); + virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_MIGRATION); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED); + ignore_value(virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm)); + } + goto cleanup; + } + + libxl_domain_destroy(priv->ctx, vm->def->id, NULL); + libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_MIGRATED); + + VIR_DEBUG("Domain '%s' successfully migrated", vm->def->name); + + if (flags & VIR_MIGRATE_UNDEFINE_SOURCE) + virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm); + + if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) + virDomainObjListRemove(driver->domains, vm); + + ret = 0; + +cleanup: + if (!libxlDomainObjEndJob(driver, vm)) + vm = NULL; + if (event) + libxlDomainEventQueue(driver, event); + if (vm) + virObjectUnlock(vm); + virObjectUnref(cfg); + return ret; +} diff --git a/src/libxl/libxl_migration.h b/src/libxl/libxl_migration.h new file mode 100644 index 0000000..63d8bdc --- /dev/null +++ b/src/libxl/libxl_migration.h @@ -0,0 +1,78 @@ +/* + * libxl_migration.h: methods for handling migration with libxenlight + * + * Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Jim Fehlig <jfehlig@suse.com> + */ + +#ifndef LIBXL_MIGRATION_H +# define LIBXL_MIGRATION_H + +# include "libxl_conf.h" + +# define LIBXL_MIGRATION_FLAGS \ + (VIR_MIGRATE_LIVE | \ + VIR_MIGRATE_UNDEFINE_SOURCE | \ + VIR_MIGRATE_PAUSED) + +/* All supported migration parameters and their types. */ +# define LIBXL_MIGRATION_PARAMETERS \ + VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ + NULL + +char * +libxlDomainMigrationBegin(virConnectPtr conn, + virDomainObjPtr vm, + const char *xmlin); + +virDomainDefPtr +libxlDomainMigrationPrepareDef(libxlDriverPrivatePtr driver, + const char *dom_xml, + const char *dname); + +int +libxlDomainMigrationPrepare(virConnectPtr dconn, + virDomainDefPtr def, + const char *uri_in, + char **uri_out); + +int +libxlDomainMigrationPerform(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + const char *dom_xml, + const char *dconnuri, + const char *uri_str, + const char *dname, + unsigned int flags); + +virDomainPtr +libxlDomainMigrationFinish(virConnectPtr dconn, + virDomainObjPtr vm, + unsigned int flags, + int cancelled); + +int +libxlDomainMigrationConfirm(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + unsigned int flags, + int cancelled); + +#endif /* LIBXL_DRIVER_H */ -- 1.8.1.4

On 13.03.2014 23:11, Jim Fehlig wrote:
This patch adds initial migration support to the libxl driver, using the VIR_DRV_FEATURE_MIGRATION_PARAMS family of migration functions.
Signed-off-by: Jim Fehlig <jfehlig@suse.com> ---
V2: - Now that the libxl driver supports hostdev passthrough, ensure domain has no hostdevs before migration - Fail early in libxlDomainMigrateBegin3Params if domain is inactive - Change name of local variable in libxlDoMigrateSend from 'live' to 'xl_flags'.
po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/libxl/libxl_conf.h | 6 + src/libxl/libxl_domain.h | 1 + src/libxl/libxl_driver.c | 225 +++++++++++++++++ src/libxl/libxl_migration.c | 598 ++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_migration.h | 78 ++++++ 7 files changed, 911 insertions(+), 1 deletion(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 3306dc1..6fc5266 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c
@@ -4313,6 +4323,216 @@ cleanup: return ret; }
+static char * +libxlDomainMigrateBegin3Params(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags) +{ + const char *xmlin = NULL; + const char *dname = NULL; + virDomainObjPtr vm = NULL; + + virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL); + if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0) + return NULL; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_XML, + &xmlin) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0)
I'd expect @dname to be used somewhere...
+ return NULL; + + if (!(vm = libxlDomObjFromDomain(domain))) + return NULL; + + if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, vm->def) < 0) { + virObjectUnlock(vm); + return NULL; + } + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + virObjectUnlock(vm); + return NULL; + } + + return libxlDomainMigrationBegin(domain->conn, vm, xmlin); +} +
diff --git a/src/libxl/libxl_migration.c b/src/libxl/libxl_migration.c new file mode 100644 index 0000000..01023db --- /dev/null +++ b/src/libxl/libxl_migration.c @@ -0,0 +1,598 @@ +/* + * libxl_migration.c: methods for handling migration with libxenlight + * + * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Jim Fehlig <jfehlig@suse.com> + * Chunyan Liu <cyliu@suse.com> + */ + +#include <config.h> + +#include "internal.h" +#include "virlog.h" +#include "virerror.h" +#include "virconf.h" +#include "datatypes.h" +#include "virfile.h" +#include "viralloc.h" +#include "viruuid.h" +#include "vircommand.h" +#include "virstring.h" +#include "rpc/virnetsocket.h" +#include "libxl_domain.h" +#include "libxl_driver.h" +#include "libxl_conf.h" +#include "libxl_migration.h" + +#define VIR_FROM_THIS VIR_FROM_LIBXL + +typedef struct _libxlMigrateReceiveArgs { + virConnectPtr conn; + virDomainObjPtr vm; + + /* for freeing listen sockets */ + virNetSocketPtr *socks; + size_t nsocks; +} libxlMigrateReceiveArgs; + +static const char libxlMigrateReceiverReady[] = + "libvirt libxl migration receiver ready, send binary domain data"; +static const char libxlMigrateReceiverFinish[] = + "domain received, ready to unpause";
So you're using these to sync source and destination on migration. Kudos for using text protocol not a binary blob. I haven't followed v1 closely, so what was resolution on this? I mean, my concern is if this is extensible.
+ + +static int +libxlCheckMessageBanner(int fd, const char *banner, int banner_sz) +{ + char buf[banner_sz]; + int ret = 0; + + do { + ret = saferead(fd, buf, banner_sz); + } while (ret == -1 && errno == EAGAIN);
The @fd is in blocking state, so we should never get EAGAIN here. But it doesn't hurt to check.
+ + if (ret != banner_sz || memcmp(buf, banner, banner_sz)) { + return -1; + } + + return 0; +} + +static void +libxlDoMigrateReceive(virNetSocketPtr sock, + int events ATTRIBUTE_UNUSED, + void *opaque) +{ + libxlMigrateReceiveArgs *data = opaque; + virConnectPtr conn = data->conn; + virDomainObjPtr vm = data->vm; + virNetSocketPtr *socks = data->socks; + size_t nsocks = data->nsocks; + libxlDriverPrivatePtr driver = conn->privateData; + virNetSocketPtr client_sock; + int recv_fd; + int len; + size_t i; + int ret; + + virNetSocketAccept(sock, &client_sock); + if (client_sock == NULL) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Fail to accept migration connection")); + goto cleanup; + } + VIR_DEBUG("Accepted migration\n"); + recv_fd = virNetSocketDupFD(client_sock, true); + virObjectUnref(client_sock); + + len = sizeof(libxlMigrateReceiverReady); + if (safewrite(recv_fd, libxlMigrateReceiverReady, len) != len) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to write libxlMigrateReceiverReady")); + goto cleanup; + } + + virObjectLock(vm); + ret = libxlDomainStart(driver, vm, false, recv_fd); + virObjectUnlock(vm); + + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to restore domain with libxenlight")); + if (!vm->persistent) { + virDomainObjListRemove(driver->domains, vm); + vm = NULL; + } + goto cleanup; + } + + len = sizeof(libxlMigrateReceiverFinish); + if (safewrite(recv_fd, libxlMigrateReceiverFinish, len) != len) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to write libxlMigrateReceiverFinish")); + } + + /* Remove all listen socks from event handler, and close them. */ + if (nsocks) {
Useless 'if'
+ for (i = 0; i < nsocks; i++) { + virNetSocketUpdateIOCallback(socks[i], 0); + virNetSocketRemoveIOCallback(socks[i]); + virNetSocketClose(socks[i]); + virObjectUnref(socks[i]); + } + VIR_FREE(socks); + } + +cleanup: + VIR_FORCE_CLOSE(recv_fd); + VIR_FREE(opaque); + return; +} +
+int +libxlDomainMigrationPrepare(virConnectPtr dconn, + virDomainDefPtr def, + const char *uri_in, + char **uri_out) +{ + libxlDriverPrivatePtr driver = dconn->privateData; + virDomainObjPtr vm = NULL; + char *hostname = NULL; + unsigned short port; + char portstr[100]; + virURIPtr uri = NULL; + virNetSocketPtr *socks = NULL; + size_t nsocks = 0; + int nsocks_listen = 0; + libxlMigrateReceiveArgs *args; + size_t i; + int ret = -1; + + if (!(vm = virDomainObjListAdd(driver->domains, def, + driver->xmlopt, + VIR_DOMAIN_OBJ_LIST_ADD_LIVE | + VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, + NULL))) + goto cleanup; + + /* Create socket connection to receive migration data */ + if (!uri_in) { + if ((hostname = virGetHostname()) == NULL) + goto cleanup; + + if (STRPREFIX(hostname, "localhost")) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("hostname on destination resolved to localhost," + " but migration requires an FQDN")); + goto cleanup; + } + + if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) + goto cleanup; + + if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0) + goto cleanup; + } else { + if (!(STRPREFIX(uri_in, "tcp://"))) { + /* not full URI, add prefix tcp:// */ + char *tmp; + if (virAsprintf(&tmp, "tcp://%s", uri_in) < 0) + goto cleanup; + uri = virURIParse(tmp); + VIR_FREE(tmp); + } else { + uri = virURIParse(uri_in); + } + + if (uri == NULL) { + virReportError(VIR_ERR_INVALID_ARG, + _("unable to parse URI: %s"), + uri_in); + goto cleanup; + } + + if (uri->server == NULL) { + virReportError(VIR_ERR_INVALID_ARG, + _("missing host in migration URI: %s"), + uri_in); + goto cleanup; + } else { + hostname = uri->server; + } + + if (uri->port == 0) { + if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) + goto cleanup; + + } else { + port = uri->port; + } + + if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0) + goto cleanup; + } + + snprintf(portstr, sizeof(portstr), "%d", port); + + if (virNetSocketNewListenTCP(hostname, portstr, &socks, &nsocks) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Fail to create socket for incoming migration")); + goto cleanup; + } + + if (VIR_ALLOC(args) < 0) + goto cleanup; + + args->conn = dconn; + args->vm = vm; + args->socks = socks; + args->nsocks = nsocks; + + for (i = 0; i < nsocks; i++) { + if (virNetSocketSetBlocking(socks[i], true) < 0) + continue; + if (virNetSocketListen(socks[i], 1) < 0) + continue; + + if (virNetSocketAddIOCallback(socks[i], + 0, + libxlDoMigrateReceive, + args, + NULL) < 0) { + continue; + } + + virNetSocketUpdateIOCallback(socks[i], VIR_EVENT_HANDLE_READABLE); + nsocks_listen++; + } + + if (!nsocks_listen) + goto cleanup; + + ret = 0; + goto done; + +cleanup: + if (nsocks) {
There's no need for this 'if'.
+ for (i = 0; i < nsocks; i++) { + virNetSocketClose(socks[i]); + virObjectUnref(socks[i]); + } + VIR_FREE(socks); + } + +done: + virURIFree(uri); + if (vm) + virObjectUnlock(vm); + return ret; +} + +int +libxlDomainMigrationPerform(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + const char *dom_xml ATTRIBUTE_UNUSED, + const char *dconnuri ATTRIBUTE_UNUSED, + const char *uri_str, + const char *dname ATTRIBUTE_UNUSED, + unsigned int flags) +{ + char *hostname = NULL; + unsigned short port = 0; + char portstr[100]; + virURIPtr uri = NULL; + virNetSocketPtr sock; + int sockfd = -1; + int saved_errno = EINVAL; + int ret = -1; +
Missing virCheckFlags(VIR_MIGRATE_LIVE, -1);
+ /* parse dst host:port from uri */ + uri = virURIParse(uri_str); + if (uri == NULL || uri->server == NULL || uri->port == 0) + goto cleanup; + + hostname = uri->server; + port = uri->port; + snprintf(portstr, sizeof(portstr), "%d", port); + + /* socket connect to dst host:port */ + if (virNetSocketNewConnectTCP(hostname, portstr, &sock) < 0) { + virReportSystemError(saved_errno, + _("unable to connect to '%s:%s'"), + hostname, portstr); + goto cleanup; + } + + if (virNetSocketSetBlocking(sock, true) < 0) { + virObjectUnref(sock); + goto cleanup; + } + + sockfd = virNetSocketDupFD(sock, true); + virObjectUnref(sock); + + /* suspend vm and send saved data to dst through socket fd */ + virObjectUnlock(vm); + ret = libxlDoMigrateSend(driver, vm, flags, sockfd); + virObjectLock(vm); + +cleanup: + VIR_FORCE_CLOSE(sockfd); + virURIFree(uri); + return ret; +} + +virDomainPtr +libxlDomainMigrationFinish(virConnectPtr dconn, + virDomainObjPtr vm, + unsigned int flags, + int cancelled) +{ + libxlDriverPrivatePtr driver = dconn->privateData; + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + libxlDomainObjPrivatePtr priv = vm->privateData; + virObjectEventPtr event = NULL; + virDomainPtr dom = NULL; + + virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort); + priv->migrationPort = 0; + + if (cancelled) + goto cleanup; + + if (!(flags & VIR_MIGRATE_PAUSED)) { + if (libxl_domain_unpause(priv->ctx, vm->def->id) != 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to unpause domain")); + goto cleanup; + } + + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_MIGRATED); + event = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_RESUMED, + VIR_DOMAIN_EVENT_RESUMED_MIGRATED); + } else { + virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER); + event = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_SUSPENDED_PAUSED); + } + + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) + goto cleanup; + + dom = virGetDomain(dconn, vm->def->name, vm->def->uuid); + + if (dom == NULL) { + libxl_domain_destroy(priv->ctx, vm->def->id, NULL); + libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_FAILED); + libxlDomainEventQueue(driver, event); + } + +cleanup: + if (event) + libxlDomainEventQueue(driver, event); + if (vm) + virObjectUnlock(vm); + virObjectUnref(cfg); + return dom; +} + +int +libxlDomainMigrationConfirm(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + unsigned int flags, + int cancelled) +{ + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + libxlDomainObjPrivatePtr priv = vm->privateData; + virObjectEventPtr event = NULL; + int ret = -1; + + if (cancelled) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("migration failed, attempting to resume on source host")); + if (libxl_domain_resume(priv->ctx, vm->def->id, 1, 0) == 0) { + ret = 0; + } else { + VIR_DEBUG("Unable to resume domain '%s' after failed migration", + vm->def->name); + virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_MIGRATION); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED); + ignore_value(virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm)); + } + goto cleanup; + } + + libxl_domain_destroy(priv->ctx, vm->def->id, NULL); + libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_MIGRATED); + + VIR_DEBUG("Domain '%s' successfully migrated", vm->def->name); + + if (flags & VIR_MIGRATE_UNDEFINE_SOURCE) + virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm); + + if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) + virDomainObjListRemove(driver->domains, vm); + + ret = 0; + +cleanup: + if (!libxlDomainObjEndJob(driver, vm)) + vm = NULL; + if (event) + libxlDomainEventQueue(driver, event); + if (vm) + virObjectUnlock(vm); + virObjectUnref(cfg); + return ret; +} diff --git a/src/libxl/libxl_migration.h b/src/libxl/libxl_migration.h new file mode 100644 index 0000000..63d8bdc --- /dev/null +++ b/src/libxl/libxl_migration.h @@ -0,0 +1,78 @@ +/* + * libxl_migration.h: methods for handling migration with libxenlight + * + * Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Jim Fehlig <jfehlig@suse.com> + */ + +#ifndef LIBXL_MIGRATION_H +# define LIBXL_MIGRATION_H + +# include "libxl_conf.h" + +# define LIBXL_MIGRATION_FLAGS \ + (VIR_MIGRATE_LIVE | \ + VIR_MIGRATE_UNDEFINE_SOURCE | \ + VIR_MIGRATE_PAUSED) + +/* All supported migration parameters and their types. */ +# define LIBXL_MIGRATION_PARAMETERS \ + VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ + NULL + +char * +libxlDomainMigrationBegin(virConnectPtr conn, + virDomainObjPtr vm, + const char *xmlin); + +virDomainDefPtr +libxlDomainMigrationPrepareDef(libxlDriverPrivatePtr driver, + const char *dom_xml, + const char *dname); + +int +libxlDomainMigrationPrepare(virConnectPtr dconn, + virDomainDefPtr def, + const char *uri_in, + char **uri_out); + +int +libxlDomainMigrationPerform(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + const char *dom_xml, + const char *dconnuri, + const char *uri_str, + const char *dname, + unsigned int flags); + +virDomainPtr +libxlDomainMigrationFinish(virConnectPtr dconn, + virDomainObjPtr vm, + unsigned int flags, + int cancelled); + +int +libxlDomainMigrationConfirm(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + unsigned int flags, + int cancelled); + +#endif /* LIBXL_DRIVER_H */
Michal

Michal Privoznik wrote:
On 13.03.2014 23:11, Jim Fehlig wrote:
This patch adds initial migration support to the libxl driver, using the VIR_DRV_FEATURE_MIGRATION_PARAMS family of migration functions.
Signed-off-by: Jim Fehlig <jfehlig@suse.com> ---
V2: - Now that the libxl driver supports hostdev passthrough, ensure domain has no hostdevs before migration - Fail early in libxlDomainMigrateBegin3Params if domain is inactive - Change name of local variable in libxlDoMigrateSend from 'live' to 'xl_flags'.
po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/libxl/libxl_conf.h | 6 + src/libxl/libxl_domain.h | 1 + src/libxl/libxl_driver.c | 225 +++++++++++++++++ src/libxl/libxl_migration.c | 598 ++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_migration.h | 78 ++++++ 7 files changed, 911 insertions(+), 1 deletion(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 3306dc1..6fc5266 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c
@@ -4313,6 +4323,216 @@ cleanup: return ret; }
+static char * +libxlDomainMigrateBegin3Params(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags) +{ + const char *xmlin = NULL; + const char *dname = NULL; + virDomainObjPtr vm = NULL; + + virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL); + if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0) + return NULL; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_XML, + &xmlin) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0)
I'd expect @dname to be used somewhere...
+ return NULL; + + if (!(vm = libxlDomObjFromDomain(domain))) + return NULL; + + if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, vm->def) < 0) { + virObjectUnlock(vm); + return NULL; + } + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + virObjectUnlock(vm); + return NULL; + } + + return libxlDomainMigrationBegin(domain->conn, vm, xmlin); +} +
diff --git a/src/libxl/libxl_migration.c b/src/libxl/libxl_migration.c new file mode 100644 index 0000000..01023db --- /dev/null +++ b/src/libxl/libxl_migration.c @@ -0,0 +1,598 @@ +/* + * libxl_migration.c: methods for handling migration with libxenlight + * + * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Jim Fehlig <jfehlig@suse.com> + * Chunyan Liu <cyliu@suse.com> + */ + +#include <config.h> + +#include "internal.h" +#include "virlog.h" +#include "virerror.h" +#include "virconf.h" +#include "datatypes.h" +#include "virfile.h" +#include "viralloc.h" +#include "viruuid.h" +#include "vircommand.h" +#include "virstring.h" +#include "rpc/virnetsocket.h" +#include "libxl_domain.h" +#include "libxl_driver.h" +#include "libxl_conf.h" +#include "libxl_migration.h" + +#define VIR_FROM_THIS VIR_FROM_LIBXL + +typedef struct _libxlMigrateReceiveArgs { + virConnectPtr conn; + virDomainObjPtr vm; + + /* for freeing listen sockets */ + virNetSocketPtr *socks; + size_t nsocks; +} libxlMigrateReceiveArgs; + +static const char libxlMigrateReceiverReady[] = + "libvirt libxl migration receiver ready, send binary domain data"; +static const char libxlMigrateReceiverFinish[] = + "domain received, ready to unpause";
So you're using these to sync source and destination on migration. Kudos for using text protocol not a binary blob. I haven't followed v1 closely, so what was resolution on this? I mean, my concern is if this is extensible.
I was hoping to keep the libxl side of the protocol simple with only a "ready to receive" and "received" ping-pong, and do most of the heavy lifting within the libvirt V3 protocol. For example subsequent patches can make use of the cookie to do more checks in the begin and prepare phases. But this has made me a bit nervous wrt migrating between a libvirtd containing such enhancements and a libvirtd running this initial migration patch that doesn't support cookies. Perhaps this initial series should ensure any cookiein is NULL? Sadly, I forgot to cc xen-devel on this series (done now) in case the Xen community has some input as well. I'll be sure to include xen-devel on a V3 addressing your comments. Thanks for reviewing the series! Regards, Jim
+ + +static int +libxlCheckMessageBanner(int fd, const char *banner, int banner_sz) +{ + char buf[banner_sz]; + int ret = 0; + + do { + ret = saferead(fd, buf, banner_sz); + } while (ret == -1 && errno == EAGAIN);
The @fd is in blocking state, so we should never get EAGAIN here. But it doesn't hurt to check.
+ + if (ret != banner_sz || memcmp(buf, banner, banner_sz)) { + return -1; + } + + return 0; +} + +static void +libxlDoMigrateReceive(virNetSocketPtr sock, + int events ATTRIBUTE_UNUSED, + void *opaque) +{ + libxlMigrateReceiveArgs *data = opaque; + virConnectPtr conn = data->conn; + virDomainObjPtr vm = data->vm; + virNetSocketPtr *socks = data->socks; + size_t nsocks = data->nsocks; + libxlDriverPrivatePtr driver = conn->privateData; + virNetSocketPtr client_sock; + int recv_fd; + int len; + size_t i; + int ret; + + virNetSocketAccept(sock, &client_sock); + if (client_sock == NULL) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Fail to accept migration connection")); + goto cleanup; + } + VIR_DEBUG("Accepted migration\n"); + recv_fd = virNetSocketDupFD(client_sock, true); + virObjectUnref(client_sock); + + len = sizeof(libxlMigrateReceiverReady); + if (safewrite(recv_fd, libxlMigrateReceiverReady, len) != len) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to write libxlMigrateReceiverReady")); + goto cleanup; + } + + virObjectLock(vm); + ret = libxlDomainStart(driver, vm, false, recv_fd); + virObjectUnlock(vm); + + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to restore domain with libxenlight")); + if (!vm->persistent) { + virDomainObjListRemove(driver->domains, vm); + vm = NULL; + } + goto cleanup; + } + + len = sizeof(libxlMigrateReceiverFinish); + if (safewrite(recv_fd, libxlMigrateReceiverFinish, len) != len) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to write libxlMigrateReceiverFinish")); + } + + /* Remove all listen socks from event handler, and close them. */ + if (nsocks) {
Useless 'if'
+ for (i = 0; i < nsocks; i++) { + virNetSocketUpdateIOCallback(socks[i], 0); + virNetSocketRemoveIOCallback(socks[i]); + virNetSocketClose(socks[i]); + virObjectUnref(socks[i]); + } + VIR_FREE(socks); + } + +cleanup: + VIR_FORCE_CLOSE(recv_fd); + VIR_FREE(opaque); + return; +} +
+int +libxlDomainMigrationPrepare(virConnectPtr dconn, + virDomainDefPtr def, + const char *uri_in, + char **uri_out) +{ + libxlDriverPrivatePtr driver = dconn->privateData; + virDomainObjPtr vm = NULL; + char *hostname = NULL; + unsigned short port; + char portstr[100]; + virURIPtr uri = NULL; + virNetSocketPtr *socks = NULL; + size_t nsocks = 0; + int nsocks_listen = 0; + libxlMigrateReceiveArgs *args; + size_t i; + int ret = -1; + + if (!(vm = virDomainObjListAdd(driver->domains, def, + driver->xmlopt, + VIR_DOMAIN_OBJ_LIST_ADD_LIVE | + VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, + NULL))) + goto cleanup; + + /* Create socket connection to receive migration data */ + if (!uri_in) { + if ((hostname = virGetHostname()) == NULL) + goto cleanup; + + if (STRPREFIX(hostname, "localhost")) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("hostname on destination resolved to localhost," + " but migration requires an FQDN")); + goto cleanup; + } + + if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) + goto cleanup; + + if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0) + goto cleanup; + } else { + if (!(STRPREFIX(uri_in, "tcp://"))) { + /* not full URI, add prefix tcp:// */ + char *tmp; + if (virAsprintf(&tmp, "tcp://%s", uri_in) < 0) + goto cleanup; + uri = virURIParse(tmp); + VIR_FREE(tmp); + } else { + uri = virURIParse(uri_in); + } + + if (uri == NULL) { + virReportError(VIR_ERR_INVALID_ARG, + _("unable to parse URI: %s"), + uri_in); + goto cleanup; + } + + if (uri->server == NULL) { + virReportError(VIR_ERR_INVALID_ARG, + _("missing host in migration URI: %s"), + uri_in); + goto cleanup; + } else { + hostname = uri->server; + } + + if (uri->port == 0) { + if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) + goto cleanup; + + } else { + port = uri->port; + } + + if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0) + goto cleanup; + } + + snprintf(portstr, sizeof(portstr), "%d", port); + + if (virNetSocketNewListenTCP(hostname, portstr, &socks, &nsocks) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Fail to create socket for incoming migration")); + goto cleanup; + } + + if (VIR_ALLOC(args) < 0) + goto cleanup; + + args->conn = dconn; + args->vm = vm; + args->socks = socks; + args->nsocks = nsocks; + + for (i = 0; i < nsocks; i++) { + if (virNetSocketSetBlocking(socks[i], true) < 0) + continue; + if (virNetSocketListen(socks[i], 1) < 0) + continue; + + if (virNetSocketAddIOCallback(socks[i], + 0, + libxlDoMigrateReceive, + args, + NULL) < 0) { + continue; + } + + virNetSocketUpdateIOCallback(socks[i], VIR_EVENT_HANDLE_READABLE); + nsocks_listen++; + } + + if (!nsocks_listen) + goto cleanup; + + ret = 0; + goto done; + +cleanup: + if (nsocks) {
There's no need for this 'if'.
+ for (i = 0; i < nsocks; i++) { + virNetSocketClose(socks[i]); + virObjectUnref(socks[i]); + } + VIR_FREE(socks); + } + +done: + virURIFree(uri); + if (vm) + virObjectUnlock(vm); + return ret; +} + +int +libxlDomainMigrationPerform(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + const char *dom_xml ATTRIBUTE_UNUSED, + const char *dconnuri ATTRIBUTE_UNUSED, + const char *uri_str, + const char *dname ATTRIBUTE_UNUSED, + unsigned int flags) +{ + char *hostname = NULL; + unsigned short port = 0; + char portstr[100]; + virURIPtr uri = NULL; + virNetSocketPtr sock; + int sockfd = -1; + int saved_errno = EINVAL; + int ret = -1; +
Missing virCheckFlags(VIR_MIGRATE_LIVE, -1);
+ /* parse dst host:port from uri */ + uri = virURIParse(uri_str); + if (uri == NULL || uri->server == NULL || uri->port == 0) + goto cleanup; + + hostname = uri->server; + port = uri->port; + snprintf(portstr, sizeof(portstr), "%d", port); + + /* socket connect to dst host:port */ + if (virNetSocketNewConnectTCP(hostname, portstr, &sock) < 0) { + virReportSystemError(saved_errno, + _("unable to connect to '%s:%s'"), + hostname, portstr); + goto cleanup; + } + + if (virNetSocketSetBlocking(sock, true) < 0) { + virObjectUnref(sock); + goto cleanup; + } + + sockfd = virNetSocketDupFD(sock, true); + virObjectUnref(sock); + + /* suspend vm and send saved data to dst through socket fd */ + virObjectUnlock(vm); + ret = libxlDoMigrateSend(driver, vm, flags, sockfd); + virObjectLock(vm); + +cleanup: + VIR_FORCE_CLOSE(sockfd); + virURIFree(uri); + return ret; +} + +virDomainPtr +libxlDomainMigrationFinish(virConnectPtr dconn, + virDomainObjPtr vm, + unsigned int flags, + int cancelled) +{ + libxlDriverPrivatePtr driver = dconn->privateData; + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + libxlDomainObjPrivatePtr priv = vm->privateData; + virObjectEventPtr event = NULL; + virDomainPtr dom = NULL; + + virPortAllocatorRelease(driver->migrationPorts, priv->migrationPort); + priv->migrationPort = 0; + + if (cancelled) + goto cleanup; + + if (!(flags & VIR_MIGRATE_PAUSED)) { + if (libxl_domain_unpause(priv->ctx, vm->def->id) != 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to unpause domain")); + goto cleanup; + } + + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_MIGRATED); + event = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_RESUMED, + VIR_DOMAIN_EVENT_RESUMED_MIGRATED); + } else { + virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER); + event = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_SUSPENDED_PAUSED); + } + + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) + goto cleanup; + + dom = virGetDomain(dconn, vm->def->name, vm->def->uuid); + + if (dom == NULL) { + libxl_domain_destroy(priv->ctx, vm->def->id, NULL); + libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_FAILED); + libxlDomainEventQueue(driver, event); + } + +cleanup: + if (event) + libxlDomainEventQueue(driver, event); + if (vm) + virObjectUnlock(vm); + virObjectUnref(cfg); + return dom; +} + +int +libxlDomainMigrationConfirm(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + unsigned int flags, + int cancelled) +{ + libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver); + libxlDomainObjPrivatePtr priv = vm->privateData; + virObjectEventPtr event = NULL; + int ret = -1; + + if (cancelled) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("migration failed, attempting to resume on source host")); + if (libxl_domain_resume(priv->ctx, vm->def->id, 1, 0) == 0) { + ret = 0; + } else { + VIR_DEBUG("Unable to resume domain '%s' after failed migration", + vm->def->name); + virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, + VIR_DOMAIN_PAUSED_MIGRATION); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED); + ignore_value(virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm)); + } + goto cleanup; + } + + libxl_domain_destroy(priv->ctx, vm->def->id, NULL); + libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_MIGRATED); + + VIR_DEBUG("Domain '%s' successfully migrated", vm->def->name); + + if (flags & VIR_MIGRATE_UNDEFINE_SOURCE) + virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm); + + if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) + virDomainObjListRemove(driver->domains, vm); + + ret = 0; + +cleanup: + if (!libxlDomainObjEndJob(driver, vm)) + vm = NULL; + if (event) + libxlDomainEventQueue(driver, event); + if (vm) + virObjectUnlock(vm); + virObjectUnref(cfg); + return ret; +} diff --git a/src/libxl/libxl_migration.h b/src/libxl/libxl_migration.h new file mode 100644 index 0000000..63d8bdc --- /dev/null +++ b/src/libxl/libxl_migration.h @@ -0,0 +1,78 @@ +/* + * libxl_migration.h: methods for handling migration with libxenlight + * + * Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Jim Fehlig <jfehlig@suse.com> + */ + +#ifndef LIBXL_MIGRATION_H +# define LIBXL_MIGRATION_H + +# include "libxl_conf.h" + +# define LIBXL_MIGRATION_FLAGS \ + (VIR_MIGRATE_LIVE | \ + VIR_MIGRATE_UNDEFINE_SOURCE | \ + VIR_MIGRATE_PAUSED) + +/* All supported migration parameters and their types. */ +# define LIBXL_MIGRATION_PARAMETERS \ + VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ + NULL + +char * +libxlDomainMigrationBegin(virConnectPtr conn, + virDomainObjPtr vm, + const char *xmlin); + +virDomainDefPtr +libxlDomainMigrationPrepareDef(libxlDriverPrivatePtr driver, + const char *dom_xml, + const char *dname); + +int +libxlDomainMigrationPrepare(virConnectPtr dconn, + virDomainDefPtr def, + const char *uri_in, + char **uri_out); + +int +libxlDomainMigrationPerform(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + const char *dom_xml, + const char *dconnuri, + const char *uri_str, + const char *dname, + unsigned int flags); + +virDomainPtr +libxlDomainMigrationFinish(virConnectPtr dconn, + virDomainObjPtr vm, + unsigned int flags, + int cancelled); + +int +libxlDomainMigrationConfirm(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + unsigned int flags, + int cancelled); + +#endif /* LIBXL_DRIVER_H */
Michal

Michal Privoznik wrote:
On 13.03.2014 23:11, Jim Fehlig wrote:
This patch adds initial migration support to the libxl driver, using the VIR_DRV_FEATURE_MIGRATION_PARAMS family of migration functions.
Signed-off-by: Jim Fehlig <jfehlig@suse.com> ---
V2: - Now that the libxl driver supports hostdev passthrough, ensure domain has no hostdevs before migration - Fail early in libxlDomainMigrateBegin3Params if domain is inactive - Change name of local variable in libxlDoMigrateSend from 'live' to 'xl_flags'.
po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/libxl/libxl_conf.h | 6 + src/libxl/libxl_domain.h | 1 + src/libxl/libxl_driver.c | 225 +++++++++++++++++ src/libxl/libxl_migration.c | 598 ++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_migration.h | 78 ++++++ 7 files changed, 911 insertions(+), 1 deletion(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 3306dc1..6fc5266 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c
@@ -4313,6 +4323,216 @@ cleanup: return ret; }
+static char * +libxlDomainMigrateBegin3Params(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags) +{ + const char *xmlin = NULL; + const char *dname = NULL; + virDomainObjPtr vm = NULL; + + virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL); + if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0) + return NULL; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_XML, + &xmlin) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0)
I'd expect @dname to be used somewhere...
Seems I followed the qemu driver too closely, where AFAICT dname isn't used in the begin phase either. Is there even anything to do with dname in the begin phase on the migration source?
+ return NULL; + + if (!(vm = libxlDomObjFromDomain(domain))) + return NULL; + + if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, vm->def) < 0) { + virObjectUnlock(vm); + return NULL; + } + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + virObjectUnlock(vm); + return NULL; + } + + return libxlDomainMigrationBegin(domain->conn, vm, xmlin); +} +
diff --git a/src/libxl/libxl_migration.c b/src/libxl/libxl_migration.c new file mode 100644 index 0000000..01023db --- /dev/null +++ b/src/libxl/libxl_migration.c @@ -0,0 +1,598 @@ +/* + * libxl_migration.c: methods for handling migration with libxenlight + * + * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Jim Fehlig <jfehlig@suse.com> + * Chunyan Liu <cyliu@suse.com> + */ + +#include <config.h> + +#include "internal.h" +#include "virlog.h" +#include "virerror.h" +#include "virconf.h" +#include "datatypes.h" +#include "virfile.h" +#include "viralloc.h" +#include "viruuid.h" +#include "vircommand.h" +#include "virstring.h" +#include "rpc/virnetsocket.h" +#include "libxl_domain.h" +#include "libxl_driver.h" +#include "libxl_conf.h" +#include "libxl_migration.h" + +#define VIR_FROM_THIS VIR_FROM_LIBXL + +typedef struct _libxlMigrateReceiveArgs { + virConnectPtr conn; + virDomainObjPtr vm; + + /* for freeing listen sockets */ + virNetSocketPtr *socks; + size_t nsocks; +} libxlMigrateReceiveArgs; + +static const char libxlMigrateReceiverReady[] = + "libvirt libxl migration receiver ready, send binary domain data"; +static const char libxlMigrateReceiverFinish[] = + "domain received, ready to unpause";
So you're using these to sync source and destination on migration. Kudos for using text protocol not a binary blob. I haven't followed v1 closely, so what was resolution on this? I mean, my concern is if this is extensible.
+ + +static int +libxlCheckMessageBanner(int fd, const char *banner, int banner_sz) +{ + char buf[banner_sz]; + int ret = 0; + + do { + ret = saferead(fd, buf, banner_sz); + } while (ret == -1 && errno == EAGAIN);
The @fd is in blocking state, so we should never get EAGAIN here. But it doesn't hurt to check.
+ + if (ret != banner_sz || memcmp(buf, banner, banner_sz)) { + return -1; + } + + return 0; +} + +static void +libxlDoMigrateReceive(virNetSocketPtr sock, + int events ATTRIBUTE_UNUSED, + void *opaque) +{ + libxlMigrateReceiveArgs *data = opaque; + virConnectPtr conn = data->conn; + virDomainObjPtr vm = data->vm; + virNetSocketPtr *socks = data->socks; + size_t nsocks = data->nsocks; + libxlDriverPrivatePtr driver = conn->privateData; + virNetSocketPtr client_sock; + int recv_fd; + int len; + size_t i; + int ret; + + virNetSocketAccept(sock, &client_sock); + if (client_sock == NULL) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Fail to accept migration connection")); + goto cleanup; + } + VIR_DEBUG("Accepted migration\n"); + recv_fd = virNetSocketDupFD(client_sock, true); + virObjectUnref(client_sock); + + len = sizeof(libxlMigrateReceiverReady); + if (safewrite(recv_fd, libxlMigrateReceiverReady, len) != len) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to write libxlMigrateReceiverReady")); + goto cleanup; + } + + virObjectLock(vm); + ret = libxlDomainStart(driver, vm, false, recv_fd); + virObjectUnlock(vm); + + if (ret < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to restore domain with libxenlight")); + if (!vm->persistent) { + virDomainObjListRemove(driver->domains, vm); + vm = NULL; + } + goto cleanup; + } + + len = sizeof(libxlMigrateReceiverFinish); + if (safewrite(recv_fd, libxlMigrateReceiverFinish, len) != len) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to write libxlMigrateReceiverFinish")); + } + + /* Remove all listen socks from event handler, and close them. */ + if (nsocks) {
Useless 'if'
+ for (i = 0; i < nsocks; i++) { + virNetSocketUpdateIOCallback(socks[i], 0); + virNetSocketRemoveIOCallback(socks[i]); + virNetSocketClose(socks[i]); + virObjectUnref(socks[i]); + } + VIR_FREE(socks); + } + +cleanup: + VIR_FORCE_CLOSE(recv_fd); + VIR_FREE(opaque); + return; +} +
+int +libxlDomainMigrationPrepare(virConnectPtr dconn, + virDomainDefPtr def, + const char *uri_in, + char **uri_out) +{ + libxlDriverPrivatePtr driver = dconn->privateData; + virDomainObjPtr vm = NULL; + char *hostname = NULL; + unsigned short port; + char portstr[100]; + virURIPtr uri = NULL; + virNetSocketPtr *socks = NULL; + size_t nsocks = 0; + int nsocks_listen = 0; + libxlMigrateReceiveArgs *args; + size_t i; + int ret = -1; + + if (!(vm = virDomainObjListAdd(driver->domains, def, + driver->xmlopt, + VIR_DOMAIN_OBJ_LIST_ADD_LIVE | + VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, + NULL))) + goto cleanup; + + /* Create socket connection to receive migration data */ + if (!uri_in) { + if ((hostname = virGetHostname()) == NULL) + goto cleanup; + + if (STRPREFIX(hostname, "localhost")) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("hostname on destination resolved to localhost," + " but migration requires an FQDN")); + goto cleanup; + } + + if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) + goto cleanup; + + if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0) + goto cleanup; + } else { + if (!(STRPREFIX(uri_in, "tcp://"))) { + /* not full URI, add prefix tcp:// */ + char *tmp; + if (virAsprintf(&tmp, "tcp://%s", uri_in) < 0) + goto cleanup; + uri = virURIParse(tmp); + VIR_FREE(tmp); + } else { + uri = virURIParse(uri_in); + } + + if (uri == NULL) { + virReportError(VIR_ERR_INVALID_ARG, + _("unable to parse URI: %s"), + uri_in); + goto cleanup; + } + + if (uri->server == NULL) { + virReportError(VIR_ERR_INVALID_ARG, + _("missing host in migration URI: %s"), + uri_in); + goto cleanup; + } else { + hostname = uri->server; + } + + if (uri->port == 0) { + if (virPortAllocatorAcquire(driver->migrationPorts, &port) < 0) + goto cleanup; + + } else { + port = uri->port; + } + + if (virAsprintf(uri_out, "tcp://%s:%d", hostname, port) < 0) + goto cleanup; + } + + snprintf(portstr, sizeof(portstr), "%d", port); + + if (virNetSocketNewListenTCP(hostname, portstr, &socks, &nsocks) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Fail to create socket for incoming migration")); + goto cleanup; + } + + if (VIR_ALLOC(args) < 0) + goto cleanup; + + args->conn = dconn; + args->vm = vm; + args->socks = socks; + args->nsocks = nsocks; + + for (i = 0; i < nsocks; i++) { + if (virNetSocketSetBlocking(socks[i], true) < 0) + continue; + if (virNetSocketListen(socks[i], 1) < 0) + continue; + + if (virNetSocketAddIOCallback(socks[i], + 0, + libxlDoMigrateReceive, + args, + NULL) < 0) { + continue; + } + + virNetSocketUpdateIOCallback(socks[i], VIR_EVENT_HANDLE_READABLE); + nsocks_listen++; + } + + if (!nsocks_listen) + goto cleanup; + + ret = 0; + goto done; + +cleanup: + if (nsocks) {
There's no need for this 'if'.
+ for (i = 0; i < nsocks; i++) { + virNetSocketClose(socks[i]); + virObjectUnref(socks[i]); + } + VIR_FREE(socks); + } + +done: + virURIFree(uri); + if (vm) + virObjectUnlock(vm); + return ret; +} + +int +libxlDomainMigrationPerform(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + const char *dom_xml ATTRIBUTE_UNUSED, + const char *dconnuri ATTRIBUTE_UNUSED, + const char *uri_str, + const char *dname ATTRIBUTE_UNUSED, + unsigned int flags) +{ + char *hostname = NULL; + unsigned short port = 0; + char portstr[100]; + virURIPtr uri = NULL; + virNetSocketPtr sock; + int sockfd = -1; + int saved_errno = EINVAL; + int ret = -1; +
Missing virCheckFlags(VIR_MIGRATE_LIVE, -1);
Flags are checked in the calling function, libxlDomainMigratePerform3Params. I've fixed up the other issues you mentioned, but will wait to send a V3 until clarifying the use of dname in the begin phase. Regards, Jim

On 19.03.2014 23:52, Jim Fehlig wrote:
Michal Privoznik wrote:
On 13.03.2014 23:11, Jim Fehlig wrote:
This patch adds initial migration support to the libxl driver, using the VIR_DRV_FEATURE_MIGRATION_PARAMS family of migration functions.
Signed-off-by: Jim Fehlig <jfehlig@suse.com> ---
V2: - Now that the libxl driver supports hostdev passthrough, ensure domain has no hostdevs before migration - Fail early in libxlDomainMigrateBegin3Params if domain is inactive - Change name of local variable in libxlDoMigrateSend from 'live' to 'xl_flags'.
po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/libxl/libxl_conf.h | 6 + src/libxl/libxl_domain.h | 1 + src/libxl/libxl_driver.c | 225 +++++++++++++++++ src/libxl/libxl_migration.c | 598 ++++++++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_migration.h | 78 ++++++ 7 files changed, 911 insertions(+), 1 deletion(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 3306dc1..6fc5266 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c
@@ -4313,6 +4323,216 @@ cleanup: return ret; }
+static char * +libxlDomainMigrateBegin3Params(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags) +{ + const char *xmlin = NULL; + const char *dname = NULL; + virDomainObjPtr vm = NULL; + + virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL); + if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0) + return NULL; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_XML, + &xmlin) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + &dname) < 0)
I'd expect @dname to be used somewhere...
Seems I followed the qemu driver too closely, where AFAICT dname isn't used in the begin phase either. Is there even anything to do with dname in the begin phase on the migration source?
Yes, it's not used in qemu driver either. It's not a bug though. I've just spotted an unused variable so I've pointed it out during review. I'd go with removing it both here and there (in two separate patches) and call it the day.
+libxlDomainMigrationPerform(libxlDriverPrivatePtr driver, + virDomainObjPtr vm, + const char *dom_xml ATTRIBUTE_UNUSED, + const char *dconnuri ATTRIBUTE_UNUSED, + const char *uri_str, + const char *dname ATTRIBUTE_UNUSED, + unsigned int flags) +{ + char *hostname = NULL; + unsigned short port = 0; + char portstr[100]; + virURIPtr uri = NULL; + virNetSocketPtr sock; + int sockfd = -1; + int saved_errno = EINVAL; + int ret = -1; +
Missing virCheckFlags(VIR_MIGRATE_LIVE, -1);
Flags are checked in the calling function, libxlDomainMigratePerform3Params.
Oh, right.
I've fixed up the other issues you mentioned, but will wait to send a V3 until clarifying the use of dname in the begin phase.
Regards, Jim
Michal

On 13.03.2014 23:11, Jim Fehlig wrote:
V2 of
https://www.redhat.com/archives/libvir-list/2014-March/msg00156.html
New in this version: not much. I rebased on the hostdev passthrough changes and added a few 'begin phase' checks to fail early if the domain is not migratable. See 13/13 for details.
Based on an earlier patch from Chunyan Liu
https://www.redhat.com/archives/libvir-list/2013-September/msg00667.html
This patch series adds basic migration support to the libxl driver. Follow-up patches can improve pre-migration checks and add support for additional migration flags.
Patches 1-12 are almost exclusively code motion, moving functions from the main driver module into the libxl_domain and libxl_conf modules. Patch 13 contains the actual migration impl.
Jim Fehlig (13): libxl: move libxlDomainEventQueue to libxl_domain libxl: move libxlDomainManagedSavePath to libxl_domain libxl: move libxlSaveImageOpen to libxl_domain libxl: move libxlVmCleanup{,Job} to libxl_domain libxl: move libxlDomEventsRegister to libxl_domain libxl: move libxlDomainAutoCoreDump to libxl_domain libxl: move libxlDoNodeGetInfo to libxl_conf libxl: move libxlDomainSetVcpuAffinities to libxl_domain libxl: move libxlFreeMem to libxl_domain libxl: move libxlVmStart to libxl_domain libxl: include a pointer to the driver in libxlDomainObjPrivate libxl: move domain event handler to libxl_domain libxl: add migration support
po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/libxl/libxl_conf.c | 36 ++ src/libxl/libxl_conf.h | 10 + src/libxl/libxl_domain.c | 705 +++++++++++++++++++++++++++++++ src/libxl/libxl_domain.h | 51 ++- src/libxl/libxl_driver.c | 988 +++++++++++--------------------------------- src/libxl/libxl_migration.c | 598 +++++++++++++++++++++++++++ src/libxl/libxl_migration.h | 78 ++++ 9 files changed, 1716 insertions(+), 754 deletions(-) create mode 100644 src/libxl/libxl_migration.c create mode 100644 src/libxl/libxl_migration.h
ACK series. The first 12 patches are pure code movement (except for 11/13 which is trivial) and therefore can be pushed right now. However, in the last one I have one question, well concern, so I'd suggest to not push it straight away, but give others a few moments to disagree. And push it after that. You know, it's inventing a new protocol which I fear is not extensible (but do we need an extensibility there anyway?). From code POV, it's clean though. Michal

Michal Privoznik wrote:
On 13.03.2014 23:11, Jim Fehlig wrote:
V2 of
https://www.redhat.com/archives/libvir-list/2014-March/msg00156.html
New in this version: not much. I rebased on the hostdev passthrough changes and added a few 'begin phase' checks to fail early if the domain is not migratable. See 13/13 for details.
Based on an earlier patch from Chunyan Liu
https://www.redhat.com/archives/libvir-list/2013-September/msg00667.html
This patch series adds basic migration support to the libxl driver. Follow-up patches can improve pre-migration checks and add support for additional migration flags.
Patches 1-12 are almost exclusively code motion, moving functions from the main driver module into the libxl_domain and libxl_conf modules. Patch 13 contains the actual migration impl.
Jim Fehlig (13): libxl: move libxlDomainEventQueue to libxl_domain libxl: move libxlDomainManagedSavePath to libxl_domain libxl: move libxlSaveImageOpen to libxl_domain libxl: move libxlVmCleanup{,Job} to libxl_domain libxl: move libxlDomEventsRegister to libxl_domain libxl: move libxlDomainAutoCoreDump to libxl_domain libxl: move libxlDoNodeGetInfo to libxl_conf libxl: move libxlDomainSetVcpuAffinities to libxl_domain libxl: move libxlFreeMem to libxl_domain libxl: move libxlVmStart to libxl_domain libxl: include a pointer to the driver in libxlDomainObjPrivate libxl: move domain event handler to libxl_domain libxl: add migration support
po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/libxl/libxl_conf.c | 36 ++ src/libxl/libxl_conf.h | 10 + src/libxl/libxl_domain.c | 705 +++++++++++++++++++++++++++++++ src/libxl/libxl_domain.h | 51 ++- src/libxl/libxl_driver.c | 988 +++++++++++--------------------------------- src/libxl/libxl_migration.c | 598 +++++++++++++++++++++++++++ src/libxl/libxl_migration.h | 78 ++++ 9 files changed, 1716 insertions(+), 754 deletions(-) create mode 100644 src/libxl/libxl_migration.c create mode 100644 src/libxl/libxl_migration.h
ACK series. The first 12 patches are pure code movement (except for 11/13 which is trivial) and therefore can be pushed right now.
Thanks, 1-12 pushed. I'll send a V3 of 13 addressing your comments. Regards, Jim
participants (2)
-
Jim Fehlig
-
Michal Privoznik