Blame SOURCES/libvirt-qemu-block-Add-validator-for-bitmap-chains-accross-backing-chains.patch

d76c62
From eeb1315a8015aeda4d2fb7ce590c85c40ffb567d Mon Sep 17 00:00:00 2001
d76c62
Message-Id: <eeb1315a8015aeda4d2fb7ce590c85c40ffb567d@dist-git>
d76c62
From: Peter Krempa <pkrempa@redhat.com>
d76c62
Date: Tue, 4 Feb 2020 15:08:23 +0100
d76c62
Subject: [PATCH] qemu: block: Add validator for bitmap chains accross backing
d76c62
 chains
d76c62
MIME-Version: 1.0
d76c62
Content-Type: text/plain; charset=UTF-8
d76c62
Content-Transfer-Encoding: 8bit
d76c62
d76c62
Add a validator which checks that a bitmap spanning multiple backing
d76c62
chain members doesn't look broken. The current rules are that no
d76c62
intermediate birmaps are missing (unfortunately it's hard to know
d76c62
whether the topmost or bottommost bitmap is missing) and none of the
d76c62
components is inconsistent.
d76c62
d76c62
We can obviously improve it over time.
d76c62
d76c62
The validator is also tested against the existing bitmap data we have
d76c62
for the backup merging test as well as some of the existing broken
d76c62
bitmap synthetic test cases.
d76c62
d76c62
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
d76c62
Reviewed-by: Ján Tomko <jtomko@redhat.com>
d76c62
(cherry picked from commit 41c7e5c2a689a4ad091cec40b61beeeb3dde49b8)
d76c62
d76c62
https://bugzilla.redhat.com/show_bug.cgi?id=1207659
d76c62
Message-Id: <a1020495b33e99b2c1bb847dff26565d4def1e20.1580824112.git.pkrempa@redhat.com>
d76c62
Reviewed-by: Ján Tomko <jtomko@redhat.com>
d76c62
---
d76c62
 src/qemu/qemu_block.c | 41 +++++++++++++++++++++++++
d76c62
 src/qemu/qemu_block.h |  5 ++++
d76c62
 tests/qemublocktest.c | 70 +++++++++++++++++++++++++++++++++++++++++++
d76c62
 3 files changed, 116 insertions(+)
d76c62
d76c62
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
d76c62
index 03f029368e..b19290e677 100644
d76c62
--- a/src/qemu/qemu_block.c
d76c62
+++ b/src/qemu/qemu_block.c
d76c62
@@ -2687,3 +2687,44 @@ qemuBlockGetNamedNodeData(virDomainObjPtr vm,
d76c62
 
d76c62
     return g_steal_pointer(&blockNamedNodeData);
d76c62
 }
d76c62
+
d76c62
+
d76c62
+/**
d76c62
+ * qemuBlockBitmapChainIsValid:
d76c62
+ *
d76c62
+ * Validates that the backing chain of @src contains proper consistent bitmap
d76c62
+ * data for a chain of bitmaps named @bitmapname.
d76c62
+ *
d76c62
+ * A valid chain:
d76c62
+ * 1) bitmaps of same name are in a consecutive subset of images without gap
d76c62
+ * 2) don't have any inconsistent bitmaps
d76c62
+ */
d76c62
+bool
d76c62
+qemuBlockBitmapChainIsValid(virStorageSourcePtr src,
d76c62
+                            const char *bitmapname,
d76c62
+                            virHashTablePtr blockNamedNodeData)
d76c62
+{
d76c62
+    qemuBlockNamedNodeDataBitmapPtr bitmap;
d76c62
+    virStorageSourcePtr n;
d76c62
+    bool chain_started = false;
d76c62
+    bool chain_ended = false;
d76c62
+
d76c62
+    for (n = src; n; n = n->backingStore) {
d76c62
+        if (!(bitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData, n, bitmapname))) {
d76c62
+            if (chain_started)
d76c62
+                chain_ended = true;
d76c62
+
d76c62
+            continue;
d76c62
+        }
d76c62
+
d76c62
+        if (chain_ended)
d76c62
+            return false;
d76c62
+
d76c62
+        chain_started = true;
d76c62
+
d76c62
+        if (bitmap->inconsistent)
d76c62
+            return false;
d76c62
+    }
d76c62
+
d76c62
+    return chain_started;
d76c62
+}
d76c62
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
d76c62
index 68646cbf2e..cf51b9bf4e 100644
d76c62
--- a/src/qemu/qemu_block.h
d76c62
+++ b/src/qemu/qemu_block.h
d76c62
@@ -212,3 +212,8 @@ qemuBlockNamedNodeDataGetBitmapByName(virHashTablePtr blockNamedNodeData,
d76c62
 virHashTablePtr
d76c62
 qemuBlockGetNamedNodeData(virDomainObjPtr vm,
d76c62
                           qemuDomainAsyncJob asyncJob);
d76c62
+
d76c62
+bool
d76c62
+qemuBlockBitmapChainIsValid(virStorageSourcePtr src,
d76c62
+                            const char *bitmapname,
d76c62
+                            virHashTablePtr blockNamedNodeData);
d76c62
diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c
d76c62
index 5946cd6c6b..6a7b07cfee 100644
d76c62
--- a/tests/qemublocktest.c
d76c62
+++ b/tests/qemublocktest.c
d76c62
@@ -764,6 +764,41 @@ testQemuCheckpointDeleteMerge(const void *opaque)
d76c62
 }
