block: add bdrv_replace_child_safe() transaction action

To be used in the following commit.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Message-Id: <20210428151804.439460-17-vsementsov@virtuozzo.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
stable-6.1
Vladimir Sementsov-Ogievskiy 2021-04-28 18:17:44 +03:00 committed by Kevin Wolf
parent b1d2bbeb3a
commit 0978623e0f
1 changed files with 54 additions and 0 deletions

54
block.c
View File

@ -83,6 +83,9 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
BdrvChildRole child_role,
Error **errp);
static void bdrv_replace_child_noperm(BdrvChild *child,
BlockDriverState *new_bs);
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue
*queue, Error **errp);
static void bdrv_reopen_commit(BDRVReopenState *reopen_state);
@ -2237,6 +2240,57 @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
return 0;
}
typedef struct BdrvReplaceChildState {
BdrvChild *child;
BlockDriverState *old_bs;
} BdrvReplaceChildState;
static void bdrv_replace_child_commit(void *opaque)
{
BdrvReplaceChildState *s = opaque;
bdrv_unref(s->old_bs);
}
static void bdrv_replace_child_abort(void *opaque)
{
BdrvReplaceChildState *s = opaque;
BlockDriverState *new_bs = s->child->bs;
/* old_bs reference is transparently moved from @s to @s->child */
bdrv_replace_child_noperm(s->child, s->old_bs);
bdrv_unref(new_bs);
}
static TransactionActionDrv bdrv_replace_child_drv = {
.commit = bdrv_replace_child_commit,
.abort = bdrv_replace_child_abort,
.clean = g_free,
};
/*
* bdrv_replace_child_safe
*
* Note: real unref of old_bs is done only on commit.
*/
__attribute__((unused))
static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs,
Transaction *tran)
{
BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
*s = (BdrvReplaceChildState) {
.child = child,
.old_bs = child->bs,
};
tran_add(tran, &bdrv_replace_child_drv, s);
if (new_bs) {
bdrv_ref(new_bs);
}
bdrv_replace_child_noperm(child, new_bs);
/* old_bs reference is transparently moved from @child to @s */
}
/*
* Check whether permissions on this node can be changed in a way that
* @cumulative_perms and @cumulative_shared_perms are the new cumulative