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

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