This makes use of op_blocker and blocks all the operations except for commit target, on each BlockDriverState->backing_hd.
Signed-off-by: Fam Zheng <f...@redhat.com> --- block.c | 13 +++++++++++++ include/block/block_int.h | 3 +++ 2 files changed, 16 insertions(+) diff --git a/block.c b/block.c index 63a5918..b3993d7 100644 --- a/block.c +++ b/block.c @@ -961,7 +961,13 @@ fail: void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd) { if (bs->backing_hd) { + assert(error_is_set(&bs->backing_blocker)); + bdrv_op_unblock_all(bs->backing_hd, bs->backing_blocker); bdrv_unref(bs->backing_hd); + } else { + error_setg(&bs->backing_blocker, + "device is used as backing hd of '%s'", + bs->device_name); } bs->backing_hd = backing_hd; @@ -970,6 +976,10 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd) } bdrv_ref(bs->backing_hd); + bdrv_op_block_all(bs->backing_hd, bs->backing_blocker); + /* Otherwise we won't be able to commit due to check in bdrv_commit */ + bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT, + bs->backing_blocker); pstrcpy(bs->backing_file, sizeof(bs->backing_file), bs->backing_hd->file->filename); pstrcpy(bs->backing_format, sizeof(bs->backing_format), @@ -1476,6 +1486,9 @@ void bdrv_close(BlockDriverState *bs) if (bs->drv) { if (bs->backing_hd) { + assert(error_is_set(&bs->backing_blocker)); + bdrv_op_unblock_all(bs->backing_hd, bs->backing_blocker); + error_free(bs->backing_blocker); bdrv_unref(bs->backing_hd); bs->backing_hd = NULL; } diff --git a/include/block/block_int.h b/include/block/block_int.h index 2f6556d..1ac17d5 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -341,6 +341,9 @@ struct BlockDriverState { BlockJob *job; QDict *options; + + /* The error object in use for blocking operations on backing_hd */ + Error *backing_blocker; }; int get_tmp_filename(char *filename, int size); -- 1.8.5.1