Migrating domains with disks using cache != none is unsafe unless the
disk images are stored on coherent clustered filesystem. Thus we forbid
migrating such domains unless VIR_MIGRATE_UNSAFE flags is used.
---
src/qemu/qemu_driver.c | 3 ++-
src/qemu/qemu_migration.c | 36 ++++++++++++++++++++++++++++++++----
src/qemu/qemu_migration.h | 6 ++++--
3 files changed, 38 insertions(+), 7 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 717bdf1..63a0703 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -8767,7 +8767,8 @@ qemuDomainMigrateBegin3(virDomainPtr domain,
goto endjob;
if (!(xml = qemuMigrationBegin(driver, vm, xmlin, dname,
- cookieout, cookieoutlen)))
+ cookieout, cookieoutlen,
+ flags)))
goto endjob;
if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index f0af494..127b35c 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -817,6 +817,27 @@ qemuMigrationIsAllowed(struct qemud_driver *driver, virDomainObjPtr
vm,
return true;
}
+static bool
+qemuMigrationIsSafe(virDomainDefPtr def)
+{
+ int i;
+
+ for (i = 0 ; i < def->ndisks ; i++) {
+ virDomainDiskDefPtr disk = def->disks[i];
+
+ /* shared && !readonly implies cache=none */
+ if (disk->cachemode != VIR_DOMAIN_DISK_CACHE_DISABLE &&
+ (disk->cachemode || !disk->shared || disk->readonly)) {
+ qemuReportError(VIR_ERR_MIGRATE_UNSAFE, "%s",
+ _("Migration may lead to data corruption if disks"
+ " use cache != none"));
+ return false;
+ }
+ }
+
+ return true;
+}
+
/** qemuMigrationSetOffline
* Pause domain for non-live migration.
*/
@@ -1010,7 +1031,8 @@ char *qemuMigrationBegin(struct qemud_driver *driver,
const char *xmlin,
const char *dname,
char **cookieout,
- int *cookieoutlen)
+ int *cookieoutlen,
+ unsigned long flags)
{
char *rv = NULL;
qemuMigrationCookiePtr mig = NULL;
@@ -1018,9 +1040,9 @@ char *qemuMigrationBegin(struct qemud_driver *driver,
qemuDomainObjPrivatePtr priv = vm->privateData;
VIR_DEBUG("driver=%p, vm=%p, xmlin=%s, dname=%s,"
- " cookieout=%p, cookieoutlen=%p",
+ " cookieout=%p, cookieoutlen=%p, flags=%lx",
driver, vm, NULLSTR(xmlin), NULLSTR(dname),
- cookieout, cookieoutlen);
+ cookieout, cookieoutlen, flags);
/* Only set the phase if we are inside QEMU_ASYNC_JOB_MIGRATION_OUT.
* Otherwise we will start the async job later in the perform phase losing
@@ -1032,6 +1054,9 @@ char *qemuMigrationBegin(struct qemud_driver *driver,
if (!qemuMigrationIsAllowed(driver, vm, NULL))
goto cleanup;
+ if (!(flags & VIR_MIGRATE_UNSAFE) && !qemuMigrationIsSafe(vm->def))
+ goto cleanup;
+
if (!(mig = qemuMigrationEatCookie(driver, vm, NULL, 0, 0)))
goto cleanup;
@@ -2070,7 +2095,7 @@ static int doPeer2PeerMigrate3(struct qemud_driver *driver,
* a single job. */
dom_xml = qemuMigrationBegin(driver, vm, xmlin, dname,
- &cookieout, &cookieoutlen);
+ &cookieout, &cookieoutlen, flags);
if (!dom_xml)
goto cleanup;
@@ -2354,6 +2379,9 @@ qemuMigrationPerformJob(struct qemud_driver *driver,
if (!qemuMigrationIsAllowed(driver, vm, NULL))
goto cleanup;
+ if (!(flags & VIR_MIGRATE_UNSAFE) && !qemuMigrationIsSafe(vm->def))
+ goto cleanup;
+
resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index f806ca1..41e4eac 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -35,7 +35,8 @@
VIR_MIGRATE_PAUSED | \
VIR_MIGRATE_NON_SHARED_DISK | \
VIR_MIGRATE_NON_SHARED_INC | \
- VIR_MIGRATE_CHANGE_PROTECTION)
+ VIR_MIGRATE_CHANGE_PROTECTION | \
+ VIR_MIGRATE_UNSAFE)
enum qemuMigrationJobPhase {
QEMU_MIGRATION_PHASE_NONE = 0,
@@ -81,7 +82,8 @@ char *qemuMigrationBegin(struct qemud_driver *driver,
const char *xmlin,
const char *dname,
char **cookieout,
- int *cookieoutlen);
+ int *cookieoutlen,
+ unsigned long flags);
int qemuMigrationPrepareTunnel(struct qemud_driver *driver,
virConnectPtr dconn,
--
1.7.8.4