render / rpms / libvirt

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