BlockDriverState *new_bs)
{
BlockDriverState *old_bs = child->bs;
+ int i;
if (old_bs && new_bs) {
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
}
if (old_bs) {
if (old_bs->quiesce_counter && child->role->drained_end) {
- child->role->drained_end(child);
+ for (i = 0; i < old_bs->quiesce_counter; i++) {
+ child->role->drained_end(child);
+ }
}
if (child->role->detach) {
child->role->detach(child);
if (new_bs) {
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
if (new_bs->quiesce_counter && child->role->drained_begin) {
- child->role->drained_begin(child);
+ for (i = 0; i < new_bs->quiesce_counter; i++) {
+ child->role->drained_begin(child);
+ }
}
if (child->role->attach) {
AioContext *ctx = bdrv_get_aio_context(bs);
aio_disable_external(ctx);
- bdrv_parent_drained_begin(bs);
+ bdrv_parent_drained_begin(bs, NULL);
bdrv_drain(bs); /* ensure there are no in-flight requests */
while (aio_poll(ctx, false)) {
*/
aio_context_acquire(new_context);
bdrv_attach_aio_context(bs, new_context);
- bdrv_parent_drained_end(bs);
+ bdrv_parent_drained_end(bs, NULL);
aio_enable_external(ctx);
aio_context_release(new_context);
}
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int bytes, BdrvRequestFlags flags);
-void bdrv_parent_drained_begin(BlockDriverState *bs)
+void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
{
BdrvChild *c, *next;
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
+ if (c == ignore) {
+ continue;
+ }
if (c->role->drained_begin) {
c->role->drained_begin(c);
}
}
}
-void bdrv_parent_drained_end(BlockDriverState *bs)
+void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
{
BdrvChild *c, *next;
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
+ if (c == ignore) {
+ continue;
+ }
if (c->role->drained_end) {
c->role->drained_end(c);
}
BlockDriverState *bs;
bool done;
bool begin;
+ BdrvChild *parent;
} BdrvCoDrainData;
static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
return waited;
}
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent);
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent);
+
static void bdrv_co_drain_bh_cb(void *opaque)
{
BdrvCoDrainData *data = opaque;
bdrv_dec_in_flight(bs);
if (data->begin) {
- bdrv_drained_begin(bs);
+ bdrv_do_drained_begin(bs, data->parent);
} else {
- bdrv_drained_end(bs);
+ bdrv_do_drained_end(bs, data->parent);
}
data->done = true;
}
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
- bool begin)
+ bool begin, BdrvChild *parent)
{
BdrvCoDrainData data;
.bs = bs,
.done = false,
.begin = begin,
+ .parent = parent,
};
bdrv_inc_in_flight(bs);
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
assert(data.done);
}
-void bdrv_drained_begin(BlockDriverState *bs)
+static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent)
{
if (qemu_in_coroutine()) {
- bdrv_co_yield_to_drain(bs, true);
+ bdrv_co_yield_to_drain(bs, true, parent);
return;
}
/* Stop things in parent-to-child order */
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
aio_disable_external(bdrv_get_aio_context(bs));
- bdrv_parent_drained_begin(bs);
}
+ bdrv_parent_drained_begin(bs, parent);
bdrv_drain_invoke(bs, true, false);
bdrv_drain_recurse(bs);
}
-void bdrv_drained_end(BlockDriverState *bs)
+void bdrv_drained_begin(BlockDriverState *bs)
+{
+ bdrv_do_drained_begin(bs, NULL);
+}
+
+static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
{
int old_quiesce_counter;
if (qemu_in_coroutine()) {
- bdrv_co_yield_to_drain(bs, false);
+ bdrv_co_yield_to_drain(bs, false, parent);
return;
}
assert(bs->quiesce_counter > 0);
/* Re-enable things in child-to-parent order */
bdrv_drain_invoke(bs, false, false);
+ bdrv_parent_drained_end(bs, parent);
if (old_quiesce_counter == 1) {
- bdrv_parent_drained_end(bs);
aio_enable_external(bdrv_get_aio_context(bs));
}
}
+void bdrv_drained_end(BlockDriverState *bs)
+{
+ bdrv_do_drained_end(bs, NULL);
+}
+
/*
* Wait for pending requests to complete on a single BlockDriverState subtree,
* and suspend block driver's internal I/O until next request arrives.
/* Stop things in parent-to-child order */
aio_context_acquire(aio_context);
aio_disable_external(aio_context);
- bdrv_parent_drained_begin(bs);
+ bdrv_parent_drained_begin(bs, NULL);
bdrv_drain_invoke(bs, true, true);
aio_context_release(aio_context);
/* Re-enable things in child-to-parent order */
aio_context_acquire(aio_context);
bdrv_drain_invoke(bs, false, true);
- bdrv_parent_drained_end(bs);
+ bdrv_parent_drained_end(bs, NULL);
aio_enable_external(aio_context);
aio_context_release(aio_context);
}