a41c76
From e7b1604c5848861db0896b3c7869c0ad1d971084 Mon Sep 17 00:00:00 2001
a41c76
Message-Id: <e7b1604c5848861db0896b3c7869c0ad1d971084@dist-git>
a41c76
From: Peter Krempa <pkrempa@redhat.com>
a41c76
Date: Tue, 23 Jun 2020 12:23:53 +0200
a41c76
Subject: [PATCH] qemu: checkpoint: Don't merge checkpoints during deletion
a41c76
MIME-Version: 1.0
a41c76
Content-Type: text/plain; charset=UTF-8
a41c76
Content-Transfer-Encoding: 8bit
a41c76
a41c76
Now that we've switched to the simple handling, the first thing that can
a41c76
be massively simplified is checkpoint deletion. We now need to only go
a41c76
through the backing chain and find the appropriately named bitmaps and
a41c76
delete them, no complex lookups or merging.
a41c76
a41c76
Note that compared to other functions this deletes the bitmap in all
a41c76
layers compared to others where we expect only exactly 1 bitmap of a
a41c76
name in the backing chain to prevent potential problems.
a41c76
a41c76
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
a41c76
Reviewed-by: Eric Blake <eblake@redhat.com>
a41c76
(cherry picked from commit 4c33c5568c3ee3c5952e5f3b217d78df95683b71)
a41c76
https://bugzilla.redhat.com/show_bug.cgi?id=1804593
a41c76
Message-Id: <aa99845392d5d5141672bf8d50655034e6783794.1592906423.git.pkrempa@redhat.com>
a41c76
Reviewed-by: Ján Tomko <jtomko@redhat.com>
a41c76
---
a41c76
 src/qemu/qemu_checkpoint.c | 153 ++++++-------------------------------
a41c76
 src/qemu/qemu_checkpoint.h |   1 -
a41c76
 tests/qemublocktest.c      |   7 +-
a41c76
 3 files changed, 25 insertions(+), 136 deletions(-)
a41c76
a41c76
diff --git a/src/qemu/qemu_checkpoint.c b/src/qemu/qemu_checkpoint.c
a41c76
index 9762a3eb9d..b44ff05c32 100644
a41c76
--- a/src/qemu/qemu_checkpoint.c
a41c76
+++ b/src/qemu/qemu_checkpoint.c
a41c76
@@ -105,140 +105,41 @@ qemuCheckpointWriteMetadata(virDomainObjPtr vm,
a41c76
 }
a41c76
 
a41c76
 
