93 lines
3.5 KiB
Diff
93 lines
3.5 KiB
Diff
|
From eaade87072e903cf550dfdb8ed1480dddc6bb0e3 Mon Sep 17 00:00:00 2001
|
|||
|
From: Hanna Reitz <hreitz@redhat.com>
|
|||
|
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 <hreitz@redhat.com>
|
|||
|
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 <stefanha@redhat.com>
|
|||
|
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
|||
|
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
|||
|
|
|||
|
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 <pbonzini@redhat.com>
|
|||
|
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
|
|||
|
Message-Id: <20220120142259.120189-1-hreitz@redhat.com>
|
|||
|
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
|
|||
|
Reviewed-by: John Snow <jsnow@redhat.com>
|
|||
|
Tested-by: John Snow <jsnow@redhat.com>
|
|||
|
(cherry picked from commit 7e5cdb345f77d76cb4877fe6230c4e17a7d0d0ca)
|
|||
|
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
|
|||
|
---
|
|||
|
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
|
|||
|
|