From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, peter.maydell@linaro.org, qemu-devel@nongnu.org
Subject: [PULL 15/51] block: Call drain callbacks only once
Date: Wed, 14 Dec 2022 14:44:17 +0100 [thread overview]
Message-ID: <20221214134453.31665-16-kwolf@redhat.com> (raw)
In-Reply-To: <20221214134453.31665-1-kwolf@redhat.com>
We only need to call both the BlockDriver's callback and the parent
callbacks when going from undrained to drained or vice versa. A second
drain section doesn't make a difference for the driver or the parent,
they weren't supposed to send new requests before and after the second
drain.
One thing that gets in the way is the 'ignore_bds_parents' parameter in
bdrv_do_drained_begin_quiesce() and bdrv_do_drained_end(): It means that
bdrv_drain_all_begin() increases bs->quiesce_counter, but does not
quiesce the parent through BdrvChildClass callbacks. If an additional
drain section is started now, bs->quiesce_counter will be non-zero, but
we would still need to quiesce the parent through BdrvChildClass in
order to keep things consistent (and unquiesce it on the matching
bdrv_drained_end(), even though the counter would not reach 0 yet as
long as the bdrv_drain_all() section is still active).
Instead of keeping track of this, let's just get rid of the parameter.
It was introduced in commit 6cd5c9d7b2d as an optimisation so that
during bdrv_drain_all(), we wouldn't recursively drain all parents up to
the root for each node, resulting in quadratic complexity. As it happens,
calling the callbacks only once solves the same problem, so as of this
patch, we'll still have O(n) complexity and ignore_bds_parents is not
needed any more.
This patch only ignores the 'ignore_bds_parents' parameter. It will be
removed in a separate patch.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
Message-Id: <20221118174110.55183-12-kwolf@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
include/block/block_int-common.h | 8 ++++----
block.c | 25 +++++++------------------
block/io.c | 30 ++++++++++++++++++------------
tests/unit/test-bdrv-drain.c | 16 ++++++++++------
4 files changed, 39 insertions(+), 40 deletions(-)
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
index 791dddfd7d..a6bc6b7fe9 100644
--- a/include/block/block_int-common.h
+++ b/include/block/block_int-common.h
@@ -980,13 +980,13 @@ struct BdrvChild {
bool frozen;
/*
- * How many times the parent of this child has been drained
+ * True if the parent of this child has been drained by this BdrvChild
* (through klass->drained_*).
- * Usually, this is equal to bs->quiesce_counter (potentially
- * reduced by bdrv_drain_all_count). It may differ while the
+ *
+ * It is generally true if bs->quiesce_counter > 0. It may differ while the
* child is entering or leaving a drained section.
*/
- int parent_quiesce_counter;
+ bool quiesced_parent;
QLIST_ENTRY(BdrvChild) next;
QLIST_ENTRY(BdrvChild) next_parent;
diff --git a/block.c b/block.c
index 7ea0b82049..b8bab06e55 100644
--- a/block.c
+++ b/block.c
@@ -2855,7 +2855,6 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
{
BlockDriverState *old_bs = child->bs;
int new_bs_quiesce_counter;
- int drain_saldo;
assert(!child->frozen);
assert(old_bs != new_bs);
@@ -2865,16 +2864,13 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
}
- new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
- drain_saldo = new_bs_quiesce_counter - child->parent_quiesce_counter;
-
/*
* If the new child node is drained but the old one was not, flush
* all outstanding requests to the old child node.
*/
- while (drain_saldo > 0 && child->klass->drained_begin) {
+ new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
+ if (new_bs_quiesce_counter && !child->quiesced_parent) {
bdrv_parent_drained_begin_single(child, true);
- drain_saldo--;
}
if (old_bs) {
@@ -2890,16 +2886,6 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
if (new_bs) {
assert_bdrv_graph_writable(new_bs);
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
-
- /*
- * Polling in bdrv_parent_drained_begin_single() may have led to the new
- * node's quiesce_counter having been decreased. Not a problem, we just
- * need to recognize this here and then invoke drained_end appropriately
- * more often.
- */
- assert(new_bs->quiesce_counter <= new_bs_quiesce_counter);
- drain_saldo += new_bs->quiesce_counter - new_bs_quiesce_counter;
-
if (child->klass->attach) {
child->klass->attach(child);
}
@@ -2908,10 +2894,13 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
/*
* If the old child node was drained but the new one is not, allow
* requests to come in only after the new node has been attached.
+ *
+ * Update new_bs_quiesce_counter because bdrv_parent_drained_begin_single()
+ * polls, which could have changed the value.
*/
- while (drain_saldo < 0 && child->klass->drained_end) {
+ new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
+ if (!new_bs_quiesce_counter && child->quiesced_parent) {
bdrv_parent_drained_end_single(child);
- drain_saldo++;
}
}
diff --git a/block/io.c b/block/io.c
index 75224480d0..87d6f22ec4 100644
--- a/block/io.c
+++ b/block/io.c
@@ -62,8 +62,9 @@ void bdrv_parent_drained_end_single(BdrvChild *c)
{
IO_OR_GS_CODE();
- assert(c->parent_quiesce_counter > 0);
- c->parent_quiesce_counter--;
+ assert(c->quiesced_parent);
+ c->quiesced_parent = false;
+
if (c->klass->drained_end) {
c->klass->drained_end(c);
}
@@ -110,7 +111,10 @@ void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll)
{
AioContext *ctx = bdrv_child_get_parent_aio_context(c);
IO_OR_GS_CODE();
- c->parent_quiesce_counter++;
+
+ assert(!c->quiesced_parent);
+ c->quiesced_parent = true;
+
if (c->klass->drained_begin) {
c->klass->drained_begin(c);
}
@@ -358,11 +362,12 @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
/* Stop things in parent-to-child order */
if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
aio_disable_external(bdrv_get_aio_context(bs));
- }
- bdrv_parent_drained_begin(bs, parent, ignore_bds_parents);
- if (bs->drv && bs->drv->bdrv_drain_begin) {
- bs->drv->bdrv_drain_begin(bs);
+ /* TODO Remove ignore_bds_parents, we don't consider it any more */
+ bdrv_parent_drained_begin(bs, parent, false);
+ if (bs->drv && bs->drv->bdrv_drain_begin) {
+ bs->drv->bdrv_drain_begin(bs);
+ }
}
}
@@ -413,13 +418,14 @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent,
assert(bs->quiesce_counter > 0);
/* Re-enable things in child-to-parent order */
- if (bs->drv && bs->drv->bdrv_drain_end) {
- bs->drv->bdrv_drain_end(bs);
- }
- bdrv_parent_drained_end(bs, parent, ignore_bds_parents);
-
old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
if (old_quiesce_counter == 1) {
+ if (bs->drv && bs->drv->bdrv_drain_end) {
+ bs->drv->bdrv_drain_end(bs);
+ }
+ /* TODO Remove ignore_bds_parents, we don't consider it any more */
+ bdrv_parent_drained_end(bs, parent, false);
+
aio_enable_external(bdrv_get_aio_context(bs));
}
}
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
index dda08de8db..172bc6debc 100644
--- a/tests/unit/test-bdrv-drain.c
+++ b/tests/unit/test-bdrv-drain.c
@@ -296,7 +296,11 @@ static void test_quiesce_common(enum drain_type drain_type, bool recursive)
do_drain_begin(drain_type, bs);
- g_assert_cmpint(bs->quiesce_counter, ==, 1);
+ if (drain_type == BDRV_DRAIN_ALL) {
+ g_assert_cmpint(bs->quiesce_counter, ==, 2);
+ } else {
+ g_assert_cmpint(bs->quiesce_counter, ==, 1);
+ }
g_assert_cmpint(backing->quiesce_counter, ==, !!recursive);
do_drain_end(drain_type, bs);
@@ -348,8 +352,8 @@ static void test_nested(void)
for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) {
for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) {
- int backing_quiesce = (outer != BDRV_DRAIN) +
- (inner != BDRV_DRAIN);
+ int backing_quiesce = (outer == BDRV_DRAIN_ALL) +
+ (inner == BDRV_DRAIN_ALL);
g_assert_cmpint(bs->quiesce_counter, ==, 0);
g_assert_cmpint(backing->quiesce_counter, ==, 0);
@@ -359,10 +363,10 @@ static void test_nested(void)
do_drain_begin(outer, bs);
do_drain_begin(inner, bs);
- g_assert_cmpint(bs->quiesce_counter, ==, 2);
+ g_assert_cmpint(bs->quiesce_counter, ==, 2 + !!backing_quiesce);
g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce);
- g_assert_cmpint(s->drain_count, ==, 2);
- g_assert_cmpint(backing_s->drain_count, ==, backing_quiesce);
+ g_assert_cmpint(s->drain_count, ==, 1);
+ g_assert_cmpint(backing_s->drain_count, ==, !!backing_quiesce);
do_drain_end(inner, bs);
do_drain_end(outer, bs);
--
2.38.1
next prev parent reply other threads:[~2022-12-14 13:56 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-12-14 13:44 [PULL 00/51] Block layer patches Kevin Wolf
2022-12-14 13:44 ` [PULL 01/51] block: Inline bdrv_detach_child() Kevin Wolf
2022-12-14 13:44 ` [PULL 02/51] block: drop bdrv_remove_filter_or_cow_child Kevin Wolf
2022-12-14 13:44 ` [PULL 03/51] block: bdrv_refresh_perms(): allow external tran Kevin Wolf
2022-12-14 13:44 ` [PULL 04/51] block: refactor bdrv_list_refresh_perms to allow any list of nodes Kevin Wolf
2022-12-14 13:44 ` [PULL 05/51] qed: Don't yield in bdrv_qed_co_drain_begin() Kevin Wolf
2022-12-14 13:44 ` [PULL 06/51] test-bdrv-drain: Don't yield in .bdrv_co_drained_begin/end() Kevin Wolf
2022-12-14 13:44 ` [PULL 07/51] block: Revert .bdrv_drained_begin/end to non-coroutine_fn Kevin Wolf
2022-12-14 13:44 ` [PULL 08/51] block: Remove drained_end_counter Kevin Wolf
2022-12-14 13:44 ` [PULL 09/51] block: Inline bdrv_drain_invoke() Kevin Wolf
2022-12-14 13:44 ` [PULL 10/51] block: Fix locking for bdrv_reopen_queue_child() Kevin Wolf
2022-12-14 13:44 ` [PULL 11/51] block: Drain individual nodes during reopen Kevin Wolf
2022-12-14 13:44 ` [PULL 12/51] block: Don't use subtree drains in bdrv_drop_intermediate() Kevin Wolf
2022-12-14 13:44 ` [PULL 13/51] stream: Replace subtree drain with a single node drain Kevin Wolf
2022-12-14 13:44 ` [PULL 14/51] block: Remove subtree drains Kevin Wolf
2022-12-14 13:44 ` Kevin Wolf [this message]
2022-12-14 13:44 ` [PULL 16/51] block: Remove ignore_bds_parents parameter from drain_begin/end Kevin Wolf
2022-12-14 13:44 ` [PULL 17/51] block: Drop out of coroutine in bdrv_do_drained_begin_quiesce() Kevin Wolf
2022-12-14 13:44 ` [PULL 18/51] block: Don't poll in bdrv_replace_child_noperm() Kevin Wolf
2022-12-14 13:44 ` [PULL 19/51] block: Remove poll parameter from bdrv_parent_drained_begin_single() Kevin Wolf
2022-12-14 13:44 ` [PULL 20/51] block-io: introduce coroutine_fn duplicates for bdrv_common_block_status_above callers Kevin Wolf
2022-12-14 13:44 ` [PULL 21/51] block-copy: add coroutine_fn annotations Kevin Wolf
2022-12-14 13:44 ` [PULL 22/51] nbd/server.c: " Kevin Wolf
2022-12-14 13:44 ` [PULL 23/51] block-backend: replace bdrv_*_above with blk_*_above Kevin Wolf
2022-12-14 13:44 ` [PULL 24/51] block/vmdk: add coroutine_fn annotations Kevin Wolf
2022-12-14 13:44 ` [PULL 25/51] block: avoid duplicating filename string in bdrv_create Kevin Wolf
2022-12-14 13:44 ` [PULL 26/51] block: distinguish between bdrv_create running in coroutine and not Kevin Wolf
2022-12-14 13:44 ` [PULL 27/51] block: bdrv_create_file is a coroutine_fn Kevin Wolf
2022-12-14 13:44 ` [PULL 28/51] block: rename generated_co_wrapper in co_wrapper_mixed Kevin Wolf
2022-12-14 13:44 ` [PULL 29/51] block-coroutine-wrapper.py: introduce co_wrapper Kevin Wolf
2022-12-14 13:44 ` [PULL 30/51] block-coroutine-wrapper.py: support functions without bs arg Kevin Wolf
2022-12-14 13:44 ` [PULL 31/51] block-coroutine-wrapper.py: support also basic return types Kevin Wolf
2022-12-14 13:44 ` [PULL 32/51] block: convert bdrv_create to co_wrapper Kevin Wolf
2022-12-14 13:44 ` [PULL 33/51] block/dirty-bitmap: convert coroutine-only functions " Kevin Wolf
2022-12-14 13:44 ` [PULL 34/51] block: Factor out bdrv_drain_all_begin_nopoll() Kevin Wolf
2022-12-14 13:44 ` [PULL 35/51] graph-lock: Introduce a lock to protect block graph operations Kevin Wolf
2022-12-14 13:44 ` [PULL 36/51] graph-lock: Implement guard macros Kevin Wolf
2022-12-14 13:44 ` [PULL 37/51] async: Register/unregister aiocontext in graph lock list Kevin Wolf
2022-12-14 13:44 ` [PULL 38/51] Import clang-tsa.h Kevin Wolf
2022-12-14 13:44 ` [PULL 39/51] clang-tsa: Add TSA_ASSERT() macro Kevin Wolf
2022-12-14 13:44 ` [PULL 40/51] clang-tsa: Add macros for shared locks Kevin Wolf
2022-12-14 13:44 ` [PULL 41/51] configure: Enable -Wthread-safety if present Kevin Wolf
2022-12-14 13:44 ` [PULL 42/51] test-bdrv-drain: Fix incorrrect drain assumptions Kevin Wolf
2022-12-14 13:44 ` [PULL 43/51] block: Fix locking in external_snapshot_prepare() Kevin Wolf
2022-12-14 13:44 ` [PULL 44/51] block: wrlock in bdrv_replace_child_noperm Kevin Wolf
2022-12-14 13:44 ` [PULL 45/51] block: remove unnecessary assert_bdrv_graph_writable() Kevin Wolf
2022-12-14 13:44 ` [PULL 46/51] block: assert that graph read and writes are performed correctly Kevin Wolf
2022-12-14 13:44 ` [PULL 47/51] graph-lock: TSA annotations for lock/unlock functions Kevin Wolf
2022-12-14 13:44 ` [PULL 48/51] Mark assert_bdrv_graph_readable/writable() GRAPH_RD/WRLOCK Kevin Wolf
2022-12-14 13:44 ` [PULL 49/51] block-coroutine-wrapper.py: introduce annotations that take the graph rdlock Kevin Wolf
2022-12-14 13:44 ` [PULL 50/51] block: use co_wrapper_mixed_bdrv_rdlock in functions taking the rdlock Kevin Wolf
2022-12-14 13:44 ` [PULL 51/51] block: GRAPH_RDLOCK for functions only called by co_wrappers Kevin Wolf
2022-12-14 22:35 ` [PULL 00/51] Block layer patches Peter Maydell
2022-12-15 9:44 ` Kevin Wolf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20221214134453.31665-16-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).