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

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