]> Git Repo - qemu.git/commitdiff
block: Don't poll in parent drain callbacks
authorKevin Wolf <[email protected]>
Fri, 23 Mar 2018 14:57:20 +0000 (15:57 +0100)
committerKevin Wolf <[email protected]>
Mon, 18 Jun 2018 13:03:25 +0000 (15:03 +0200)
bdrv_do_drained_begin() is only safe if we have a single
BDRV_POLL_WHILE() after quiescing all affected nodes. We cannot allow
that parent callbacks introduce a nested polling loop that could cause
graph changes while we're traversing the graph.

Split off bdrv_do_drained_begin_quiesce(), which only quiesces a single
node without waiting for its requests to complete. These requests will
be waited for in the BDRV_POLL_WHILE() call down the call chain.

Signed-off-by: Kevin Wolf <[email protected]>
block.c
block/io.c
include/block/block.h

diff --git a/block.c b/block.c
index 80abd3c2ae97f3a8dc91615fcc53b045b62b62da..50f8e3dc3b89f61dc2b94465ecea6a769ae36851 100644 (file)
--- a/block.c
+++ b/block.c
@@ -818,7 +818,7 @@ static char *bdrv_child_get_parent_desc(BdrvChild *c)
 static void bdrv_child_cb_drained_begin(BdrvChild *child)
 {
     BlockDriverState *bs = child->opaque;
-    bdrv_drained_begin(bs);
+    bdrv_do_drained_begin_quiesce(bs, NULL);
 }
 
 static bool bdrv_child_cb_drained_poll(BdrvChild *child)
index a413841bfc50e6037199d4d2118d66a606357a4a..ffb273708a57ccd8a21116f071bfeb008ff03282 100644 (file)
@@ -286,15 +286,10 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
     assert(data.done);
 }
 
-void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
-                           BdrvChild *parent, bool poll)
+void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
+                                   BdrvChild *parent)
 {
-    BdrvChild *child, *next;
-
-    if (qemu_in_coroutine()) {
-        bdrv_co_yield_to_drain(bs, true, recursive, parent, poll);
-        return;
-    }
+    assert(!qemu_in_coroutine());
 
     /* Stop things in parent-to-child order */
     if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
@@ -303,6 +298,19 @@ void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
 
     bdrv_parent_drained_begin(bs, parent);
     bdrv_drain_invoke(bs, true);
+}
+
+static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
+                                  BdrvChild *parent, bool poll)
+{
+    BdrvChild *child, *next;
+
+    if (qemu_in_coroutine()) {
+        bdrv_co_yield_to_drain(bs, true, recursive, parent, poll);
+        return;
+    }
+
+    bdrv_do_drained_begin_quiesce(bs, parent);
 
     if (recursive) {
         bs->recursive_quiesce_counter++;
index 254ed2e4c930c6cede9203e02842ae9fb5e5889d..067d24cc4afc5135ac598c529ddb69ef3e4a36b6 100644 (file)
@@ -590,6 +590,15 @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive,
  */
 void bdrv_drained_begin(BlockDriverState *bs);
 
+/**
+ * bdrv_do_drained_begin_quiesce:
+ *
+ * Quiesces a BDS like bdrv_drained_begin(), but does not wait for already
+ * running requests to complete.
+ */
+void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
+                                   BdrvChild *parent);
+
 /**
  * Like bdrv_drained_begin, but recursively begins a quiesced section for
  * exclusive access to all child nodes as well.
This page took 0.050762 seconds and 4 git commands to generate.