7f1c5b
From 3009e49f242ab371ffad35bb29c2c26ddfac75d4 Mon Sep 17 00:00:00 2001
7f1c5b
From: Kevin Wolf <kwolf@redhat.com>
7f1c5b
Date: Fri, 18 Nov 2022 18:40:59 +0100
7f1c5b
Subject: [PATCH 17/31] block: Remove drained_end_counter
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: [5/16] 5589e3f05dece5394a05641f7f42096e8dc62bdb (sgarzarella/qemu-kvm-c-9-s)
7f1c5b
7f1c5b
drained_end_counter is unused now, nobody changes its value any more. It
7f1c5b
can be removed.
7f1c5b
7f1c5b
In cases where we had two almost identical functions that only differed
7f1c5b
in whether the caller passes drained_end_counter, or whether they would
7f1c5b
poll for a local drained_end_counter to reach 0, these become a single
7f1c5b
function.
7f1c5b
7f1c5b
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7f1c5b
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
7f1c5b
Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
7f1c5b
Message-Id: <20221118174110.55183-5-kwolf@redhat.com>
7f1c5b
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
7f1c5b
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7f1c5b
(cherry picked from commit 2f65df6e16dea2d6e7212fa675f4779d9281e26f)
7f1c5b
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
7f1c5b
---
7f1c5b
 block.c                          |  5 +-
7f1c5b
 block/block-backend.c            |  4 +-
7f1c5b
 block/io.c                       | 98 ++++++++------------------------
7f1c5b
 blockjob.c                       |  2 +-
7f1c5b
 include/block/block-io.h         | 24 --------
7f1c5b
 include/block/block_int-common.h |  6 +-
7f1c5b
 6 files changed, 30 insertions(+), 109 deletions(-)
7f1c5b
7f1c5b
diff --git a/block.c b/block.c
7f1c5b
index 16a62a329c..7999fd08c5 100644
7f1c5b
--- a/block.c
7f1c5b
+++ b/block.c
7f1c5b
@@ -1235,11 +1235,10 @@ static bool bdrv_child_cb_drained_poll(BdrvChild *child)
7f1c5b
     return bdrv_drain_poll(bs, false, NULL, false);
7f1c5b
 }
7f1c5b
 
7f1c5b
-static void bdrv_child_cb_drained_end(BdrvChild *child,
7f1c5b
-                                      int *drained_end_counter)
7f1c5b
+static void bdrv_child_cb_drained_end(BdrvChild *child)
7f1c5b
 {
7f1c5b
     BlockDriverState *bs = child->opaque;
7f1c5b
-    bdrv_drained_end_no_poll(bs, drained_end_counter);
7f1c5b
+    bdrv_drained_end(bs);
7f1c5b
 }
7f1c5b
 
7f1c5b
 static int bdrv_child_cb_inactivate(BdrvChild *child)
7f1c5b
diff --git a/block/block-backend.c b/block/block-backend.c
7f1c5b
index d98a96ff37..feaf2181fa 100644
7f1c5b
--- a/block/block-backend.c
7f1c5b
+++ b/block/block-backend.c
7f1c5b
@@ -129,7 +129,7 @@ static void blk_root_inherit_options(BdrvChildRole role, bool parent_is_format,
7f1c5b
 }
7f1c5b
 static void blk_root_drained_begin(BdrvChild *child);
7f1c5b
 static bool blk_root_drained_poll(BdrvChild *child);
7f1c5b
-static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter);
7f1c5b
+static void blk_root_drained_end(BdrvChild *child);
7f1c5b
 
7f1c5b
 static void blk_root_change_media(BdrvChild *child, bool load);
7f1c5b
 static void blk_root_resize(BdrvChild *child);
7f1c5b
@@ -2556,7 +2556,7 @@ static bool blk_root_drained_poll(BdrvChild *child)
7f1c5b
     return busy || !!blk->in_flight;
7f1c5b
 }
