John Ferlan wrote: > This patch has resulted in a new Coverity warnings (looking at them was > just lower on my list of things to do lately)... > > Anyway - see libxlDoMigrateReceive() and libxlDomainMigrationFinish() > for the details... > Should have looked at this before responding to your patch to fix the warnings. Does that patch fix all the issues noted below? Regards, Jim > John > > On 06/04/2014 04:35 PM, 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@xxxxxxxx> >> --- >> 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 | 235 ++++++++++++++++++ >> src/libxl/libxl_migration.c | 585 ++++++++++++++++++++++++++++++++++++++++++++ >> src/libxl/libxl_migration.h | 79 ++++++ >> 7 files changed, 909 insertions(+), 1 deletion(-) >> >> diff --git a/po/POTFILES.in b/po/POTFILES.in >> index cff92d9..2ee7225 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/network/leaseshelper.c >> diff --git a/src/Makefile.am b/src/Makefile.am >> index d82ca26..01af164 100644 >> --- a/src/Makefile.am >> +++ b/src/Makefile.am >> @@ -707,7 +707,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 433d6da..6aa36d2 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 6939008..f459fdf 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 515d5c9..9feacb1 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" >> @@ -209,6 +210,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); >> @@ -301,6 +303,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; >> >> @@ -4153,6 +4162,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; >> @@ -4331,6 +4341,226 @@ libxlNodeDeviceReset(virNodeDevicePtr dev) >> 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; >> + 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) >> + 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, flags) < 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) { >> + /* Job terminated and vm unlocked if MigrationPerform failed */ >> + vm = NULL; >> + 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))) { >> + /* Migration obviously failed if the domain doesn't exist */ >> + virReportError(VIR_ERR_OPERATION_FAILED, >> + _("Migration failed. No domain on destination host " >> + "with matching name '%s'"), >> + NULLSTR(dname)); >> + return NULL; >> + } >> + >> + if (virDomainMigrateFinish3ParamsEnsureACL(dconn, vm->def) < 0) { >> + virObjectUnlock(vm); >> + return NULL; >> + } >> + >> + if (!virDomainObjIsActive(vm)) { >> + /* Migration failed if domain is inactive */ >> + virReportError(VIR_ERR_OPERATION_FAILED, >> + "%s", _("Migration failed. Domain is not running " >> + "on destination host")); >> + 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, >> @@ -4421,6 +4651,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..9fe904e >> --- /dev/null >> +++ b/src/libxl/libxl_migration.c >> @@ -0,0 +1,585 @@ >> +/* >> + * 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@xxxxxxxx> >> + * Chunyan Liu <cyliu@xxxxxxxx> >> + */ >> + >> +#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 "virobject.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 >> + >> +VIR_LOG_INIT("libxl.libxl_migration"); >> + >> +typedef struct _libxlMigrationDstArgs { >> + virObject parent; >> + >> + virConnectPtr conn; >> + virDomainObjPtr vm; >> + unsigned int flags; >> + >> + /* for freeing listen sockets */ >> + virNetSocketPtr *socks; >> + size_t nsocks; >> +} libxlMigrationDstArgs; >> + >> +static virClassPtr libxlMigrationDstArgsClass; >> + >> +static void >> +libxlMigrationDstArgsDispose(void *obj) >> +{ >> + libxlMigrationDstArgs *args = obj; >> + >> + VIR_FREE(args->socks); >> +} >> + >> +static int >> +libxlMigrationDstArgsOnceInit(void) >> +{ >> + if (!(libxlMigrationDstArgsClass = virClassNew(virClassForObject(), >> + "libxlMigrationDstArgs", >> + sizeof(libxlMigrationDstArgs), >> + libxlMigrationDstArgsDispose))) >> + return -1; >> + >> + return 0; >> +} >> + >> +VIR_ONCE_GLOBAL_INIT(libxlMigrationDstArgs) >> + >> +static void >> +libxlDoMigrateReceive(virNetSocketPtr sock, >> + int events ATTRIBUTE_UNUSED, >> + void *opaque) >> +{ >> + libxlMigrationDstArgs *args = opaque; >> + virConnectPtr conn = args->conn; >> + virDomainObjPtr vm = args->vm; >> + virNetSocketPtr *socks = args->socks; >> + size_t nsocks = args->nsocks; >> + bool paused = args->flags & VIR_MIGRATE_PAUSED; >> + libxlDriverPrivatePtr driver = conn->privateData; >> + virNetSocketPtr client_sock; >> + int recvfd = -1; >> + size_t i; >> + int ret; >> + >> + virNetSocketAccept(sock, &client_sock); >> > > (1) Event check_return: Calling "virNetSocketAccept" without checking > return value (as is done elsewhere 5 out of 6 times). > > >> + if (client_sock == NULL) { >> + virReportError(VIR_ERR_OPERATION_INVALID, "%s", >> + _("Fail to accept migration connection")); >> + goto cleanup; >> + } >> + VIR_DEBUG("Accepted migration connection\n"); >> + recvfd = virNetSocketDupFD(client_sock, true); >> + virObjectUnref(client_sock); >> + >> + virObjectLock(vm); >> + ret = libxlDomainStart(driver, vm, paused, recvfd); >> + virObjectUnlock(vm); >> + >> + if (ret < 0 && !vm->persistent) >> + virDomainObjListRemove(driver->domains, vm); >> + >> + cleanup: >> + /* Remove all listen socks from event handler, and close them. */ >> + for (i = 0; i < nsocks; i++) { >> + virNetSocketUpdateIOCallback(socks[i], 0); >> + virNetSocketRemoveIOCallback(socks[i]); >> + virNetSocketClose(socks[i]); >> + virObjectUnref(socks[i]); >> + socks[i] = NULL; >> + } >> + args->nsocks = 0; >> + VIR_FORCE_CLOSE(recvfd); >> +} >> + >> +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; >> + >> + if (flags & VIR_MIGRATE_LIVE) >> + xl_flags = LIBXL_SUSPEND_LIVE; >> + >> + priv = vm->privateData; >> + ret = libxl_domain_suspend(priv->ctx, vm->def->id, sockfd, >> + xl_flags, NULL); >> + if (ret != 0) { >> + /* attempt to resume the domain on failure */ >> + if (libxl_domain_resume(priv->ctx, vm->def->id, 0, 0) != 0) { >> + VIR_DEBUG("Failed to resume domain following failed migration"); >> + 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)); >> + } >> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", >> + _("Failed to send migration data to destination host")); >> + ret = -1; >> + goto cleanup; >> + } >> + >> + 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; >> + >> + if (!libxlDomainDefCheckABIStability(driver, vm->def, tmpdef)) >> + 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, >> + unsigned int flags) >> +{ >> + 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; >> + libxlMigrationDstArgs *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 (libxlMigrationDstArgsInitialize() < 0) >> + goto cleanup; >> + >> + if (!(args = virObjectNew(libxlMigrationDstArgsClass))) >> + goto cleanup; >> + >> + args->conn = dconn; >> + args->vm = vm; >> + args->flags = flags; >> + 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], >> + VIR_EVENT_HANDLE_READABLE, >> + libxlDoMigrateReceive, >> + args, >> + virObjectFreeCallback) < 0) >> + continue; >> + >> + /* >> + * Successfully added sock to event loop. Take a ref on args to >> + * ensure it is not freed until sock is removed from the event loop. >> + * Ref is dropped in virObjectFreeCallback after being removed >> + * from the event loop. >> + */ >> + virObjectRef(args); >> + nsocks_listen++; >> + } >> + >> + /* Done with args in this function, drop reference */ >> + virObjectUnref(args); >> + >> + if (!nsocks_listen) >> + goto cleanup; >> + >> + ret = 0; >> + goto done; >> + >> + cleanup: >> + for (i = 0; i < nsocks; i++) { >> + virNetSocketClose(socks[i]); >> + virObjectUnref(socks[i]); >> + } >> + >> + 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: >> + /* If failure, terminate the job started in MigrationBegin */ >> + if (ret == -1) { >> + if (libxlDomainObjEndJob(driver, vm)) >> + virObjectUnlock(vm); >> + } >> + 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; >> > > The 'vm' is dereferenced here without checking for !vm, although down > below in the cleanup: section there is a "if (vm)" done. Coverity > throws out the following: > > (1) Event deref_ptr: Directly dereferencing pointer "vm". > > >> + 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); >> > > (2) Event check_after_deref: Null-checking "vm" suggests that it may be > null, but it has already been dereferenced on all paths leading to the > check. > > >> + 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) { >> + 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..aab96f5 >> --- /dev/null >> +++ b/src/libxl/libxl_migration.h >> @@ -0,0 +1,79 @@ >> +/* >> + * 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@xxxxxxxx> >> + */ >> + >> +#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, >> + unsigned int flags); >> + >> +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 */ >> >> > > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list