thebeanogamer / rpms / qemu-kvm

Forked from rpms/qemu-kvm 5 months ago
Clone

Blame SOURCES/kvm-block-Don-t-poll-in-bdrv_replace_child_noperm.patch

ed5979
From 150ef3356cc6732fede7ca059168fc0565ed0b76 Mon Sep 17 00:00:00 2001
ed5979
From: Kevin Wolf <kwolf@redhat.com>
ed5979
Date: Fri, 18 Nov 2022 18:41:09 +0100
ed5979
Subject: [PATCH 27/31] block: Don't poll in bdrv_replace_child_noperm()
ed5979
ed5979
RH-Author: Stefano Garzarella <sgarzare@redhat.com>
ed5979
RH-MergeRequest: 135: block: Simplify drain to prevent QEMU from crashing during snapshot
ed5979
RH-Bugzilla: 2155112
ed5979
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
ed5979
RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
ed5979
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
ed5979
RH-Commit: [15/16] 5fc7d6b703a2d6c1118d875056f0afbd6ba5cca9 (sgarzarella/qemu-kvm-c-9-s)
ed5979
ed5979
In order to make sure that bdrv_replace_child_noperm() doesn't have to
ed5979
poll any more, get rid of the bdrv_parent_drained_begin_single() call.
ed5979
ed5979
This is possible now because we can require that the parent is already
ed5979
drained through the child in question when the function is called and we
ed5979
don't call the parent drain callbacks more than once.
ed5979
ed5979
The additional drain calls needed in callers cause the test case to run
ed5979
its code in the drain handler too early (bdrv_attach_child() drains
ed5979
now), so modify it to only enable the code after the test setup has
ed5979
completed.
ed5979
ed5979
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ed5979
Message-Id: <20221118174110.55183-15-kwolf@redhat.com>
ed5979
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
ed5979
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
ed5979
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ed5979
(cherry picked from commit 23987471285a26397e3152a9244b652445fd36c4)
ed5979
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
ed5979
---
ed5979
 block.c                      | 103 ++++++++++++++++++++++++++++++-----
ed5979
 block/io.c                   |   2 +-
ed5979
 include/block/block-io.h     |   8 +++
ed5979
 tests/unit/test-bdrv-drain.c |  10 ++++
ed5979
 4 files changed, 108 insertions(+), 15 deletions(-)
ed5979
ed5979
diff --git a/block.c b/block.c
ed5979
index af31a94863..65588d313a 100644
ed5979
--- a/block.c
ed5979
+++ b/block.c
ed5979
@@ -2407,6 +2407,20 @@ static void bdrv_replace_child_abort(void *opaque)
ed5979
 
ed5979
     GLOBAL_STATE_CODE();
ed5979
     /* old_bs reference is transparently moved from @s to @s->child */
ed5979
+    if (!s->child->bs) {
ed5979
+        /*
ed5979
+         * The parents were undrained when removing old_bs from the child. New
ed5979
+         * requests can't have been made, though, because the child was empty.
ed5979
+         *
ed5979
+         * TODO Make bdrv_replace_child_noperm() transactionable to avoid
ed5979
+         * undraining the parent in the first place. Once this is done, having
ed5979
+         * new_bs drained when calling bdrv_replace_child_tran() is not a
ed5979
+         * requirement any more.
ed5979
+         */
ed5979
+        bdrv_parent_drained_begin_single(s->child, false);
ed5979
+        assert(!bdrv_parent_drained_poll_single(s->child));
ed5979
+    }
ed5979
+    assert(s->child->quiesced_parent);
ed5979
     bdrv_replace_child_noperm(s->child, s->old_bs);
ed5979
     bdrv_unref(new_bs);
ed5979
 }
ed5979
@@ -2422,12 +2436,19 @@ static TransactionActionDrv bdrv_replace_child_drv = {
ed5979
  *
ed5979
  * Note: real unref of old_bs is done only on commit.
ed5979
  *
ed5979
+ * Both @child->bs and @new_bs (if non-NULL) must be drained. @new_bs must be
ed5979
+ * kept drained until the transaction is completed.
ed5979
+ *
ed5979
  * The function doesn't update permissions, caller is responsible for this.
ed5979
  */
ed5979
 static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
ed5979
                                     Transaction *tran)
