diff options
author | Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 2021-04-28 18:17:44 +0300 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2021-04-30 12:27:48 +0200 |
commit | 0978623e0f485266b015f533e76f2efab0769100 (patch) | |
tree | 3ee4e52171a026e57f7e5173d53ac5780598277e | |
parent | b1d2bbeb3aecdfe109134c9dfb43a431e5280f24 (diff) |
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>
-rw-r--r-- | block.c | 54 |
1 files changed, 54 insertions, 0 deletions
@@ -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 |