d76c62
 
d76c62
 
d76c62
+struct testQemuBlockBitmapValidateData {
d76c62
+    const char *name;
d76c62
+    const char *bitmapname;
d76c62
+    virStorageSourcePtr chain;
d76c62
+    bool expect;
d76c62
+};
d76c62
+
d76c62
+static int
d76c62
+testQemuBlockBitmapValidate(const void *opaque)
d76c62
+{
d76c62
+    const struct testQemuBlockBitmapValidateData *data = opaque;
d76c62
+    g_autoptr(virJSONValue) nodedatajson = NULL;
d76c62
+    g_autoptr(virHashTable) nodedata = NULL;
d76c62
+    bool actual;
d76c62
+
d76c62
+    if (!(nodedatajson = virTestLoadFileJSON(bitmapDetectPrefix, data->name,
d76c62
+                                             ".json", NULL)))
d76c62
+        return -1;
d76c62
+
d76c62
+    if (!(nodedata = qemuMonitorJSONBlockGetNamedNodeDataJSON(nodedatajson))) {
d76c62
+        VIR_TEST_VERBOSE("failed to load nodedata JSON\n");
d76c62
+        return -1;
d76c62
+    }
d76c62
+
d76c62
+    actual = qemuBlockBitmapChainIsValid(data->chain, data->bitmapname, nodedata);
d76c62
+
d76c62
+    if (actual != data->expect) {
d76c62
+        VIR_TEST_VERBOSE("expected rv:'%d' actual rv:'%d'\n", data->expect, actual);
d76c62
+        return -1;
d76c62
+    }
d76c62
+
d76c62
+    return 0;
d76c62
+}
d76c62
+
d76c62
+
d76c62
 static int
d76c62
 mymain(void)
d76c62
 {
d76c62
@@ -774,6 +809,7 @@ mymain(void)
d76c62
     struct testQemuImageCreateData imagecreatedata;
d76c62
     struct testQemuBackupIncrementalBitmapCalculateData backupbitmapcalcdata;
d76c62
     struct testQemuCheckpointDeleteMergeData checkpointdeletedata;
d76c62
+    struct testQemuBlockBitmapValidateData blockbitmapvalidatedata;
d76c62
     char *capslatest_x86_64 = NULL;
d76c62
     virQEMUCapsPtr caps_x86_64 = NULL;
d76c62
     g_autoptr(virStorageSource) bitmapSourceChain = NULL;
d76c62
@@ -1041,7 +1077,41 @@ mymain(void)
d76c62
     TEST_CHECKPOINT_DELETE_MERGE("snapshots-synthetic-checkpoint-intermediate3", "d", "c", "snapshots-synthetic-checkpoint");
d76c62
     TEST_CHECKPOINT_DELETE_MERGE("snapshots-synthetic-checkpoint-current", "current", "d", "snapshots-synthetic-checkpoint");
d76c62
 
d76c62
+#define TEST_BITMAP_VALIDATE(testname, bitmap, rc) \
d76c62
+    do { \
d76c62
+        blockbitmapvalidatedata.name = testname; \
d76c62
+        blockbitmapvalidatedata.chain = bitmapSourceChain; \
d76c62
+        blockbitmapvalidatedata.bitmapname = bitmap; \
d76c62
+        blockbitmapvalidatedata.expect = rc; \
d76c62
+        if (virTestRun("bitmap validate " testname " " bitmap, \
d76c62
+                       testQemuBlockBitmapValidate, \
d76c62
+                       &blockbitmapvalidatedata) < 0) \
d76c62
+            ret = -1; \
d76c62
+    } while (0)
d76c62
 
d76c62
+    TEST_BITMAP_VALIDATE("basic", "a", true);
d76c62
+    TEST_BITMAP_VALIDATE("basic", "b", true);
d76c62
+    TEST_BITMAP_VALIDATE("basic", "c", true);
d76c62
+    TEST_BITMAP_VALIDATE("basic", "d", true);
d76c62
+    TEST_BITMAP_VALIDATE("basic", "current", true);
d76c62
+
d76c62
+    TEST_BITMAP_VALIDATE("snapshots", "a", true);
d76c62
+    TEST_BITMAP_VALIDATE("snapshots", "b", true);
d76c62
+    TEST_BITMAP_VALIDATE("snapshots", "c", true);
d76c62
+    TEST_BITMAP_VALIDATE("snapshots", "d", true);
d76c62
+    TEST_BITMAP_VALIDATE("snapshots", "current", true);
d76c62
+
d76c62
+    TEST_BITMAP_VALIDATE("synthetic", "a", false);
d76c62
+    TEST_BITMAP_VALIDATE("synthetic", "b", true);
d76c62
+    TEST_BITMAP_VALIDATE("synthetic", "c", true);
d76c62
+    TEST_BITMAP_VALIDATE("synthetic", "d", true);
d76c62
+    TEST_BITMAP_VALIDATE("synthetic", "current", true);
d76c62
+
d76c62
+    TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "a", true);
d76c62
+    TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "b", true);
d76c62
+    TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "c", true);
d76c62
+    TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "d", true);
d76c62
+    TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "current", true);
d76c62
  cleanup:
d76c62
     virHashFree(diskxmljsondata.schema);
d76c62
     qemuTestDriverFree(&driver);
d76c62
-- 
d76c62
2.25.0
d76c62