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...@parallels.com> --- block.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/block/block.h | 3 +++ 2 files changed, 46 insertions(+) diff --git a/block.c b/block.c index 2466ba8..7237b95 100644 --- a/block.c +++ b/block.c @@ -54,6 +54,7 @@ struct BdrvDirtyBitmap { HBitmap *bitmap; BdrvDirtyBitmap *originator; + BlockDriverState *file; int64_t size; int64_t granularity; char *name; @@ -1840,6 +1841,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); @@ -1849,6 +1851,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; @@ -5373,6 +5384,29 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs, return originator; } +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_store_data(bitmap->bitmap, buf, 0, bitmap->size); + + int res = bs->drv->bdrv_dirty_bitmap_store(bs, buf, + bitmap->name, + bitmap->size, + bitmap->granularity); + + g_free(buf); + return res; +} BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity, @@ -5421,6 +5455,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) { bitmap->enabled = false; diff --git a/include/block/block.h b/include/block/block.h index cb1f28d..0dfefe3 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -442,6 +442,8 @@ BdrvDirtyBitmap *bdrv_copy_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *failed); 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); @@ -458,6 +460,7 @@ void bdrv_dirty_iter_init(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi); void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset); int64_t bdrv_get_dirty_count(BlockDriverState *bs, 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