Blame SOURCES/libvirt-qemu-block-Implement-helpers-for-dealing-with-bitmaps-during-block-commit.patch

d76c62
From 3e71c9c766a0452e0bae3b4593f3cba3d1caec60 Mon Sep 17 00:00:00 2001
d76c62
Message-Id: <3e71c9c766a0452e0bae3b4593f3cba3d1caec60@dist-git>
d76c62
From: Peter Krempa <pkrempa@redhat.com>
d76c62
Date: Mon, 16 Mar 2020 22:12:24 +0100
d76c62
Subject: [PATCH] qemu: block: Implement helpers for dealing with bitmaps
d76c62
 during block commit
d76c62
MIME-Version: 1.0
d76c62
Content-Type: text/plain; charset=UTF-8
d76c62
Content-Transfer-Encoding: 8bit
d76c62
d76c62
qemuBlockBitmapsHandleCommitStart prepares for disabling the bitmaps in
d76c62
the 'base' of the commit job so that the bitmaps are not dirtied by the
d76c62
commit job. This needs to be done prior to start of the commit job.
d76c62
d76c62
qemuBlockBitmapsHandleCommitFinish then calculates the necessary merges
d76c62
that agregate all the bitmaps between the commited images and write them
d76c62
into the base bitmap.
d76c62
d76c62
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
d76c62
Reviewed-by: Eric Blake <eblake@redhat.com>
d76c62
(cherry picked from commit 1753f605506e28eb42bc5bb6fa9abe8fcbe6fb9b)
d76c62
https://bugzilla.redhat.com/show_bug.cgi?id=1799013
d76c62
Message-Id: <c0624f94e802043ca10819aaaa9111ae230cfb7f.1584391727.git.pkrempa@redhat.com>
d76c62
Reviewed-by: Ján Tomko <jtomko@redhat.com>
d76c62
---
d76c62
 src/qemu/qemu_block.c | 219 ++++++++++++++++++++++++++++++++++++++++++
d76c62
 src/qemu/qemu_block.h |  14 +++
d76c62
 2 files changed, 233 insertions(+)
d76c62
d76c62
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
d76c62
index b4da323610..21c1ad9618 100644
d76c62
--- a/src/qemu/qemu_block.c
d76c62
+++ b/src/qemu/qemu_block.c
d76c62
@@ -2988,6 +2988,225 @@ qemuBlockBitmapsHandleBlockcopy(virStorageSourcePtr src,
d76c62
 }
d76c62
 
d76c62
 
