Split out no-perm part of bdrv_root_attach_child() into separate
transaction action. bdrv_root_attach_child() now moves to new
permission update paradigm: first update graph relations then update
permissions.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block.c | 162 ++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 117 insertions(+), 45 deletions(-)
diff --git a/block.c b/block.c
index f0fcd75555..a7ccbb4fb1 100644
--- a/block.c
+++ b/block.c
@@ -86,6 +86,13 @@ static void bdrv_parent_set_aio_context_ignore(BdrvChild *c,
AioContext *ctx,
GSList **ignore);
static void bdrv_replace_child_noperm(BdrvChild *child,
BlockDriverState *new_bs);
+static int bdrv_attach_child_common(BlockDriverState *child_bs,
+ const char *child_name,
+ const BdrvChildClass *child_class,
+ BdrvChildRole child_role,
+ uint64_t perm, uint64_t shared_perm,
+ void *opaque, BdrvChild **child,
+ GSList **tran, Error **errp);
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue
*queue, Error **errp);
@@ -2898,55 +2905,22 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState
*child_bs,
uint64_t perm, uint64_t shared_perm,
void *opaque, Error **errp)
{
- BdrvChild *child;
- Error *local_err = NULL;
int ret;
- AioContext *ctx;
+ BdrvChild *child = NULL;
+ GSList *tran = NULL;
- ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, errp);
+ ret = bdrv_attach_child_common(child_bs, child_name, child_class,
+ child_role, perm, shared_perm, opaque,
+ &child, &tran, errp);
if (ret < 0) {
- bdrv_abort_perm_update(child_bs);
bdrv_unref(child_bs);
return NULL;
}
- child = g_new(BdrvChild, 1);
- *child = (BdrvChild) {
- .bs = NULL,
- .name = g_strdup(child_name),
- .klass = child_class,
- .role = child_role,
- .perm = perm,
- .shared_perm = shared_perm,
- .opaque = opaque,
- };
-
- ctx = bdrv_child_get_parent_aio_context(child);
-
- /* If the AioContexts don't match, first try to move the subtree of
- * child_bs into the AioContext of the new parent. If this doesn't work,
- * try moving the parent into the AioContext of child_bs instead. */
- if (bdrv_get_aio_context(child_bs) != ctx) {
- ret = bdrv_try_set_aio_context(child_bs, ctx, &local_err);
- if (ret < 0) {
- if (bdrv_parent_try_set_aio_context(child, ctx, NULL) == 0) {
- ret = 0;
- error_free(local_err);
- local_err = NULL;
- }
- }
- if (ret < 0) {
- error_propagate(errp, local_err);
- g_free(child);
- bdrv_abort_perm_update(child_bs);
- bdrv_unref(child_bs);
- return NULL;
- }
- }
-
- /* This performs the matching bdrv_set_perm() for the above check. */
- bdrv_replace_child(child, child_bs);
+ ret = bdrv_refresh_perms(child_bs, errp);
+ tran_finalize(tran, ret);
+ bdrv_unref(child_bs);
return child;
}
@@ -2988,16 +2962,114 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
return child;
}
-static void bdrv_detach_child(BdrvChild *child)
+static void bdrv_remove_empty_child(BdrvChild *child)
{
+ assert(!child->bs);
QLIST_SAFE_REMOVE(child, next);
-
- bdrv_replace_child(child, NULL);
-
g_free(child->name);
g_free(child);
}
+typedef struct BdrvAttachChildCommonState {
+ BdrvChild **child;
+ AioContext *old_parent_ctx;
+ AioContext *old_child_ctx;
+} BdrvAttachChildCommonState;
+
+static void bdrv_attach_child_common_abort(void *opaque)
+{
+ BdrvAttachChildCommonState *s = opaque;
+ BdrvChild *child = *s->child;
+ BlockDriverState *bs = child->bs;
+
+ bdrv_replace_child_noperm(child, NULL);
+
+ if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
+ bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort);