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