@@ -4953,22 +4953,50 @@ int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
Error **errp)
{
- Error *local_err = NULL;
+ int ret;
+ GSList *tran = NULL;
+ AioContext *bs_new_ctx = bdrv_get_aio_context(bs_new);
+ AioContext *bs_top_ctx = bdrv_get_aio_context(bs_top);
- bdrv_set_backing_hd(bs_new, bs_top, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return -EPERM;
+ assert(!bs_new->backing);
+
+ if (bs_new_ctx != bs_top_ctx) {
+ ret = bdrv_try_set_aio_context(bs_new, bs_top_ctx, NULL);
+ if (ret < 0) {
+ ret = bdrv_try_set_aio_context(bs_top, bs_new_ctx, errp);
+ }
+ if (ret < 0) {
+ return ret;
+ }
}
- bdrv_replace_node(bs_top, bs_new, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- bdrv_set_backing_hd(bs_new, NULL, &error_abort);
- return -EPERM;
+ bs_new->backing = bdrv_attach_child_noperm(bs_new, bs_top, "backing",
+ bdrv_backing_role(bs_new),
+ &tran, errp);
+ if (!bs_new->backing) {
+ ret = -EINVAL;
+ goto out;
}
- return 0;
+ ret = bdrv_replace_node_noperm(bs_top, bs_new, true, &tran, errp);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = bdrv_refresh_perms(bs_new, errp);
+out:
+ tran_finalize(tran, ret);
+ if (ret < 0) {
+ bs_new->backing = NULL;
+ if (bs_new_ctx != bdrv_get_aio_context(bs_new)) {
+ bdrv_try_set_aio_context(bs_new, bs_new_ctx, &error_abort);
+ }
+ if (bs_top_ctx != bdrv_get_aio_context(bs_top)) {
+ bdrv_try_set_aio_context(bs_top, bs_top_ctx, &error_abort);
+ }
+ }
+
+ return ret;
}
static void bdrv_delete(BlockDriverState *bs)
bdrv_append is not very good for inserting filters: it does extra permission update as part of bdrv_set_backing_hd(). During this update filter may conflict with other parents of top_bs. Instead, let's first do all graph modifications and after it update permissions. Note: bdrv_append() is still only works for backing-child based filters. It's something to improve later. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> --- block.c | 50 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 11 deletions(-)