mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
migration: Make erroring out on I/O error controllable by flag
Paolo Bonzini pointed out that it's actually possible to migrate a qemu instance that was paused due to I/O error and it will be able to work on the destination if the storage is accessible. This patch introduces flag VIR_MIGRATE_ABORT_ON_ERROR that cancels the migration in case an I/O error happens while it's being performed and allows migration without this flag. This flag can be possibly used for other error reasons that may be introduced in the future.
This commit is contained in:
parent
ddf8ad82eb
commit
cf6d56ac43
@ -1188,6 +1188,7 @@ typedef enum {
|
||||
VIR_MIGRATE_UNSAFE = (1 << 9), /* force migration even if it is considered unsafe */
|
||||
VIR_MIGRATE_OFFLINE = (1 << 10), /* offline migrate */
|
||||
VIR_MIGRATE_COMPRESSED = (1 << 11), /* compress data during migration */
|
||||
VIR_MIGRATE_ABORT_ON_ERROR = (1 << 12), /* abort migration on I/O errors happened during migration */
|
||||
} virDomainMigrateFlags;
|
||||
|
||||
/* Domain migration. */
|
||||
|
@ -2819,7 +2819,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
|
||||
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
|
||||
goto cleanup;
|
||||
|
||||
if (!qemuMigrationIsAllowed(driver, vm, vm->def, false))
|
||||
if (!qemuMigrationIsAllowed(driver, vm, vm->def, false, false))
|
||||
goto cleanup;
|
||||
|
||||
if (qemuDomainObjBeginAsyncJob(driver, vm,
|
||||
@ -11670,7 +11670,7 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
|
||||
/* do the memory snapshot if necessary */
|
||||
if (memory) {
|
||||
/* check if migration is possible */
|
||||
if (!qemuMigrationIsAllowed(driver, vm, vm->def, false))
|
||||
if (!qemuMigrationIsAllowed(driver, vm, vm->def, false, false))
|
||||
goto endjob;
|
||||
|
||||
/* allow the migration job to be cancelled or the domain to be paused */
|
||||
|
@ -1420,7 +1420,7 @@ cleanup:
|
||||
* the fact that older servers did not do checks on the source. */
|
||||
bool
|
||||
qemuMigrationIsAllowed(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
||||
virDomainDefPtr def, bool remote)
|
||||
virDomainDefPtr def, bool remote, bool abort_on_error)
|
||||
{
|
||||
int nsnapshots;
|
||||
int pauseReason;
|
||||
@ -1448,7 +1448,8 @@ qemuMigrationIsAllowed(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
||||
}
|
||||
|
||||
/* cancel migration if disk I/O error is emitted while migrating */
|
||||
if (virDomainObjGetState(vm, &pauseReason) == VIR_DOMAIN_PAUSED &&
|
||||
if (abort_on_error &&
|
||||
virDomainObjGetState(vm, &pauseReason) == VIR_DOMAIN_PAUSED &&
|
||||
pauseReason == VIR_DOMAIN_PAUSED_IOERROR) {
|
||||
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
||||
_("cannot migrate domain with I/O error"));
|
||||
@ -1709,7 +1710,7 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver,
|
||||
static int
|
||||
qemuMigrationWaitForCompletion(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
||||
enum qemuDomainAsyncJob asyncJob,
|
||||
virConnectPtr dconn)
|
||||
virConnectPtr dconn, bool abort_on_error)
|
||||
{
|
||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||
const char *job;
|
||||
@ -1736,7 +1737,7 @@ qemuMigrationWaitForCompletion(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
||||
struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };
|
||||
|
||||
/* cancel migration if disk I/O error is emitted while migrating */
|
||||
if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT &&
|
||||
if (abort_on_error &&
|
||||
virDomainObjGetState(vm, &pauseReason) == VIR_DOMAIN_PAUSED &&
|
||||
pauseReason == VIR_DOMAIN_PAUSED_IOERROR)
|
||||
goto cancel;
|
||||
@ -1937,6 +1938,7 @@ char *qemuMigrationBegin(virQEMUDriverPtr driver,
|
||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||
virCapsPtr caps = NULL;
|
||||
unsigned int cookieFlags = QEMU_MIGRATION_COOKIE_LOCKSTATE;
|
||||
bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR);
|
||||
|
||||
VIR_DEBUG("driver=%p, vm=%p, xmlin=%s, dname=%s,"
|
||||
" cookieout=%p, cookieoutlen=%p, flags=%lx",
|
||||
@ -1953,7 +1955,7 @@ char *qemuMigrationBegin(virQEMUDriverPtr driver,
|
||||
if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT)
|
||||
qemuMigrationJobSetPhase(driver, vm, QEMU_MIGRATION_PHASE_BEGIN3);
|
||||
|
||||
if (!qemuMigrationIsAllowed(driver, vm, NULL, true))
|
||||
if (!qemuMigrationIsAllowed(driver, vm, NULL, true, abort_on_error))
|
||||
goto cleanup;
|
||||
|
||||
if (!(flags & VIR_MIGRATE_UNSAFE) && !qemuMigrationIsSafe(vm->def))
|
||||
@ -2069,6 +2071,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
|
||||
virCapsPtr caps = NULL;
|
||||
const char *listenAddr = NULL;
|
||||
char *migrateFrom = NULL;
|
||||
bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR);
|
||||
|
||||
if (virTimeMillisNow(&now) < 0)
|
||||
return -1;
|
||||
@ -2098,7 +2101,7 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
|
||||
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
|
||||
goto cleanup;
|
||||
|
||||
if (!qemuMigrationIsAllowed(driver, NULL, *def, true))
|
||||
if (!qemuMigrationIsAllowed(driver, NULL, *def, true, abort_on_error))
|
||||
goto cleanup;
|
||||
|
||||
/* Let migration hook filter domain XML */
|
||||
@ -2795,6 +2798,7 @@ qemuMigrationRun(virQEMUDriverPtr driver,
|
||||
unsigned long migrate_speed = resource ? resource : priv->migMaxBandwidth;
|
||||
virErrorPtr orig_err = NULL;
|
||||
unsigned int cookieFlags = 0;
|
||||
bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR);
|
||||
|
||||
VIR_DEBUG("driver=%p, vm=%p, cookiein=%s, cookieinlen=%d, "
|
||||
"cookieout=%p, cookieoutlen=%p, flags=%lx, resource=%lu, "
|
||||
@ -2947,7 +2951,7 @@ qemuMigrationRun(virQEMUDriverPtr driver,
|
||||
|
||||
if (qemuMigrationWaitForCompletion(driver, vm,
|
||||
QEMU_ASYNC_JOB_MIGRATION_OUT,
|
||||
dconn) < 0)
|
||||
dconn, abort_on_error) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* When migration completed, QEMU will have paused the
|
||||
@ -3628,6 +3632,7 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver,
|
||||
int resume = 0;
|
||||
virErrorPtr orig_err = NULL;
|
||||
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
||||
bool abort_on_error = !!(flags & VIR_MIGRATE_ABORT_ON_ERROR);
|
||||
|
||||
if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
|
||||
goto cleanup;
|
||||
@ -3638,7 +3643,7 @@ qemuMigrationPerformJob(virQEMUDriverPtr driver,
|
||||
goto endjob;
|
||||
}
|
||||
|
||||
if (!qemuMigrationIsAllowed(driver, vm, NULL, true))
|
||||
if (!qemuMigrationIsAllowed(driver, vm, NULL, true, abort_on_error))
|
||||
goto endjob;
|
||||
|
||||
if (!(flags & VIR_MIGRATE_UNSAFE) && !qemuMigrationIsSafe(vm->def))
|
||||
@ -4338,7 +4343,7 @@ qemuMigrationToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
||||
if (rc < 0)
|
||||
goto cleanup;
|
||||
|
||||
rc = qemuMigrationWaitForCompletion(driver, vm, asyncJob, NULL);
|
||||
rc = qemuMigrationWaitForCompletion(driver, vm, asyncJob, NULL, false);
|
||||
|
||||
if (rc < 0)
|
||||
goto cleanup;
|
||||
|
@ -38,7 +38,8 @@
|
||||
VIR_MIGRATE_CHANGE_PROTECTION | \
|
||||
VIR_MIGRATE_UNSAFE | \
|
||||
VIR_MIGRATE_OFFLINE | \
|
||||
VIR_MIGRATE_COMPRESSED)
|
||||
VIR_MIGRATE_COMPRESSED | \
|
||||
VIR_MIGRATE_ABORT_ON_ERROR)
|
||||
|
||||
enum qemuMigrationJobPhase {
|
||||
QEMU_MIGRATION_PHASE_NONE = 0,
|
||||
@ -147,7 +148,8 @@ int qemuMigrationConfirm(virQEMUDriverPtr driver,
|
||||
int retcode);
|
||||
|
||||
bool qemuMigrationIsAllowed(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
||||
virDomainDefPtr def, bool remote);
|
||||
virDomainDefPtr def, bool remote,
|
||||
bool abort_on_error);
|
||||
|
||||
int qemuMigrationToFile(virQEMUDriverPtr driver, virDomainObjPtr vm,
|
||||
int fd, off_t offset, const char *path,
|
||||
|
@ -8306,6 +8306,10 @@ static const vshCmdOptDef opts_migrate[] = {
|
||||
.type = VSH_OT_BOOL,
|
||||
.help = N_("compress repeated pages during live migration")
|
||||
},
|
||||
{.name = "abort-on-error",
|
||||
.type = VSH_OT_BOOL,
|
||||
.help = N_("abort on soft errors during migration")
|
||||
},
|
||||
{.name = "domain",
|
||||
.type = VSH_OT_DATA,
|
||||
.flags = VSH_OFLAG_REQ,
|
||||
@ -8399,6 +8403,9 @@ doMigrate(void *opaque)
|
||||
flags |= VIR_MIGRATE_OFFLINE;
|
||||
}
|
||||
|
||||
if (vshCommandOptBool(cmd, "abort-on-error"))
|
||||
flags |= VIR_MIGRATE_ABORT_ON_ERROR;
|
||||
|
||||
if (xmlfile &&
|
||||
virFileReadAll(xmlfile, 8192, &xml) < 0) {
|
||||
vshError(ctl, _("file '%s' doesn't exist"), xmlfile);
|
||||
|
@ -1043,7 +1043,8 @@ stats.
|
||||
=item B<migrate> [I<--live>] [I<--offline>] [I<--direct>] [I<--p2p> [I<--tunnelled>]]
|
||||
[I<--persistent>] [I<--undefinesource>] [I<--suspend>] [I<--copy-storage-all>]
|
||||
[I<--copy-storage-inc>] [I<--change-protection>] [I<--unsafe>] [I<--verbose>]
|
||||
[I<--compressed>] I<domain> I<desturi> [I<migrateuri>] [I<dname>]
|
||||
[I<--compressed>] [I<--abort-on-error>]
|
||||
I<domain> I<desturi> [I<migrateuri>] [I<dname>]
|
||||
[I<--timeout> B<seconds>] [I<--xml> B<file>]
|
||||
|
||||
Migrate domain to another host. Add I<--live> for live migration; <--p2p>
|
||||
@ -1066,7 +1067,8 @@ is implicitly enabled when supported by the hypervisor, but can be explicitly
|
||||
used to reject the migration if the hypervisor lacks change protection
|
||||
support. I<--verbose> displays the progress of migration. I<--compressed>
|
||||
activates compression of memory pages that have to be transferred repeatedly
|
||||
during live migration.
|
||||
during live migration. I<--abort-on-error> cancels the migration if a soft
|
||||
error (for example I/O error) happens during the migration.
|
||||
|
||||
B<Note>: Individual hypervisors usually do not support all possible types of
|
||||
migration. For example, QEMU does not support direct migration.
|
||||
|
Loading…
Reference in New Issue
Block a user