b971b8
From 8d813e074a1bbe7636c487487e661a5e1a713fd1 Mon Sep 17 00:00:00 2001
b971b8
Message-Id: <8d813e074a1bbe7636c487487e661a5e1a713fd1@dist-git>
b971b8
From: Peter Krempa <pkrempa@redhat.com>
b971b8
Date: Tue, 23 Jun 2020 12:24:04 +0200
b971b8
Subject: [PATCH] qemu: Rewrite bitmap handling for block copy
b971b8
MIME-Version: 1.0
b971b8
Content-Type: text/plain; charset=UTF-8
b971b8
Content-Transfer-Encoding: 8bit
b971b8
b971b8
Reuse qemuBlockGetBitmapMergeActions which allows the removal of the
b971b8
ad-hoc implementation of bitmap merging for block copy.
b971b8
b971b8
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
b971b8
Reviewed-by: Eric Blake <eblake@redhat.com>
b971b8
(cherry picked from commit 7bfff40fdfe5410c446c1cd8ec413e00530faf7d)
b971b8
https://bugzilla.redhat.com/show_bug.cgi?id=1804593
b971b8
Message-Id: <6a254120769a0071ef6867e4c15aca7d3760cf3c.1592906423.git.pkrempa@redhat.com>
b971b8
Reviewed-by: Ján Tomko <jtomko@redhat.com>
b971b8
---
b971b8
 src/qemu/qemu_block.c    | 113 ++-------------------------------------
b971b8
 src/qemu/qemu_blockjob.c |  40 ++++++++++++++
b971b8
 src/qemu/qemu_driver.c   |  13 ++---
b971b8
 tests/qemublocktest.c    |   6 ++-
b971b8
 4 files changed, 57 insertions(+), 115 deletions(-)
b971b8
b971b8
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
b971b8
index ff9e000461..18c3861a2e 100644
b971b8
--- a/src/qemu/qemu_block.c
b971b8
+++ b/src/qemu/qemu_block.c
b971b8
@@ -3053,38 +3053,6 @@ qemuBlockBitmapChainIsValid(virStorageSourcePtr src,
b971b8
 }
b971b8
 
b971b8
 
b971b8
-struct qemuBlockBitmapsHandleBlockcopyConcatData {
b971b8
-    virHashTablePtr bitmaps_merge;
b971b8
-    virJSONValuePtr actions;
b971b8
-    const char *mirrornodeformat;
b971b8
-    bool has_bitmaps;
b971b8
-};
b971b8
-
b971b8
-
b971b8
-static int
b971b8
-qemuBlockBitmapsHandleBlockcopyConcatActions(void *payload,
b971b8
-                                             const void *name,
b971b8
-                                             void *opaque)
b971b8
-{
b971b8
-    struct qemuBlockBitmapsHandleBlockcopyConcatData *data = opaque;
b971b8
-    virJSONValuePtr createactions = payload;
b971b8
-    const char *bitmapname = name;
b971b8
-    g_autoptr(virJSONValue) mergebitmaps = virHashSteal(data->bitmaps_merge, bitmapname);
b971b8
-
b971b8
-    data->has_bitmaps = true;
b971b8
-
b971b8
-    virJSONValueArrayConcat(data->actions, createactions);
b971b8
-
b971b8
-    if (qemuMonitorTransactionBitmapMerge(data->actions,
b971b8
-                                          data->mirrornodeformat,
b971b8
-                                          bitmapname,
b971b8
-                                          &mergebitmaps) < 0)
b971b8
-        return -1;
b971b8
-
b971b8
-    return 0;
b971b8
-}
b971b8
-
b971b8
-
b971b8
 /**
b971b8
  * qemuBlockBitmapsHandleBlockcopy:
b971b8
  * @src: disk source
b971b8
@@ -3107,86 +3075,15 @@ qemuBlockBitmapsHandleBlockcopy(virStorageSourcePtr src,
b971b8
                                 bool shallow,
b971b8
                                 virJSONValuePtr *actions)
b971b8
 {
b971b8
-    g_autoptr(virHashTable) bitmaps = virHashNew(virJSONValueHashFree);
b971b8
-    g_autoptr(virHashTable) bitmaps_merge = virHashNew(virJSONValueHashFree);
b971b8
-    g_autoptr(virHashTable) bitmaps_skip = virHashNew(NULL);
b971b8
-    g_autoptr(virJSONValue) tmpactions = virJSONValueNewArray();
b971b8
-    qemuBlockNamedNodeDataPtr entry;
b971b8
-    virStorageSourcePtr n;
b971b8
-    size_t i;
b971b8
-    struct qemuBlockBitmapsHandleBlockcopyConcatData data = { .bitmaps_merge = bitmaps_merge,
b971b8
-                                                              .actions = tmpactions,
b971b8
-                                                              .mirrornodeformat = mirror->nodeformat,
b971b8
-                                                              .has_bitmaps = false, };
b971b8
-
b971b8
-    for (n = src; n; n = n->backingStore) {
b971b8
-        if (!(entry = virHashLookup(blockNamedNodeData, n->nodeformat)))
b971b8
-            continue;
b971b8
-
b971b8
-        for (i = 0; i < entry->nbitmaps; i++) {
b971b8
-            qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
b971b8
-            virJSONValuePtr bitmap_merge;
b971b8
-
b971b8
-            if (virHashHasEntry(bitmaps_skip, bitmap->name))
b971b8
-                continue;
b971b8
-
b971b8
-            if (!(bitmap_merge = virHashLookup(bitmaps_merge, bitmap->name))) {
b971b8
-                g_autoptr(virJSONValue) tmp = NULL;
b971b8
-                bool disabled = !bitmap->recording;
b971b8
-
b971b8
-                /* disable any non top-layer bitmaps */
b971b8
-                if (n != src)
b971b8
-                    disabled = true;
b971b8
-
b971b8
-                if (!bitmap->persistent ||
b971b8
-                    !(qemuBlockBitmapChainIsValid(n, bitmap->name,
b971b8
-                                                  blockNamedNodeData))) {
b971b8
-                    ignore_value(virHashAddEntry(bitmaps_skip, bitmap->name, NULL));
b971b8
-                    continue;
b971b8
-                }
b971b8
-
b971b8
-                /* prepare the data for adding the bitmap to the mirror */
b971b8
-                tmp = virJSONValueNewArray();
b971b8
-
b971b8
-                if (qemuMonitorTransactionBitmapAdd(tmp,
b971b8
-                                                    mirror->nodeformat,
b971b8
-                                                    bitmap->name,
b971b8
-                                                    true,
b971b8
-                                                    disabled,
b971b8
-                                                    bitmap->granularity) < 0)
b971b8
-                    return -1;
b971b8
+    virStorageSourcePtr base = NULL;
b971b8
 