7f1c5b
 
7f1c5b
-static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter)
7f1c5b
+static void blk_root_drained_end(BdrvChild *child)
7f1c5b
 {
7f1c5b
     BlockBackend *blk = child->opaque;
7f1c5b
     assert(blk->quiesce_counter);
7f1c5b
diff --git a/block/io.c b/block/io.c
7f1c5b
index c2ed4b2af9..f4ca62b034 100644
7f1c5b
--- a/block/io.c
7f1c5b
+++ b/block/io.c
7f1c5b
@@ -58,28 +58,19 @@ static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
7f1c5b
     }
7f1c5b
 }
7f1c5b
 
7f1c5b
-static void bdrv_parent_drained_end_single_no_poll(BdrvChild *c,
7f1c5b
-                                                   int *drained_end_counter)
7f1c5b
+void bdrv_parent_drained_end_single(BdrvChild *c)
7f1c5b
 {
7f1c5b
+    IO_OR_GS_CODE();
7f1c5b
+
7f1c5b
     assert(c->parent_quiesce_counter > 0);
7f1c5b
     c->parent_quiesce_counter--;
7f1c5b
     if (c->klass->drained_end) {
7f1c5b
-        c->klass->drained_end(c, drained_end_counter);
7f1c5b
+        c->klass->drained_end(c);
7f1c5b
     }
7f1c5b
 }
7f1c5b
 
7f1c5b
-void bdrv_parent_drained_end_single(BdrvChild *c)
7f1c5b
-{
7f1c5b
-    int drained_end_counter = 0;
7f1c5b
-    AioContext *ctx = bdrv_child_get_parent_aio_context(c);
7f1c5b
-    IO_OR_GS_CODE();
7f1c5b
-    bdrv_parent_drained_end_single_no_poll(c, &drained_end_counter);
7f1c5b
-    AIO_WAIT_WHILE(ctx, qatomic_read(&drained_end_counter) > 0);
7f1c5b
-}
7f1c5b
-
7f1c5b
 static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
7f1c5b
-                                    bool ignore_bds_parents,
7f1c5b
-                                    int *drained_end_counter)
7f1c5b
+                                    bool ignore_bds_parents)
7f1c5b
 {
7f1c5b
     BdrvChild *c;
7f1c5b
 
7f1c5b
@@ -87,7 +78,7 @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
7f1c5b
         if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
7f1c5b
             continue;
7f1c5b
         }
7f1c5b
-        bdrv_parent_drained_end_single_no_poll(c, drained_end_counter);
7f1c5b
+        bdrv_parent_drained_end_single(c);
7f1c5b
     }
7f1c5b
 }
7f1c5b
 
7f1c5b
@@ -249,12 +240,10 @@ typedef struct {
7f1c5b
     bool poll;
7f1c5b
     BdrvChild *parent;
7f1c5b
     bool ignore_bds_parents;
7f1c5b
-    int *drained_end_counter;
7f1c5b
 } BdrvCoDrainData;
7f1c5b
 
7f1c5b
 /* Recursively call BlockDriver.bdrv_drain_begin/end callbacks */
7f1c5b
-static void bdrv_drain_invoke(BlockDriverState *bs, bool begin,
7f1c5b
-                              int *drained_end_counter)
7f1c5b
+static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
7f1c5b
 {
7f1c5b
     if (!bs->drv || (begin && !bs->drv->bdrv_drain_begin) ||
7f1c5b
             (!begin && !bs->drv->bdrv_drain_end)) {
7f1c5b
@@ -305,8 +294,7 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
7f1c5b
                                   BdrvChild *parent, bool ignore_bds_parents,
7f1c5b
                                   bool poll);
7f1c5b
 static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
7f1c5b
-                                BdrvChild *parent, bool ignore_bds_parents,
7f1c5b
-                                int *drained_end_counter);
7f1c5b
+                                BdrvChild *parent, bool ignore_bds_parents);
7f1c5b
 
