From eeb1315a8015aeda4d2fb7ce590c85c40ffb567d Mon Sep 17 00:00:00 2001 Message-Id: From: Peter Krempa Date: Tue, 4 Feb 2020 15:08:23 +0100 Subject: [PATCH] qemu: block: Add validator for bitmap chains accross backing chains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Ján Tomko (cherry picked from commit 41c7e5c2a689a4ad091cec40b61beeeb3dde49b8) https://bugzilla.redhat.com/show_bug.cgi?id=1207659 Message-Id: Reviewed-by: Ján Tomko --- src/qemu/qemu_block.c | 41 +++++++++++++++++++++++++ src/qemu/qemu_block.h | 5 ++++ tests/qemublocktest.c | 70 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 03f029368e..b19290e677 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -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; +} diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h index 68646cbf2e..cf51b9bf4e 100644 --- a/src/qemu/qemu_block.h +++ b/src/qemu/qemu_block.h @@ -212,3 +212,8 @@ qemuBlockNamedNodeDataGetBitmapByName(virHashTablePtr blockNamedNodeData, virHashTablePtr qemuBlockGetNamedNodeData(virDomainObjPtr vm, qemuDomainAsyncJob asyncJob); + +bool +qemuBlockBitmapChainIsValid(virStorageSourcePtr src, + const char *bitmapname, + virHashTablePtr blockNamedNodeData); diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c index 5946cd6c6b..6a7b07cfee 100644 --- a/tests/qemublocktest.c +++ b/tests/qemublocktest.c @@ -764,6 +764,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) { @@ -774,6 +809,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; @@ -1041,7 +1077,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); -- 2.25.0