We'll need this functionality as part of external transaction, so make the whole function to be transaction action. For this we need to introduce a transaction action helper: bdrv_drained(), which calls bdrv_drained_begin() and postpone bdrv_drained_end() to .clean() phase.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsement...@openvz.org> --- block.c | 42 +++++++++++++++++++----------- block/block-backend.c | 9 ++++++- include/block/block-global-state.h | 2 +- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/block.c b/block.c index 9e1be402e2..4b5b7d8794 100644 --- a/block.c +++ b/block.c @@ -5341,32 +5341,44 @@ out: return ret; } +static void bdrv_drained_clean(void *opaque) +{ + BlockDriverState *bs = opaque; + + bdrv_drained_end(bs); + bdrv_unref(bs); +} + +TransactionActionDrv bdrv_drained_drv = { + .clean = bdrv_drained_clean, +}; + +/* + * Start drained section on @bs, and finish it in .clean action. + * Reference to @bs is kept, so @bs can't be removed during transaction. + */ +static void bdrv_drained(BlockDriverState *bs, Transaction *tran) +{ + bdrv_ref(bs); + bdrv_drained_begin(bs); + tran_add(tran, &bdrv_drained_drv, bs); +} + /* Not for empty child */ int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, - Error **errp) + Transaction *tran, Error **errp) { - int ret; - Transaction *tran = tran_new(); g_autoptr(GSList) refresh_list = NULL; BlockDriverState *old_bs = child->bs; GLOBAL_STATE_CODE(); - bdrv_ref(old_bs); - bdrv_drained_begin(old_bs); - bdrv_drained_begin(new_bs); + bdrv_drained(old_bs, tran); + bdrv_drained(new_bs, tran); bdrv_replace_child_tran(child, new_bs, &refresh_list, tran); - ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp); - - tran_finalize(tran, ret); - - bdrv_drained_end(old_bs); - bdrv_drained_end(new_bs); - bdrv_unref(old_bs); - - return ret; + return bdrv_list_refresh_perms(refresh_list, NULL, tran, errp); } static void bdrv_delete(BlockDriverState *bs) diff --git a/block/block-backend.c b/block/block-backend.c index f5476bb9fc..fa1d810da2 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -929,8 +929,15 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) */ int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp) { + int ret; + Transaction *tran = tran_new(); + GLOBAL_STATE_CODE(); - return bdrv_replace_child_bs(blk->root, new_bs, errp); + + ret = bdrv_replace_child_bs(blk->root, new_bs, tran, errp); + tran_finalize(tran, ret); + + return ret; } /* diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index 8527bcad28..fa5f698228 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -65,7 +65,7 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, Error **errp); int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs, - Error **errp); + Transaction *tran, Error **errp); BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options, int flags, Error **errp); int bdrv_drop_filter(BlockDriverState *bs, Error **errp); -- 2.35.1