7f1c5b
 static void bdrv_co_drain_bh_cb(void *opaque)
7f1c5b
 {
7f1c5b
@@ -319,14 +307,12 @@ static void bdrv_co_drain_bh_cb(void *opaque)
7f1c5b
         aio_context_acquire(ctx);
7f1c5b
         bdrv_dec_in_flight(bs);
7f1c5b
         if (data->begin) {
7f1c5b
-            assert(!data->drained_end_counter);
7f1c5b
             bdrv_do_drained_begin(bs, data->recursive, data->parent,
7f1c5b
                                   data->ignore_bds_parents, data->poll);
7f1c5b
         } else {
7f1c5b
             assert(!data->poll);
7f1c5b
             bdrv_do_drained_end(bs, data->recursive, data->parent,
7f1c5b
-                                data->ignore_bds_parents,
7f1c5b
-                                data->drained_end_counter);
7f1c5b
+                                data->ignore_bds_parents);
7f1c5b
         }
7f1c5b
         aio_context_release(ctx);
7f1c5b
     } else {
7f1c5b
@@ -342,8 +328,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
7f1c5b
                                                 bool begin, bool recursive,
7f1c5b
                                                 BdrvChild *parent,
7f1c5b
                                                 bool ignore_bds_parents,
7f1c5b
-                                                bool poll,
7f1c5b
-                                                int *drained_end_counter)
7f1c5b
+                                                bool poll)
7f1c5b
 {
7f1c5b
     BdrvCoDrainData data;
7f1c5b
     Coroutine *self = qemu_coroutine_self();
7f1c5b
@@ -363,7 +348,6 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
7f1c5b
         .parent = parent,
7f1c5b
         .ignore_bds_parents = ignore_bds_parents,
7f1c5b
         .poll = poll,
7f1c5b
-        .drained_end_counter = drained_end_counter,
7f1c5b
     };
7f1c5b
 
7f1c5b
     if (bs) {
7f1c5b
@@ -406,7 +390,7 @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
7f1c5b
     }
7f1c5b
 
7f1c5b
     bdrv_parent_drained_begin(bs, parent, ignore_bds_parents);
7f1c5b
-    bdrv_drain_invoke(bs, true, NULL);
7f1c5b
+    bdrv_drain_invoke(bs, true);
7f1c5b
 }
7f1c5b
 
7f1c5b
 static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
7f1c5b
@@ -417,7 +401,7 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
7f1c5b
 
7f1c5b
     if (qemu_in_coroutine()) {
7f1c5b
         bdrv_co_yield_to_drain(bs, true, recursive, parent, ignore_bds_parents,
7f1c5b
-                               poll, NULL);
7f1c5b
+                               poll);
7f1c5b
         return;
7f1c5b
     }
7f1c5b
 
7f1c5b
@@ -461,38 +445,24 @@ void bdrv_subtree_drained_begin(BlockDriverState *bs)
7f1c5b
 
7f1c5b
 /**
7f1c5b
  * This function does not poll, nor must any of its recursively called
7f1c5b
- * functions.  The *drained_end_counter pointee will be incremented
7f1c5b
- * once for every background operation scheduled, and decremented once
7f1c5b
- * the operation settles.  Therefore, the pointer must remain valid
7f1c5b
- * until the pointee reaches 0.  That implies that whoever sets up the
7f1c5b
- * pointee has to poll until it is 0.
7f1c5b
- *
7f1c5b
- * We use atomic operations to access *drained_end_counter, because
7f1c5b
- * (1) when called from bdrv_set_aio_context_ignore(), the subgraph of
7f1c5b
- *     @bs may contain nodes in different AioContexts,
7f1c5b
- * (2) bdrv_drain_all_end() uses the same counter for all nodes,
7f1c5b
- *     regardless of which AioContext they are in.
7f1c5b
+ * functions.
7f1c5b
  */