a41c76
-/**
a41c76
- * qemuCheckpointFindActiveDiskInParent:
a41c76
- * @vm: domain object
a41c76
- * @from: starting moment object
a41c76
- * @diskname: name (target) of the disk to find
a41c76
- *
a41c76
- * Find the first checkpoint starting from @from continuing through parents
a41c76
- * of the checkpoint which describes disk @diskname. Return the pointer to the
a41c76
- * definition of the disk.
a41c76
- */
a41c76
-static virDomainCheckpointDiskDef *
a41c76
-qemuCheckpointFindActiveDiskInParent(virDomainObjPtr vm,
a41c76
-                                     virDomainMomentObjPtr from,
a41c76
-                                     const char *diskname)
a41c76
-{
a41c76
-    virDomainMomentObjPtr parent = from;
a41c76
-    virDomainCheckpointDefPtr parentdef = NULL;
a41c76
-    size_t i;
a41c76
-
a41c76
-    while (parent) {
a41c76
-        parentdef = virDomainCheckpointObjGetDef(parent);
a41c76
-
a41c76
-        for (i = 0; i < parentdef->ndisks; i++) {
a41c76
-            virDomainCheckpointDiskDef *chkdisk = &parentdef->disks[i];
a41c76
-
a41c76
-            if (STRNEQ(chkdisk->name, diskname))
a41c76
-                continue;
a41c76
-
a41c76
-            /* currently inspected checkpoint doesn't describe the disk,
a41c76
-             * continue into parent checkpoint */
a41c76
-            if (chkdisk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
a41c76
-                break;
a41c76
-
a41c76
-            return chkdisk;
a41c76
-        }
a41c76
-
a41c76
-        parent = virDomainCheckpointFindByName(vm->checkpoints,
a41c76
-                                               parentdef->parent.parent_name);
a41c76
-    }
a41c76
-
a41c76
-    return NULL;
a41c76
-}
a41c76
-
a41c76
-
a41c76
 int
a41c76
 qemuCheckpointDiscardDiskBitmaps(virStorageSourcePtr src,
a41c76
                                  virHashTablePtr blockNamedNodeData,
a41c76
                                  const char *delbitmap,
a41c76
-                                 const char *parentbitmap,
a41c76
                                  virJSONValuePtr actions,
a41c76
                                  const char *diskdst,
a41c76
                                  GSList **reopenimages)
a41c76
 {
a41c76
-    virStorageSourcePtr n = src;
a41c76
+    virStorageSourcePtr n;
a41c76
+    bool found = false;
a41c76
 
a41c76
     /* find the backing chain entry with bitmap named '@delbitmap' */
a41c76
-    while (n) {
a41c76
-        qemuBlockNamedNodeDataBitmapPtr tmp;
a41c76
-
a41c76
-        if ((tmp = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
a41c76
-                                                         n, delbitmap))) {
a41c76
-            break;
a41c76
-        }
a41c76
-
a41c76
-        n = n->backingStore;
a41c76
-    }
a41c76
-
a41c76
-    if (!n) {
a41c76
-        virReportError(VIR_ERR_INTERNAL_ERROR,
a41c76
-                       _("bitmap '%s' not found in backing chain of '%s'"),
a41c76
-                       delbitmap, diskdst);
a41c76
-        return -1;
a41c76
-    }
a41c76
-
a41c76
-    while (n) {
a41c76
-        qemuBlockNamedNodeDataBitmapPtr srcbitmap;
a41c76
-
a41c76
-        if (!(srcbitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
a41c76
-                                                                n, delbitmap)))
a41c76
-            break;
a41c76
-
a41c76
-        /* For the actual checkpoint deletion we will merge any bitmap into the
a41c76
-         * bitmap of the parent checkpoint (@parentbitmap) or for any image
a41c76
-         * where the parent checkpoint bitmap is not present we must rename
a41c76
-         * the bitmap of the deleted checkpoint into the bitmap of the parent
a41c76
-         * checkpoint as qemu can't currently take the allocation map and turn
a41c76
-         * it into a bitmap and thus we wouldn't be able to do a backup. */
a41c76
-        if (parentbitmap) {
a41c76
-            qemuBlockNamedNodeDataBitmapPtr dstbitmap;
a41c76
-            g_autoptr(virJSONValue) arr = NULL;
a41c76
-
a41c76
-            dstbitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
a41c76
-                                                              n, parentbitmap);
a41c76
-
a41c76
-            if (dstbitmap) {
a41c76
-                if (srcbitmap->recording && !dstbitmap->recording) {
a41c76
-                    if (qemuMonitorTransactionBitmapEnable(actions,
a41c76
-                                                           n->nodeformat,
a41c76
-                                                           dstbitmap->name) < 0)
a41c76
-                        return -1;
a41c76
-                }
a41c76
-
a41c76
-            } else {
a41c76
-                if (qemuMonitorTransactionBitmapAdd(actions,
a41c76
-                                                    n->nodeformat,
a41c76
-                                                    parentbitmap,
a41c76
-                                                    true,
a41c76
-                                                    !srcbitmap->recording,
a41c76
-                                                    srcbitmap->granularity) < 0)
a41c76
-                    return -1;
a41c76
-            }
a41c76
+    for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
a41c76
+        qemuBlockNamedNodeDataBitmapPtr bitmapdata;
a41c76
 
a41c76
-            arr = virJSONValueNewArray();
a41c76
-
a41c76
-            if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(arr,
a41c76
-                                                                 n->nodeformat,
a41c76
-                                                                 srcbitmap->name) < 0)
a41c76
-                return -1;
a41c76
+        if (!(bitmapdata = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
a41c76
+                                                                 n, delbitmap)))
a41c76
+            continue;
a41c76
 
a41c76
-            if (qemuMonitorTransactionBitmapMerge(actions,
a41c76
-                                                  n->nodeformat,
a41c76
-                                                  parentbitmap, &arr) < 0)
a41c76
-                return -1;
a41c76
-        }
a41c76
+        found = true;
a41c76
 