b971b8
-                if (virHashAddEntry(bitmaps, bitmap->name, tmp) < 0)
b971b8
-                    return -1;
b971b8
-
b971b8
-                tmp = NULL;
b971b8
-
b971b8
-                /* prepare array for merging all the bitmaps from the original chain */
b971b8
-                tmp = virJSONValueNewArray();
b971b8
-
b971b8
-                if (virHashAddEntry(bitmaps_merge, bitmap->name, tmp) < 0)
b971b8
-                    return -1;
b971b8
-
b971b8
-                bitmap_merge = g_steal_pointer(&tmp);
b971b8
-            }
b971b8
+    if (shallow)
b971b8
+        base = src->backingStore;
b971b8
 
b971b8
-            if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(bitmap_merge,
b971b8
-                                                                 n->nodeformat,
b971b8
-                                                                 bitmap->name) < 0)
b971b8
-                return -1;
b971b8
-        }
b971b8
-
b971b8
-        if (shallow)
b971b8
-            break;
b971b8
-    }
b971b8
-
b971b8
-    if (virHashForEach(bitmaps, qemuBlockBitmapsHandleBlockcopyConcatActions,
b971b8
-                       &data) < 0)
b971b8
+    if (qemuBlockGetBitmapMergeActions(src, base, mirror, NULL, NULL, mirror, actions,
b971b8
+                                       blockNamedNodeData) < 0)
b971b8
         return -1;
b971b8
 
b971b8
-    if (data.has_bitmaps)
b971b8
-        *actions = g_steal_pointer(&tmpactions);
b971b8
-
b971b8
     return 0;
b971b8
 }
b971b8
 
b971b8
diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
b971b8
index d106165175..6e33f8666c 100644
b971b8
--- a/src/qemu/qemu_blockjob.c
b971b8
+++ b/src/qemu/qemu_blockjob.c
b971b8
@@ -1281,6 +1281,43 @@ qemuBlockJobProcessEventCompletedActiveCommit(virQEMUDriverPtr driver,
b971b8
 }
b971b8
 
b971b8
 
b971b8
+static int
b971b8
+qemuBlockJobProcessEventCompletedCopyBitmaps(virDomainObjPtr vm,
b971b8
+                                             qemuBlockJobDataPtr job,
b971b8
+                                             qemuDomainAsyncJob asyncJob)
b971b8
+{
b971b8
+    qemuDomainObjPrivatePtr priv = vm->privateData;
b971b8
+    g_autoptr(virHashTable) blockNamedNodeData = NULL;
b971b8
+    g_autoptr(virJSONValue) actions = NULL;
b971b8
+    bool shallow = job->jobflags & VIR_DOMAIN_BLOCK_COPY_SHALLOW;
b971b8
+
b971b8
+    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN))
b971b8
+        return 0;
b971b8
+
b971b8
+    if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, asyncJob)))
b971b8
+        return -1;
b971b8
+
b971b8
+    if (qemuBlockBitmapsHandleBlockcopy(job->disk->src,
b971b8
+                                        job->disk->mirror,
b971b8
+                                        blockNamedNodeData,
b971b8
+                                        shallow,
b971b8
+                                        &actions) < 0)
b971b8
+        return 0;
b971b8
+
b971b8
+    if (!actions)
b971b8
+        return 0;
b971b8
+
b971b8
+    if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0)
b971b8
+        return -1;
b971b8
+
b971b8
+    qemuMonitorTransaction(priv->mon, &actions);
b971b8
+
b971b8
+    if (qemuDomainObjExitMonitor(priv->driver, vm) < 0)
b971b8
+        return -1;
b971b8
+
b971b8
+    return 0;
b971b8
+}
b971b8
+
b971b8
 static void