7f1c5b
 static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
7f1c5b
-                                BdrvChild *parent, bool ignore_bds_parents,
7f1c5b
-                                int *drained_end_counter)
7f1c5b
+                                BdrvChild *parent, bool ignore_bds_parents)
7f1c5b
 {
7f1c5b
     BdrvChild *child;
7f1c5b
     int old_quiesce_counter;
7f1c5b
 
7f1c5b
-    assert(drained_end_counter != NULL);
7f1c5b
-
7f1c5b
     if (qemu_in_coroutine()) {
7f1c5b
         bdrv_co_yield_to_drain(bs, false, recursive, parent, ignore_bds_parents,
7f1c5b
-                               false, drained_end_counter);
7f1c5b
+                               false);
7f1c5b
         return;
7f1c5b
     }
7f1c5b
     assert(bs->quiesce_counter > 0);
7f1c5b
 
7f1c5b
     /* Re-enable things in child-to-parent order */
7f1c5b
-    bdrv_drain_invoke(bs, false, drained_end_counter);
7f1c5b
-    bdrv_parent_drained_end(bs, parent, ignore_bds_parents,
7f1c5b
-                            drained_end_counter);
7f1c5b
+    bdrv_drain_invoke(bs, false);
7f1c5b
+    bdrv_parent_drained_end(bs, parent, ignore_bds_parents);
7f1c5b
 
7f1c5b
     old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
7f1c5b
     if (old_quiesce_counter == 1) {
7f1c5b
@@ -503,32 +473,21 @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
7f1c5b
         assert(!ignore_bds_parents);
7f1c5b
         bs->recursive_quiesce_counter--;
7f1c5b
         QLIST_FOREACH(child, &bs->children, next) {
7f1c5b
-            bdrv_do_drained_end(child->bs, true, child, ignore_bds_parents,
7f1c5b
-                                drained_end_counter);
7f1c5b
+            bdrv_do_drained_end(child->bs, true, child, ignore_bds_parents);
7f1c5b
         }
7f1c5b
     }
7f1c5b
 }
7f1c5b
 
7f1c5b
 void bdrv_drained_end(BlockDriverState *bs)
7f1c5b
 {
7f1c5b
-    int drained_end_counter = 0;
7f1c5b
     IO_OR_GS_CODE();
7f1c5b
-    bdrv_do_drained_end(bs, false, NULL, false, &drained_end_counter);
7f1c5b
-    BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0);
7f1c5b
-}
7f1c5b
-
7f1c5b
-void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter)
7f1c5b
-{
7f1c5b
-    IO_CODE();
7f1c5b
-    bdrv_do_drained_end(bs, false, NULL, false, drained_end_counter);
7f1c5b
+    bdrv_do_drained_end(bs, false, NULL, false);
7f1c5b
 }
7f1c5b
 
7f1c5b
 void bdrv_subtree_drained_end(BlockDriverState *bs)
7f1c5b
 {
7f1c5b
-    int drained_end_counter = 0;
7f1c5b
     IO_OR_GS_CODE();
7f1c5b
-    bdrv_do_drained_end(bs, true, NULL, false, &drained_end_counter);
7f1c5b
-    BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0);
7f1c5b
+    bdrv_do_drained_end(bs, true, NULL, false);
7f1c5b
 }
7f1c5b
 
7f1c5b
 void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
7f1c5b
@@ -543,16 +502,12 @@ void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
7f1c5b
 
7f1c5b
 void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
7f1c5b
 {
7f1c5b
-    int drained_end_counter = 0;
7f1c5b
     int i;
7f1c5b
     IO_OR_GS_CODE();
7f1c5b
 
7f1c5b
     for (i = 0; i < old_parent->recursive_quiesce_counter; i++) {
7f1c5b
-        bdrv_do_drained_end(child->bs, true, child, false,
7f1c5b
-                            &drained_end_counter);
7f1c5b
+        bdrv_do_drained_end(child->bs, true, child, false);
7f1c5b
     }
7f1c5b
-
7f1c5b
-    BDRV_POLL_WHILE(child->bs, qatomic_read(&drained_end_counter) > 0);
7f1c5b
 }
