Calling blk_wait_while_drained() while blk->in_flight is increased for the current request is wrong because it will cause the drain operation to deadlock.
Many callers of blk_wait_while_drained() have already increased blk->in_flight when called in a blk_aio_*() path, but can also be called in synchonous code paths where blk->in_flight isn't increased. This means that these calls of blk_wait_while_drained() are wrong at least in some cases. In order to fix this, increase blk->in_flight even for synchronous operations and temporarily decrease the counter again in blk_wait_while_drained(). Fixes: cf3129323f900ef5ddbccbe86e4fa801e88c566e Signed-off-by: Kevin Wolf <kw...@redhat.com> --- block/block-backend.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index 3124e367b3..7bd16402b8 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1143,7 +1143,9 @@ static int blk_check_byte_request(BlockBackend *blk, int64_t offset, static void coroutine_fn blk_wait_while_drained(BlockBackend *blk) { if (blk->quiesce_counter && !blk->disable_request_queuing) { + blk_dec_in_flight(blk); qemu_co_queue_wait(&blk->queued_requests, NULL); + blk_inc_in_flight(blk); } } @@ -1260,6 +1262,7 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf, .ret = NOT_DONE, }; + blk_inc_in_flight(blk); if (qemu_in_coroutine()) { /* Fast-path if already in coroutine context */ co_entry(&rwco); @@ -1268,6 +1271,7 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf, bdrv_coroutine_enter(blk_bs(blk), co); BDRV_POLL_WHILE(blk_bs(blk), rwco.ret == NOT_DONE); } + blk_dec_in_flight(blk); return rwco.ret; } @@ -1386,9 +1390,7 @@ static void blk_aio_read_entry(void *opaque) QEMUIOVector *qiov = rwco->iobuf; if (rwco->blk->quiesce_counter) { - blk_dec_in_flight(rwco->blk); blk_wait_while_drained(rwco->blk); - blk_inc_in_flight(rwco->blk); } assert(qiov->size == acb->bytes); @@ -1404,9 +1406,7 @@ static void blk_aio_write_entry(void *opaque) QEMUIOVector *qiov = rwco->iobuf; if (rwco->blk->quiesce_counter) { - blk_dec_in_flight(rwco->blk); blk_wait_while_drained(rwco->blk); - blk_inc_in_flight(rwco->blk); } assert(!qiov || qiov->size == acb->bytes); -- 2.20.1