b971b8
 qemuBlockJobProcessEventConcludedCopyPivot(virQEMUDriverPtr driver,
b971b8
                                            virDomainObjPtr vm,
b971b8
@@ -1295,6 +1332,8 @@ qemuBlockJobProcessEventConcludedCopyPivot(virQEMUDriverPtr driver,
b971b8
         !job->disk->mirror)
b971b8
         return;
b971b8
 
b971b8
+    qemuBlockJobProcessEventCompletedCopyBitmaps(vm, job, asyncJob);
b971b8
+
b971b8
     /* for shallow copy without reusing external image the user can either not
b971b8
      * specify the backing chain in which case libvirt will open and use the
b971b8
      * chain the user provided or not specify a chain in which case we'll
b971b8
@@ -1328,6 +1367,7 @@ qemuBlockJobProcessEventConcludedCopyAbort(virQEMUDriverPtr driver,
b971b8
         !job->disk->mirror)
b971b8
         return;
b971b8
 
b971b8
+    /* activeWrite bitmap is removed automatically here */
b971b8
     qemuBlockJobEventProcessConcludedRemoveChain(driver, vm, asyncJob, job->disk->mirror);
b971b8
     virObjectUnref(job->disk->mirror);
b971b8
     job->disk->mirror = NULL;
b971b8
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
b971b8
index ed5498d2bc..9e3a455814 100644
b971b8
--- a/src/qemu/qemu_driver.c
b971b8
+++ b/src/qemu/qemu_driver.c
b971b8
@@ -17596,14 +17596,15 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
b971b8
         if (blockdev && !job->jobflagsmissing) {
b971b8
             bool shallow = job->jobflags & VIR_DOMAIN_BLOCK_COPY_SHALLOW;
b971b8
             bool reuse = job->jobflags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT;
b971b8
-            g_autoptr(virHashTable) blockNamedNodeData = NULL;
b971b8
 
b971b8
-            if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
b971b8
-                return -1;
b971b8
+            actions = virJSONValueNewArray();
b971b8
 
b971b8
-            if (qemuBlockBitmapsHandleBlockcopy(disk->src, disk->mirror,
b971b8
-                                                blockNamedNodeData,
b971b8
-                                                shallow, &actions) < 0)
b971b8
+            if (qemuMonitorTransactionBitmapAdd(actions,
b971b8
+                                                disk->mirror->nodeformat,
b971b8
+                                                "libvirt-tmp-activewrite",
b971b8
+                                                false,
b971b8
+                                                false,
b971b8
+                                                0) < 0)
b971b8
                 return -1;
b971b8
 
b971b8
             /* Open and install the backing chain of 'mirror' late if we can use
b971b8
diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c
b971b8
index e1468f13fa..193b4aaed0 100644
b971b8
--- a/tests/qemublocktest.c
b971b8
+++ b/tests/qemublocktest.c
b971b8
@@ -881,6 +881,7 @@ testQemuBlockBitmapBlockcopy(const void *opaque)
b971b8
     g_autoptr(virJSONValue) nodedatajson = NULL;
b971b8
     g_autoptr(virHashTable) nodedata = NULL;
b971b8
     g_autoptr(virStorageSource) fakemirror = virStorageSourceNew();
b971b8
+    g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
b971b8
 
b971b8
     if (!fakemirror)
b971b8
         return -1;
b971b8
@@ -903,10 +904,13 @@ testQemuBlockBitmapBlockcopy(const void *opaque)
b971b8
                                         data->shallow, &actions) < 0)
b971b8
         return -1;
b971b8
 
b971b8
+
b971b8
     if (actions &&
b971b8
-        !(actual = virJSONValueToString(actions, true)))
b971b8
+        virJSONValueToBuffer(actions, &buf, true) < 0)
b971b8
         return -1;
b971b8
 
b971b8
+    actual = virBufferContentAndReset(&buf;;
b971b8
+
b971b8
     return virTestCompareToFile(actual, expectpath);
b971b8
 }
b971b8
 
b971b8
-- 
b971b8
2.27.0
b971b8