a41c76
         if (qemuMonitorTransactionBitmapRemove(actions,
a41c76
                                                n->nodeformat,
a41c76
-                                               srcbitmap->name) < 0)
a41c76
+                                               bitmapdata->name) < 0)
a41c76
             return -1;
a41c76
 
a41c76
         if (n != src)
a41c76
             *reopenimages = g_slist_prepend(*reopenimages, n);
a41c76
+    }
a41c76
 
a41c76
-        n = n->backingStore;
a41c76
+    if (!found) {
a41c76
+        virReportError(VIR_ERR_INTERNAL_ERROR,
a41c76
+                       _("bitmap '%s' not found in backing chain of '%s'"),
a41c76
+                       delbitmap, diskdst);
a41c76
+        return -1;
a41c76
     }
a41c76
 
a41c76
     return 0;
a41c76
@@ -247,8 +148,7 @@ qemuCheckpointDiscardDiskBitmaps(virStorageSourcePtr src,
a41c76
 
a41c76
 static int
a41c76
 qemuCheckpointDiscardBitmaps(virDomainObjPtr vm,
a41c76
-                             virDomainCheckpointDefPtr chkdef,
a41c76
-                             virDomainMomentObjPtr parent)
a41c76
+                             virDomainCheckpointDefPtr chkdef)
a41c76
 {
a41c76
     qemuDomainObjPrivatePtr priv = vm->privateData;
a41c76
     virQEMUDriverPtr driver = priv->driver;
a41c76
@@ -270,8 +170,6 @@ qemuCheckpointDiscardBitmaps(virDomainObjPtr vm,
a41c76
     for (i = 0; i < chkdef->ndisks; i++) {
a41c76
         virDomainCheckpointDiskDef *chkdisk = &chkdef->disks[i];
a41c76
         virDomainDiskDefPtr domdisk = virDomainDiskByTarget(vm->def, chkdisk->name);
a41c76
-        virDomainCheckpointDiskDef *parentchkdisk = NULL;
a41c76
-        const char *parentbitmap = NULL;
a41c76
 
a41c76
         /* domdisk can be missing e.g. when it was unplugged */
a41c76
         if (!domdisk)
a41c76
@@ -280,15 +178,8 @@ qemuCheckpointDiscardBitmaps(virDomainObjPtr vm,
a41c76
         if (chkdisk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
a41c76
             continue;
a41c76
 
a41c76
-        /* If any ancestor checkpoint has a bitmap for the same
a41c76
-         * disk, then this bitmap must be merged to the
a41c76
-         * ancestor. */
a41c76
-        if ((parentchkdisk = qemuCheckpointFindActiveDiskInParent(vm, parent,
a41c76
-                                                                  chkdisk->name)))
a41c76
-            parentbitmap = parentchkdisk->bitmap;
a41c76
-
a41c76
         if (qemuCheckpointDiscardDiskBitmaps(domdisk->src, blockNamedNodeData,
a41c76
-                                             chkdisk->bitmap, parentbitmap,
a41c76
+                                             chkdisk->bitmap,
a41c76
                                              actions, domdisk->dst,
a41c76
                                              &reopenimages) < 0)
a41c76
             return -1;
a41c76
@@ -336,7 +227,6 @@ qemuCheckpointDiscard(virQEMUDriverPtr driver,
a41c76
                       bool update_parent,
a41c76
                       bool metadata_only)
a41c76
 {
a41c76
-    virDomainMomentObjPtr parent = NULL;
a41c76
     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
a41c76
     g_autofree char *chkFile = NULL;
a41c76
     bool chkcurrent = chk == virDomainCheckpointGetCurrent(vm->checkpoints);
a41c76
@@ -352,14 +242,17 @@ qemuCheckpointDiscard(virQEMUDriverPtr driver,
a41c76
 
a41c76
     if (!metadata_only) {
a41c76
         virDomainCheckpointDefPtr chkdef = virDomainCheckpointObjGetDef(chk);
a41c76
-        parent = virDomainCheckpointFindByName(vm->checkpoints,
a41c76
-                                               chk->def->parent_name);
a41c76
-        if (qemuCheckpointDiscardBitmaps(vm, chkdef, parent) < 0)
a41c76
+        if (qemuCheckpointDiscardBitmaps(vm, chkdef) < 0)
a41c76
             return -1;
a41c76
     }
a41c76
 
a41c76
     if (chkcurrent) {
a41c76
+        virDomainMomentObjPtr parent = NULL;
a41c76
+
a41c76
         virDomainCheckpointSetCurrent(vm->checkpoints, NULL);
a41c76
+        parent = virDomainCheckpointFindByName(vm->checkpoints,
a41c76
+                                               chk->def->parent_name);
a41c76
+
a41c76
         if (update_parent && parent) {
a41c76
             virDomainCheckpointSetCurrent(vm->checkpoints, parent);
a41c76
             if (qemuCheckpointWriteMetadata(vm, parent,
a41c76
diff --git a/src/qemu/qemu_checkpoint.h b/src/qemu/qemu_checkpoint.h
a41c76
index cf1e9e46cb..0d267a188c 100644
a41c76
--- a/src/qemu/qemu_checkpoint.h
a41c76
+++ b/src/qemu/qemu_checkpoint.h
a41c76
@@ -76,7 +76,6 @@ int
a41c76
 qemuCheckpointDiscardDiskBitmaps(virStorageSourcePtr src,
a41c76
                                  virHashTablePtr blockNamedNodeData,
a41c76
                                  const char *delbitmap,
a41c76
-                                 const char *parentbitmap,
a41c76
                                  virJSONValuePtr actions,
a41c76
                                  const char *diskdst,
a41c76
                                  GSList **reopenimages);
a41c76
diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c
a41c76
index 2f675d7e03..201e5df6b4 100644
a41c76
--- a/tests/qemublocktest.c
a41c76
+++ b/tests/qemublocktest.c
a41c76
@@ -830,7 +830,6 @@ struct testQemuCheckpointDeleteMergeData {
a41c76
     const char *name;
a41c76
     virStorageSourcePtr chain;
a41c76
     const char *deletebitmap;
a41c76
-    const char *parentbitmap;
a41c76
     const char *nodedatafile;
a41c76
 };
a41c76
 
a41c76
@@ -864,7 +863,6 @@ testQemuCheckpointDeleteMerge(const void *opaque)
a41c76
     if (qemuCheckpointDiscardDiskBitmaps(data->chain,
a41c76
                                          nodedata,
a41c76
                                          data->deletebitmap,
a41c76
-                                         data->parentbitmap,
a41c76
                                          actions,
a41c76
                                          "testdisk",
a41c76
                                          &reopenimages) >= 0) {
a41c76
@@ -1318,19 +1316,18 @@ mymain(void)
a41c76
 
a41c76
     TEST_BACKUP_BITMAP_CALCULATE("empty", bitmapSourceChain, "a", "empty");
a41c76
 
a41c76
-#define TEST_CHECKPOINT_DELETE_MERGE(testname, delbmp, parbmp, named) \
a41c76
+#define TEST_CHECKPOINT_DELETE_MERGE(testname, delbmp, named) \
a41c76
     do { \
a41c76
         checkpointdeletedata.name = testname; \
a41c76
         checkpointdeletedata.chain = bitmapSourceChain; \
a41c76
         checkpointdeletedata.deletebitmap = delbmp; \
a41c76
-        checkpointdeletedata.parentbitmap = parbmp; \
a41c76
         checkpointdeletedata.nodedatafile = named; \
a41c76
         if (virTestRun("checkpoint delete " testname, \
a41c76
                        testQemuCheckpointDeleteMerge, &checkpointdeletedata) < 0) \
a41c76
         ret = -1; \
a41c76
     } while (0)
a41c76
 
a41c76
-    TEST_CHECKPOINT_DELETE_MERGE("empty", "a", NULL, "empty");
a41c76
+    TEST_CHECKPOINT_DELETE_MERGE("empty", "a", "empty");
a41c76
 
a41c76
 #define TEST_BITMAP_VALIDATE(testname, bitmap, rc) \
a41c76
     do { \
a41c76
-- 
a41c76
2.27.0
a41c76