ed5979
From 093c4a6834f3ec5a05390a3630ae4edec80885b8 Mon Sep 17 00:00:00 2001
ed5979
From: Kevin Wolf <kwolf@redhat.com>
ed5979
Date: Fri, 18 Nov 2022 18:40:57 +0100
ed5979
Subject: [PATCH 15/31] test-bdrv-drain: Don't yield in
ed5979
 .bdrv_co_drained_begin/end()
ed5979
ed5979
RH-Author: Stefano Garzarella <sgarzare@redhat.com>
ed5979
RH-MergeRequest: 135: block: Simplify drain to prevent QEMU from crashing during snapshot
ed5979
RH-Bugzilla: 2155112
ed5979
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
ed5979
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
ed5979
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
ed5979
RH-Commit: [3/16] 5282d3e13cb85dfb480edb11b7eb2769248465df (sgarzarella/qemu-kvm-c-9-s)
ed5979
ed5979
We want to change .bdrv_co_drained_begin/end() back to be non-coroutine
ed5979
callbacks, so in preparation, avoid yielding in their implementation.
ed5979
ed5979
This does almost the same as the existing logic in bdrv_drain_invoke(),
ed5979
by creating and entering coroutines internally. However, since the test
ed5979
case is by far the heaviest user of coroutine code in drain callbacks,
ed5979
it is preferable to have the complexity in the test case rather than the
ed5979
drain core, which is already complicated enough without this.
ed5979
ed5979
The behaviour for bdrv_drain_begin() is unchanged because we increase
ed5979
bs->in_flight and this is still polled. However, bdrv_drain_end()
ed5979
doesn't wait for the spawned coroutine to complete any more. This is
ed5979
fine, we don't rely on bdrv_drain_end() restarting all operations
ed5979
immediately before the next aio_poll().
ed5979
ed5979
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ed5979
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
ed5979
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
ed5979
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
ed5979
Message-Id: <20221118174110.55183-3-kwolf@redhat.com>
ed5979
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ed5979
(cherry picked from commit 7bce1c299834557bffd92294608ea528648cfe75)
ed5979
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
ed5979
---
ed5979
 tests/unit/test-bdrv-drain.c | 64 ++++++++++++++++++++++++++----------
ed5979
 1 file changed, 46 insertions(+), 18 deletions(-)
ed5979
ed5979
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
ed5979
index 09dc4a4891..24f34e24ad 100644
ed5979
--- a/tests/unit/test-bdrv-drain.c
ed5979
+++ b/tests/unit/test-bdrv-drain.c
ed5979
@@ -38,12 +38,22 @@ typedef struct BDRVTestState {
ed5979
     bool sleep_in_drain_begin;
ed5979
 } BDRVTestState;
ed5979
 
ed5979
+static void coroutine_fn sleep_in_drain_begin(void *opaque)
ed5979
+{
ed5979
+    BlockDriverState *bs = opaque;
ed5979
+
ed5979
+    qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
ed5979
+    bdrv_dec_in_flight(bs);
ed5979
+}
ed5979
+
ed5979
 static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
ed5979
 {
ed5979
     BDRVTestState *s = bs->opaque;
ed5979
     s->drain_count++;
ed5979
     if (s->sleep_in_drain_begin) {
ed5979
-        qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
ed5979
+        Coroutine *co = qemu_coroutine_create(sleep_in_drain_begin, bs);
ed5979
+        bdrv_inc_in_flight(bs);
ed5979
+        aio_co_enter(bdrv_get_aio_context(bs), co);
ed5979
     }
ed5979
 }
ed5979
 
ed5979
@@ -1916,6 +1926,21 @@ static int coroutine_fn bdrv_replace_test_co_preadv(BlockDriverState *bs,
ed5979
     return 0;
ed5979
 }
ed5979
 
ed5979
+static void coroutine_fn bdrv_replace_test_drain_co(void *opaque)
ed5979
+{
ed5979
+    BlockDriverState *bs = opaque;
ed5979
+    BDRVReplaceTestState *s = bs->opaque;
ed5979
+
ed5979
+    /* Keep waking io_co up until it is done */
ed5979
+    while (s->io_co) {
ed5979
+        aio_co_wake(s->io_co);
ed5979
+        s->io_co = NULL;
ed5979
+        qemu_coroutine_yield();
ed5979
+    }
ed5979
+    s->drain_co = NULL;
ed5979
+    bdrv_dec_in_flight(bs);
ed5979
+}
ed5979
+
ed5979
 /**
ed5979
  * If .drain_count is 0, wake up .io_co if there is one; and set
ed5979
  * .was_drained.
ed5979
@@ -1926,20 +1951,27 @@ static void coroutine_fn bdrv_replace_test_co_drain_begin(BlockDriverState *bs)
ed5979
     BDRVReplaceTestState *s = bs->opaque;
ed5979
 
ed5979
     if (!s->drain_count) {
ed5979
-        /* Keep waking io_co up until it is done */
ed5979
-        s->drain_co = qemu_coroutine_self();
ed5979
-        while (s->io_co) {
ed5979
-            aio_co_wake(s->io_co);
ed5979
-            s->io_co = NULL;
ed5979
-            qemu_coroutine_yield();
ed5979
-        }
ed5979
-        s->drain_co = NULL;
ed5979
-
ed5979
+        s->drain_co = qemu_coroutine_create(bdrv_replace_test_drain_co, bs);
ed5979
+        bdrv_inc_in_flight(bs);
ed5979
+        aio_co_enter(bdrv_get_aio_context(bs), s->drain_co);
ed5979
         s->was_drained = true;
ed5979
     }
ed5979
     s->drain_count++;
ed5979
 }
ed5979
 
ed5979
+static void coroutine_fn bdrv_replace_test_read_entry(void *opaque)
ed5979
+{
ed5979
+    BlockDriverState *bs = opaque;
ed5979
+    char data;
ed5979
+    QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, &data, 1);
ed5979
+    int ret;
ed5979
+
ed5979
+    /* Queue a read request post-drain */
ed5979
+    ret = bdrv_replace_test_co_preadv(bs, 0, 1, &qiov, 0);
ed5979
+    g_assert(ret >= 0);
ed5979
+    bdrv_dec_in_flight(bs);
ed5979
+}
ed5979
+
ed5979
 /**
ed5979
  * Reduce .drain_count, set .was_undrained once it reaches 0.
ed5979
  * If .drain_count reaches 0 and the node has a backing file, issue a
ed5979
@@ -1951,17 +1983,13 @@ static void coroutine_fn bdrv_replace_test_co_drain_end(BlockDriverState *bs)
ed5979
 
ed5979
     g_assert(s->drain_count > 0);
ed5979
     if (!--s->drain_count) {
ed5979
-        int ret;
ed5979
-
ed5979
         s->was_undrained = true;
ed5979
 
ed5979
         if (bs->backing) {
ed5979
-            char data;
ed5979
-            QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, &data, 1);
ed5979
-
ed5979
-            /* Queue a read request post-drain */
ed5979
-            ret = bdrv_replace_test_co_preadv(bs, 0, 1, &qiov, 0);
ed5979
-            g_assert(ret >= 0);
ed5979
+            Coroutine *co = qemu_coroutine_create(bdrv_replace_test_read_entry,
ed5979
+                                                  bs);
ed5979
+            bdrv_inc_in_flight(bs);
ed5979
+            aio_co_enter(bdrv_get_aio_context(bs), co);
ed5979
         }
ed5979
     }
ed5979
 }
ed5979
-- 
ed5979
2.31.1
ed5979