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(a)suse.com>
> ---
> 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(a)suse.com>
> + * Chunyan Liu <cyliu(a)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 "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(a)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,
> + 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 */
>
>