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