7f1c5b
 
7f1c5b
 void bdrv_drain(BlockDriverState *bs)
7f1c5b
@@ -610,7 +565,7 @@ void bdrv_drain_all_begin(void)
7f1c5b
     GLOBAL_STATE_CODE();
7f1c5b
 
7f1c5b
     if (qemu_in_coroutine()) {
7f1c5b
-        bdrv_co_yield_to_drain(NULL, true, false, NULL, true, true, NULL);
7f1c5b
+        bdrv_co_yield_to_drain(NULL, true, false, NULL, true, true);
7f1c5b
         return;
7f1c5b
     }
7f1c5b
 
7f1c5b
@@ -649,22 +604,19 @@ void bdrv_drain_all_begin(void)
7f1c5b
 
7f1c5b
 void bdrv_drain_all_end_quiesce(BlockDriverState *bs)
7f1c5b
 {
7f1c5b
-    int drained_end_counter = 0;
7f1c5b
     GLOBAL_STATE_CODE();
7f1c5b
 
7f1c5b
     g_assert(bs->quiesce_counter > 0);
7f1c5b
     g_assert(!bs->refcnt);
7f1c5b
 
7f1c5b
     while (bs->quiesce_counter) {
7f1c5b
-        bdrv_do_drained_end(bs, false, NULL, true, &drained_end_counter);
7f1c5b
+        bdrv_do_drained_end(bs, false, NULL, true);
7f1c5b
     }
7f1c5b
-    BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0);
7f1c5b
 }
7f1c5b
 
7f1c5b
 void bdrv_drain_all_end(void)
7f1c5b
 {
7f1c5b
     BlockDriverState *bs = NULL;
7f1c5b
-    int drained_end_counter = 0;
7f1c5b
     GLOBAL_STATE_CODE();
7f1c5b
 
7f1c5b
     /*
7f1c5b
@@ -680,13 +632,11 @@ void bdrv_drain_all_end(void)
7f1c5b
         AioContext *aio_context = bdrv_get_aio_context(bs);
7f1c5b
 
7f1c5b
         aio_context_acquire(aio_context);
7f1c5b
-        bdrv_do_drained_end(bs, false, NULL, true, &drained_end_counter);
7f1c5b
+        bdrv_do_drained_end(bs, false, NULL, true);
7f1c5b
         aio_context_release(aio_context);
7f1c5b
     }
7f1c5b
 
7f1c5b
     assert(qemu_get_current_aio_context() == qemu_get_aio_context());
7f1c5b
-    AIO_WAIT_WHILE(NULL, qatomic_read(&drained_end_counter) > 0);
7f1c5b
-
7f1c5b
     assert(bdrv_drain_all_count > 0);
7f1c5b
     bdrv_drain_all_count--;
7f1c5b
 }
7f1c5b
diff --git a/blockjob.c b/blockjob.c
7f1c5b
index f51d4e18f3..0ab721e139 100644
7f1c5b
--- a/blockjob.c
7f1c5b
+++ b/blockjob.c
7f1c5b
@@ -120,7 +120,7 @@ static bool child_job_drained_poll(BdrvChild *c)
7f1c5b
     }
7f1c5b
 }
7f1c5b
 
7f1c5b
-static void child_job_drained_end(BdrvChild *c, int *drained_end_counter)
7f1c5b
+static void child_job_drained_end(BdrvChild *c)
7f1c5b
 {
7f1c5b
     BlockJob *job = c->opaque;
7f1c5b
     job_resume(&job->job);
7f1c5b
diff --git a/include/block/block-io.h b/include/block/block-io.h
7f1c5b
index b099d7db45..054e964c9b 100644
7f1c5b
--- a/include/block/block-io.h
7f1c5b
+++ b/include/block/block-io.h
7f1c5b
@@ -237,21 +237,6 @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
7f1c5b
                                     int64_t bytes, BdrvRequestFlags read_flags,
7f1c5b
                                     BdrvRequestFlags write_flags);
7f1c5b
 
7f1c5b
-/**
7f1c5b
- * bdrv_drained_end_no_poll:
7f1c5b
- *
7f1c5b
- * Same as bdrv_drained_end(), but do not poll for the subgraph to
7f1c5b
- * actually become unquiesced.  Therefore, no graph changes will occur
7f1c5b
- * with this function.
7f1c5b
- *
7f1c5b
- * *drained_end_counter is incremented for every background operation
7f1c5b
- * that is scheduled, and will be decremented for every operation once
7f1c5b
- * it settles.  The caller must poll until it reaches 0.  The counter
7f1c5b
- * should be accessed using atomic operations only.
7f1c5b
- */
7f1c5b
-void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter);
7f1c5b
-
7f1c5b
-
7f1c5b
 /*
7f1c5b
  * "I/O or GS" API functions. These functions can run without
7f1c5b
  * the BQL, but only in one specific iothread/main loop.
7f1c5b
@@ -311,9 +296,6 @@ void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll);
7f1c5b
  * bdrv_parent_drained_end_single:
7f1c5b
  *
7f1c5b
  * End a quiesced section for the parent of @c.
7f1c5b
- *
7f1c5b
- * This polls @bs's AioContext until all scheduled sub-drained_ends
7f1c5b
- * have settled, which may result in graph changes.
7f1c5b
  */
