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