mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-07 17:28:15 +00:00
qemu: keep pre-migration domain state after failed migration
Couple of codepaths shared the same code which can be moved out to a function and on one of such places, qemuMigrationConfirmPhase(), the domain was resumed even if it wasn't running before the migration started. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1057407 Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
This commit is contained in:
parent
630b645695
commit
440a1aa508
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* qemu_domain.h: QEMU domain private state
|
* qemu_domain.h: QEMU domain private state
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006-2013 Red Hat, Inc.
|
* Copyright (C) 2006-2014 Red Hat, Inc.
|
||||||
* Copyright (C) 2006 Daniel P. Berrange
|
* Copyright (C) 2006 Daniel P. Berrange
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
@ -161,6 +161,7 @@ struct _qemuDomainObjPrivate {
|
|||||||
char *origname;
|
char *origname;
|
||||||
int nbdPort; /* Port used for migration with NBD */
|
int nbdPort; /* Port used for migration with NBD */
|
||||||
unsigned short migrationPort;
|
unsigned short migrationPort;
|
||||||
|
int preMigrationState;
|
||||||
|
|
||||||
virChrdevsPtr devs;
|
virChrdevsPtr devs;
|
||||||
|
|
||||||
|
@ -1075,6 +1075,53 @@ error:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qemuMigrationStoreDomainState(virDomainObjPtr vm)
|
||||||
|
{
|
||||||
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
priv->preMigrationState = virDomainObjGetState(vm, NULL);
|
||||||
|
|
||||||
|
VIR_DEBUG("Storing pre-migration state=%d domain=%p",
|
||||||
|
priv->preMigrationState, vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if the domain was resumed, false otherwise */
|
||||||
|
static bool
|
||||||
|
qemuMigrationRestoreDomainState(virConnectPtr conn, virDomainObjPtr vm)
|
||||||
|
{
|
||||||
|
virQEMUDriverPtr driver = conn->privateData;
|
||||||
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
int state = virDomainObjGetState(vm, NULL);
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
VIR_DEBUG("driver=%p, vm=%p, pre-mig-state=%d, state=%d",
|
||||||
|
driver, vm, priv->preMigrationState, state);
|
||||||
|
|
||||||
|
if (state == VIR_DOMAIN_PAUSED &&
|
||||||
|
priv->preMigrationState == VIR_DOMAIN_RUNNING) {
|
||||||
|
/* This is basically the only restore possibility that's safe
|
||||||
|
* and we should attempt to do */
|
||||||
|
|
||||||
|
VIR_DEBUG("Restoring pre-migration state due to migration error");
|
||||||
|
|
||||||
|
/* we got here through some sort of failure; start the domain again */
|
||||||
|
if (qemuProcessStartCPUs(driver, vm, conn,
|
||||||
|
VIR_DOMAIN_RUNNING_MIGRATION_CANCELED,
|
||||||
|
QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) {
|
||||||
|
/* Hm, we already know we are in error here. We don't want to
|
||||||
|
* overwrite the previous error, though, so we just throw something
|
||||||
|
* to the logs and hope for the best */
|
||||||
|
VIR_ERROR(_("Failed to resume guest %s after failure"), vm->def->name);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
priv->preMigrationState = VIR_DOMAIN_NOSTATE;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qemuMigrationStartNBDServer:
|
* qemuMigrationStartNBDServer:
|
||||||
* @driver: qemu driver
|
* @driver: qemu driver
|
||||||
@ -2075,6 +2122,8 @@ qemuMigrationBegin(virConnectPtr conn,
|
|||||||
asyncJob = QEMU_ASYNC_JOB_NONE;
|
asyncJob = QEMU_ASYNC_JOB_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qemuMigrationStoreDomainState(vm);
|
||||||
|
|
||||||
if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
|
if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
|
||||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
"%s", _("domain is not running"));
|
"%s", _("domain is not running"));
|
||||||
@ -2744,22 +2793,12 @@ qemuMigrationConfirmPhase(virQEMUDriverPtr driver,
|
|||||||
/* cancel any outstanding NBD jobs */
|
/* cancel any outstanding NBD jobs */
|
||||||
qemuMigrationCancelDriveMirror(mig, driver, vm);
|
qemuMigrationCancelDriveMirror(mig, driver, vm);
|
||||||
|
|
||||||
/* run 'cont' on the destination, which allows migration on qemu
|
if (qemuMigrationRestoreDomainState(conn, vm)) {
|
||||||
* >= 0.10.6 to work properly. This isn't strictly necessary on
|
event = virDomainEventLifecycleNewFromObj(vm,
|
||||||
* older qemu's, but it also doesn't hurt anything there
|
VIR_DOMAIN_EVENT_RESUMED,
|
||||||
*/
|
VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
|
||||||
if (qemuProcessStartCPUs(driver, vm, conn,
|
|
||||||
VIR_DOMAIN_RUNNING_MIGRATED,
|
|
||||||
QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) {
|
|
||||||
if (virGetLastError() == NULL)
|
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
||||||
"%s", _("resume operation failed"));
|
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event = virDomainEventLifecycleNewFromObj(vm,
|
|
||||||
VIR_DOMAIN_EVENT_RESUMED,
|
|
||||||
VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
|
|
||||||
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
|
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
|
||||||
VIR_WARN("Failed to save status on vm %s", vm->def->name);
|
VIR_WARN("Failed to save status on vm %s", vm->def->name);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -4065,7 +4104,6 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver,
|
|||||||
{
|
{
|
||||||
virObjectEventPtr event = NULL;
|
virObjectEventPtr event = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int resume = 0;
|
|
||||||
virErrorPtr orig_err = NULL;
|
virErrorPtr orig_err = NULL;
|
||||||
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
||||||
bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR);
|
bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR);
|
||||||
@ -4085,7 +4123,7 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver,
|
|||||||
if (!(flags & VIR_MIGRATE_UNSAFE) && !qemuMigrationIsSafe(vm->def))
|
if (!(flags & VIR_MIGRATE_UNSAFE) && !qemuMigrationIsSafe(vm->def))
|
||||||
goto endjob;
|
goto endjob;
|
||||||
|
|
||||||
resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
|
qemuMigrationStoreDomainState(vm);
|
||||||
|
|
||||||
if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
|
if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
|
||||||
ret = doPeer2PeerMigrate(driver, conn, vm, xmlin,
|
ret = doPeer2PeerMigrate(driver, conn, vm, xmlin,
|
||||||
@ -4112,25 +4150,12 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver,
|
|||||||
VIR_DOMAIN_EVENT_STOPPED,
|
VIR_DOMAIN_EVENT_STOPPED,
|
||||||
VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
|
VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
|
||||||
}
|
}
|
||||||
resume = 0;
|
|
||||||
|
|
||||||
endjob:
|
endjob:
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
orig_err = virSaveLastError();
|
orig_err = virSaveLastError();
|
||||||
|
|
||||||
if (resume && virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
|
if (qemuMigrationRestoreDomainState(conn, vm)) {
|
||||||
/* we got here through some sort of failure; start the domain again */
|
|
||||||
if (qemuProcessStartCPUs(driver, vm, conn,
|
|
||||||
VIR_DOMAIN_RUNNING_MIGRATION_CANCELED,
|
|
||||||
QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) {
|
|
||||||
/* Hm, we already know we are in error here. We don't want to
|
|
||||||
* overwrite the previous error, though, so we just throw something
|
|
||||||
* to the logs and hope for the best
|
|
||||||
*/
|
|
||||||
VIR_ERROR(_("Failed to resume guest %s after failure"),
|
|
||||||
vm->def->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
event = virDomainEventLifecycleNewFromObj(vm,
|
event = virDomainEventLifecycleNewFromObj(vm,
|
||||||
VIR_DOMAIN_EVENT_RESUMED,
|
VIR_DOMAIN_EVENT_RESUMED,
|
||||||
VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
|
VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
|
||||||
@ -4179,7 +4204,6 @@ qemuMigrationPerformPhase(virQEMUDriverPtr driver,
|
|||||||
{
|
{
|
||||||
virObjectEventPtr event = NULL;
|
virObjectEventPtr event = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
bool resume;
|
|
||||||
bool hasrefs;
|
bool hasrefs;
|
||||||
|
|
||||||
/* If we didn't start the job in the begin phase, start it now. */
|
/* If we didn't start the job in the begin phase, start it now. */
|
||||||
@ -4194,32 +4218,18 @@ qemuMigrationPerformPhase(virQEMUDriverPtr driver,
|
|||||||
virCloseCallbacksUnset(driver->closeCallbacks, vm,
|
virCloseCallbacksUnset(driver->closeCallbacks, vm,
|
||||||
qemuMigrationCleanup);
|
qemuMigrationCleanup);
|
||||||
|
|
||||||
resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
|
|
||||||
ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen,
|
ret = doNativeMigrate(driver, vm, uri, cookiein, cookieinlen,
|
||||||
cookieout, cookieoutlen,
|
cookieout, cookieoutlen,
|
||||||
flags, resource, NULL, graphicsuri);
|
flags, resource, NULL, graphicsuri);
|
||||||
|
|
||||||
if (ret < 0 && resume &&
|
if (ret < 0) {
|
||||||
virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
|
if (qemuMigrationRestoreDomainState(conn, vm)) {
|
||||||
/* we got here through some sort of failure; start the domain again */
|
event = virDomainEventLifecycleNewFromObj(vm,
|
||||||
if (qemuProcessStartCPUs(driver, vm, conn,
|
VIR_DOMAIN_EVENT_RESUMED,
|
||||||
VIR_DOMAIN_RUNNING_MIGRATION_CANCELED,
|
VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
|
||||||
QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) {
|
|
||||||
/* Hm, we already know we are in error here. We don't want to
|
|
||||||
* overwrite the previous error, though, so we just throw something
|
|
||||||
* to the logs and hope for the best
|
|
||||||
*/
|
|
||||||
VIR_ERROR(_("Failed to resume guest %s after failure"),
|
|
||||||
vm->def->name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event = virDomainEventLifecycleNewFromObj(vm,
|
|
||||||
VIR_DOMAIN_EVENT_RESUMED,
|
|
||||||
VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
goto endjob;
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3_DONE);
|
qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_PERFORM3_DONE);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user