From eaade87072e903cf550dfdb8ed1480dddc6bb0e3 Mon Sep 17 00:00:00 2001 From: Hanna Reitz Date: Thu, 20 Jan 2022 15:22:59 +0100 Subject: [PATCH 21/24] ide: Increment BB in-flight counter for TRIM BH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RH-Author: Hanna Reitz RH-MergeRequest: 188: ide: Increment BB in-flight counter for TRIM BH RH-Commit: [1/1] 1e702e735ff63f2b8b69c20cac1b309dd085cd62 RH-Bugzilla: 2029980 RH-Acked-by: Stefan Hajnoczi RH-Acked-by: Kevin Wolf RH-Acked-by: Paolo Bonzini When we still have an AIOCB registered for DMA operations, we try to settle the respective operation by draining the BlockBackend associated with the IDE device. However, this assumes that every DMA operation is associated with an increment of the BlockBackend’s in-flight counter (e.g. through some ongoing I/O operation), so that draining the BB until its in-flight counter reaches 0 will settle all DMA operations. That is not the case: For TRIM, the guest can issue a zero-length operation that will not result in any I/O operation forwarded to the BlockBackend, and also not increment the in-flight counter in any other way. In such a case, blk_drain() will be a no-op if no other operations are in flight. It is clear that if blk_drain() is a no-op, the value of s->bus->dma->aiocb will not change between checking it in the `if` condition and asserting that it is NULL after blk_drain(). The particular problem is that ide_issue_trim() creates a BH (ide_trim_bh_cb()) to settle the TRIM request: iocb->common.cb() is ide_dma_cb(), which will either create a new request, or find the transfer to be done and call ide_set_inactive(), which clears s->bus->dma->aiocb. Therefore, the blk_drain() must wait for ide_trim_bh_cb() to run, which currently it will not always do. To fix this issue, we increment the BlockBackend's in-flight counter when the TRIM operation begins (in ide_issue_trim(), when the ide_trim_bh_cb() BH is created) and decrement it when ide_trim_bh_cb() is done. Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2029980 Suggested-by: Paolo Bonzini Signed-off-by: Hanna Reitz Message-Id: <20220120142259.120189-1-hreitz@redhat.com> Reviewed-by: Paolo Bonzini Reviewed-by: John Snow Tested-by: John Snow (cherry picked from commit 7e5cdb345f77d76cb4877fe6230c4e17a7d0d0ca) Signed-off-by: Hanna Reitz --- hw/ide/core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/ide/core.c b/hw/ide/core.c index e28f8aad61..15138225be 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -433,12 +433,16 @@ static const AIOCBInfo trim_aiocb_info = { static void ide_trim_bh_cb(void *opaque) { TrimAIOCB *iocb = opaque; + BlockBackend *blk = iocb->s->blk; iocb->common.cb(iocb->common.opaque, iocb->ret); qemu_bh_delete(iocb->bh); iocb->bh = NULL; qemu_aio_unref(iocb); + + /* Paired with an increment in ide_issue_trim() */ + blk_dec_in_flight(blk); } static void ide_issue_trim_cb(void *opaque, int ret) @@ -508,6 +512,9 @@ BlockAIOCB *ide_issue_trim( IDEState *s = opaque; TrimAIOCB *iocb; + /* Paired with a decrement in ide_trim_bh_cb() */ + blk_inc_in_flight(s->blk); + iocb = blk_aio_get(&trim_aiocb_info, s->blk, cb, cb_opaque); iocb->s = s; iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); -- 2.35.3