ed5979
 {
ed5979
     BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
ed5979
+
ed5979
+    assert(child->quiesced_parent);
ed5979
+    assert(!new_bs || new_bs->quiesce_counter);
ed5979
+
ed5979
     *s = (BdrvReplaceChildState) {
ed5979
         .child = child,
ed5979
         .old_bs = child->bs,
ed5979
@@ -2819,6 +2840,14 @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
ed5979
     return permissions[qapi_perm];
ed5979
 }
ed5979
 
ed5979
+/*
ed5979
+ * Replaces the node that a BdrvChild points to without updating permissions.
ed5979
+ *
ed5979
+ * If @new_bs is non-NULL, the parent of @child must already be drained through
ed5979
+ * @child.
ed5979
+ *
ed5979
+ * This function does not poll.
ed5979
+ */
ed5979
 static void bdrv_replace_child_noperm(BdrvChild *child,
ed5979
                                       BlockDriverState *new_bs)
ed5979
 {
ed5979
@@ -2826,6 +2855,28 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
ed5979
     int new_bs_quiesce_counter;
ed5979
 
ed5979
     assert(!child->frozen);
ed5979
+
ed5979
+    /*
ed5979
+     * If we want to change the BdrvChild to point to a drained node as its new
ed5979
+     * child->bs, we need to make sure that its new parent is drained, too. In
ed5979
+     * other words, either child->quiesce_parent must already be true or we must
ed5979
+     * be able to set it and keep the parent's quiesce_counter consistent with
ed5979
+     * that, but without polling or starting new requests (this function
ed5979
+     * guarantees that it doesn't poll, and starting new requests would be
ed5979
+     * against the invariants of drain sections).
ed5979
+     *
ed5979
+     * To keep things simple, we pick the first option (child->quiesce_parent
ed5979
+     * must already be true). We also generalise the rule a bit to make it
ed5979
+     * easier to verify in callers and more likely to be covered in test cases:
ed5979
+     * The parent must be quiesced through this child even if new_bs isn't
ed5979
+     * currently drained.
ed5979
+     *
ed5979
+     * The only exception is for callers that always pass new_bs == NULL. In
ed5979
+     * this case, we obviously never need to consider the case of a drained
ed5979
+     * new_bs, so we can keep the callers simpler by allowing them not to drain
ed5979
+     * the parent.
ed5979
+     */
ed5979
+    assert(!new_bs || child->quiesced_parent);
ed5979
     assert(old_bs != new_bs);
ed5979
     GLOBAL_STATE_CODE();
ed5979
 
ed5979
@@ -2833,15 +2884,6 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
ed5979
         assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
ed5979
     }
ed5979
 
ed5979
-    /*
ed5979
-     * If the new child node is drained but the old one was not, flush
ed5979
-     * all outstanding requests to the old child node.
ed5979
-     */
ed5979
-    new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
ed5979
-    if (new_bs_quiesce_counter && !child->quiesced_parent) {
ed5979
-        bdrv_parent_drained_begin_single(child, true);
ed5979
-    }
ed5979
-
ed5979
     if (old_bs) {
ed5979
         if (child->klass->detach) {
ed5979
             child->klass->detach(child);
ed5979
@@ -2861,11 +2903,9 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
ed5979
     }
ed5979
 
ed5979
     /*
ed5979
-     * If the old child node was drained but the new one is not, allow
ed5979
-     * requests to come in only after the new node has been attached.
ed5979
-     *
ed5979
-     * Update new_bs_quiesce_counter because bdrv_parent_drained_begin_single()
ed5979
-     * polls, which could have changed the value.
ed5979
+     * If the parent was drained through this BdrvChild previously, but new_bs
ed5979
+     * is not drained, allow requests to come in only after the new node has
ed5979
+     * been attached.
ed5979
      */
ed5979
     new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
ed5979
     if (!new_bs_quiesce_counter && child->quiesced_parent) {
ed5979
@@ -3002,6 +3042,24 @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
ed5979
     }
ed5979
 
ed5979
     bdrv_ref(child_bs);
ed5979
+    /*
ed5979
+     * Let every new BdrvChild start with a drained parent. Inserting the child
ed5979
+     * in the graph with bdrv_replace_child_noperm() will undrain it if
ed5979
+     * @child_bs is not drained.
ed5979
+     *
ed5979
+     * The child was only just created and is not yet visible in global state
ed5979
+     * until bdrv_replace_child_noperm() inserts it into the graph, so nobody
ed5979
+     * could have sent requests and polling is not necessary.
ed5979
+     *
ed5979
+     * Note that this means that the parent isn't fully drained yet, we only
ed5979
+     * stop new requests from coming in. This is fine, we don't care about the
ed5979
+     * old requests here, they are not for this child. If another place enters a
ed5979
+     * drain section for the same parent, but wants it to be fully quiesced, it
ed5979
+     * will not run most of the the code in .drained_begin() again (which is not
ed5979
+     * a problem, we already did this), but it will still poll until the parent
ed5979
+     * is fully quiesced, so it will not be negatively affected either.
ed5979
+     */
ed5979
+    bdrv_parent_drained_begin_single(new_child, false);
ed5979
     bdrv_replace_child_noperm(new_child, child_bs);
ed5979
 
ed5979
     BdrvAttachChildCommonState *s = g_new(BdrvAttachChildCommonState, 1);
ed5979
@@ -5059,12 +5117,24 @@ static void bdrv_remove_child(BdrvChild *child, Transaction *tran)
ed5979
     }
ed5979
 
ed5979
     if (child->bs) {
ed5979
+        BlockDriverState *bs = child->bs;
ed5979
+        bdrv_drained_begin(bs);
ed5979
         bdrv_replace_child_tran(child, NULL, tran);
ed5979
+        bdrv_drained_end(bs);
ed5979
     }
ed5979
 
ed5979
     tran_add(tran, &bdrv_remove_child_drv, child);
ed5979
 }
