From 8767d53aa1dd2df28d3093bb1c6d99e54916eb4a Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 6 Feb 2019 22:12:28 +0100 Subject: [PATCH 18/33] dirty-bitmap: make it possible to restore bitmap after merge RH-Author: John Snow Message-id: <20190206221243.7407-9-jsnow@redhat.com> Patchwork-id: 84267 O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH v2 08/23] dirty-bitmap: make it possible to restore bitmap after merge Bugzilla: 1658343 RH-Acked-by: Thomas Huth RH-Acked-by: Laurent Vivier RH-Acked-by: Stefan Hajnoczi From: Vladimir Sementsov-Ogievskiy Add backup parameter to bdrv_merge_dirty_bitmap() to be used then with bdrv_restore_dirty_bitmap() if it needed to restore the bitmap after merge operation. This is needed to implement bitmap merge transaction action in further commit. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow (cherry picked from commit fa000f2f9fd96a75a0a33d50ead247fce11da92a) Signed-off-by: John Snow Signed-off-by: Miroslav Rezanina --- block/dirty-bitmap.c | 17 ++++++++++++++--- blockdev.c | 2 +- include/block/dirty-bitmap.h | 2 +- include/qemu/hbitmap.h | 25 ++++++++++++++++--------- util/hbitmap.c | 11 ++++++++--- 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index cadde5c..a9421cd 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -314,7 +314,7 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, return NULL; } - if (!hbitmap_merge(parent->bitmap, successor->bitmap)) { + if (!hbitmap_merge(parent->bitmap, successor->bitmap, parent->bitmap)) { error_setg(errp, "Merging of parent and successor bitmap failed"); return NULL; } @@ -790,8 +790,10 @@ int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset) } void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, - Error **errp) + HBitmap **backup, Error **errp) { + bool ret; + /* only bitmaps from one bds are supported */ assert(dest->mutex == src->mutex); @@ -809,11 +811,20 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, goto out; } - if (!hbitmap_merge(dest->bitmap, src->bitmap)) { + if (!hbitmap_can_merge(dest->bitmap, src->bitmap)) { error_setg(errp, "Bitmaps are incompatible and can't be merged"); goto out; } + if (backup) { + *backup = dest->bitmap; + dest->bitmap = hbitmap_alloc(dest->size, hbitmap_granularity(*backup)); + ret = hbitmap_merge(*backup, src->bitmap, dest->bitmap); + } else { + ret = hbitmap_merge(dest->bitmap, src->bitmap, dest->bitmap); + } + assert(ret); + out: qemu_mutex_unlock(dest->mutex); } diff --git a/blockdev.c b/blockdev.c index 5d9508c..823a97f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3119,7 +3119,7 @@ void qmp_x_block_dirty_bitmap_merge(const char *node, const char *dst_name, return; } - bdrv_merge_dirty_bitmap(dst, src, errp); + bdrv_merge_dirty_bitmap(dst, src, NULL, errp); } BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index 259bd27..201ff7f 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -71,7 +71,7 @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent); void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked); void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, - Error **errp); + HBitmap **backup, Error **errp); /* Functions that require manual locking. */ void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index ddca52c..a7cb780 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -73,16 +73,23 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size); /** * hbitmap_merge: - * @a: The bitmap to store the result in. - * @b: The bitmap to merge into @a. - * @return true if the merge was successful, - * false if it was not attempted. - * - * Merge two bitmaps together. - * A := A (BITOR) B. - * B is left unmodified. + * + * Store result of merging @a and @b into @result. + * @result is allowed to be equal to @a or @b. + * + * Return true if the merge was successful, + * false if it was not attempted. + */ +bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result); + +/** + * hbitmap_can_merge: + * + * hbitmap_can_merge(a, b) && hbitmap_can_merge(a, result) is sufficient and + * necessary for hbitmap_merge will not fail. + * */ -bool hbitmap_merge(HBitmap *a, const HBitmap *b); +bool hbitmap_can_merge(const HBitmap *a, const HBitmap *b); /** * hbitmap_empty: diff --git a/util/hbitmap.c b/util/hbitmap.c index bcd3040..d5aca51 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -723,6 +723,10 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size) } } +bool hbitmap_can_merge(const HBitmap *a, const HBitmap *b) +{ + return (a->size == b->size) && (a->granularity == b->granularity); +} /** * Given HBitmaps A and B, let A := A (BITOR) B. @@ -731,14 +735,15 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size) * @return true if the merge was successful, * false if it was not attempted. */ -bool hbitmap_merge(HBitmap *a, const HBitmap *b) +bool hbitmap_merge(const HBitmap *a, const HBitmap *b, HBitmap *result) { int i; uint64_t j; - if ((a->size != b->size) || (a->granularity != b->granularity)) { + if (!hbitmap_can_merge(a, b) || !hbitmap_can_merge(a, result)) { return false; } + assert(hbitmap_can_merge(b, result)); if (hbitmap_count(b) == 0) { return true; @@ -750,7 +755,7 @@ bool hbitmap_merge(HBitmap *a, const HBitmap *b) */ for (i = HBITMAP_LEVELS - 1; i >= 0; i--) { for (j = 0; j < a->sizes[i]; j++) { - a->levels[i][j] |= b->levels[i][j]; + result->levels[i][j] = a->levels[i][j] | b->levels[i][j]; } } -- 1.8.3.1