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