The added group of operations enables tracking of the changed bits in the dirty bitmap.
Signed-off-by: Fam Zheng <f...@redhat.com> --- block.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- block/mirror.c | 3 ++- blockdev.c | 3 ++- include/block/block.h | 11 +++++++++++ migration/block.c | 2 +- 5 files changed, 61 insertions(+), 4 deletions(-) diff --git a/block.c b/block.c index 3a7324b..a9beb04 100644 --- a/block.c +++ b/block.c @@ -64,6 +64,7 @@ */ struct BdrvDirtyBitmap { HBitmap *bitmap; /* Dirty sector bitmap implementation */ + HBitmap *meta; /* Meta dirty bitmap */ BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */ char *name; /* Optional non-empty unique ID */ int64_t size; /* Size of the bitmap (Number of sectors) */ @@ -3153,6 +3154,7 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap) BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, uint32_t granularity, const char *name, + bool create_meta, Error **errp) { int64_t bitmap_size; @@ -3178,10 +3180,52 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, bitmap->size = bitmap_size; bitmap->name = g_strdup(name); bitmap->disabled = false; + if (create_meta) { + bitmap->meta = hbitmap_create_meta(bitmap->bitmap); + } QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list); return bitmap; } +void bdrv_create_meta_dirty_bitmap(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap) +{ + assert(!bitmap->meta); + bitmap->meta = hbitmap_create_meta(bitmap->bitmap); +} + +void bdrv_release_meta_dirty_bitmap(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap) +{ + assert(bitmap->meta); + hbitmap_free(bitmap->meta); + bitmap->meta = NULL; +} + +int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, int64_t sector, + int nb_sectors) +{ + uint64_t i; + int gran = bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS; + + /* To optimize: we can make hbitmap to internally check the range in a + * coarse level, or at least do it word by word. */ + for (i = sector; i < nb_sectors; i += gran) { + if (hbitmap_get(bitmap->meta, i)) { + return true; + } + } + return false; +} + +void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, int64_t sector, + int nb_sectors) +{ + hbitmap_reset(bitmap->meta, sector, nb_sectors); +} + bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap) { return bitmap->successor; @@ -3222,7 +3266,7 @@ int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, /* Create an anonymous successor */ granularity = bdrv_dirty_bitmap_granularity(bitmap); - child = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp); + child = bdrv_create_dirty_bitmap(bs, granularity, NULL, false, errp); if (!child) { return -1; } diff --git a/block/mirror.c b/block/mirror.c index 0e8f556..e381b9d 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -743,7 +743,8 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, s->buf_size = ROUND_UP(buf_size, granularity); s->unmap = unmap; - s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp); + s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, false, + errp); if (!s->dirty_bitmap) { g_free(s->replaces); block_job_unref(&s->common); diff --git a/blockdev.c b/blockdev.c index 313841b..2507d96 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2671,7 +2671,8 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, granularity = bdrv_get_default_bitmap_granularity(bs); } - bdrv_create_dirty_bitmap(bs, granularity, name, errp); + bdrv_create_dirty_bitmap(bs, granularity, name, false, + errp); out: aio_context_release(aio_context); diff --git a/include/block/block.h b/include/block/block.h index 3477328..e749461 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -475,7 +475,12 @@ typedef struct BdrvDirtyBitmap BdrvDirtyBitmap; BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, uint32_t granularity, const char *name, + bool create_meta, Error **errp); +void bdrv_create_meta_dirty_bitmap(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap); +void bdrv_release_meta_dirty_bitmap(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap); int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, Error **errp); @@ -504,6 +509,12 @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap, int64_t cur_sector, int nr_sectors); void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi); void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset); +int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, int64_t sector, + int nb_sectors); +void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs, + BdrvDirtyBitmap *bitmap, int64_t sector, + int nb_sectors); int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap); void bdrv_enable_copy_on_read(BlockDriverState *bs); diff --git a/migration/block.c b/migration/block.c index 656f38f..43b64a5 100644 --- a/migration/block.c +++ b/migration/block.c @@ -322,7 +322,7 @@ static int set_dirty_tracking(void) QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) { bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE, - NULL, NULL); + NULL, false, NULL); if (!bmds->dirty_bitmap) { ret = -errno; goto fail; -- 2.4.3