mirror of https://gitee.com/openkylin/qemu.git
block: Add missing locking in bdrv_co_drain_bh_cb()
bdrv_do_drained_begin/end() assume that they are called with the AioContext lock of bs held. If we call drain functions from a coroutine with the AioContext lock held, we yield and schedule a BH to move out of coroutine context. This means that the lock for the home context of the coroutine is released and must be re-acquired in the bottom half. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
ae23dde9dd
commit
aa1361d54a
15
block/io.c
15
block/io.c
|
@ -288,6 +288,18 @@ static void bdrv_co_drain_bh_cb(void *opaque)
|
|||
BlockDriverState *bs = data->bs;
|
||||
|
||||
if (bs) {
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
AioContext *co_ctx = qemu_coroutine_get_aio_context(co);
|
||||
|
||||
/*
|
||||
* When the coroutine yielded, the lock for its home context was
|
||||
* released, so we need to re-acquire it here. If it explicitly
|
||||
* acquired a different context, the lock is still held and we don't
|
||||
* want to lock it a second time (or AIO_WAIT_WHILE() would hang).
|
||||
*/
|
||||
if (ctx == co_ctx) {
|
||||
aio_context_acquire(ctx);
|
||||
}
|
||||
bdrv_dec_in_flight(bs);
|
||||
if (data->begin) {
|
||||
bdrv_do_drained_begin(bs, data->recursive, data->parent,
|
||||
|
@ -296,6 +308,9 @@ static void bdrv_co_drain_bh_cb(void *opaque)
|
|||
bdrv_do_drained_end(bs, data->recursive, data->parent,
|
||||
data->ignore_bds_parents);
|
||||
}
|
||||
if (ctx == co_ctx) {
|
||||
aio_context_release(ctx);
|
||||
}
|
||||
} else {
|
||||
assert(data->begin);
|
||||
bdrv_drain_all_begin();
|
||||
|
|
|
@ -89,6 +89,11 @@ void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co);
|
|||
*/
|
||||
void coroutine_fn qemu_coroutine_yield(void);
|
||||
|
||||
/**
|
||||
* Get the AioContext of the given coroutine
|
||||
*/
|
||||
AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co);
|
||||
|
||||
/**
|
||||
* Get the currently executing coroutine
|
||||
*/
|
||||
|
|
|
@ -198,3 +198,8 @@ bool qemu_coroutine_entered(Coroutine *co)
|
|||
{
|
||||
return co->caller;
|
||||
}
|
||||
|
||||
AioContext *coroutine_fn qemu_coroutine_get_aio_context(Coroutine *co)
|
||||
{
|
||||
return co->ctx;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue