block: Remove subtree drains

Subtree drains are not used any more. Remove them.

After this, BdrvChildClass.attach/detach() don't poll any more.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
Message-Id: <20221118174110.55183-11-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Kevin Wolf 2022-11-18 18:41:05 +01:00
parent 92140b9f3f
commit 299403aeda
6 changed files with 44 additions and 389 deletions

20
block.c
View File

@ -1232,7 +1232,7 @@ static void bdrv_child_cb_drained_begin(BdrvChild *child)
static bool bdrv_child_cb_drained_poll(BdrvChild *child) static bool bdrv_child_cb_drained_poll(BdrvChild *child)
{ {
BlockDriverState *bs = child->opaque; BlockDriverState *bs = child->opaque;
return bdrv_drain_poll(bs, false, NULL, false); return bdrv_drain_poll(bs, NULL, false);
} }
static void bdrv_child_cb_drained_end(BdrvChild *child) static void bdrv_child_cb_drained_end(BdrvChild *child)
@ -1482,8 +1482,6 @@ static void bdrv_child_cb_attach(BdrvChild *child)
assert(!bs->file); assert(!bs->file);
bs->file = child; bs->file = child;
} }
bdrv_apply_subtree_drain(child, bs);
} }
static void bdrv_child_cb_detach(BdrvChild *child) static void bdrv_child_cb_detach(BdrvChild *child)
@ -1494,8 +1492,6 @@ static void bdrv_child_cb_detach(BdrvChild *child)
bdrv_backing_detach(child); bdrv_backing_detach(child);
} }
bdrv_unapply_subtree_drain(child, bs);
assert_bdrv_graph_writable(bs); assert_bdrv_graph_writable(bs);
QLIST_REMOVE(child, next); QLIST_REMOVE(child, next);
if (child == bs->backing) { if (child == bs->backing) {
@ -2882,9 +2878,6 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
} }
if (old_bs) { if (old_bs) {
/* Detach first so that the recursive drain sections coming from @child
* are already gone and we only end the drain sections that came from
* elsewhere. */
if (child->klass->detach) { if (child->klass->detach) {
child->klass->detach(child); child->klass->detach(child);
} }
@ -2899,17 +2892,14 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent); QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
/* /*
* Detaching the old node may have led to the new node's * Polling in bdrv_parent_drained_begin_single() may have led to the new
* quiesce_counter having been decreased. Not a problem, we * node's quiesce_counter having been decreased. Not a problem, we just
* just need to recognize this here and then invoke * need to recognize this here and then invoke drained_end appropriately
* drained_end appropriately more often. * more often.
*/ */
assert(new_bs->quiesce_counter <= new_bs_quiesce_counter); assert(new_bs->quiesce_counter <= new_bs_quiesce_counter);
drain_saldo += new_bs->quiesce_counter - new_bs_quiesce_counter; drain_saldo += new_bs->quiesce_counter - new_bs_quiesce_counter;
/* Attach only after starting new drained sections, so that recursive
* drain sections coming from @child don't get an extra .drained_begin
* callback. */
if (child->klass->attach) { if (child->klass->attach) {
child->klass->attach(child); child->klass->attach(child);
} }

View File

@ -236,17 +236,15 @@ typedef struct {
BlockDriverState *bs; BlockDriverState *bs;
bool done; bool done;
bool begin; bool begin;
bool recursive;
bool poll; bool poll;
BdrvChild *parent; BdrvChild *parent;
bool ignore_bds_parents; bool ignore_bds_parents;
} BdrvCoDrainData; } BdrvCoDrainData;
/* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */ /* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */
bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
BdrvChild *ignore_parent, bool ignore_bds_parents) bool ignore_bds_parents)
{ {
BdrvChild *child, *next;
IO_OR_GS_CODE(); IO_OR_GS_CODE();
if (bdrv_parent_drained_poll(bs, ignore_parent, ignore_bds_parents)) { if (bdrv_parent_drained_poll(bs, ignore_parent, ignore_bds_parents)) {
@ -257,29 +255,19 @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive,
return true; return true;
} }
if (recursive) {
assert(!ignore_bds_parents);
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
if (bdrv_drain_poll(child->bs, recursive, child, false)) {
return true;
}
}
}
return false; return false;
} }
static bool bdrv_drain_poll_top_level(BlockDriverState *bs, bool recursive, static bool bdrv_drain_poll_top_level(BlockDriverState *bs,
BdrvChild *ignore_parent) BdrvChild *ignore_parent)
{ {
return bdrv_drain_poll(bs, recursive, ignore_parent, false); return bdrv_drain_poll(bs, ignore_parent, false);
} }
static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
BdrvChild *parent, bool ignore_bds_parents, bool ignore_bds_parents, bool poll);
bool poll); static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent,
static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, bool ignore_bds_parents);
BdrvChild *parent, bool ignore_bds_parents);
static void bdrv_co_drain_bh_cb(void *opaque) static void bdrv_co_drain_bh_cb(void *opaque)
{ {
@ -292,12 +280,11 @@ static void bdrv_co_drain_bh_cb(void *opaque)
aio_context_acquire(ctx); aio_context_acquire(ctx);
bdrv_dec_in_flight(bs); bdrv_dec_in_flight(bs);
if (data->begin) { if (data->begin) {
bdrv_do_drained_begin(bs, data->recursive, data->parent, bdrv_do_drained_begin(bs, data->parent, data->ignore_bds_parents,
data->ignore_bds_parents, data->poll); data->poll);
} else { } else {
assert(!data->poll); assert(!data->poll);
bdrv_do_drained_end(bs, data->recursive, data->parent, bdrv_do_drained_end(bs, data->parent, data->ignore_bds_parents);
data->ignore_bds_parents);
} }
aio_context_release(ctx); aio_context_release(ctx);
} else { } else {
@ -310,7 +297,7 @@ static void bdrv_co_drain_bh_cb(void *opaque)
} }
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
bool begin, bool recursive, bool begin,
BdrvChild *parent, BdrvChild *parent,
bool ignore_bds_parents, bool ignore_bds_parents,
bool poll) bool poll)
@ -329,7 +316,6 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
.bs = bs, .bs = bs,
.done = false, .done = false,
.begin = begin, .begin = begin,
.recursive = recursive,
.parent = parent, .parent = parent,
.ignore_bds_parents = ignore_bds_parents, .ignore_bds_parents = ignore_bds_parents,
.poll = poll, .poll = poll,
@ -380,29 +366,16 @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
} }
} }
static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
BdrvChild *parent, bool ignore_bds_parents, bool ignore_bds_parents, bool poll)
bool poll)
{ {
BdrvChild *child, *next;
if (qemu_in_coroutine()) { if (qemu_in_coroutine()) {
bdrv_co_yield_to_drain(bs, true, recursive, parent, ignore_bds_parents, bdrv_co_yield_to_drain(bs, true, parent, ignore_bds_parents, poll);
poll);
return; return;
} }
bdrv_do_drained_begin_quiesce(bs, parent, ignore_bds_parents); bdrv_do_drained_begin_quiesce(bs, parent, ignore_bds_parents);
if (recursive) {
assert(!ignore_bds_parents);
bs->recursive_quiesce_counter++;
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
bdrv_do_drained_begin(child->bs, true, child, ignore_bds_parents,
false);
}
}
/* /*
* Wait for drained requests to finish. * Wait for drained requests to finish.
* *
@ -414,35 +387,27 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
*/ */
if (poll) { if (poll) {
assert(!ignore_bds_parents); assert(!ignore_bds_parents);
BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, recursive, parent)); BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, parent));
} }
} }
void bdrv_drained_begin(BlockDriverState *bs) void bdrv_drained_begin(BlockDriverState *bs)
{ {
IO_OR_GS_CODE(); IO_OR_GS_CODE();
bdrv_do_drained_begin(bs, false, NULL, false, true); bdrv_do_drained_begin(bs, NULL, false, true);
}
void bdrv_subtree_drained_begin(BlockDriverState *bs)
{
IO_OR_GS_CODE();
bdrv_do_drained_begin(bs, true, NULL, false, true);
} }
/** /**
* This function does not poll, nor must any of its recursively called * This function does not poll, nor must any of its recursively called
* functions. * functions.
*/ */
static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent,
BdrvChild *parent, bool ignore_bds_parents) bool ignore_bds_parents)
{ {
BdrvChild *child;
int old_quiesce_counter; int old_quiesce_counter;
if (qemu_in_coroutine()) { if (qemu_in_coroutine()) {
bdrv_co_yield_to_drain(bs, false, recursive, parent, ignore_bds_parents, bdrv_co_yield_to_drain(bs, false, parent, ignore_bds_parents, false);
false);
return; return;
} }
assert(bs->quiesce_counter > 0); assert(bs->quiesce_counter > 0);
@ -457,46 +422,12 @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive,
if (old_quiesce_counter == 1) { if (old_quiesce_counter == 1) {
aio_enable_external(bdrv_get_aio_context(bs)); aio_enable_external(bdrv_get_aio_context(bs));
} }
if (recursive) {
assert(!ignore_bds_parents);
bs->recursive_quiesce_counter--;
QLIST_FOREACH(child, &bs->children, next) {
bdrv_do_drained_end(child->bs, true, child, ignore_bds_parents);
}
}
} }
void bdrv_drained_end(BlockDriverState *bs) void bdrv_drained_end(BlockDriverState *bs)
{ {
IO_OR_GS_CODE(); IO_OR_GS_CODE();
bdrv_do_drained_end(bs, false, NULL, false); bdrv_do_drained_end(bs, NULL, false);
}
void bdrv_subtree_drained_end(BlockDriverState *bs)
{
IO_OR_GS_CODE();
bdrv_do_drained_end(bs, true, NULL, false);
}
void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent)
{
int i;
IO_OR_GS_CODE();
for (i = 0; i < new_parent->recursive_quiesce_counter; i++) {
bdrv_do_drained_begin(child->bs, true, child, false, true);
}
}
void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent)
{
int i;
IO_OR_GS_CODE();
for (i = 0; i < old_parent->recursive_quiesce_counter; i++) {
bdrv_do_drained_end(child->bs, true, child, false);
}
} }
void bdrv_drain(BlockDriverState *bs) void bdrv_drain(BlockDriverState *bs)
@ -529,7 +460,7 @@ static bool bdrv_drain_all_poll(void)
while ((bs = bdrv_next_all_states(bs))) { while ((bs = bdrv_next_all_states(bs))) {
AioContext *aio_context = bdrv_get_aio_context(bs); AioContext *aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
result |= bdrv_drain_poll(bs, false, NULL, true); result |= bdrv_drain_poll(bs, NULL, true);
aio_context_release(aio_context); aio_context_release(aio_context);
} }
@ -554,7 +485,7 @@ void bdrv_drain_all_begin(void)
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
if (qemu_in_coroutine()) { if (qemu_in_coroutine()) {
bdrv_co_yield_to_drain(NULL, true, false, NULL, true, true); bdrv_co_yield_to_drain(NULL, true, NULL, true, true);
return; return;
} }
@ -579,7 +510,7 @@ void bdrv_drain_all_begin(void)
AioContext *aio_context = bdrv_get_aio_context(bs); AioContext *aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
bdrv_do_drained_begin(bs, false, NULL, true, false); bdrv_do_drained_begin(bs, NULL, true, false);
aio_context_release(aio_context); aio_context_release(aio_context);
} }
@ -599,7 +530,7 @@ void bdrv_drain_all_end_quiesce(BlockDriverState *bs)
g_assert(!bs->refcnt); g_assert(!bs->refcnt);
while (bs->quiesce_counter) { while (bs->quiesce_counter) {
bdrv_do_drained_end(bs, false, NULL, true); bdrv_do_drained_end(bs, NULL, true);
} }
} }
@ -621,7 +552,7 @@ void bdrv_drain_all_end(void)
AioContext *aio_context = bdrv_get_aio_context(bs); AioContext *aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
bdrv_do_drained_end(bs, false, NULL, true); bdrv_do_drained_end(bs, NULL, true);
aio_context_release(aio_context); aio_context_release(aio_context);
} }

