diff options
-rw-r--r-- | block.c | 9 | ||||
-rw-r--r-- | block/io.c | 13 | ||||
-rw-r--r-- | include/block/block.h | 6 | ||||
-rw-r--r-- | tests/test-bdrv-drain.c | 1 |
4 files changed, 29 insertions, 0 deletions
@@ -4458,6 +4458,15 @@ static void bdrv_close(BlockDriverState *bs) } QLIST_INIT(&bs->aio_notifiers); bdrv_drained_end(bs); + + /* + * If we're still inside some bdrv_drain_all_begin()/end() sections, end + * them now since this BDS won't exist anymore when bdrv_drain_all_end() + * gets called. + */ + if (bs->quiesce_counter) { + bdrv_drain_all_end_quiesce(bs); + } } void bdrv_close_all(void) @@ -633,6 +633,19 @@ void bdrv_drain_all_begin(void) } } +void bdrv_drain_all_end_quiesce(BlockDriverState *bs) +{ + int drained_end_counter = 0; + + g_assert(bs->quiesce_counter > 0); + g_assert(!bs->refcnt); + + while (bs->quiesce_counter) { + bdrv_do_drained_end(bs, false, NULL, true, &drained_end_counter); + } + BDRV_POLL_WHILE(bs, qatomic_read(&drained_end_counter) > 0); +} + void bdrv_drain_all_end(void) { BlockDriverState *bs = NULL; diff --git a/include/block/block.h b/include/block/block.h index c9d7c58..4bfe3b5 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -782,6 +782,12 @@ void bdrv_drained_end(BlockDriverState *bs); void bdrv_drained_end_no_poll(BlockDriverState *bs, int *drained_end_counter); /** + * End all quiescent sections started by bdrv_drain_all_begin(). This is + * only needed when deleting a BDS before bdrv_drain_all_end() is called. + */ +void bdrv_drain_all_end_quiesce(BlockDriverState *bs); + +/** * End a quiescent section started by bdrv_subtree_drained_begin(). */ void bdrv_subtree_drained_end(BlockDriverState *bs); diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 1595bbc..8a29e33 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -594,6 +594,7 @@ static void test_graph_change_drain_all(void) g_assert_cmpint(bs_b->quiesce_counter, ==, 0); g_assert_cmpint(b_s->drain_count, ==, 0); + g_assert_cmpint(qemu_get_aio_context()->external_disable_cnt, ==, 0); bdrv_unref(bs_b); blk_unref(blk_b); |