diff mbox series

[18/21] block: adapt bdrv_append() for inserting filters

Message ID 20201123201233.9534-21-vsementsov@virtuozzo.com
State New
Headers show
Series block: update graph permissions update | expand

Commit Message

Vladimir Sementsov-Ogievskiy Nov. 23, 2020, 8:12 p.m. UTC
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(-)
diff mbox series

Patch

diff --git a/block.c b/block.c
index f2e714a81d..cf7b859a81 100644
--- a/block.c
+++ b/block.c
@@ -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)