thebeanogamer / rpms / qemu-kvm

Forked from rpms/qemu-kvm 5 months ago
Clone

Blame SOURCES/kvm-stream-Replace-subtree-drain-with-a-single-node-drai.patch

ed5979
From 5defda06ec4c24818a34126c5048be5e274b63f5 Mon Sep 17 00:00:00 2001
ed5979
From: Kevin Wolf <kwolf@redhat.com>
ed5979
Date: Fri, 18 Nov 2022 18:41:04 +0100
ed5979
Subject: [PATCH 22/31] stream: Replace subtree drain with a single node drain
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: [10/16] a93250b1f6ef296e903df0ba5d8b29bc2ed540a8 (sgarzarella/qemu-kvm-c-9-s)
ed5979
ed5979
The subtree drain was introduced in commit b1e1af394d9 as a way to avoid
ed5979
graph changes between finding the base node and changing the block graph
ed5979
as necessary on completion of the image streaming job.
ed5979
ed5979
The block graph could change between these two points because
ed5979
bdrv_set_backing_hd() first drains the parent node, which involved
ed5979
polling and can do anything.
ed5979
ed5979
Subtree draining was an imperfect way to make this less likely (because
ed5979
with it, fewer callbacks are called during this window). Everyone agreed
ed5979
that it's not really the right solution, and it was only committed as a
ed5979
stopgap solution.
ed5979
ed5979
This replaces the subtree drain with a solution that simply drains the
ed5979
parent node before we try to find the base node, and then call a version
ed5979
of bdrv_set_backing_hd() that doesn't drain, but just asserts that the
ed5979
parent node is already drained.
ed5979
ed5979
This way, any graph changes caused by draining happen before we start
ed5979
looking at the graph and things stay consistent between finding the base
ed5979
node and changing the graph.
ed5979
ed5979
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ed5979
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
ed5979
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
ed5979
Message-Id: <20221118174110.55183-10-kwolf@redhat.com>
ed5979
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
ed5979
(cherry picked from commit 92140b9f3f07d80e2c27edcc6e32f392be2135e6)
ed5979
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
ed5979
---
ed5979
 block.c                            | 17 ++++++++++++++---
ed5979
 block/stream.c                     | 26 ++++++++++++++++----------
ed5979
 include/block/block-global-state.h |  3 +++
ed5979
 3 files changed, 33 insertions(+), 13 deletions(-)
ed5979
ed5979
diff --git a/block.c b/block.c
ed5979
index b3449a312e..5330e89903 100644
ed5979
--- a/block.c
ed5979
+++ b/block.c
ed5979
@@ -3403,14 +3403,15 @@ static int bdrv_set_backing_noperm(BlockDriverState *bs,
ed5979
     return bdrv_set_file_or_backing_noperm(bs, backing_hd, true, tran, errp);
ed5979
 }
ed5979
 
ed5979
-int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
ed5979
-                        Error **errp)
ed5979
+int bdrv_set_backing_hd_drained(BlockDriverState *bs,
ed5979
+                                BlockDriverState *backing_hd,
ed5979
+                                Error **errp)
ed5979
 {
ed5979
     int ret;
ed5979
     Transaction *tran = tran_new();
ed5979
 
ed5979
     GLOBAL_STATE_CODE();
ed5979
-    bdrv_drained_begin(bs);
ed5979
+    assert(bs->quiesce_counter > 0);
ed5979
 
ed5979
     ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp);
ed5979
     if (ret < 0) {
ed5979
@@ -3420,7 +3421,17 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
ed5979
     ret = bdrv_refresh_perms(bs, errp);
ed5979
 out:
ed5979
     tran_finalize(tran, ret);
ed5979
+    return ret;
ed5979
+}
ed5979
 
ed5979
+int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
ed5979
+                        Error **errp)
ed5979
+{
ed5979
+    int ret;
ed5979
+    GLOBAL_STATE_CODE();
ed5979
+
ed5979
+    bdrv_drained_begin(bs);
ed5979
+    ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
ed5979
     bdrv_drained_end(bs);
ed5979
 
ed5979
     return ret;
ed5979
diff --git a/block/stream.c b/block/stream.c
ed5979
index 694709bd25..8744ad103f 100644
ed5979
--- a/block/stream.c
ed5979
+++ b/block/stream.c
ed5979
@@ -64,13 +64,16 @@ static int stream_prepare(Job *job)
ed5979
     bdrv_cor_filter_drop(s->cor_filter_bs);
ed5979
     s->cor_filter_bs = NULL;
ed5979
 
ed5979
-    bdrv_subtree_drained_begin(s->above_base);
ed5979
+    /*
ed5979
+     * bdrv_set_backing_hd() requires that unfiltered_bs is drained. Drain
ed5979
+     * already here and use bdrv_set_backing_hd_drained() instead because
ed5979
+     * the polling during drained_begin() might change the graph, and if we do
ed5979
+     * this only later, we may end up working with the wrong base node (or it
ed5979
+     * might even have gone away by the time we want to use it).
ed5979
+     */
ed5979
+    bdrv_drained_begin(unfiltered_bs);
ed5979
 
ed5979
     base = bdrv_filter_or_cow_bs(s->above_base);
ed5979
-    if (base) {
ed5979
-        bdrv_ref(base);
ed5979
-    }
ed5979
-
ed5979
     unfiltered_base = bdrv_skip_filters(base);
ed5979
 
ed5979
     if (bdrv_cow_child(unfiltered_bs)) {
ed5979
@@ -82,7 +85,13 @@ static int stream_prepare(Job *job)
ed5979
             }
ed5979
         }
ed5979
 
ed5979
-        bdrv_set_backing_hd(unfiltered_bs, base, &local_err);
ed5979
+        bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
ed5979
+
ed5979
+        /*
ed5979
+         * This call will do I/O, so the graph can change again from here on.
ed5979
+         * We have already completed the graph change, so we are not in danger
ed5979
+         * of operating on the wrong node any more if this happens.
ed5979
+         */
ed5979
         ret = bdrv_change_backing_file(unfiltered_bs, base_id, base_fmt, false);
ed5979
         if (local_err) {
ed5979
             error_report_err(local_err);
ed5979
@@ -92,10 +101,7 @@ static int stream_prepare(Job *job)
ed5979
     }
ed5979
 
ed5979
 out:
ed5979
-    if (base) {
ed5979
-        bdrv_unref(base);
ed5979
-    }
ed5979
-    bdrv_subtree_drained_end(s->above_base);
ed5979
+    bdrv_drained_end(unfiltered_bs);
ed5979
     return ret;
ed5979
 }
ed5979
 
ed5979
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
ed5979
index c7bd4a2088..00e0cf8aea 100644
ed5979
--- a/include/block/block-global-state.h
ed5979
+++ b/include/block/block-global-state.h
ed5979
@@ -82,6 +82,9 @@ int bdrv_open_file_child(const char *filename,
ed5979
 BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
ed5979
 int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
ed5979
                         Error **errp);
ed5979
+int bdrv_set_backing_hd_drained(BlockDriverState *bs,
ed5979
+                                BlockDriverState *backing_hd,
ed5979
+                                Error **errp);
ed5979
 int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
ed5979
                            const char *bdref_key, Error **errp);
ed5979
 BlockDriverState *bdrv_open(const char *filename, const char *reference,
ed5979
-- 
ed5979
2.31.1
ed5979