From 539343c0a47e19d5dd64d846d64d084d9793681f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 29 Jul 2019 23:34:16 +0200 Subject: [PATCH] dma-helpers: ensure AIO callback is invoked after cancellation dma_aio_cancel unschedules the BH if there is one, which corresponds to the reschedule_dma case of dma_blk_cb. This can stall the DMA permanently, because dma_complete will never get invoked and therefore nobody will ever invoke the original AIO callback in dbs->common.cb. Fix this by invoking the callback (which is ensured to happen after a bdrv_aio_cancel_async, or done manually in the dbs->bh case), and add assertions to check that the DMA state machine is indeed waiting for dma_complete or reschedule_dma, but never both. Reported-by: John Snow Signed-off-by: Paolo Bonzini Message-id: 20190729213416.1972-1-pbonzini@redhat.com Signed-off-by: John Snow --- dma-helpers.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dma-helpers.c b/dma-helpers.c index 2d7e02d35e..d3871dc61e 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -90,6 +90,7 @@ static void reschedule_dma(void *opaque) { DMAAIOCB *dbs = (DMAAIOCB *)opaque; + assert(!dbs->acb && dbs->bh); qemu_bh_delete(dbs->bh); dbs->bh = NULL; dma_blk_cb(dbs, 0); @@ -111,15 +112,12 @@ static void dma_complete(DMAAIOCB *dbs, int ret) { trace_dma_complete(dbs, ret, dbs->common.cb); + assert(!dbs->acb && !dbs->bh); dma_blk_unmap(dbs); if (dbs->common.cb) { dbs->common.cb(dbs->common.opaque, ret); } qemu_iovec_destroy(&dbs->iov); - if (dbs->bh) { - qemu_bh_delete(dbs->bh); - dbs->bh = NULL; - } qemu_aio_unref(dbs); } @@ -179,14 +177,21 @@ static void dma_aio_cancel(BlockAIOCB *acb) trace_dma_aio_cancel(dbs); + assert(!(dbs->acb && dbs->bh)); if (dbs->acb) { + /* This will invoke dma_blk_cb. */ blk_aio_cancel_async(dbs->acb); + return; } + if (dbs->bh) { cpu_unregister_map_client(dbs->bh); qemu_bh_delete(dbs->bh); dbs->bh = NULL; } + if (dbs->common.cb) { + dbs->common.cb(dbs->common.opaque, -ECANCELED); + } } static AioContext *dma_get_aio_context(BlockAIOCB *acb)