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

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