7f1c5b
 void bdrv_parent_drained_end_single(BdrvChild *c);
7f1c5b
 
7f1c5b
@@ -361,12 +343,6 @@ void bdrv_subtree_drained_begin(BlockDriverState *bs);
7f1c5b
  * bdrv_drained_end:
7f1c5b
  *
7f1c5b
  * End a quiescent section started by bdrv_drained_begin().
7f1c5b
- *
7f1c5b
- * This polls @bs's AioContext until all scheduled sub-drained_ends
7f1c5b
- * have settled.  On one hand, that may result in graph changes.  On
7f1c5b
- * the other, this requires that the caller either runs in the main
7f1c5b
- * loop; or that all involved nodes (@bs and all of its parents) are
7f1c5b
- * in the caller's AioContext.
7f1c5b
  */
7f1c5b
 void bdrv_drained_end(BlockDriverState *bs);
7f1c5b
 
7f1c5b
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
7f1c5b
index 40d646d1ed..2b97576f6d 100644
7f1c5b
--- a/include/block/block_int-common.h
7f1c5b
+++ b/include/block/block_int-common.h
7f1c5b
@@ -939,15 +939,11 @@ struct BdrvChildClass {
7f1c5b
      * These functions must not change the graph (and therefore also must not
7f1c5b
      * call aio_poll(), which could change the graph indirectly).
7f1c5b
      *
7f1c5b
-     * If drained_end() schedules background operations, it must atomically
7f1c5b
-     * increment *drained_end_counter for each such operation and atomically
7f1c5b
-     * decrement it once the operation has settled.
7f1c5b
-     *
7f1c5b
      * Note that this can be nested. If drained_begin() was called twice, new
7f1c5b
      * I/O is allowed only after drained_end() was called twice, too.
7f1c5b
      */
7f1c5b
     void (*drained_begin)(BdrvChild *child);
7f1c5b
-    void (*drained_end)(BdrvChild *child, int *drained_end_counter);
7f1c5b
+    void (*drained_end)(BdrvChild *child);
7f1c5b
 
7f1c5b
     /*
7f1c5b
      * Returns whether the parent has pending requests for the child. This
7f1c5b
-- 
7f1c5b
2.31.1
7f1c5b