From: Vladimir Sementsov-Ogievskiy <vsement...@parallels.com> Persistent dirty bitmaps are the bitmaps, for which the new field BdrvDirtyBitmap.file is not NULL. We save all persistent dirty bitmaps owned by BlockDriverState in corresponding bdrv_close(). BdrvDirtyBitmap.file is a BlockDriverState, where we want to save the bitmap. It may be set in bdrv_dirty_bitmap_set_file() only once. bdrv_ref/bdrv_unref are used for BdrvDirtyBitmap.file to be sure that files will be closed and resources will be freed.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsement...@virtuozzo.com> --- block.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ include/block/block.h | 4 ++++ 2 files changed, 49 insertions(+) diff --git a/block.c b/block.c index 575584d..74d4edc 100644 --- a/block.c +++ b/block.c @@ -70,6 +70,8 @@ struct BdrvDirtyBitmap { BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */ char *name; /* Optional non-empty unique ID */ int64_t size; /* Size of the bitmap (Number of sectors) */ + BlockDriverState *file; /* File where bitmap is loaded from (and should + be saved to) */ bool disabled; /* Bitmap is read-only */ QLIST_ENTRY(BdrvDirtyBitmap) list; }; @@ -1710,6 +1712,7 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state) void bdrv_close(BlockDriverState *bs) { BdrvAioNotifier *ban, *ban_next; + BdrvDirtyBitmap *bm, *bm_next; if (bs->job) { block_job_cancel_sync(bs->job); @@ -1719,6 +1722,15 @@ void bdrv_close(BlockDriverState *bs) bdrv_drain_all(); /* in case flush left pending I/O */ notifier_list_notify(&bs->close_notifiers, bs); + /* save and release persistent dirty bitmaps */ + QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, bm_next) { + if (bm->file) { + bdrv_store_dirty_bitmap(bm); + bdrv_unref(bm->file); + bdrv_release_dirty_bitmap(bs, bm); + } + } + if (bs->drv) { if (bs->backing_hd) { BlockDriverState *backing_hd = bs->backing_hd; @@ -3097,6 +3109,30 @@ void bdrv_release_meta_bitmap(BdrvDirtyBitmap *bitmap) } } +int bdrv_store_dirty_bitmap(BdrvDirtyBitmap *bitmap) +{ + BlockDriverState *bs = bitmap->file; + uint8_t *buf; + uint64_t size; + assert(bs); + assert(bs->drv); + assert(bs->drv->bdrv_dirty_bitmap_store); + + size = hbitmap_data_size(bitmap->bitmap, bitmap->size); + size = (size + 3) & ~3; + buf = g_malloc(size); + + hbitmap_serialize_part(bitmap->bitmap, buf, 0, bitmap->size); + + int res = bs->drv->bdrv_dirty_bitmap_store(bs, buf, + bitmap->name, + bitmap->size, + bdrv_dirty_bitmap_granularity(bitmap)); + + g_free(buf); + return res; +} + BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, uint32_t granularity, const char *name, @@ -3257,6 +3293,15 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap) } } +void bdrv_dirty_bitmap_set_file(BdrvDirtyBitmap *bitmap, BlockDriverState *file) +{ + assert(bitmap->file == NULL); + bitmap->file = file; + if (file != NULL) { + bdrv_ref(file); + } +} + void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap) { assert(!bdrv_dirty_bitmap_frozen(bitmap)); diff --git a/include/block/block.h b/include/block/block.h index 593c29e..6e82597 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -468,6 +468,8 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name); void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap); void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); +void bdrv_dirty_bitmap_set_file(BdrvDirtyBitmap *bitmap, + BlockDriverState *file); void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap); void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap); BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs); @@ -506,6 +508,8 @@ HBitmap *bdrv_create_meta_bitmap(BdrvDirtyBitmap *bitmap, uint64_t granularity); void bdrv_release_meta_bitmap(BdrvDirtyBitmap *bitmap); +int bdrv_store_dirty_bitmap(BdrvDirtyBitmap *bitmap); + void bdrv_enable_copy_on_read(BlockDriverState *bs); void bdrv_disable_copy_on_read(BlockDriverState *bs); -- 1.9.1