Blame SOURCES/libvirt-qemu-backup-Rewrite-backup-bitmap-handling-to-the-new-bitmap-semantics.patch

fbe740
From 1fd01969c2a7c4deefc28363c9748786ca5d7169 Mon Sep 17 00:00:00 2001
fbe740
Message-Id: <1fd01969c2a7c4deefc28363c9748786ca5d7169@dist-git>
fbe740
From: Peter Krempa <pkrempa@redhat.com>
fbe740
Date: Tue, 23 Jun 2020 12:23:57 +0200
fbe740
Subject: [PATCH] qemu: backup: Rewrite backup bitmap handling to the new
fbe740
 bitmap semantics
fbe740
MIME-Version: 1.0
fbe740
Content-Type: text/plain; charset=UTF-8
fbe740
Content-Transfer-Encoding: 8bit
fbe740
fbe740
Reuse qemuBlockGetBitmapMergeActions which allows removal of the ad-hoc
fbe740
implementation of bitmap merging for backup. The new approach is simpler
fbe740
and also more robust in case some of the bitmaps break as they remove
fbe740
the dependency on the whole chain of bitmaps working.
fbe740
fbe740
The new approach also allows backups if a snapshot is created outside of
fbe740
libvirt.
fbe740
fbe740
Additionally the code is greatly simplified.
fbe740
fbe740
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
fbe740
Reviewed-by: Eric Blake <eblake@redhat.com>
fbe740
(cherry picked from commit e0d8d989e2bc9024f85b676166da0305c4b4014d)
fbe740
https://bugzilla.redhat.com/show_bug.cgi?id=1804593
fbe740
Message-Id: <468adeee4056441afbf7b452def02179da043030.1592906423.git.pkrempa@redhat.com>
fbe740
Reviewed-by: Ján Tomko <jtomko@redhat.com>
fbe740
---
fbe740
 src/qemu/qemu_backup.c                        | 220 +++---------------
fbe740
 src/qemu/qemu_backup.h                        |  12 +-
fbe740
 tests/qemublocktest.c                         |  86 ++-----
fbe740
 .../backupmerge/empty-out.json                |   4 +-
fbe740
 4 files changed, 63 insertions(+), 259 deletions(-)
fbe740
fbe740
diff --git a/src/qemu/qemu_backup.c b/src/qemu/qemu_backup.c
fbe740
index 13e2a7412b..67d646f477 100644
fbe740
--- a/src/qemu/qemu_backup.c
fbe740
+++ b/src/qemu/qemu_backup.c
fbe740
@@ -173,199 +173,58 @@ qemuBackupDiskDataCleanup(virDomainObjPtr vm,
fbe740
 }
fbe740
 
fbe740
 
