Skip to content

Commit 2d19629

Browse files
stefanhaRHkevmw
authored andcommitted
block-backend: split blk_do_set_aio_context()
blk_set_aio_context() is not fully transactional because blk_do_set_aio_context() updates blk->ctx outside the transaction. Most of the time this goes unnoticed but a BlockDevOps.drained_end() callback that invokes blk_get_aio_context() fails assert(ctx == blk->ctx). This happens because blk->ctx is only assigned after BlockDevOps.drained_end() is called and we're in an intermediate state where BlockDrvierState nodes already have the new context and the BlockBackend still has the old context. Making blk_set_aio_context() fully transactional solves this assertion failure because the BlockBackend's context is updated as part of the transaction (before BlockDevOps.drained_end() is called). Split blk_do_set_aio_context() in order to solve this assertion failure. This helper function actually serves two different purposes: 1. It drives blk_set_aio_context(). 2. It responds to BdrvChildClass->change_aio_ctx(). Get rid of the helper function. Do #1 inside blk_set_aio_context() and do qemu#2 inside blk_root_set_aio_ctx_commit(). This simplifies the code. The only drawback of the fully transactional approach is that blk_set_aio_context() must contend with blk_root_set_aio_ctx_commit() being invoked as part of the AioContext change propagation. This can be solved by temporarily setting blk->allow_aio_context_change to true. Future patches call blk_get_aio_context() from BlockDevOps->drained_end(), so this patch will become necessary. Signed-off-by: Stefan Hajnoczi <[email protected]> Reviewed-by: Kevin Wolf <[email protected]> Message-Id: <[email protected]> Signed-off-by: Kevin Wolf <[email protected]>
1 parent 80e7faa commit 2d19629

File tree

1 file changed

+23
-38
lines changed

1 file changed

+23
-38
lines changed

block/block-backend.c

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2433,52 +2433,31 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
24332433
return blk_get_aio_context(blk_acb->blk);
24342434
}
24352435

2436-
static int blk_do_set_aio_context(BlockBackend *blk, AioContext *new_context,
2437-
bool update_root_node, Error **errp)
2436+
int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
2437+
Error **errp)
24382438
{
2439+
bool old_allow_change;
24392440
BlockDriverState *bs = blk_bs(blk);
2440-
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
24412441
int ret;
24422442

2443-
if (bs) {
2444-
bdrv_ref(bs);
2445-
2446-
if (update_root_node) {
2447-
/*
2448-
* update_root_node MUST be false for blk_root_set_aio_ctx_commit(),
2449-
* as we are already in the commit function of a transaction.
2450-
*/
2451-
ret = bdrv_try_change_aio_context(bs, new_context, blk->root, errp);
2452-
if (ret < 0) {
2453-
bdrv_unref(bs);
2454-
return ret;
2455-
}
2456-
}
2457-
/*
2458-
* Make blk->ctx consistent with the root node before we invoke any
2459-
* other operations like drain that might inquire blk->ctx
2460-
*/
2461-
blk->ctx = new_context;
2462-
if (tgm->throttle_state) {
2463-
bdrv_drained_begin(bs);
2464-
throttle_group_detach_aio_context(tgm);
2465-
throttle_group_attach_aio_context(tgm, new_context);
2466-
bdrv_drained_end(bs);
2467-
}
2443+
GLOBAL_STATE_CODE();
24682444

2469-
bdrv_unref(bs);
2470-
} else {
2445+
if (!bs) {
24712446
blk->ctx = new_context;
2447+
return 0;
24722448
}
24732449

2474-
return 0;
2475-
}
2450+
bdrv_ref(bs);
24762451

2477-
int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
2478-
Error **errp)
2479-
{
2480-
GLOBAL_STATE_CODE();
2481-
return blk_do_set_aio_context(blk, new_context, true, errp);
2452+
old_allow_change = blk->allow_aio_context_change;
2453+
blk->allow_aio_context_change = true;
2454+
2455+
ret = bdrv_try_change_aio_context(bs, new_context, NULL, errp);
2456+
2457+
blk->allow_aio_context_change = old_allow_change;
2458+
2459+
bdrv_unref(bs);
2460+
return ret;
24822461
}
24832462

24842463
typedef struct BdrvStateBlkRootContext {
@@ -2490,8 +2469,14 @@ static void blk_root_set_aio_ctx_commit(void *opaque)
24902469
{
24912470
BdrvStateBlkRootContext *s = opaque;
24922471
BlockBackend *blk = s->blk;
2472+
AioContext *new_context = s->new_ctx;
2473+
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
24932474

2494-
blk_do_set_aio_context(blk, s->new_ctx, false, &error_abort);
2475+
blk->ctx = new_context;
2476+
if (tgm->throttle_state) {
2477+
throttle_group_detach_aio_context(tgm);
2478+
throttle_group_attach_aio_context(tgm, new_context);
2479+
}
24952480
}
24962481

24972482
static TransactionActionDrv set_blk_root_context = {

0 commit comments

Comments
 (0)