qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Hanna Reitz <hreitz@redhat.com>
To: qemu-block@nongnu.org
Cc: Hanna Reitz <hreitz@redhat.com>, John Snow <jsnow@redhat.com>,
	qemu-devel@nongnu.org
Subject: [PATCH] ide: Explicitly poll for BHs on cancel
Date: Wed,  5 Jan 2022 12:13:37 +0100	[thread overview]
Message-ID: <20220105111337.10366-1-hreitz@redhat.com> (raw)

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 some
I/O operation on the BlockBackend, and so settling the latter will
settle the former.  That is not the case; for example, the guest is free
to issue a zero-length TRIM operation that will not result in any I/O
operation forwarded to the BlockBackend.  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().

To settle the DMA operation, we will thus need to explicitly invoke
aio_poll() ourselves, which will run any outstanding BHs (like
ide_trim_bh_cb()), until s->bus->dma->aiocb is NULL.  To stop this from
being an infinite loop, assert that we made progress with every
aio_poll() call (i.e., invoked some BH).

Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2029980
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
---
Perhaps for a lack of being aware of all the kinds of tests we have, I
found it impossible to write a reproducer in any of our current test
frameworks: From how I understand the issue, to reproduce it, you need
to issue a TRIM request and immediately cancel it, before
ide_trim_bh_cb() (scheduled as a BH) can run.

I wanted to do this via qtest, but that does not work, because every
port I/O operation is done via a qtest command, and QEMU will happily
poll the main context between each qtest command, which means that you
cannot cancel an ongoing IDE request before a BH scheduled by it is run.

Therefore, I wrote an x86 boot sector that sets up a no-op TRIM request
(i.e. one where all TRIM ranges have length 0) and immediately cancels
it by setting SRST.  It is attached to the BZ linked above, and can be
tested as follows:

$ TEST_BIN=test.bin
$ (sleep 1; echo 'info registers'; echo quit) \
    | ./qemu-system-x86_64 \
        -drive if=ide,file=$TEST_BIN,format=raw \
        -monitor stdio \
    | grep EIP= \
    | sed -e 's/ EFL.*//'

The result should be:
EIP=00007c72

Not:
qemu-system-x86_64: ../hw/ide/core.c:734: ide_cancel_dma_sync: Assertion
`s->bus->dma->aiocb == NULL' failed.
---
 hw/ide/core.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/hw/ide/core.c b/hw/ide/core.c
index e28f8aad61..c7f7a1016c 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -731,7 +731,17 @@ void ide_cancel_dma_sync(IDEState *s)
     if (s->bus->dma->aiocb) {
         trace_ide_cancel_dma_sync_remaining();
         blk_drain(s->blk);
-        assert(s->bus->dma->aiocb == NULL);
+
+        /*
+         * Wait for potentially still-scheduled BHs, like ide_trim_bh_cb()
+         * (blk_drain() will only poll if there are in-flight requests on the
+         * BlockBackend, which there may not necessarily be, e.g. when the
+         * guest has issued a zero-length TRIM request)
+         */
+        while (s->bus->dma->aiocb) {
+            bool progress = aio_poll(qemu_get_aio_context(), true);
+            assert(progress);
+        }
     }
 }
 
-- 
2.33.1



             reply	other threads:[~2022-01-05 11:16 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-05 11:13 Hanna Reitz [this message]
2022-01-05 13:53 ` [PATCH] ide: Explicitly poll for BHs on cancel Hanna Reitz
2022-01-06  0:11 ` Philippe Mathieu-Daudé
2022-01-07  8:05   ` Mark Cave-Ayland
2022-01-19 11:11 ` Paolo Bonzini
2022-01-19 11:29   ` Hanna Reitz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220105111337.10366-1-hreitz@redhat.com \
    --to=hreitz@redhat.com \
    --cc=jsnow@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).