fbe740
-/**
fbe740
- * qemuBackupBeginCollectIncrementalCheckpoints:
fbe740
- * @vm: domain object
fbe740
- * @incrFrom: name of checkpoint representing starting point of incremental backup
fbe740
- *
fbe740
- * Returns a NULL terminated list of pointers to checkpoint definitions in
fbe740
- * chronological order starting from the 'current' checkpoint until reaching
fbe740
- * @incrFrom.
fbe740
- */
fbe740
-static virDomainMomentDefPtr *
fbe740
-qemuBackupBeginCollectIncrementalCheckpoints(virDomainObjPtr vm,
fbe740
-                                             const char *incrFrom)
fbe740
-{
fbe740
-    virDomainMomentObjPtr n = virDomainCheckpointGetCurrent(vm->checkpoints);
fbe740
-    g_autofree virDomainMomentDefPtr *incr = NULL;
fbe740
-    size_t nincr = 0;
fbe740
-
fbe740
-    while (n) {
fbe740
-        virDomainMomentDefPtr def = n->def;
fbe740
-
fbe740
-        if (VIR_APPEND_ELEMENT_COPY(incr, nincr, def) < 0)
fbe740
-            return NULL;
fbe740
-
fbe740
-        if (STREQ(def->name, incrFrom)) {
fbe740
-            def = NULL;
fbe740
-            if (VIR_APPEND_ELEMENT_COPY(incr, nincr, def) < 0)
fbe740
-                return NULL;
fbe740
-
fbe740
-            return g_steal_pointer(&incr;;
fbe740
-        }
fbe740
-
fbe740
-        if (!n->def->parent_name)
fbe740
-            break;
fbe740
-
fbe740
-        n = virDomainCheckpointFindByName(vm->checkpoints, n->def->parent_name);
fbe740
-    }
fbe740
-
fbe740
-    virReportError(VIR_ERR_OPERATION_INVALID,
fbe740
-                   _("could not locate checkpoint '%s' for incremental backup"),
fbe740
-                   incrFrom);
fbe740
-    return NULL;
fbe740
-}
fbe740
-
fbe740
-
fbe740
-static int
fbe740
-qemuBackupGetBitmapMergeRange(virStorageSourcePtr from,
fbe740
-                              const char *bitmapname,
fbe740
-                              virJSONValuePtr *actions,
fbe740
-                              virStorageSourcePtr *to,
fbe740
-                              const char *diskdst,
fbe740
-                              virHashTablePtr blockNamedNodeData)
fbe740
+int
fbe740
+qemuBackupDiskPrepareOneBitmapsChain(virStorageSourcePtr backingChain,
fbe740
+                                     virStorageSourcePtr targetsrc,
fbe740
+                                     const char *targetbitmap,
fbe740
+                                     const char *incremental,
fbe740
+                                     virJSONValuePtr actions,
fbe740
+                                     virHashTablePtr blockNamedNodeData)
fbe740
 {
fbe740
-    g_autoptr(virJSONValue) act = virJSONValueNewArray();
fbe740
-    virStorageSourcePtr tmpsrc = NULL;
fbe740
-    virStorageSourcePtr n;
fbe740
-    bool foundbitmap = false;
fbe740
+    g_autoptr(virJSONValue) tmpactions = NULL;
fbe740
 
fbe740
-    for (n = from; virStorageSourceIsBacking(n); n = n->backingStore) {
fbe740
-        qemuBlockNamedNodeDataBitmapPtr bitmap = NULL;
fbe740
-
fbe740
-        if (!(bitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
fbe740
-                                                             n,
fbe740
-                                                             bitmapname)))
fbe740
-            break;
fbe740
-
fbe740
-        foundbitmap = true;
fbe740
-
fbe740
-        if (bitmap->inconsistent) {
fbe740
-            virReportError(VIR_ERR_INVALID_ARG,
fbe740
-                           _("bitmap '%s' for image '%s%u' is inconsistent"),
fbe740
-                           bitmap->name, diskdst, n->id);
fbe740
-            return -1;
fbe740
-        }
fbe740
-
fbe740
-        if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(act,
fbe740
-                                                             n->nodeformat,
fbe740
-                                                             bitmapname) < 0)
fbe740
-            return -1;
fbe740
-
fbe740
-        tmpsrc = n;
fbe740
-    }
fbe740
-
fbe740
-    if (!foundbitmap) {
fbe740
-        virReportError(VIR_ERR_INVALID_ARG,
fbe740
-                       _("failed to find bitmap '%s' in image '%s%u'"),
fbe740
-                       bitmapname, diskdst, from->id);
fbe740
+    if (qemuBlockGetBitmapMergeActions(backingChain, NULL, targetsrc,
fbe740
+                                       incremental, targetbitmap, NULL,
fbe740
+                                       &tmpactions,
fbe740
+                                       blockNamedNodeData) < 0)
fbe740
         return -1;
fbe740
-    }
fbe740
 
fbe740
-    *actions = g_steal_pointer(&act;;
fbe740
-    *to = tmpsrc;
fbe740
+    if (tmpactions &&
fbe740
+        virJSONValueArrayConcat(actions, tmpactions) < 0)
fbe740
+        return -1;
fbe740
 
fbe740
     return 0;
fbe740
 }
fbe740
 
