Signed-off-by: Vladimir Sementsov-Ogievskiy <vsement...@virtuozzo.com> --- block.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-)
diff --git a/block.c b/block.c index 7094922509..b1394b721c 100644 --- a/block.c +++ b/block.c @@ -2973,12 +2973,19 @@ out: return child; } +static void bdrv_child_free(void *opaque) +{ + BdrvChild *c = opaque; + + g_free(c->name); + g_free(c); +} + static void bdrv_remove_empty_child(BdrvChild *child) { assert(!child->bs); QLIST_SAFE_REMOVE(child, next); - g_free(child->name); - g_free(child); + bdrv_child_free(child); } typedef struct BdrvAttachChildCommonState { @@ -4897,6 +4904,37 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to) return ret; } +/* this doesn't restore original child bs, only the child itself */ +static void bdrv_remove_backing_abort(void *opaque) +{ + BdrvChild *c = opaque; + BlockDriverState *parent_bs = c->opaque; + + QLIST_INSERT_HEAD(&parent_bs->children, c, next); + parent_bs->backing = c; +} + +static TransactionActionDrv bdrv_remove_backing_drv = { + .abort = bdrv_remove_backing_abort, + .commit = bdrv_child_free, +}; + +__attribute__((unused)) +static void bdrv_remove_backing(BlockDriverState *bs, GSList **tran) +{ + if (!bs->backing) { + return; + } + + if (bs->backing->bs) { + bdrv_replace_child_safe(bs->backing, NULL, tran); + } + + tran_prepend(tran, &bdrv_remove_backing_drv, bs->backing); + QLIST_SAFE_REMOVE(bs->backing, next); + bs->backing = NULL; +} + static int bdrv_replace_node_noperm(BlockDriverState *from, BlockDriverState *to, bool auto_skip, GSList **tran, Error **errp) -- 2.21.3