ed5979
 
ed5979
+static void undrain_on_clean_cb(void *opaque)
ed5979
+{
ed5979
+    bdrv_drained_end(opaque);
ed5979
+}
ed5979
+
ed5979
+static TransactionActionDrv undrain_on_clean = {
ed5979
+    .clean = undrain_on_clean_cb,
ed5979
+};
ed5979
+
ed5979
 static int bdrv_replace_node_noperm(BlockDriverState *from,
ed5979
                                     BlockDriverState *to,
ed5979
                                     bool auto_skip, Transaction *tran,
ed5979
@@ -5074,6 +5144,11 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
ed5979
 
ed5979
     GLOBAL_STATE_CODE();
ed5979
 
ed5979
+    bdrv_drained_begin(from);
ed5979
+    bdrv_drained_begin(to);
ed5979
+    tran_add(tran, &undrain_on_clean, from);
ed5979
+    tran_add(tran, &undrain_on_clean, to);
ed5979
+
ed5979
     QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
ed5979
         assert(c->bs == from);
ed5979
         if (!should_update_child(c, to)) {
ed5979
diff --git a/block/io.c b/block/io.c
ed5979
index 5e9150d92c..ae64830eac 100644
ed5979
--- a/block/io.c
ed5979
+++ b/block/io.c
ed5979
@@ -81,7 +81,7 @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
ed5979
     }
ed5979
 }
ed5979
 
ed5979
-static bool bdrv_parent_drained_poll_single(BdrvChild *c)
ed5979
+bool bdrv_parent_drained_poll_single(BdrvChild *c)
ed5979
 {
ed5979
     if (c->klass->drained_poll) {
ed5979
         return c->klass->drained_poll(c);
ed5979
diff --git a/include/block/block-io.h b/include/block/block-io.h
ed5979
index 8f5e75756a..65e6d2569b 100644
ed5979
--- a/include/block/block-io.h
ed5979
+++ b/include/block/block-io.h
ed5979
@@ -292,6 +292,14 @@ bdrv_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos);
ed5979
  */
ed5979
 void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll);
ed5979
 
ed5979
+/**
ed5979
+ * bdrv_parent_drained_poll_single:
ed5979
+ *
ed5979
+ * Returns true if there is any pending activity to cease before @c can be
ed5979
+ * called quiesced, false otherwise.
ed5979
+ */
ed5979
+bool bdrv_parent_drained_poll_single(BdrvChild *c);
ed5979
+
ed5979
 /**
ed5979
  * bdrv_parent_drained_end_single:
ed5979
  *
ed5979
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
ed5979
index 172bc6debc..2686a8acee 100644
ed5979
--- a/tests/unit/test-bdrv-drain.c
ed5979
+++ b/tests/unit/test-bdrv-drain.c
ed5979
@@ -1654,6 +1654,7 @@ static void test_drop_intermediate_poll(void)
ed5979
 
ed5979
 
ed5979
 typedef struct BDRVReplaceTestState {
ed5979
+    bool setup_completed;
ed5979
     bool was_drained;
ed5979
     bool was_undrained;
ed5979
     bool has_read;
ed5979
@@ -1738,6 +1739,10 @@ static void bdrv_replace_test_drain_begin(BlockDriverState *bs)
ed5979
 {
ed5979
     BDRVReplaceTestState *s = bs->opaque;
ed5979
 
ed5979
+    if (!s->setup_completed) {
ed5979
+        return;
ed5979
+    }
ed5979
+
ed5979
     if (!s->drain_count) {
ed5979
         s->drain_co = qemu_coroutine_create(bdrv_replace_test_drain_co, bs);
ed5979
         bdrv_inc_in_flight(bs);
ed5979
@@ -1769,6 +1774,10 @@ static void bdrv_replace_test_drain_end(BlockDriverState *bs)
ed5979
 {
ed5979
     BDRVReplaceTestState *s = bs->opaque;
ed5979
 
ed5979
+    if (!s->setup_completed) {
ed5979
+        return;
ed5979
+    }
ed5979
+
ed5979
     g_assert(s->drain_count > 0);
ed5979
     if (!--s->drain_count) {
ed5979
         s->was_undrained = true;
ed5979
@@ -1867,6 +1876,7 @@ static void do_test_replace_child_mid_drain(int old_drain_count,
ed5979
     bdrv_ref(old_child_bs);
ed5979
     bdrv_attach_child(parent_bs, old_child_bs, "child", &child_of_bds,
ed5979
                       BDRV_CHILD_COW, &error_abort);
ed5979
+    parent_s->setup_completed = true;
ed5979
 
ed5979
     for (i = 0; i < old_drain_count; i++) {
ed5979
         bdrv_drained_begin(old_child_bs);
ed5979
-- 
ed5979
2.31.1
ed5979