View File

@ -302,8 +302,7 @@ void bdrv_parent_drained_end_single(BdrvChild *c);
/** /**
* bdrv_drain_poll: * bdrv_drain_poll:
* *
* Poll for pending requests in @bs, its parents (except for @ignore_parent), * Poll for pending requests in @bs and its parents (except for @ignore_parent).
* and if @recursive is true its children as well (used for subtree drain).
* *
* If @ignore_bds_parents is true, parents that are BlockDriverStates must * If @ignore_bds_parents is true, parents that are BlockDriverStates must
* ignore the drain request because they will be drained separately (used for * ignore the drain request because they will be drained separately (used for
@ -311,8 +310,8 @@ void bdrv_parent_drained_end_single(BdrvChild *c);
* *
* This is part of bdrv_drained_begin. * This is part of bdrv_drained_begin.
*/ */
bool bdrv_drain_poll(BlockDriverState *bs, bool recursive, bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
BdrvChild *ignore_parent, bool ignore_bds_parents); bool ignore_bds_parents);
/** /**
* bdrv_drained_begin: * bdrv_drained_begin:
@ -333,12 +332,6 @@ void bdrv_drained_begin(BlockDriverState *bs);
void bdrv_do_drained_begin_quiesce(BlockDriverState *bs, void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
BdrvChild *parent, bool ignore_bds_parents); BdrvChild *parent, bool ignore_bds_parents);
/**
* Like bdrv_drained_begin, but recursively begins a quiesced section for
* exclusive access to all child nodes as well.
*/
void bdrv_subtree_drained_begin(BlockDriverState *bs);
/** /**
* bdrv_drained_end: * bdrv_drained_end:
* *
@ -346,9 +339,4 @@ void bdrv_subtree_drained_begin(BlockDriverState *bs);
*/ */
void bdrv_drained_end(BlockDriverState *bs); void bdrv_drained_end(BlockDriverState *bs);
/**
* End a quiescent section started by bdrv_subtree_drained_begin().
*/
void bdrv_subtree_drained_end(BlockDriverState *bs);
#endif /* BLOCK_IO_H */ #endif /* BLOCK_IO_H */

