]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: block: Add validator for bitmap chains accross backing chains
authorPeter Krempa <pkrempa@redhat.com>
Wed, 29 Jan 2020 11:08:50 +0000 (12:08 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Tue, 4 Feb 2020 12:45:33 +0000 (13:45 +0100)
Add a validator which checks that a bitmap spanning multiple backing
chain members doesn't look broken. The current rules are that no
intermediate birmaps are missing (unfortunately it's hard to know
whether the topmost or bottommost bitmap is missing) and none of the
components is inconsistent.

We can obviously improve it over time.

The validator is also tested against the existing bitmap data we have
for the backup merging test as well as some of the existing broken
bitmap synthetic test cases.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
src/qemu/qemu_block.c
src/qemu/qemu_block.h
tests/qemublocktest.c

index 03f029368e2ae07eddccceaf3fbd42067483af09..b19290e677ebdfd3dcff78c351038906f5c54507 100644 (file)
@@ -2687,3 +2687,44 @@ qemuBlockGetNamedNodeData(virDomainObjPtr vm,
 
     return g_steal_pointer(&blockNamedNodeData);
 }
+
+
+/**
+ * qemuBlockBitmapChainIsValid:
+ *
+ * Validates that the backing chain of @src contains proper consistent bitmap
+ * data for a chain of bitmaps named @bitmapname.
+ *
+ * A valid chain:
+ * 1) bitmaps of same name are in a consecutive subset of images without gap
+ * 2) don't have any inconsistent bitmaps
+ */
+bool
+qemuBlockBitmapChainIsValid(virStorageSourcePtr src,
+                            const char *bitmapname,
+                            virHashTablePtr blockNamedNodeData)
+{
+    qemuBlockNamedNodeDataBitmapPtr bitmap;
+    virStorageSourcePtr n;
+    bool chain_started = false;
+    bool chain_ended = false;
+
+    for (n = src; n; n = n->backingStore) {
+        if (!(bitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData, n, bitmapname))) {
+            if (chain_started)
+                chain_ended = true;
+
+            continue;
+        }
+
+        if (chain_ended)
+            return false;
+
+        chain_started = true;
+
+        if (bitmap->inconsistent)
+            return false;
+    }
+
+    return chain_started;
+}
index 68646cbf2eb5e256edbca8a1c91b649300052d3c..cf51b9bf4e6fd2150c84e95c1659be18351ccda5 100644 (file)
@@ -212,3 +212,8 @@ qemuBlockNamedNodeDataGetBitmapByName(virHashTablePtr blockNamedNodeData,
 virHashTablePtr
 qemuBlockGetNamedNodeData(virDomainObjPtr vm,
                           qemuDomainAsyncJob asyncJob);
+
+bool
+qemuBlockBitmapChainIsValid(virStorageSourcePtr src,
+                            const char *bitmapname,
+                            virHashTablePtr blockNamedNodeData);
index b45649eaa28bc18ad6f4d251ac247322af96cf35..65ed50bb518c9b3fbb8fd8cb178c9b1ad8856183 100644 (file)
@@ -768,6 +768,41 @@ testQemuCheckpointDeleteMerge(const void *opaque)
 }
 
 
+struct testQemuBlockBitmapValidateData {
+    const char *name;
+    const char *bitmapname;
+    virStorageSourcePtr chain;
+    bool expect;
+};
+
+static int
+testQemuBlockBitmapValidate(const void *opaque)
+{
+    const struct testQemuBlockBitmapValidateData *data = opaque;
+    g_autoptr(virJSONValue) nodedatajson = NULL;
+    g_autoptr(virHashTable) nodedata = NULL;
+    bool actual;
+
+    if (!(nodedatajson = virTestLoadFileJSON(bitmapDetectPrefix, data->name,
+                                             ".json", NULL)))
+        return -1;
+
+    if (!(nodedata = qemuMonitorJSONBlockGetNamedNodeDataJSON(nodedatajson))) {
+        VIR_TEST_VERBOSE("failed to load nodedata JSON\n");
+        return -1;
+    }
+
+    actual = qemuBlockBitmapChainIsValid(data->chain, data->bitmapname, nodedata);
+
+    if (actual != data->expect) {
+        VIR_TEST_VERBOSE("expected rv:'%d' actual rv:'%d'\n", data->expect, actual);
+        return -1;
+    }
+
+    return 0;
+}
+
+
 static int
 mymain(void)
 {
@@ -778,6 +813,7 @@ mymain(void)
     struct testQemuImageCreateData imagecreatedata;
     struct testQemuBackupIncrementalBitmapCalculateData backupbitmapcalcdata;
     struct testQemuCheckpointDeleteMergeData checkpointdeletedata;
+    struct testQemuBlockBitmapValidateData blockbitmapvalidatedata;
     char *capslatest_x86_64 = NULL;
     virQEMUCapsPtr caps_x86_64 = NULL;
     g_autoptr(virStorageSource) bitmapSourceChain = NULL;
@@ -1045,7 +1081,41 @@ mymain(void)
     TEST_CHECKPOINT_DELETE_MERGE("snapshots-synthetic-checkpoint-intermediate3", "d", "c", "snapshots-synthetic-checkpoint");
     TEST_CHECKPOINT_DELETE_MERGE("snapshots-synthetic-checkpoint-current", "current", "d", "snapshots-synthetic-checkpoint");
 
+#define TEST_BITMAP_VALIDATE(testname, bitmap, rc) \
+    do { \
+        blockbitmapvalidatedata.name = testname; \
+        blockbitmapvalidatedata.chain = bitmapSourceChain; \
+        blockbitmapvalidatedata.bitmapname = bitmap; \
+        blockbitmapvalidatedata.expect = rc; \
+        if (virTestRun("bitmap validate " testname " " bitmap, \
+                       testQemuBlockBitmapValidate, \
+                       &blockbitmapvalidatedata) < 0) \
+            ret = -1; \
+    } while (0)
 
+    TEST_BITMAP_VALIDATE("basic", "a", true);
+    TEST_BITMAP_VALIDATE("basic", "b", true);
+    TEST_BITMAP_VALIDATE("basic", "c", true);
+    TEST_BITMAP_VALIDATE("basic", "d", true);
+    TEST_BITMAP_VALIDATE("basic", "current", true);
+
+    TEST_BITMAP_VALIDATE("snapshots", "a", true);
+    TEST_BITMAP_VALIDATE("snapshots", "b", true);
+    TEST_BITMAP_VALIDATE("snapshots", "c", true);
+    TEST_BITMAP_VALIDATE("snapshots", "d", true);
+    TEST_BITMAP_VALIDATE("snapshots", "current", true);
+
+    TEST_BITMAP_VALIDATE("synthetic", "a", false);
+    TEST_BITMAP_VALIDATE("synthetic", "b", true);
+    TEST_BITMAP_VALIDATE("synthetic", "c", true);
+    TEST_BITMAP_VALIDATE("synthetic", "d", true);
+    TEST_BITMAP_VALIDATE("synthetic", "current", true);
+
+    TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "a", true);
+    TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "b", true);
+    TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "c", true);
+    TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "d", true);
+    TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "current", true);
  cleanup:
     virHashFree(diskxmljsondata.schema);
     qemuTestDriverFree(&driver);