From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, richard.henderson@linaro.org, qemu-devel@nongnu.org
Subject: [PULL 18/18] tested: add test for nested aio_poll() in poll handlers
Date: Wed, 17 May 2023 18:51:16 +0200 [thread overview]
Message-ID: <20230517165116.475123-19-kwolf@redhat.com> (raw)
In-Reply-To: <20230517165116.475123-1-kwolf@redhat.com>
From: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <20230502184134.534703-3-stefanha@redhat.com>
Tested-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
tests/unit/test-nested-aio-poll.c | 130 ++++++++++++++++++++++++++++++
tests/unit/meson.build | 1 +
2 files changed, 131 insertions(+)
create mode 100644 tests/unit/test-nested-aio-poll.c
diff --git a/tests/unit/test-nested-aio-poll.c b/tests/unit/test-nested-aio-poll.c
new file mode 100644
index 0000000000..9bbe18b839
--- /dev/null
+++ b/tests/unit/test-nested-aio-poll.c
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Test that poll handlers are not re-entrant in nested aio_poll()
+ *
+ * Copyright Red Hat
+ *
+ * Poll handlers are usually level-triggered. That means they continue firing
+ * until the condition is reset (e.g. a virtqueue becomes empty). If a poll
+ * handler calls nested aio_poll() before the condition is reset, then infinite
+ * recursion occurs.
+ *
+ * aio_poll() is supposed to prevent this by disabling poll handlers in nested
+ * aio_poll() calls. This test case checks that this is indeed what happens.
+ */
+#include "qemu/osdep.h"
+#include "block/aio.h"
+#include "qapi/error.h"
+
+typedef struct {
+ AioContext *ctx;
+
+ /* This is the EventNotifier that drives the test */
+ EventNotifier poll_notifier;
+
+ /* This EventNotifier is only used to wake aio_poll() */
+ EventNotifier dummy_notifier;
+
+ bool nested;
+} TestData;
+
+static void io_read(EventNotifier *notifier)
+{
+ fprintf(stderr, "%s %p\n", __func__, notifier);
+ event_notifier_test_and_clear(notifier);
+}
+
+static bool io_poll_true(void *opaque)
+{
+ fprintf(stderr, "%s %p\n", __func__, opaque);
+ return true;
+}
+
+static bool io_poll_false(void *opaque)
+{
+ fprintf(stderr, "%s %p\n", __func__, opaque);
+ return false;
+}
+
+static void io_poll_ready(EventNotifier *notifier)
+{
+ TestData *td = container_of(notifier, TestData, poll_notifier);
+
+ fprintf(stderr, "> %s\n", __func__);
+
+ g_assert(!td->nested);
+ td->nested = true;
+
+ /* Wake the following nested aio_poll() call */
+ event_notifier_set(&td->dummy_notifier);
+
+ /* This nested event loop must not call io_poll()/io_poll_ready() */
+ g_assert(aio_poll(td->ctx, true));
+
+ td->nested = false;
+
+ fprintf(stderr, "< %s\n", __func__);
+}
+
+/* dummy_notifier never triggers */
+static void io_poll_never_ready(EventNotifier *notifier)
+{
+ g_assert_not_reached();
+}
+
+static void test(void)
+{
+ TestData td = {
+ .ctx = aio_context_new(&error_abort),
+ };
+
+ qemu_set_current_aio_context(td.ctx);
+
+ /* Enable polling */
+ aio_context_set_poll_params(td.ctx, 1000000, 2, 2, &error_abort);
+
+ /*
+ * The GSource is unused but this has the side-effect of changing the fdmon
+ * that AioContext uses.
+ */
+ aio_get_g_source(td.ctx);
+
+ /* Make the event notifier active (set) right away */
+ event_notifier_init(&td.poll_notifier, 1);
+ aio_set_event_notifier(td.ctx, &td.poll_notifier, false,
+ io_read, io_poll_true, io_poll_ready);
+
+ /* This event notifier will be used later */
+ event_notifier_init(&td.dummy_notifier, 0);
+ aio_set_event_notifier(td.ctx, &td.dummy_notifier, false,
+ io_read, io_poll_false, io_poll_never_ready);
+
+ /* Consume aio_notify() */
+ g_assert(!aio_poll(td.ctx, false));
+
+ /*
+ * Run the io_read() handler. This has the side-effect of activating
+ * polling in future aio_poll() calls.
+ */
+ g_assert(aio_poll(td.ctx, true));
+
+ /* The second time around the io_poll()/io_poll_ready() handler runs */
+ g_assert(aio_poll(td.ctx, true));
+
+ /* Run io_poll()/io_poll_ready() one more time to show it keeps working */
+ g_assert(aio_poll(td.ctx, true));
+
+ aio_set_event_notifier(td.ctx, &td.dummy_notifier, false,
+ NULL, NULL, NULL);
+ aio_set_event_notifier(td.ctx, &td.poll_notifier, false, NULL, NULL, NULL);
+ event_notifier_cleanup(&td.dummy_notifier);
+ event_notifier_cleanup(&td.poll_notifier);
+ aio_context_unref(td.ctx);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/nested-aio-poll", test);
+ return g_test_run();
+}
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index 3bc78d8660..a314f82baa 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -67,6 +67,7 @@ if have_block
'test-coroutine': [testblock],
'test-aio': [testblock],
'test-aio-multithread': [testblock],
+ 'test-nested-aio-poll': [testblock],
'test-throttle': [testblock],
'test-thread-pool': [testblock],
'test-hbitmap': [testblock],
--
2.40.1
next prev parent reply other threads:[~2023-05-17 16:53 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-05-17 16:50 [PULL 00/18] Block layer patches Kevin Wolf
2023-05-17 16:50 ` [PULL 01/18] blockdev: refactor transaction to use Transaction API Kevin Wolf
2023-05-17 16:51 ` [PULL 02/18] blockdev: transactions: rename some things Kevin Wolf
2023-05-17 16:51 ` [PULL 03/18] blockdev: qmp_transaction: refactor loop to classic for Kevin Wolf
2023-05-17 16:51 ` [PULL 04/18] blockdev: transaction: refactor handling transaction properties Kevin Wolf
2023-05-17 16:51 ` [PULL 05/18] blockdev: use state.bitmap in block-dirty-bitmap-add action Kevin Wolf
2023-05-17 16:51 ` [PULL 06/18] blockdev: qmp_transaction: drop extra generic layer Kevin Wolf
2023-05-17 16:51 ` [PULL 07/18] docs/interop/qcow2.txt: fix description about "zlib" clusters Kevin Wolf
2023-05-17 16:51 ` [PULL 08/18] block: Call .bdrv_co_create(_opts) unlocked Kevin Wolf
2023-05-17 16:51 ` [PULL 09/18] block/export: Fix null pointer dereference in error path Kevin Wolf
2023-05-17 16:51 ` [PULL 10/18] qcow2: Unlock the graph in qcow2_do_open() where necessary Kevin Wolf
2023-05-17 16:51 ` [PULL 11/18] qemu-img: Take graph lock more selectively Kevin Wolf
2023-05-17 16:51 ` [PULL 12/18] test-bdrv-drain: " Kevin Wolf
2023-05-17 16:51 ` [PULL 13/18] test-bdrv-drain: Call bdrv_co_unref() in coroutine context Kevin Wolf
2023-05-17 16:51 ` [PULL 14/18] blockjob: Adhere to rate limit even when reentered early Kevin Wolf
2023-05-17 16:51 ` [PULL 15/18] graph-lock: Honour read locks even in the main thread Kevin Wolf
2023-05-17 16:51 ` [PULL 16/18] iotests/245: Check if 'compress' driver is available Kevin Wolf
2023-05-17 16:51 ` [PULL 17/18] aio-posix: do not nest poll handlers Kevin Wolf
2023-05-18 7:13 ` Michael Tokarev
2023-05-18 15:05 ` Stefan Hajnoczi
2023-05-17 16:51 ` Kevin Wolf [this message]
2023-05-17 19:10 ` [PULL 18/18] tested: add test for nested aio_poll() in " Richard Henderson
2023-05-19 9:23 ` Kevin Wolf
2023-05-23 15:36 ` Stefan Hajnoczi
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=20230517165116.475123-19-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=richard.henderson@linaro.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.