On Thu, Feb 11, 2021 at 16:37:57 +0100, Peter Krempa wrote:
Preserve block dirty bitmaps after migration with
QEMU_MONITOR_MIGRATE_NON_SHARED_(DISK|INC).
This patch implements functions which offer the bitmaps to the
destination, check for eligibility on destination and then configure
source for the migration.
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
src/qemu/qemu_migration.c | 333 +++++++++++++++++++++++++++++++++++++-
1 file changed, 331 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 36424f8493..16bfad0390 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
...
@@ -2528,6 +2619,92 @@ qemuMigrationDstPrepare(virDomainObjPtr vm,
migrateFrom, fd, NULL);
}
+
+/**
+ * qemuMigrationDstPrepareAnyBlockDirtyBitmaps:
+ * @vm: domain object
+ * @mig: migration cookie
+ * @migParams: migration parameters
+ * @flags: migration flags
+ *
+ * Checks whether block dirty bitmaps offered by the migration source are
+ * to be migrated (e.g. they don't exist, the destination is compatible etc)
+ * and sets up destination qemu for migrating the bitmaps as well as updates the
+ * list of eligible bitmaps in the migration cookie to be sent back to the
+ * source.
+ */
+static int
+qemuMigrationDstPrepareAnyBlockDirtyBitmaps(virDomainObjPtr vm,
+ qemuMigrationCookiePtr mig,
+ qemuMigrationParamsPtr migParams,
+ unsigned int flags)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ g_autoptr(virJSONValue) mapping = NULL;
+ g_autoptr(GHashTable) blockNamedNodeData = NULL;
+ GSList *nextdisk;
+
+ if (!mig->nbd ||
+ !mig->blockDirtyBitmaps ||
+ !(flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC)) ||
+ !virQEMUCapsGet(priv->qemuCaps,
QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING))
+ return 0;
Shouldn't we report an error in case the source sent bitmaps, but local
QEMU does not support QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING?
+
+ if (qemuMigrationCookieBlockDirtyBitmapsMatchDisks(vm->def,
mig->blockDirtyBitmaps) < 0)
+ return -1;
+
+ if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm,
QEMU_ASYNC_JOB_MIGRATION_IN)))
+ return -1;
+
+ for (nextdisk = mig->blockDirtyBitmaps; nextdisk; nextdisk = nextdisk->next)
{
+ qemuMigrationBlockDirtyBitmapsDiskPtr disk = nextdisk->data;
+ qemuBlockNamedNodeDataPtr nodedata;
+ GSList *nextbitmap;
+
+ if (!(nodedata = virHashLookup(blockNamedNodeData, disk->nodename))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to find data for block node
'%s'"),
+ disk->nodename);
+ return -1;
+ }
+
+ /* don't migrate bitmaps into non-qcow2v3+ images */
How about "Bitmaps can only be migrated to qcow2 v3+"?
+ if (disk->disk->src->format !=
VIR_STORAGE_FILE_QCOW2 ||
+ nodedata->qcow2v2) {
+ disk->skip = true;
Is skipping the disk the right thing to do? Should we report an error
and abort migration instead? Just checking, maybe we can't do so for
backward compatibility...
+ continue;
+ }
+
+ for (nextbitmap = disk->bitmaps; nextbitmap; nextbitmap =
nextbitmap->next) {
+ qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap = nextbitmap->data;
+ size_t k;
+
+ /* don't migrate into existing bitmaps */
+ for (k = 0; k < nodedata->nbitmaps; k++) {
+ if (STREQ(bitmap->bitmapname, nodedata->bitmaps[k]->name)) {
+ bitmap->skip = true;
And similar questions for bitmaps here.
+ break;
+ }
+ }
+
+ if (bitmap->skip)
+ continue;
+ }
+ }
+
+ if (qemuMigrationCookieBlockDirtyBitmapsToParams(mig->blockDirtyBitmaps,
+ &mapping) < 0)
+ return -1;
+
+ if (!mapping)
+ return 0;
+
+ qemuMigrationParamsSetBlockDirtyBitmapMapping(migParams, &mapping);
+ mig->flags |= QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS;
+ return 0;
+}
+
+
static int
qemuMigrationDstPrepareAny(virQEMUDriverPtr driver,
virConnectPtr dconn,
...
+static int
+qemuMigrationSrcRunPrepareBlockDirtyBitmaps(virDomainObjPtr vm,
+ qemuMigrationCookiePtr mig,
+ qemuMigrationParamsPtr migParams,
+ unsigned int flags)
+
+{
+ g_autoptr(virJSONValue) mapping = NULL;
+
+ if (!mig->blockDirtyBitmaps)
+ return 0;
+
+ if (qemuMigrationCookieBlockDirtyBitmapsMatchDisks(vm->def,
mig->blockDirtyBitmaps) < 0)
+ return -1;
+
+ /* For QEMU_MONITOR_MIGRATE_NON_SHARED_INC we can migrate the bitmaps
+ * directly, otherwise we must create merged bitmaps from the whole
+ * chain */
+
+ if (!(flags & QEMU_MONITOR_MIGRATE_NON_SHARED_INC) &&
+ qemuMigrationSrcRunPrepareBlockDirtyBitmapsMerge(vm, mig))
"< 0" is missing in the check.
+ return -1;
+
+ if (qemuMigrationCookieBlockDirtyBitmapsToParams(mig->blockDirtyBitmaps,
+ &mapping) < 0)
+ return -1;
+
+ qemuMigrationParamsSetBlockDirtyBitmapMapping(migParams, &mapping);
+ return 0;
+}
+
+
static int
qemuMigrationSrcRun(virQEMUDriverPtr driver,
virDomainObjPtr vm,
Jirka