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 | 33 +++++++++++++++++++++++++++++++++ include/block/block.h | 3 +++ 2 files changed, 36 insertions(+) diff --git a/block.c b/block.c index 69d7c30..492abb4 100644 --- a/block.c +++ b/block.c @@ -73,6 +73,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; }; @@ -1897,6 +1899,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); @@ -1906,6 +1909,15 @@ void bdrv_close(BlockDriverState *bs) bdrv_drain(bs); /* 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) { BdrvChild *child, *next; @@ -3362,6 +3374,18 @@ bool bdrv_load_check_dirty_bitmap(BlockDriverState *file, const char *name) return false; } +int bdrv_store_dirty_bitmap(BdrvDirtyBitmap *bitmap) +{ + BlockDriverState *bs = bitmap->file; + + if (bs == NULL || bs->drv == NULL || + bs->drv->bdrv_dirty_bitmap_store == NULL) { + return -EINVAL; + } + + return bs->drv->bdrv_dirty_bitmap_store(bs, bitmap); +} + BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, uint32_t granularity, const char *name, @@ -3532,6 +3556,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 5e95e51..4b9b898 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -491,6 +491,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); @@ -532,6 +534,7 @@ HBitmap *bdrv_create_meta_bitmap(BdrvDirtyBitmap *bitmap, void bdrv_release_meta_bitmap(BdrvDirtyBitmap *bitmap); bool bdrv_load_check_dirty_bitmap(BlockDriverState *file, const char *name); +int bdrv_store_dirty_bitmap(BdrvDirtyBitmap *bitmap); void bdrv_enable_copy_on_read(BlockDriverState *bs); void bdrv_disable_copy_on_read(BlockDriverState *bs); -- 2.1.4