dirty-bitmap: make it possible to restore bitmap after merge

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 <vsementsov@virtuozzo.com>
Reviewed-by: John Snow <jsnow@redhat.com>
This commit is contained in:
Vladimir Sementsov-Ogievskiy 2018-10-29 16:23:15 -04:00 committed by John Snow
parent 56bd662497
commit fa000f2f9f
5 changed files with 39 additions and 16 deletions

View File

@ -314,7 +314,7 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs,
return NULL; 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"); error_setg(errp, "Merging of parent and successor bitmap failed");
return NULL; return NULL;
} }
@ -791,8 +791,10 @@ int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset)
} }
void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, 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 */ /* only bitmaps from one bds are supported */
assert(dest->mutex == src->mutex); assert(dest->mutex == src->mutex);
@ -810,11 +812,20 @@ void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
goto out; 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"); error_setg(errp, "Bitmaps are incompatible and can't be merged");
goto out; 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: out:
qemu_mutex_unlock(dest->mutex); qemu_mutex_unlock(dest->mutex);
} }

View File

@ -2968,7 +2968,7 @@ void qmp_x_block_dirty_bitmap_merge(const char *node, const char *dst_name,
return; 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, BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,

View File

@ -71,7 +71,7 @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
bool persistent); bool persistent);
void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked); void bdrv_dirty_bitmap_set_qmp_locked(BdrvDirtyBitmap *bitmap, bool qmp_locked);
void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src, void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
Error **errp); HBitmap **backup, Error **errp);
/* Functions that require manual locking. */ /* Functions that require manual locking. */
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap); void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);

View File

@ -73,16 +73,23 @@ void hbitmap_truncate(HBitmap *hb, uint64_t size);
/** /**
* hbitmap_merge: * 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. * Store result of merging @a and @b into @result.
* A := A (BITOR) B. * @result is allowed to be equal to @a or @b.
* B is left unmodified. *
* 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);
/**
* 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_can_merge(const HBitmap *a, const HBitmap *b);
/** /**
* hbitmap_empty: * hbitmap_empty:

View File

@ -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. * 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, * @return true if the merge was successful,
* false if it was not attempted. * 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; int i;
uint64_t j; 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; return false;
} }
assert(hbitmap_can_merge(b, result));
if (hbitmap_count(b) == 0) { if (hbitmap_count(b) == 0) {
return true; return true;
@ -750,7 +755,7 @@ bool hbitmap_merge(HBitmap *a, const HBitmap *b)
*/ */
for (i = HBITMAP_LEVELS - 1; i >= 0; i--) { for (i = HBITMAP_LEVELS - 1; i >= 0; i--) {
for (j = 0; j < a->sizes[i]; j++) { 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];
} }
} }