d76c62
+/**
d76c62
+ * @topsrc: virStorageSource representing 'top' of the job
d76c62
+ * @basesrc: virStorageSource representing 'base' of the job
d76c62
+ * @blockNamedNodeData: hash table containing data about bitmaps
d76c62
+ * @actions: filled with arguments for a 'transaction' command
d76c62
+ * @disabledBitmapsBase: filled with a list of bitmap names which must be disabled
d76c62
+ *
d76c62
+ * Prepares data for correctly handling bitmaps during the start of a commit
d76c62
+ * job. The bitmaps in the 'base' image must be disabled, so that the writes
d76c62
+ * done by the blockjob don't dirty the enabled bitmaps.
d76c62
+ *
d76c62
+ * @actions and @disabledBitmapsBase are untouched if no bitmaps need
d76c62
+ * to be disabled.
d76c62
+ */
d76c62
+int
d76c62
+qemuBlockBitmapsHandleCommitStart(virStorageSourcePtr topsrc,
d76c62
+                                  virStorageSourcePtr basesrc,
d76c62
+                                  virHashTablePtr blockNamedNodeData,
d76c62
+                                  virJSONValuePtr *actions,
d76c62
+                                  char ***disabledBitmapsBase)
d76c62
+{
d76c62
+    g_autoptr(virJSONValue) act = virJSONValueNewArray();
d76c62
+    VIR_AUTOSTRINGLIST bitmaplist = NULL;
d76c62
+    size_t curbitmapstr = 0;
d76c62
+    qemuBlockNamedNodeDataPtr entry;
d76c62
+    bool disable_bitmaps = false;
d76c62
+    size_t i;
d76c62
+
d76c62
+    if (!(entry = virHashLookup(blockNamedNodeData, basesrc->nodeformat)))
d76c62
+        return 0;
d76c62
+
d76c62
+    bitmaplist = g_new0(char *, entry->nbitmaps);
d76c62
+
d76c62
+    for (i = 0; i < entry->nbitmaps; i++) {
d76c62
+        qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
d76c62
+
d76c62
+        if (!bitmap->recording || bitmap->inconsistent ||
d76c62
+            !qemuBlockBitmapChainIsValid(topsrc, bitmap->name, blockNamedNodeData))
d76c62
+            continue;
d76c62
+
d76c62
+        disable_bitmaps = true;
d76c62
+
d76c62
+        if (qemuMonitorTransactionBitmapDisable(act, basesrc->nodeformat,
d76c62
+                                                bitmap->name) < 0)
d76c62
+            return -1;
d76c62
+
d76c62
+        bitmaplist[curbitmapstr++] = g_strdup(bitmap->name);
d76c62
+    }
d76c62
+
d76c62
+    if (disable_bitmaps) {
d76c62
+        *actions = g_steal_pointer(&act;;
d76c62
+        *disabledBitmapsBase = g_steal_pointer(&bitmaplist);
d76c62
+    }
d76c62
+
d76c62
+    return 0;
d76c62
+}
d76c62
+
d76c62
+
d76c62
+struct qemuBlockBitmapsHandleCommitData {
d76c62
+    bool skip;
d76c62
+    bool create;
d76c62
+    bool enable;
d76c62
+    const char *basenode;
d76c62
+    virJSONValuePtr merge;
d76c62
+    unsigned long long granularity;
d76c62
+    bool persistent;
d76c62
+};
d76c62
+
d76c62
+
d76c62
+static void
d76c62
+qemuBlockBitmapsHandleCommitDataFree(void *opaque)
d76c62
+{
d76c62
+    struct qemuBlockBitmapsHandleCommitData *data = opaque;
d76c62
+
d76c62
+    virJSONValueFree(data->merge);
d76c62
+    g_free(data);
d76c62
+}
d76c62
+
d76c62
+
d76c62
+static int
d76c62
+qemuBlockBitmapsHandleCommitFinishIterate(void *payload,
d76c62
+                                          const void *entryname,
d76c62
+                                          void *opaque)
d76c62
+{
d76c62
+    struct qemuBlockBitmapsHandleCommitData *data = payload;
d76c62
+    const char *bitmapname = entryname;
d76c62
+    virJSONValuePtr actions = opaque;
d76c62
+
d76c62
+    if (data->skip)
d76c62
+        return 0;
d76c62
+
d76c62
+    if (data->create) {
d76c62
+        if (qemuMonitorTransactionBitmapAdd(actions, data->basenode, bitmapname,
d76c62
+                                            data->persistent, !data->enable,
d76c62
+                                            data->granularity) < 0)
d76c62
+            return -1;
d76c62
+    } else {
d76c62
+        if (data->enable &&
d76c62
+            qemuMonitorTransactionBitmapEnable(actions, data->basenode, bitmapname) < 0)
d76c62
+            return -1;
d76c62
+    }
d76c62
+
d76c62
+    if (data->merge &&
d76c62
+        qemuMonitorTransactionBitmapMerge(actions, data->basenode, bitmapname,
d76c62
+                                          &data->merge) < 0)
d76c62
+        return -1;
d76c62
+
d76c62
+    return 0;
d76c62
+}
d76c62
+
d76c62
+
d76c62
+/**
d76c62
+ * @topsrc: virStorageSource representing 'top' of the job
d76c62
+ * @basesrc: virStorageSource representing 'base' of the job
d76c62
+ * @blockNamedNodeData: hash table containing data about bitmaps
d76c62
+ * @actions: filled with arguments for a 'transaction' command
d76c62
+ * @disabledBitmapsBase: bitmap names which were disabled
d76c62
+ *
d76c62
+ * Calculates the necessary bitmap merges/additions/enablements to properly
d76c62
+ * handle commit of images from 'top' into 'base'. The necessary operations
d76c62
+ * in the form of arguments of the 'transaction' command are filled into
d76c62
+ * 'actions' if there is anything to do. Otherwise NULL is returned.
d76c62
+ */
d76c62
+int
d76c62
+qemuBlockBitmapsHandleCommitFinish(virStorageSourcePtr topsrc,
d76c62
+                                   virStorageSourcePtr basesrc,
d76c62
+                                   virHashTablePtr blockNamedNodeData,
d76c62
+                                   virJSONValuePtr *actions,
d76c62
+                                   char **disabledBitmapsBase)
d76c62
+{
d76c62
+    g_autoptr(virJSONValue) act = virJSONValueNewArray();
d76c62
+    virStorageSourcePtr n;
d76c62
+    qemuBlockNamedNodeDataPtr entry;
d76c62
+    g_autoptr(virHashTable) commitdata = NULL;
d76c62
+    struct qemuBlockBitmapsHandleCommitData *bitmapdata;
d76c62
+    size_t i;
d76c62
+
d76c62
+    commitdata = virHashNew(qemuBlockBitmapsHandleCommitDataFree);
d76c62
+
d76c62
+    for (n = topsrc; n != basesrc; n = n->backingStore) {
d76c62
+        if (!(entry = virHashLookup(blockNamedNodeData, n->nodeformat)))
d76c62
+            continue;
d76c62
+
d76c62
+        for (i = 0; i < entry->nbitmaps; i++) {
d76c62
+            qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
d76c62
+
d76c62
+            if (!(bitmapdata = virHashLookup(commitdata, bitmap->name))) {
d76c62
+                bitmapdata = g_new0(struct qemuBlockBitmapsHandleCommitData, 1);
d76c62
+
d76c62
+                /* we must mirror the state of the topmost bitmap and merge
d76c62
+                 * everything else */
d76c62
+                bitmapdata->create = true;
d76c62
+                bitmapdata->enable = bitmap->recording;
d76c62
+                bitmapdata->basenode = basesrc->nodeformat;
d76c62
+                bitmapdata->merge = virJSONValueNewArray();
d76c62
+                bitmapdata->granularity = bitmap->granularity;
d76c62
+                bitmapdata->persistent = bitmap->persistent;
d76c62
+
d76c62
+                if (virHashAddEntry(commitdata, bitmap->name, bitmapdata) < 0) {
d76c62
+                    qemuBlockBitmapsHandleCommitDataFree(bitmapdata);
d76c62
+                    return -1;
d76c62
+                }
d76c62
+            }
d76c62
+
d76c62
+            if (bitmap->inconsistent ||
d76c62
+                !qemuBlockBitmapChainIsValid(topsrc, bitmap->name, blockNamedNodeData))
d76c62
+                bitmapdata->skip = true;
d76c62
+
d76c62
+            if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(bitmapdata->merge,
d76c62
+                                                                 n->nodeformat,
d76c62
+                                                                 bitmap->name) < 0)
d76c62
+                return -1;
d76c62
+        }
d76c62
+    }
d76c62
+
d76c62
+    if ((entry = virHashLookup(blockNamedNodeData, basesrc->nodeformat))) {
d76c62
+        /* note that all bitmaps in 'base' were disabled when commit was started */
d76c62
+        for (i = 0; i < entry->nbitmaps; i++) {
d76c62
+            qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
d76c62
+
d76c62
+            if ((bitmapdata = virHashLookup(commitdata, bitmap->name))) {
d76c62
+                bitmapdata->create = false;
d76c62
+            } else {
d76c62
+                if (disabledBitmapsBase) {
d76c62
+                    char **disabledbitmaps;
d76c62
+
d76c62
+                    for (disabledbitmaps = disabledBitmapsBase; *disabledbitmaps; disabledbitmaps++) {
d76c62
+                        if (STREQ(*disabledBitmapsBase, bitmap->name)) {
d76c62
+                            bitmapdata = g_new0(struct qemuBlockBitmapsHandleCommitData, 1);
d76c62
+
d76c62
+                            bitmapdata->create = false;
d76c62
+                            bitmapdata->enable = true;
d76c62
+                            bitmapdata->basenode = basesrc->nodeformat;
d76c62
+                            bitmapdata->granularity = bitmap->granularity;
d76c62
+                            bitmapdata->persistent = bitmap->persistent;
d76c62
+
d76c62
+                            if (virHashAddEntry(commitdata, bitmap->name, bitmapdata) < 0) {
d76c62
+                                qemuBlockBitmapsHandleCommitDataFree(bitmapdata);
d76c62
+                                return -1;
d76c62
+                            }
d76c62
+
d76c62
+                            break;
d76c62
+                        }
d76c62
+                    }
d76c62
+                }
d76c62
+            }
d76c62
+        }
d76c62
+    }
d76c62
+
d76c62
+    if (virHashForEach(commitdata, qemuBlockBitmapsHandleCommitFinishIterate, act) < 0)
d76c62
+        return -1;
d76c62
+
d76c62
+    if (virJSONValueArraySize(act) > 0)
d76c62
+        *actions = g_steal_pointer(&act;;
d76c62
+
d76c62
+    return 0;
d76c62
+}
d76c62
+
d76c62
+
d76c62
 /**
d76c62
  * qemuBlockReopenFormat:
d76c62
  * @vm: domain object
d76c62
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
d76c62
index e012052352..75b25bfea5 100644
d76c62
--- a/src/qemu/qemu_block.h
d76c62
+++ b/src/qemu/qemu_block.h
d76c62
@@ -232,6 +232,20 @@ qemuBlockBitmapsHandleBlockcopy(virStorageSourcePtr src,
d76c62
                                 bool shallow,
d76c62
                                 virJSONValuePtr *actions);
d76c62
 
d76c62
+int
d76c62
+qemuBlockBitmapsHandleCommitStart(virStorageSourcePtr topsrc,
d76c62
+                                  virStorageSourcePtr basesrc,
d76c62
+                                  virHashTablePtr blockNamedNodeData,
d76c62
+                                  virJSONValuePtr *actions,
d76c62
+                                  char ***disabledBitmapsBase);
d76c62
+
d76c62
+int
d76c62
+qemuBlockBitmapsHandleCommitFinish(virStorageSourcePtr topsrc,
d76c62
+                                   virStorageSourcePtr basesrc,
d76c62
+                                   virHashTablePtr blockNamedNodeData,
d76c62
+                                   virJSONValuePtr *actions,
d76c62
+                                   char **disabledBitmapsBase);
d76c62
+
d76c62
 int
d76c62
 qemuBlockReopenReadWrite(virDomainObjPtr vm,
d76c62
                          virStorageSourcePtr src,
d76c62
-- 
d76c62
2.25.1
d76c62