Blame SOURCES/kvm-block-Poll-after-drain-on-attaching-a-node.patch

1bdc94
From b0c7fc7fbe64b234272db8316f81b92fe675a65a Mon Sep 17 00:00:00 2001
1bdc94
From: Kevin Wolf <kwolf@redhat.com>
1bdc94
Date: Fri, 14 Sep 2018 10:55:19 +0200
1bdc94
Subject: [PATCH 28/49] block: Poll after drain on attaching a node
1bdc94
1bdc94
RH-Author: Kevin Wolf <kwolf@redhat.com>
1bdc94
Message-id: <20180914105540.18077-22-kwolf@redhat.com>
1bdc94
Patchwork-id: 82173
1bdc94
O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 21/42] block: Poll after drain on attaching a node
1bdc94
Bugzilla: 1601212
1bdc94
RH-Acked-by: John Snow <jsnow@redhat.com>
1bdc94
RH-Acked-by: Max Reitz <mreitz@redhat.com>
1bdc94
RH-Acked-by: Fam Zheng <famz@redhat.com>
1bdc94
1bdc94
Commit dcf94a23b1 ('block: Don't poll in parent drain callbacks')
1bdc94
removed polling in bdrv_child_cb_drained_begin() on the grounds that the
1bdc94
original bdrv_drain() already will poll and BdrvChildRole.drained_begin
1bdc94
calls must not cause graph changes (and therefore must not call
1bdc94
aio_poll() or the recursion through the graph will break.
1bdc94
1bdc94
This reasoning is correct for calls through bdrv_do_drained_begin().
1bdc94
However, BdrvChildRole.drained_begin is also called when a node that is
1bdc94
already in a drained section (i.e. bdrv_do_drained_begin() has already
1bdc94
returned and therefore can't poll any more) is attached to a new parent.
1bdc94
In this case, we must explicitly poll to have all requests completed
1bdc94
before the drained new child can be attached to the parent.
1bdc94
1bdc94
In bdrv_replace_child_noperm(), we know that we're not inside the
1bdc94
recursion of bdrv_do_drained_begin() because graph changes are not
1bdc94
allowed there, and bdrv_replace_child_noperm() is a graph change. The
1bdc94
call of BdrvChildRole.drained_begin() must therefore be followed by a
1bdc94
BDRV_POLL_WHILE() that waits for the completion of requests.
1bdc94
1bdc94
Reported-by: Max Reitz <mreitz@redhat.com>
1bdc94
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1bdc94
(cherry picked from commit 4be6a6d118123340f16fb8b3bf45220d0f8ed6d4)
1bdc94
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1bdc94
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
1bdc94
---
1bdc94
 block.c                   |  2 +-
1bdc94
 block/io.c                | 26 ++++++++++++++++++++------
1bdc94
 include/block/block.h     |  8 ++++++++
1bdc94
 include/block/block_int.h |  3 +++
1bdc94
 4 files changed, 32 insertions(+), 7 deletions(-)
1bdc94
1bdc94
diff --git a/block.c b/block.c
1bdc94
index eea9c6f..e89b5e3 100644
1bdc94
--- a/block.c
1bdc94
+++ b/block.c
1bdc94
@@ -2072,7 +2072,7 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
1bdc94
             }
1bdc94
             assert(num >= 0);
1bdc94
             for (i = 0; i < num; i++) {
1bdc94
-                child->role->drained_begin(child);
1bdc94
+                bdrv_parent_drained_begin_single(child, true);
1bdc94
             }
1bdc94
         }
1bdc94
 
1bdc94
diff --git a/block/io.c b/block/io.c
1bdc94
index 38ae299..d404088 100644
1bdc94
--- a/block/io.c
1bdc94
+++ b/block/io.c
1bdc94
@@ -52,9 +52,7 @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
1bdc94
         if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) {
1bdc94
             continue;
1bdc94
         }
1bdc94
-        if (c->role->drained_begin) {
1bdc94
-            c->role->drained_begin(c);
1bdc94
-        }
1bdc94
+        bdrv_parent_drained_begin_single(c, false);
1bdc94
     }
1bdc94
 }
1bdc94
 
1bdc94
@@ -73,6 +71,14 @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
1bdc94
     }
1bdc94
 }
1bdc94
 
1bdc94
+static bool bdrv_parent_drained_poll_single(BdrvChild *c)
1bdc94
+{
1bdc94
+    if (c->role->drained_poll) {
1bdc94
+        return c->role->drained_poll(c);
1bdc94
+    }
1bdc94
+    return false;
1bdc94
+}
1bdc94
+
1bdc94
 static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
1bdc94
                                      bool ignore_bds_parents)
1bdc94
 {
1bdc94
@@ -83,14 +89,22 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
1bdc94
         if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) {
1bdc94
             continue;
1bdc94
         }
1bdc94
-        if (c->role->drained_poll) {
1bdc94
-            busy |= c->role->drained_poll(c);
1bdc94
-        }
1bdc94
+        busy |= bdrv_parent_drained_poll_single(c);
1bdc94
     }
1bdc94
 
1bdc94
     return busy;
1bdc94
 }
1bdc94
 
1bdc94
+void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll)
1bdc94
+{
1bdc94
+    if (c->role->drained_begin) {
1bdc94
+        c->role->drained_begin(c);
1bdc94
+    }
1bdc94
+    if (poll) {
1bdc94
+        BDRV_POLL_WHILE(c->bs, bdrv_parent_drained_poll_single(c));
1bdc94
+    }
1bdc94
+}
1bdc94
+
1bdc94
 static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src)
1bdc94
 {
1bdc94
     dst->opt_transfer = MAX(dst->opt_transfer, src->opt_transfer);
1bdc94
diff --git a/include/block/block.h b/include/block/block.h
1bdc94
index f9079ac..356712c 100644
1bdc94
--- a/include/block/block.h
1bdc94
+++ b/include/block/block.h
1bdc94
@@ -590,6 +590,14 @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
1bdc94
                                bool ignore_bds_parents);
1bdc94
 
1bdc94
 /**
1bdc94
+ * bdrv_parent_drained_begin_single:
1bdc94
+ *
1bdc94
+ * Begin a quiesced section for the parent of @c. If @poll is true, wait for
1bdc94
+ * any pending activity to cease.
1bdc94
+ */
1bdc94
+void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll);
1bdc94
+
1bdc94
+/**
1bdc94
  * bdrv_parent_drained_end:
1bdc94
  *
1bdc94
  * End a quiesced section of all users of @bs. This is part of
1bdc94
diff --git a/include/block/block_int.h b/include/block/block_int.h
1bdc94
index 9757d5e..b7806e3 100644
1bdc94
--- a/include/block/block_int.h
1bdc94
+++ b/include/block/block_int.h
1bdc94
@@ -610,6 +610,9 @@ struct BdrvChildRole {
1bdc94
      * requests after returning from .drained_begin() until .drained_end() is
1bdc94
      * called.
1bdc94
      *
1bdc94
+     * These functions must not change the graph (and therefore also must not
1bdc94
+     * call aio_poll(), which could change the graph indirectly).
1bdc94
+     *
1bdc94
      * Note that this can be nested. If drained_begin() was called twice, new
1bdc94
      * I/O is allowed only after drained_end() was called twice, too.
1bdc94
      */
1bdc94
-- 
1bdc94
1.8.3.1
1bdc94