26ba25
From 6fe050124f9433521227b5da8f560c7a3c248513 Mon Sep 17 00:00:00 2001
26ba25
From: Kevin Wolf <kwolf@redhat.com>
26ba25
Date: Wed, 10 Oct 2018 20:08:38 +0100
26ba25
Subject: [PATCH 07/49] block: Don't manually poll in bdrv_drain_all()
26ba25
26ba25
RH-Author: Kevin Wolf <kwolf@redhat.com>
26ba25
Message-id: <20181010200843.6710-5-kwolf@redhat.com>
26ba25
Patchwork-id: 82584
26ba25
O-Subject: [RHEL-8 qemu-kvm PATCH 04/44] block: Don't manually poll in bdrv_drain_all()
26ba25
Bugzilla: 1637976
26ba25
RH-Acked-by: Max Reitz <mreitz@redhat.com>
26ba25
RH-Acked-by: John Snow <jsnow@redhat.com>
26ba25
RH-Acked-by: Thomas Huth <thuth@redhat.com>
26ba25
26ba25
All involved nodes are already idle, we called bdrv_do_drain_begin() on
26ba25
them.
26ba25
26ba25
The comment in the code suggested that this was not correct because the
26ba25
completion of a request on one node could spawn a new request on a
26ba25
different node (which might have been drained before, so we wouldn't
26ba25
drain the new request). In reality, new requests to different nodes
26ba25
aren't spawned out of nothing, but only in the context of a parent
26ba25
request, and they aren't submitted to random nodes, but only to child
26ba25
nodes. As long as we still poll for the completion of the parent request
26ba25
(which we do), draining each root node separately is good enough.
26ba25
26ba25
Remove the additional polling code from bdrv_drain_all_begin() and
26ba25
replace it with an assertion that all nodes are already idle after we
26ba25
drained them separately.
26ba25
26ba25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26ba25
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
26ba25
(cherry picked from commit c13ad59f012cbbccb866a10477458e69bc868dbb)
26ba25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26ba25
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
26ba25
---
26ba25
 block/io.c | 41 ++++++++++++-----------------------------
26ba25
 1 file changed, 12 insertions(+), 29 deletions(-)
26ba25
26ba25
diff --git a/block/io.c b/block/io.c
26ba25
index aa41f1e..e5fc42c 100644
26ba25
--- a/block/io.c
26ba25
+++ b/block/io.c
26ba25
@@ -376,6 +376,16 @@ void bdrv_drain(BlockDriverState *bs)
26ba25
     bdrv_drained_end(bs);
26ba25
 }
26ba25
 
26ba25
+static void bdrv_drain_assert_idle(BlockDriverState *bs)
26ba25
+{
26ba25
+    BdrvChild *child, *next;
26ba25
+
26ba25
+    assert(atomic_read(&bs->in_flight) == 0);
26ba25
+    QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
26ba25
+        bdrv_drain_assert_idle(child->bs);
26ba25
+    }
26ba25
+}
26ba25
+
26ba25
 /*
26ba25
  * Wait for pending requests to complete across all BlockDriverStates
26ba25
  *
26ba25
@@ -390,11 +400,8 @@ void bdrv_drain(BlockDriverState *bs)
26ba25
  */
26ba25
 void bdrv_drain_all_begin(void)
26ba25
 {
26ba25
-    /* Always run first iteration so any pending completion BHs run */
26ba25
-    bool waited = true;
26ba25
     BlockDriverState *bs;
26ba25
     BdrvNextIterator it;
26ba25
-    GSList *aio_ctxs = NULL, *ctx;
26ba25
 
26ba25
     /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread
26ba25
      * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on
26ba25
@@ -408,35 +415,11 @@ void bdrv_drain_all_begin(void)
26ba25
         aio_context_acquire(aio_context);
26ba25
         bdrv_do_drained_begin(bs, true, NULL);
26ba25
         aio_context_release(aio_context);
26ba25
-
26ba25
-        if (!g_slist_find(aio_ctxs, aio_context)) {
26ba25
-            aio_ctxs = g_slist_prepend(aio_ctxs, aio_context);
26ba25
-        }
26ba25
     }
26ba25
 
26ba25
-    /* Note that completion of an asynchronous I/O operation can trigger any
26ba25
-     * number of other I/O operations on other devices---for example a
26ba25
-     * coroutine can submit an I/O request to another device in response to
26ba25
-     * request completion.  Therefore we must keep looping until there was no
26ba25
-     * more activity rather than simply draining each device independently.
26ba25
-     */
26ba25
-    while (waited) {
26ba25
-        waited = false;
26ba25
-
26ba25
-        for (ctx = aio_ctxs; ctx != NULL; ctx = ctx->next) {
26ba25
-            AioContext *aio_context = ctx->data;
26ba25
-
26ba25
-            aio_context_acquire(aio_context);
26ba25
-            for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
26ba25
-                if (aio_context == bdrv_get_aio_context(bs)) {
26ba25
-                    waited |= bdrv_drain_recurse(bs);
26ba25
-                }
26ba25
-            }
26ba25
-            aio_context_release(aio_context);
26ba25
-        }
26ba25
+    for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
26ba25
+        bdrv_drain_assert_idle(bs);
26ba25
     }
26ba25
-
26ba25
-    g_slist_free(aio_ctxs);
26ba25
 }
26ba25
 
26ba25
 void bdrv_drain_all_end(void)
26ba25
-- 
26ba25
1.8.3.1
26ba25