View File

@ -1184,7 +1184,6 @@ struct BlockDriverState {
/* Accessed with atomic ops. */ /* Accessed with atomic ops. */
int quiesce_counter; int quiesce_counter;
int recursive_quiesce_counter;
unsigned int write_gen; /* Current data generation */ unsigned int write_gen; /* Current data generation */

View File

@ -179,16 +179,4 @@ void bdrv_bsc_invalidate_range(BlockDriverState *bs,
*/ */
void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes); void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes);
/*
* "I/O or GS" API functions. These functions can run without
* the BQL, but only in one specific iothread/main loop.
*
* See include/block/block-io.h for more information about
* the "I/O or GS" API.
*/
void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent);
void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent);
#endif /* BLOCK_INT_IO_H */ #endif /* BLOCK_INT_IO_H */

View File

@ -156,7 +156,6 @@ static void call_in_coroutine(void (*entry)(void))
enum drain_type { enum drain_type {
BDRV_DRAIN_ALL, BDRV_DRAIN_ALL,
BDRV_DRAIN, BDRV_DRAIN,
BDRV_SUBTREE_DRAIN,
DRAIN_TYPE_MAX, DRAIN_TYPE_MAX,
}; };
@ -165,7 +164,6 @@ static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs)
switch (drain_type) { switch (drain_type) {
case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break; case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break;
case BDRV_DRAIN: bdrv_drained_begin(bs); break; case BDRV_DRAIN: bdrv_drained_begin(bs); break;
case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break;
default: g_assert_not_reached(); default: g_assert_not_reached();
} }
} }
@ -175,7 +173,6 @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs)
switch (drain_type) { switch (drain_type) {
case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break; case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break;
case BDRV_DRAIN: bdrv_drained_end(bs); break; case BDRV_DRAIN: bdrv_drained_end(bs); break;
case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break;
default: g_assert_not_reached(); default: g_assert_not_reached();
} }
} }
@ -271,11 +268,6 @@ static void test_drv_cb_drain(void)
test_drv_cb_common(BDRV_DRAIN, false); test_drv_cb_common(BDRV_DRAIN, false);
} }
static void test_drv_cb_drain_subtree(void)
{
test_drv_cb_common(BDRV_SUBTREE_DRAIN, true);
}
static void test_drv_cb_co_drain_all(void) static void test_drv_cb_co_drain_all(void)
{ {
call_in_coroutine(test_drv_cb_drain_all); call_in_coroutine(test_drv_cb_drain_all);
@ -286,11 +278,6 @@ static void test_drv_cb_co_drain(void)
call_in_coroutine(test_drv_cb_drain); call_in_coroutine(test_drv_cb_drain);
} }
static void test_drv_cb_co_drain_subtree(void)
{
call_in_coroutine(test_drv_cb_drain_subtree);
}
static void test_quiesce_common(enum drain_type drain_type, bool recursive) static void test_quiesce_common(enum drain_type drain_type, bool recursive)
{ {
BlockBackend *blk; BlockBackend *blk;
@ -332,11 +319,6 @@ static void test_quiesce_drain(void)
test_quiesce_common(BDRV_DRAIN, false); test_quiesce_common(BDRV_DRAIN, false);
} }
static void test_quiesce_drain_subtree(void)
{
test_quiesce_common(BDRV_SUBTREE_DRAIN, true);
}
static void test_quiesce_co_drain_all(void) static void test_quiesce_co_drain_all(void)
{ {
call_in_coroutine(test_quiesce_drain_all); call_in_coroutine(test_quiesce_drain_all);
@ -347,11 +329,6 @@ static void test_quiesce_co_drain(void)
call_in_coroutine(test_quiesce_drain); call_in_coroutine(test_quiesce_drain);
} }
static void test_quiesce_co_drain_subtree(void)
{
call_in_coroutine(test_quiesce_drain_subtree);
}
static void test_nested(void) static void test_nested(void)
{ {
BlockBackend *blk; BlockBackend *blk;
@ -402,158 +379,6 @@ static void test_nested(void)
blk_unref(blk); blk_unref(blk);
} }
static void test_multiparent(void)
{
BlockBackend *blk_a, *blk_b;
BlockDriverState *bs_a, *bs_b, *backing;
BDRVTestState *a_s, *b_s, *backing_s;
blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
&error_abort);
a_s = bs_a->opaque;
blk_insert_bs(blk_a, bs_a, &error_abort);
blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
&error_abort);
b_s = bs_b->opaque;
blk_insert_bs(blk_b, bs_b, &error_abort);
backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
backing_s = backing->opaque;
bdrv_set_backing_hd(bs_a, backing, &error_abort);
bdrv_set_backing_hd(bs_b, backing, &error_abort);
g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
g_assert_cmpint(backing->quiesce_counter, ==, 0);
g_assert_cmpint(a_s->drain_count, ==, 0);
g_assert_cmpint(b_s->drain_count, ==, 0);
g_assert_cmpint(backing_s->drain_count, ==, 0);
do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
g_assert_cmpint(backing->quiesce_counter, ==, 1);
g_assert_cmpint(a_s->drain_count, ==, 1);
g_assert_cmpint(b_s->drain_count, ==, 1);
g_assert_cmpint(backing_s->drain_count, ==, 1);
do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
g_assert_cmpint(bs_a->quiesce_counter, ==, 2);
g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
g_assert_cmpint(backing->quiesce_counter, ==, 2);
g_assert_cmpint(a_s->drain_count, ==, 2);
g_assert_cmpint(b_s->drain_count, ==, 2);
g_assert_cmpint(backing_s->drain_count, ==, 2);
do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
g_assert_cmpint(bs_a->quiesce_counter, ==, 1);
g_assert_cmpint(bs_b->quiesce_counter, ==, 1);
g_assert_cmpint(backing->quiesce_counter, ==, 1);
g_assert_cmpint(a_s->drain_count, ==, 1);
g_assert_cmpint(b_s->drain_count, ==, 1);
g_assert_cmpint(backing_s->drain_count, ==, 1);
do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
g_assert_cmpint(backing->quiesce_counter, ==, 0);
g_assert_cmpint(a_s->drain_count, ==, 0);
g_assert_cmpint(b_s->drain_count, ==, 0);
g_assert_cmpint(backing_s->drain_count, ==, 0);
bdrv_unref(backing);
bdrv_unref(bs_a);
bdrv_unref(bs_b);
blk_unref(blk_a);
blk_unref(blk_b);
}
static void test_graph_change_drain_subtree(void)
{
BlockBackend *blk_a, *blk_b;
BlockDriverState *bs_a, *bs_b, *backing;
BDRVTestState *a_s, *b_s, *backing_s;
blk_a = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR,
&error_abort);
a_s = bs_a->opaque;
blk_insert_bs(blk_a, bs_a, &error_abort);
blk_b = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR,
&error_abort);
b_s = bs_b->opaque;
blk_insert_bs(blk_b, bs_b, &error_abort);
backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
backing_s = backing->opaque;
bdrv_set_backing_hd(bs_a, backing, &error_abort);
g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
g_assert_cmpint(backing->quiesce_counter, ==, 0);
g_assert_cmpint(a_s->drain_count, ==, 0);
g_assert_cmpint(b_s->drain_count, ==, 0);
g_assert_cmpint(backing_s->drain_count, ==, 0);
do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a);
do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b);
bdrv_set_backing_hd(bs_b, backing, &error_abort);
g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
g_assert_cmpint(bs_b->quiesce_counter, ==, 5);
g_assert_cmpint(backing->quiesce_counter, ==, 5);
g_assert_cmpint(a_s->drain_count, ==, 5);
g_assert_cmpint(b_s->drain_count, ==, 5);
g_assert_cmpint(backing_s->drain_count, ==, 5);
bdrv_set_backing_hd(bs_b, NULL, &error_abort);
g_assert_cmpint(bs_a->quiesce_counter, ==, 3);
g_assert_cmpint(bs_b->quiesce_counter, ==, 2);
g_assert_cmpint(backing->quiesce_counter, ==, 3);
g_assert_cmpint(a_s->drain_count, ==, 3);
g_assert_cmpint(b_s->drain_count, ==, 2);
g_assert_cmpint(backing_s->drain_count, ==, 3);
bdrv_set_backing_hd(bs_b, backing, &error_abort);
g_assert_cmpint(bs_a->quiesce_counter, ==, 5);
g_assert_cmpint(bs_b->quiesce_counter, ==, 5);
g_assert_cmpint(backing->quiesce_counter, ==, 5);
g_assert_cmpint(a_s->drain_count, ==, 5);
g_assert_cmpint(b_s->drain_count, ==, 5);
g_assert_cmpint(backing_s->drain_count, ==, 5);
do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
do_drain_end(BDRV_SUBTREE_DRAIN, bs_b);
do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
do_drain_end(BDRV_SUBTREE_DRAIN, bs_a);
g_assert_cmpint(bs_a->quiesce_counter, ==, 0);
g_assert_cmpint(bs_b->quiesce_counter, ==, 0);
g_assert_cmpint(backing->quiesce_counter, ==, 0);
g_assert_cmpint(a_s->drain_count, ==, 0);
g_assert_cmpint(b_s->drain_count, ==, 0);
g_assert_cmpint(backing_s->drain_count, ==, 0);
bdrv_unref(backing);
bdrv_unref(bs_a);
bdrv_unref(bs_b);
blk_unref(blk_a);
blk_unref(blk_b);
}
static void test_graph_change_drain_all(void) static void test_graph_change_drain_all(void)
{ {
BlockBackend *blk_a, *blk_b; BlockBackend *blk_a, *blk_b;
@ -773,12 +598,6 @@ static void test_iothread_drain(void)
test_iothread_common(BDRV_DRAIN, 1); test_iothread_common(BDRV_DRAIN, 1);
} }
static void test_iothread_drain_subtree(void)
{
test_iothread_common(BDRV_SUBTREE_DRAIN, 0);
test_iothread_common(BDRV_SUBTREE_DRAIN, 1);
}
typedef struct TestBlockJob { typedef struct TestBlockJob {
BlockJob common; BlockJob common;
@ -863,7 +682,6 @@ enum test_job_result {
enum test_job_drain_node { enum test_job_drain_node {
TEST_JOB_DRAIN_SRC, TEST_JOB_DRAIN_SRC,
TEST_JOB_DRAIN_SRC_CHILD, TEST_JOB_DRAIN_SRC_CHILD,
TEST_JOB_DRAIN_SRC_PARENT,
}; };
static void test_blockjob_common_drain_node(enum drain_type drain_type, static void test_blockjob_common_drain_node(enum drain_type drain_type,
@ -901,9 +719,6 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
case TEST_JOB_DRAIN_SRC_CHILD: case TEST_JOB_DRAIN_SRC_CHILD:
drain_bs = src_backing; drain_bs = src_backing;
break; break;
case TEST_JOB_DRAIN_SRC_PARENT:
drain_bs = src_overlay;
break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
@ -1055,10 +870,6 @@ static void test_blockjob_common(enum drain_type drain_type, bool use_iothread,
TEST_JOB_DRAIN_SRC); TEST_JOB_DRAIN_SRC);
test_blockjob_common_drain_node(drain_type, use_iothread, result, test_blockjob_common_drain_node(drain_type, use_iothread, result,
TEST_JOB_DRAIN_SRC_CHILD); TEST_JOB_DRAIN_SRC_CHILD);
if (drain_type == BDRV_SUBTREE_DRAIN) {
test_blockjob_common_drain_node(drain_type, use_iothread, result,
TEST_JOB_DRAIN_SRC_PARENT);
}
} }
static void test_blockjob_drain_all(void) static void test_blockjob_drain_all(void)
@ -1071,11 +882,6 @@ static void test_blockjob_drain(void)
test_blockjob_common(BDRV_DRAIN, false, TEST_JOB_SUCCESS); test_blockjob_common(BDRV_DRAIN, false, TEST_JOB_SUCCESS);
} }
static void test_blockjob_drain_subtree(void)
{
test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_SUCCESS);
}
static void test_blockjob_error_drain_all(void) static void test_blockjob_error_drain_all(void)
{ {
test_blockjob_common(BDRV_DRAIN_ALL, false, TEST_JOB_FAIL_RUN); test_blockjob_common(BDRV_DRAIN_ALL, false, TEST_JOB_FAIL_RUN);
@ -1088,12 +894,6 @@ static void test_blockjob_error_drain(void)
test_blockjob_common(BDRV_DRAIN, false, TEST_JOB_FAIL_PREPARE); test_blockjob_common(BDRV_DRAIN, false, TEST_JOB_FAIL_PREPARE);
} }
static void test_blockjob_error_drain_subtree(void)
{
test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_FAIL_RUN);
test_blockjob_common(BDRV_SUBTREE_DRAIN, false, TEST_JOB_FAIL_PREPARE);
}
static void test_blockjob_iothread_drain_all(void) static void test_blockjob_iothread_drain_all(void)
{ {
test_blockjob_common(BDRV_DRAIN_ALL, true, TEST_JOB_SUCCESS); test_blockjob_common(BDRV_DRAIN_ALL, true, TEST_JOB_SUCCESS);
@ -1104,11 +904,6 @@ static void test_blockjob_iothread_drain(void)
test_blockjob_common(BDRV_DRAIN, true, TEST_JOB_SUCCESS); test_blockjob_common(BDRV_DRAIN, true, TEST_JOB_SUCCESS);
} }
static void test_blockjob_iothread_drain_subtree(void)
{
test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_SUCCESS);
}
static void test_blockjob_iothread_error_drain_all(void) static void test_blockjob_iothread_error_drain_all(void)
{ {
test_blockjob_common(BDRV_DRAIN_ALL, true, TEST_JOB_FAIL_RUN); test_blockjob_common(BDRV_DRAIN_ALL, true, TEST_JOB_FAIL_RUN);
@ -1121,12 +916,6 @@ static void test_blockjob_iothread_error_drain(void)
test_blockjob_common(BDRV_DRAIN, true, TEST_JOB_FAIL_PREPARE); test_blockjob_common(BDRV_DRAIN, true, TEST_JOB_FAIL_PREPARE);
} }
static void test_blockjob_iothread_error_drain_subtree(void)
{
test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_FAIL_RUN);
test_blockjob_common(BDRV_SUBTREE_DRAIN, true, TEST_JOB_FAIL_PREPARE);
}
typedef struct BDRVTestTopState { typedef struct BDRVTestTopState {
BdrvChild *wait_child; BdrvChild *wait_child;
@ -1273,14 +1062,6 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
bdrv_drain(child_bs); bdrv_drain(child_bs);
bdrv_unref(child_bs); bdrv_unref(child_bs);
break; break;
case BDRV_SUBTREE_DRAIN:
/* Would have to ref/unref bs here for !detach_instead_of_delete, but
* then the whole test becomes pointless because the graph changes
* don't occur during the drain any more. */
assert(detach_instead_of_delete);
bdrv_subtree_drained_begin(bs);
bdrv_subtree_drained_end(bs);
break;
case BDRV_DRAIN_ALL: case BDRV_DRAIN_ALL:
bdrv_drain_all_begin(); bdrv_drain_all_begin();
bdrv_drain_all_end(); bdrv_drain_all_end();
@ -1315,11 +1096,6 @@ static void test_detach_by_drain(void)
do_test_delete_by_drain(true, BDRV_DRAIN); do_test_delete_by_drain(true, BDRV_DRAIN);
} }
static void test_detach_by_drain_subtree(void)
{
do_test_delete_by_drain(true, BDRV_SUBTREE_DRAIN);
}
struct detach_by_parent_data { struct detach_by_parent_data {
BlockDriverState *parent_b; BlockDriverState *parent_b;
@ -1452,7 +1228,10 @@ static void test_detach_indirect(bool by_parent_cb)
g_assert(acb != NULL); g_assert(acb != NULL);
/* Drain and check the expected result */ /* Drain and check the expected result */
bdrv_subtree_drained_begin(parent_b); bdrv_drained_begin(parent_b);
bdrv_drained_begin(a);
bdrv_drained_begin(b);
bdrv_drained_begin(c);
g_assert(detach_by_parent_data.child_c != NULL); g_assert(detach_by_parent_data.child_c != NULL);
@ -1467,12 +1246,15 @@ static void test_detach_indirect(bool by_parent_cb)
g_assert(QLIST_NEXT(child_a, next) == NULL); g_assert(QLIST_NEXT(child_a, next) == NULL);
g_assert_cmpint(parent_a->quiesce_counter, ==, 1); g_assert_cmpint(parent_a->quiesce_counter, ==, 1);
g_assert_cmpint(parent_b->quiesce_counter, ==, 1); g_assert_cmpint(parent_b->quiesce_counter, ==, 3);
g_assert_cmpint(a->quiesce_counter, ==, 1); g_assert_cmpint(a->quiesce_counter, ==, 1);
g_assert_cmpint(b->quiesce_counter, ==, 0); g_assert_cmpint(b->quiesce_counter, ==, 1);
g_assert_cmpint(c->quiesce_counter, ==, 1); g_assert_cmpint(c->quiesce_counter, ==, 1);
bdrv_subtree_drained_end(parent_b); bdrv_drained_end(parent_b);
bdrv_drained_end(a);
bdrv_drained_end(b);
bdrv_drained_end(c);
bdrv_unref(parent_b); bdrv_unref(parent_b);
blk_unref(blk); blk_unref(blk);
@ -2202,70 +1984,47 @@ int main(int argc, char **argv)
g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all);
g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain); g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain);
g_test_add_func("/bdrv-drain/driver-cb/drain_subtree",
test_drv_cb_drain_subtree);
g_test_add_func("/bdrv-drain/driver-cb/co/drain_all", g_test_add_func("/bdrv-drain/driver-cb/co/drain_all",
test_drv_cb_co_drain_all); test_drv_cb_co_drain_all);
g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain); g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain);
g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree",
test_drv_cb_co_drain_subtree);
g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all);
g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain);
g_test_add_func("/bdrv-drain/quiesce/drain_subtree",
test_quiesce_drain_subtree);
g_test_add_func("/bdrv-drain/quiesce/co/drain_all", g_test_add_func("/bdrv-drain/quiesce/co/drain_all",
test_quiesce_co_drain_all); test_quiesce_co_drain_all);
g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain); g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain);
g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree",
test_quiesce_co_drain_subtree);
g_test_add_func("/bdrv-drain/nested", test_nested); g_test_add_func("/bdrv-drain/nested", test_nested);
g_test_add_func("/bdrv-drain/multiparent", test_multiparent);
g_test_add_func("/bdrv-drain/graph-change/drain_subtree",
test_graph_change_drain_subtree);
g_test_add_func("/bdrv-drain/graph-change/drain_all", g_test_add_func("/bdrv-drain/graph-change/drain_all",
test_graph_change_drain_all); test_graph_change_drain_all);
g_test_add_func("/bdrv-drain/iothread/drain_all", test_iothread_drain_all); g_test_add_func("/bdrv-drain/iothread/drain_all", test_iothread_drain_all);
g_test_add_func("/bdrv-drain/iothread/drain", test_iothread_drain); g_test_add_func("/bdrv-drain/iothread/drain", test_iothread_drain);
g_test_add_func("/bdrv-drain/iothread/drain_subtree",
test_iothread_drain_subtree);
g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all);
g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain);
g_test_add_func("/bdrv-drain/blockjob/drain_subtree",
test_blockjob_drain_subtree);
g_test_add_func("/bdrv-drain/blockjob/error/drain_all", g_test_add_func("/bdrv-drain/blockjob/error/drain_all",
test_blockjob_error_drain_all); test_blockjob_error_drain_all);
g_test_add_func("/bdrv-drain/blockjob/error/drain", g_test_add_func("/bdrv-drain/blockjob/error/drain",
test_blockjob_error_drain); test_blockjob_error_drain);
g_test_add_func("/bdrv-drain/blockjob/error/drain_subtree",
test_blockjob_error_drain_subtree);
g_test_add_func("/bdrv-drain/blockjob/iothread/drain_all", g_test_add_func("/bdrv-drain/blockjob/iothread/drain_all",
test_blockjob_iothread_drain_all); test_blockjob_iothread_drain_all);
g_test_add_func("/bdrv-drain/blockjob/iothread/drain", g_test_add_func("/bdrv-drain/blockjob/iothread/drain",
test_blockjob_iothread_drain); test_blockjob_iothread_drain);
g_test_add_func("/bdrv-drain/blockjob/iothread/drain_subtree",
test_blockjob_iothread_drain_subtree);
g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain_all", g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain_all",
test_blockjob_iothread_error_drain_all); test_blockjob_iothread_error_drain_all);
g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain", g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain",
test_blockjob_iothread_error_drain); test_blockjob_iothread_error_drain);
g_test_add_func("/bdrv-drain/blockjob/iothread/error/drain_subtree",
test_blockjob_iothread_error_drain_subtree);
g_test_add_func("/bdrv-drain/deletion/drain", test_delete_by_drain); g_test_add_func("/bdrv-drain/deletion/drain", test_delete_by_drain);
g_test_add_func("/bdrv-drain/detach/drain_all", test_detach_by_drain_all); g_test_add_func("/bdrv-drain/detach/drain_all", test_detach_by_drain_all);
g_test_add_func("/bdrv-drain/detach/drain", test_detach_by_drain); g_test_add_func("/bdrv-drain/detach/drain", test_detach_by_drain);
g_test_add_func("/bdrv-drain/detach/drain_subtree", test_detach_by_drain_subtree);
g_test_add_func("/bdrv-drain/detach/parent_cb", test_detach_by_parent_cb); g_test_add_func("/bdrv-drain/detach/parent_cb", test_detach_by_parent_cb);
g_test_add_func("/bdrv-drain/detach/driver_cb", test_detach_by_driver_cb); g_test_add_func("/bdrv-drain/detach/driver_cb", test_detach_by_driver_cb);