fbe740
 
fbe740
-virJSONValuePtr
fbe740
-qemuBackupDiskPrepareOneBitmapsChain(virDomainMomentDefPtr *incremental,
fbe740
-                                     virStorageSourcePtr backingChain,
fbe740
-                                     virHashTablePtr blockNamedNodeData,
fbe740
-                                     const char *diskdst)
fbe740
-{
fbe740
-    g_autoptr(virJSONValue) ret = NULL;
fbe740
-    size_t incridx = 0;
fbe740
-    virStorageSourcePtr n = backingChain;
fbe740
-
fbe740
-    ret = virJSONValueNewArray();
fbe740
-
fbe740
-    for (incridx = 0; incremental[incridx]; incridx++) {
fbe740
-        g_autoptr(virJSONValue) tmp = virJSONValueNewArray();
fbe740
-        virStorageSourcePtr tmpsrc = NULL;
fbe740
-        virDomainCheckpointDefPtr chkdef = (virDomainCheckpointDefPtr) incremental[incridx];
fbe740
-        bool checkpoint_has_disk = false;
fbe740
-        size_t i;
fbe740
-
fbe740
-        for (i = 0; i < chkdef->ndisks; i++) {
fbe740
-            if (STRNEQ_NULLABLE(diskdst, chkdef->disks[i].name))
fbe740
-                continue;
fbe740
-
fbe740
-            if (chkdef->disks[i].type == VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
fbe740
-                checkpoint_has_disk = true;
fbe740
-
fbe740
-            break;
fbe740
-        }
fbe740
-
fbe740
-        if (!checkpoint_has_disk) {
fbe740
-            if (!incremental[incridx + 1]) {
fbe740
-                virReportError(VIR_ERR_INVALID_ARG,
fbe740
-                               _("disk '%s' not found in checkpoint '%s'"),
fbe740
-                               diskdst, incremental[incridx]->name);
fbe740
-                return NULL;
fbe740
-            }
fbe740
-
fbe740
-            continue;
fbe740
-        }
fbe740
-
fbe740
-        if (qemuBackupGetBitmapMergeRange(n, incremental[incridx]->name,
fbe740
-                                          &tmp, &tmpsrc, diskdst,
fbe740
-                                          blockNamedNodeData) < 0)
fbe740
-            return NULL;
fbe740
-
fbe740
-        if (virJSONValueArrayConcat(ret, tmp) < 0)
fbe740
-            return NULL;
fbe740
-
fbe740
-        n = tmpsrc;
fbe740
-    }
fbe740
-
fbe740
-    return g_steal_pointer(&ret;;
fbe740
-}
fbe740
-
fbe740
-
fbe740
 static int
fbe740
 qemuBackupDiskPrepareOneBitmaps(struct qemuBackupDiskData *dd,
fbe740
                                 virJSONValuePtr actions,
fbe740
-                                virDomainMomentDefPtr *incremental,
fbe740
                                 virHashTablePtr blockNamedNodeData)
fbe740
 {
fbe740
-    g_autoptr(virJSONValue) mergebitmaps = NULL;
fbe740
-    g_autoptr(virJSONValue) mergebitmapsstore = NULL;
fbe740
-
fbe740
-    if (!(mergebitmaps = qemuBackupDiskPrepareOneBitmapsChain(incremental,
fbe740
-                                                              dd->domdisk->src,
fbe740
-                                                              blockNamedNodeData,
fbe740
-                                                              dd->domdisk->dst)))
fbe740
-        return -1;
fbe740
-
fbe740
-    if (!(mergebitmapsstore = virJSONValueCopy(mergebitmaps)))
fbe740
-        return -1;
fbe740
-
fbe740
-    if (qemuMonitorTransactionBitmapAdd(actions,
fbe740
-                                        dd->domdisk->src->nodeformat,
fbe740
-                                        dd->incrementalBitmap,
fbe740
-                                        false,
fbe740
-                                        true, 0) < 0)
fbe740
-        return -1;
fbe740
-
fbe740
-    if (qemuMonitorTransactionBitmapMerge(actions,
fbe740
-                                          dd->domdisk->src->nodeformat,
fbe740
-                                          dd->incrementalBitmap,
fbe740
-                                          &mergebitmaps) < 0)
fbe740
+    if (!qemuBlockBitmapChainIsValid(dd->domdisk->src,
fbe740
+                                     dd->backupdisk->incremental,
fbe740
+                                     blockNamedNodeData)) {
fbe740
+        virReportError(VIR_ERR_INVALID_ARG,
fbe740
+                       _("missing or broken bitmap '%s' for disk '%s'"),
fbe740
+                       dd->backupdisk->incremental, dd->domdisk->dst);
fbe740
         return -1;
fbe740
+    }
fbe740
 
fbe740
-    if (qemuMonitorTransactionBitmapAdd(actions,
fbe740
-                                        dd->store->nodeformat,
fbe740
-                                        dd->incrementalBitmap,
fbe740
-                                        false,
fbe740
-                                        true, 0) < 0)
fbe740
+    if (qemuBackupDiskPrepareOneBitmapsChain(dd->domdisk->src,
fbe740
+                                             dd->domdisk->src,
fbe740
+                                             dd->incrementalBitmap,
fbe740
+                                             dd->backupdisk->incremental,
fbe740
+                                             actions,
fbe740
+                                             blockNamedNodeData) < 0)
fbe740
         return -1;
fbe740
 
fbe740
-    if (qemuMonitorTransactionBitmapMerge(actions,
fbe740
-                                          dd->store->nodeformat,
fbe740
-                                          dd->incrementalBitmap,
fbe740
-                                          &mergebitmapsstore) < 0)
fbe740
+    if (qemuBackupDiskPrepareOneBitmapsChain(dd->domdisk->src,
fbe740
+                                             dd->store,
fbe740
+                                             dd->incrementalBitmap,
fbe740
+                                             dd->backupdisk->incremental,
fbe740
+                                             actions,
fbe740
+                                             blockNamedNodeData) < 0)
fbe740
         return -1;
fbe740
 
fbe740
     return 0;
fbe740
@@ -382,7 +241,6 @@ qemuBackupDiskPrepareDataOne(virDomainObjPtr vm,
fbe740
                              virQEMUDriverConfigPtr cfg)
fbe740
 {
fbe740
     qemuDomainObjPrivatePtr priv = vm->privateData;
fbe740
-    g_autofree virDomainMomentDefPtr *incremental = NULL;
fbe740
 
fbe740
     /* set data structure */
fbe740
     dd->backupdisk = backupdisk;
fbe740
@@ -418,16 +276,12 @@ qemuBackupDiskPrepareDataOne(virDomainObjPtr vm,
fbe740
         return -1;
fbe740
 
fbe740
     if (dd->backupdisk->incremental) {
fbe740
-        if (!(incremental = qemuBackupBeginCollectIncrementalCheckpoints(vm, dd->backupdisk->incremental)))
fbe740
-            return -1;
fbe740
-
fbe740
         if (dd->backupdisk->exportbitmap)
fbe740
             dd->incrementalBitmap = g_strdup(dd->backupdisk->exportbitmap);
fbe740
         else
fbe740
             dd->incrementalBitmap = g_strdup_printf("backup-%s", dd->domdisk->dst);
fbe740
 
fbe740
-        if (qemuBackupDiskPrepareOneBitmaps(dd, actions, incremental,
fbe740
-                                            blockNamedNodeData) < 0)
fbe740
+        if (qemuBackupDiskPrepareOneBitmaps(dd, actions, blockNamedNodeData) < 0)
fbe740
             return -1;
fbe740
     }
fbe740
 
fbe740
@@ -881,8 +735,8 @@ qemuBackupBegin(virDomainObjPtr vm,
fbe740
     if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_BACKUP)))
fbe740
         goto endjob;
fbe740
 
fbe740
-    if ((ndd = qemuBackupDiskPrepareData(vm, def, blockNamedNodeData,
fbe740
-                                         actions, cfg, &dd)) <= 0) {
fbe740
+    if ((ndd = qemuBackupDiskPrepareData(vm, def, blockNamedNodeData, actions,
fbe740
+                                         cfg, &dd)) <= 0) {
fbe740
         if (ndd == 0) {
fbe740
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
fbe740
                            _("no disks selected for backup"));
fbe740
diff --git a/src/qemu/qemu_backup.h b/src/qemu/qemu_backup.h
fbe740
index 3321ba0b6f..c821baf0ee 100644
fbe740
--- a/src/qemu/qemu_backup.h
fbe740
+++ b/src/qemu/qemu_backup.h
fbe740
@@ -52,8 +52,10 @@ qemuBackupGetJobInfoStats(virQEMUDriverPtr driver,
fbe740
                           qemuDomainJobInfoPtr jobInfo);
fbe740
 
fbe740
 /* exported for testing */
fbe740
-virJSONValuePtr
fbe740
-qemuBackupDiskPrepareOneBitmapsChain(virDomainMomentDefPtr *incremental,
fbe740
-                                     virStorageSourcePtr backingChain,
fbe740
-                                     virHashTablePtr blockNamedNodeData,
fbe740
-                                     const char *diskdst);
fbe740
+int
fbe740
+qemuBackupDiskPrepareOneBitmapsChain(virStorageSourcePtr backingChain,
fbe740
+                                     virStorageSourcePtr targetsrc,
fbe740
+                                     const char *targetbitmap,
fbe740
+                                     const char *incremental,
fbe740
+                                     virJSONValuePtr actions,
fbe740
+                                     virHashTablePtr blockNamedNodeData);
fbe740
diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c
fbe740
index 7c8f67dd6b..dcdc9eade0 100644
fbe740
--- a/tests/qemublocktest.c
fbe740
+++ b/tests/qemublocktest.c
fbe740
@@ -716,65 +716,6 @@ testQemuBitmapGetFakeChainEntry(virStorageSourcePtr src,
fbe740
 }
fbe740
 
fbe740
 
fbe740
-typedef virDomainMomentDefPtr testMomentList;
fbe740
-
fbe740
-static void
fbe740
-testMomentListFree(testMomentList *list)
fbe740
-{
fbe740
-    testMomentList *tmp = list;
fbe740
-
fbe740
-    if (!list)
fbe740
-        return;
fbe740
-
fbe740
-    while (*tmp) {
fbe740
-        virObjectUnref(*tmp);
fbe740
-        tmp++;
fbe740
-    }
fbe740
-
fbe740
-    g_free(list);
fbe740
-}
fbe740
-
fbe740
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(testMomentList, testMomentListFree);
fbe740
-
fbe740
-static virDomainMomentDefPtr
fbe740
-testQemuBackupGetIncrementalMoment(const char *name)
fbe740
-{
fbe740
-    virDomainCheckpointDefPtr checkpoint = NULL;
fbe740
-
fbe740
-    if (!(checkpoint = virDomainCheckpointDefNew()))
fbe740
-        abort();
fbe740
-
fbe740
-    checkpoint->disks = g_new0(virDomainCheckpointDiskDef, 1);
fbe740
-    checkpoint->ndisks = 1;
fbe740
-
fbe740
-    checkpoint->disks[0].name = g_strdup("testdisk");
fbe740
-    checkpoint->disks[0].type = VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP;
fbe740
-
fbe740
-    checkpoint->parent.name = g_strdup(name);
fbe740
-
fbe740
-    return (virDomainMomentDefPtr) checkpoint;
fbe740
-}
fbe740
-
fbe740
-
fbe740
-static virDomainMomentDefPtr *
fbe740
-testQemuBackupGetIncremental(const char *incFrom)
fbe740
-{
fbe740
-    const char *checkpoints[] = {"current", "d", "c", "b", "a"};
fbe740
-    virDomainMomentDefPtr *incr;
fbe740
-    size_t i;
fbe740
-
fbe740
-    incr = g_new0(virDomainMomentDefPtr, G_N_ELEMENTS(checkpoints) + 1);
fbe740
-
fbe740
-    for (i = 0; i < G_N_ELEMENTS(checkpoints); i++) {
fbe740
-        incr[i] = testQemuBackupGetIncrementalMoment(checkpoints[i]);
fbe740
-
fbe740
-        if (STREQ(incFrom, checkpoints[i]))
fbe740
-            break;
fbe740
-    }
fbe740
-
fbe740
-    return incr;
fbe740
-}
fbe740
-
fbe740
 static const char *backupDataPrefix = "qemublocktestdata/backupmerge/";
fbe740
 
fbe740
 struct testQemuBackupIncrementalBitmapCalculateData {
fbe740
@@ -791,10 +732,10 @@ testQemuBackupIncrementalBitmapCalculate(const void *opaque)
fbe740
     const struct testQemuBackupIncrementalBitmapCalculateData *data = opaque;
fbe740
     g_autoptr(virJSONValue) nodedatajson = NULL;
fbe740
     g_autoptr(virHashTable) nodedata = NULL;
fbe740
-    g_autoptr(virJSONValue) mergebitmaps = NULL;
fbe740
-    g_autofree char *actual = NULL;
fbe740
+    g_autoptr(virJSONValue) actions = virJSONValueNewArray();
fbe740
     g_autofree char *expectpath = NULL;
fbe740
-    g_autoptr(testMomentList) incremental = NULL;
fbe740
+    g_autoptr(virStorageSource) target = NULL;
fbe740
+    g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
fbe740
 
fbe740
     expectpath = g_strdup_printf("%s/%s%s-out.json", abs_srcdir,
fbe740
                                  backupDataPrefix, data->name);
fbe740
@@ -808,19 +749,24 @@ testQemuBackupIncrementalBitmapCalculate(const void *opaque)
fbe740
         return -1;
fbe740
     }
fbe740
 
fbe740
-    incremental = testQemuBackupGetIncremental(data->incremental);
fbe740
+    if (!(target = virStorageSourceNew()))
fbe740
+        return -1;
fbe740
 
fbe740
-    if ((mergebitmaps = qemuBackupDiskPrepareOneBitmapsChain(incremental,
fbe740
-                                                             data->chain,
fbe740
-                                                             nodedata,
fbe740
-                                                             "testdisk"))) {
fbe740
-        if (!(actual = virJSONValueToString(mergebitmaps, true)))
fbe740
+    target->nodeformat = g_strdup_printf("target_node");
fbe740
+
fbe740
+    if (qemuBackupDiskPrepareOneBitmapsChain(data->chain,
fbe740
+                                             target,
fbe740
+                                             "target-bitmap-name",
fbe740
+                                             data->incremental,
fbe740
+                                             actions,
fbe740
+                                             nodedata) >= 0) {
fbe740
+        if (virJSONValueToBuffer(actions, &buf, true) < 0)
fbe740
             return -1;
fbe740
     } else {
fbe740
-        actual = g_strdup("NULL\n");
fbe740
+        virBufferAddLit(&buf, "NULL\n");
fbe740
     }
fbe740
 
fbe740
-    return virTestCompareToFile(actual, expectpath);
fbe740
+    return virTestCompareToFile(virBufferCurrentContent(&buf), expectpath);
fbe740
 }
fbe740
 
fbe740
 
fbe740
diff --git a/tests/qemublocktestdata/backupmerge/empty-out.json b/tests/qemublocktestdata/backupmerge/empty-out.json
fbe740
index 7951defec1..41b42e677b 100644
fbe740
--- a/tests/qemublocktestdata/backupmerge/empty-out.json
fbe740
+++ b/tests/qemublocktestdata/backupmerge/empty-out.json
fbe740
@@ -1 +1,3 @@
fbe740
-NULL
fbe740
+[
fbe740
+
fbe740
+]
fbe740
-- 
fbe740
2.27.0
fbe740