Non-shared storage migration of guests which are disk I/O intensive and
have fast local storage may actually never converge if the guest happens
to dirty the disk faster than it can be copied.
This patch introduces a new flag
'VIR_MIGRATE_NON_SHARED_SYNCHRONOUS_WRITES' which will instruct
hypervisors to synchronize local I/O writes with the writes to remote
storage used for migration so that the guest can't overwhelm the
migration. This comes at a cost of decreased local I/O performance for
guests which behave well on average.
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
docs/manpages/virsh.rst | 6 +++++-
include/libvirt/libvirt-domain.h | 10 ++++++++++
src/libvirt-domain.c | 20 ++++++++++++++++++++
tools/virsh-domain.c | 13 +++++++++++++
4 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index 7c50388216..1ce3e77c9f 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -3180,7 +3180,7 @@ migrate
[--postcopy-bandwidth bandwidth]
[--parallel [--parallel-connections connections]]
[--bandwidth bandwidth] [--tls-destination hostname]
- [--disks-uri URI]
+ [--disks-uri URI] [--copy-storage-synchronous-writes]
Migrate domain to another host. Add *--live* for live migration; <--p2p>
for peer-2-peer migration; *--direct* for direct migration; or *--tunnelled*
@@ -3202,6 +3202,10 @@ images on source host to the images found at the same place on the
destination
host. By default only non-shared non-readonly images are transferred. Use
*--migrate-disks* to explicitly specify a list of disk targets to
transfer via the comma separated ``disk-list`` argument.
+With *--copy-storage-synchronous-writes* flag used the disk data migration will
+synchronous handle guest disk writes to both the original soure and the
+destination to ensure that the disk migration coverges at the price of possibly
+decreased burst performance.
*--change-protection* enforces that no incompatible configuration changes will
be made to the domain while the migration is underway; this flag is implicitly
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index f81e96d374..d0dd11ab01 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -850,6 +850,16 @@ typedef enum {
*/
VIR_MIGRATE_PARALLEL = (1 << 17),
+ /* Force the guest writes which happen when copying disk images for
+ * non-shared storage migration to be synchronously written to the
+ * destination. This ensures the storage migration converges for VMs
+ * doing heavy I/O on fast local storage and slow mirror.
+ *
+ * Requires one of VIR_MIGRATE_NON_SHARED_DISK, VIR_MIGRATE_NON_SHARED_INC
+ * to be present as well.
+ */
+ VIR_MIGRATE_NON_SHARED_SYNCHRONOUS_WRITES = (1 << 18),
+
} virDomainMigrateFlags;
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index 8ee2490867..5708ff839b 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -3567,6 +3567,10 @@ virDomainMigrate(virDomainPtr domain,
VIR_MIGRATE_PARALLEL,
error);
+ VIR_REQUIRE_FLAG_GOTO(VIR_MIGRATE_NON_SHARED_SYNCHRONOUS_WRITES,
+ VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC,
+ error);
+
if (flags & VIR_MIGRATE_OFFLINE) {
rc = VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
VIR_DRV_FEATURE_MIGRATION_OFFLINE);
@@ -3760,6 +3764,10 @@ virDomainMigrate2(virDomainPtr domain,
VIR_MIGRATE_PARALLEL,
error);
+ VIR_REQUIRE_FLAG_GOTO(VIR_MIGRATE_NON_SHARED_SYNCHRONOUS_WRITES,
+ VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC,
+ error);
+
if (flags & VIR_MIGRATE_OFFLINE) {
rc = VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
VIR_DRV_FEATURE_MIGRATION_OFFLINE);
@@ -3966,6 +3974,14 @@ virDomainMigrate3(virDomainPtr domain,
VIR_MIGRATE_NON_SHARED_INC,
error);
+ VIR_REQUIRE_FLAG_GOTO(VIR_MIGRATE_NON_SHARED_SYNCHRONOUS_WRITES,
+ VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC,
+ error);
+
+ VIR_REQUIRE_FLAG_GOTO(VIR_MIGRATE_NON_SHARED_SYNCHRONOUS_WRITES,
+ VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC,
+ error);
+
if (flags & VIR_MIGRATE_PEER2PEER) {
virReportInvalidArg(flags, "%s",
_("use virDomainMigrateToURI3 for peer-to-peer "
@@ -4137,6 +4153,10 @@ int virDomainMigrateUnmanagedCheckCompat(virDomainPtr domain,
VIR_MIGRATE_NON_SHARED_INC,
-1);
+ VIR_REQUIRE_FLAG_RET(VIR_MIGRATE_NON_SHARED_SYNCHRONOUS_WRITES,
+ VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC,
+ -1);
+
if (flags & VIR_MIGRATE_OFFLINE) {
rc = VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
VIR_DRV_FEATURE_MIGRATION_OFFLINE);
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index a00b4cc243..8379f9f135 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -10543,6 +10543,10 @@ static const vshCmdOptDef opts_migrate[] = {
.type = VSH_OT_BOOL,
.help = N_("migration with non-shared storage with incremental copy (same base
image shared between source and destination)")
},
+ {.name = "copy-storage-synchronous-writes",
+ .type = VSH_OT_BOOL,
+ .help = N_("force guest disk writes to be synchronously written to the
destination to improve storage migration convergence")
+ },
{.name = "change-protection",
.type = VSH_OT_BOOL,
.help = N_("prevent any configuration changes to domain until migration
ends")
@@ -10949,6 +10953,15 @@ doMigrate(void *opaque)
if (vshCommandOptBool(cmd, "copy-storage-inc"))
flags |= VIR_MIGRATE_NON_SHARED_INC;
+ if (vshCommandOptBool(cmd, "copy-storage-synchronous-writes")) {
+ if (!(flags & VIR_MIGRATE_NON_SHARED_DISK) &&
+ !(flags & VIR_MIGRATE_NON_SHARED_INC)) {
+ vshError(ctl, "'--copy-storage-synchronous-writes' requires one
of '--copy-storage-all', 'copy-storage-inc'");
+ goto out;
+ }
+ flags |= VIR_MIGRATE_NON_SHARED_SYNCHRONOUS_WRITES;
+ }
+
if (vshCommandOptBool(cmd, "change-protection"))
flags |= VIR_MIGRATE_CHANGE_PROTECTION;
--
2.31.1