|
|
4a2fec |
From 58a794ea48e1a6c6f5711f07e34024c037e4c4b1 Mon Sep 17 00:00:00 2001
|
|
|
4a2fec |
From: Jeffrey Cody <jcody@redhat.com>
|
|
|
4a2fec |
Date: Thu, 30 Nov 2017 22:49:05 +0100
|
|
|
4a2fec |
Subject: [PATCH 01/21] block: add bdrv_co_drain_end callback
|
|
|
4a2fec |
|
|
|
4a2fec |
RH-Author: Jeffrey Cody <jcody@redhat.com>
|
|
|
4a2fec |
Message-id: <5493cbaa3bab031054077168340f5aff55b6be2e.1511985875.git.jcody@redhat.com>
|
|
|
4a2fec |
Patchwork-id: 78040
|
|
|
4a2fec |
O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 01/11] block: add bdrv_co_drain_end callback
|
|
|
4a2fec |
Bugzilla: 1506531
|
|
|
4a2fec |
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
4a2fec |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
4a2fec |
RH-Acked-by: John Snow <jsnow@redhat.com>
|
|
|
4a2fec |
|
|
|
4a2fec |
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
|
|
|
4a2fec |
|
|
|
4a2fec |
BlockDriverState has a bdrv_co_drain() callback but no equivalent for
|
|
|
4a2fec |
the end of the drain. The throttle driver (block/throttle.c) needs a way
|
|
|
4a2fec |
to mark the end of the drain in order to toggle io_limits_disabled
|
|
|
4a2fec |
correctly, thus bdrv_co_drain_end is needed.
|
|
|
4a2fec |
|
|
|
4a2fec |
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
|
|
|
4a2fec |
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
4a2fec |
Reviewed-by: Fam Zheng <famz@redhat.com>
|
|
|
4a2fec |
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
4a2fec |
(cherry picked from commit 481cad48e5e655746893e001af31c161f4587a02)
|
|
|
4a2fec |
Signed-off-by: Jeff Cody <jcody@redhat.com>
|
|
|
4a2fec |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
4a2fec |
---
|
|
|
4a2fec |
block/io.c | 48 +++++++++++++++++++++++++++++++++--------------
|
|
|
4a2fec |
include/block/block_int.h | 11 +++++++++--
|
|
|
4a2fec |
2 files changed, 43 insertions(+), 16 deletions(-)
|
|
|
4a2fec |
|
|
|
4a2fec |
diff --git a/block/io.c b/block/io.c
|
|
|
4a2fec |
index 2600381..93fb802 100644
|
|
|
4a2fec |
--- a/block/io.c
|
|
|
4a2fec |
+++ b/block/io.c
|
|
|
4a2fec |
@@ -153,6 +153,7 @@ typedef struct {
|
|
|
4a2fec |
Coroutine *co;
|
|
|
4a2fec |
BlockDriverState *bs;
|
|
|
4a2fec |
bool done;
|
|
|
4a2fec |
+ bool begin;
|
|
|
4a2fec |
} BdrvCoDrainData;
|
|
|
4a2fec |
|
|
|
4a2fec |
static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
|
|
|
4a2fec |
@@ -160,18 +161,23 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
|
|
|
4a2fec |
BdrvCoDrainData *data = opaque;
|
|
|
4a2fec |
BlockDriverState *bs = data->bs;
|
|
|
4a2fec |
|
|
|
4a2fec |
- bs->drv->bdrv_co_drain(bs);
|
|
|
4a2fec |
+ if (data->begin) {
|
|
|
4a2fec |
+ bs->drv->bdrv_co_drain(bs);
|
|
|
4a2fec |
+ } else {
|
|
|
4a2fec |
+ bs->drv->bdrv_co_drain_end(bs);
|
|
|
4a2fec |
+ }
|
|
|
4a2fec |
|
|
|
4a2fec |
/* Set data->done before reading bs->wakeup. */
|
|
|
4a2fec |
atomic_mb_set(&data->done, true);
|
|
|
4a2fec |
bdrv_wakeup(bs);
|
|
|
4a2fec |
}
|
|
|
4a2fec |
|
|
|
4a2fec |
-static void bdrv_drain_invoke(BlockDriverState *bs)
|
|
|
4a2fec |
+static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
|
|
|
4a2fec |
{
|
|
|
4a2fec |
- BdrvCoDrainData data = { .bs = bs, .done = false };
|
|
|
4a2fec |
+ BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
|
|
|
4a2fec |
|
|
|
4a2fec |
- if (!bs->drv || !bs->drv->bdrv_co_drain) {
|
|
|
4a2fec |
+ if (!bs->drv || (begin && !bs->drv->bdrv_co_drain) ||
|
|
|
4a2fec |
+ (!begin && !bs->drv->bdrv_co_drain_end)) {
|
|
|
4a2fec |
return;
|
|
|
4a2fec |
}
|
|
|
4a2fec |
|
|
|
4a2fec |
@@ -180,15 +186,16 @@ static void bdrv_drain_invoke(BlockDriverState *bs)
|
|
|
4a2fec |
BDRV_POLL_WHILE(bs, !data.done);
|
|
|
4a2fec |
}
|
|
|
4a2fec |
|
|
|
4a2fec |
-static bool bdrv_drain_recurse(BlockDriverState *bs)
|
|
|
4a2fec |
+static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin)
|
|
|
4a2fec |
{
|
|
|
4a2fec |
BdrvChild *child, *tmp;
|
|
|
4a2fec |
bool waited;
|
|
|
4a2fec |
|
|
|
4a2fec |
- waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0);
|
|
|
4a2fec |
-
|
|
|
4a2fec |
/* Ensure any pending metadata writes are submitted to bs->file. */
|
|
|
4a2fec |
- bdrv_drain_invoke(bs);
|
|
|
4a2fec |
+ bdrv_drain_invoke(bs, begin);
|
|
|
4a2fec |
+
|
|
|
4a2fec |
+ /* Wait for drained requests to finish */
|
|
|
4a2fec |
+ waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0);
|
|
|
4a2fec |
|
|
|
4a2fec |
QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
|
|
|
4a2fec |
BlockDriverState *bs = child->bs;
|
|
|
4a2fec |
@@ -205,7 +212,7 @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
|
|
|
4a2fec |
*/
|
|
|
4a2fec |
bdrv_ref(bs);
|
|
|
4a2fec |
}
|
|
|
4a2fec |
- waited |= bdrv_drain_recurse(bs);
|
|
|
4a2fec |
+ waited |= bdrv_drain_recurse(bs, begin);
|
|
|
4a2fec |
if (in_main_loop) {
|
|
|
4a2fec |
bdrv_unref(bs);
|
|
|
4a2fec |
}
|
|
|
4a2fec |
@@ -221,12 +228,18 @@ static void bdrv_co_drain_bh_cb(void *opaque)
|
|
|
4a2fec |
BlockDriverState *bs = data->bs;
|
|
|
4a2fec |
|
|
|
4a2fec |
bdrv_dec_in_flight(bs);
|
|
|
4a2fec |
- bdrv_drained_begin(bs);
|
|
|
4a2fec |
+ if (data->begin) {
|
|
|
4a2fec |
+ bdrv_drained_begin(bs);
|
|
|
4a2fec |
+ } else {
|
|
|
4a2fec |
+ bdrv_drained_end(bs);
|
|
|
4a2fec |
+ }
|
|
|
4a2fec |
+
|
|
|
4a2fec |
data->done = true;
|
|
|
4a2fec |
aio_co_wake(co);
|
|
|
4a2fec |
}
|
|
|
4a2fec |
|
|
|
4a2fec |
-static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs)
|
|
|
4a2fec |
+static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
|
|
|
4a2fec |
+ bool begin)
|
|
|
4a2fec |
{
|
|
|
4a2fec |
BdrvCoDrainData data;
|
|
|
4a2fec |
|
|
|
4a2fec |
@@ -239,6 +252,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs)
|
|
|
4a2fec |
.co = qemu_coroutine_self(),
|
|
|
4a2fec |
.bs = bs,
|
|
|
4a2fec |
.done = false,
|
|
|
4a2fec |
+ .begin = begin,
|
|
|
4a2fec |
};
|
|
|
4a2fec |
bdrv_inc_in_flight(bs);
|
|
|
4a2fec |
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
|
|
|
4a2fec |
@@ -253,7 +267,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs)
|
|
|
4a2fec |
void bdrv_drained_begin(BlockDriverState *bs)
|
|
|
4a2fec |
{
|
|
|
4a2fec |
if (qemu_in_coroutine()) {
|
|
|
4a2fec |
- bdrv_co_yield_to_drain(bs);
|
|
|
4a2fec |
+ bdrv_co_yield_to_drain(bs, true);
|
|
|
4a2fec |
return;
|
|
|
4a2fec |
}
|
|
|
4a2fec |
|
|
|
4a2fec |
@@ -262,17 +276,22 @@ void bdrv_drained_begin(BlockDriverState *bs)
|
|
|
4a2fec |
bdrv_parent_drained_begin(bs);
|
|
|
4a2fec |
}
|
|
|
4a2fec |
|
|
|
4a2fec |
- bdrv_drain_recurse(bs);
|
|
|
4a2fec |
+ bdrv_drain_recurse(bs, true);
|
|
|
4a2fec |
}
|
|
|
4a2fec |
|
|
|
4a2fec |
void bdrv_drained_end(BlockDriverState *bs)
|
|
|
4a2fec |
{
|
|
|
4a2fec |
+ if (qemu_in_coroutine()) {
|
|
|
4a2fec |
+ bdrv_co_yield_to_drain(bs, false);
|
|
|
4a2fec |
+ return;
|
|
|
4a2fec |
+ }
|
|
|
4a2fec |
assert(bs->quiesce_counter > 0);
|
|
|
4a2fec |
if (atomic_fetch_dec(&bs->quiesce_counter) > 1) {
|
|
|
4a2fec |
return;
|
|
|
4a2fec |
}
|
|
|
4a2fec |
|
|
|
4a2fec |
bdrv_parent_drained_end(bs);
|
|
|
4a2fec |
+ bdrv_drain_recurse(bs, false);
|
|
|
4a2fec |
aio_enable_external(bdrv_get_aio_context(bs));
|
|
|
4a2fec |
}
|
|
|
4a2fec |
|
|
|
4a2fec |
@@ -350,7 +369,7 @@ void bdrv_drain_all_begin(void)
|
|
|
4a2fec |
aio_context_acquire(aio_context);
|
|
|
4a2fec |
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
|
|
4a2fec |
if (aio_context == bdrv_get_aio_context(bs)) {
|
|
|
4a2fec |
- waited |= bdrv_drain_recurse(bs);
|
|
|
4a2fec |
+ waited |= bdrv_drain_recurse(bs, true);
|
|
|
4a2fec |
}
|
|
|
4a2fec |
}
|
|
|
4a2fec |
aio_context_release(aio_context);
|
|
|
4a2fec |
@@ -371,6 +390,7 @@ void bdrv_drain_all_end(void)
|
|
|
4a2fec |
aio_context_acquire(aio_context);
|
|
|
4a2fec |
aio_enable_external(aio_context);
|
|
|
4a2fec |
bdrv_parent_drained_end(bs);
|
|
|
4a2fec |
+ bdrv_drain_recurse(bs, false);
|
|
|
4a2fec |
aio_context_release(aio_context);
|
|
|
4a2fec |
}
|
|
|
4a2fec |
|
|
|
4a2fec |
diff --git a/include/block/block_int.h b/include/block/block_int.h
|
|
|
4a2fec |
index a6faf1b..98d02ba 100644
|
|
|
4a2fec |
--- a/include/block/block_int.h
|
|
|
4a2fec |
+++ b/include/block/block_int.h
|
|
|
4a2fec |
@@ -320,10 +320,17 @@ struct BlockDriver {
|
|
|
4a2fec |
int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo);
|
|
|
4a2fec |
|
|
|
4a2fec |
/**
|
|
|
4a2fec |
- * Drain and stop any internal sources of requests in the driver, and
|
|
|
4a2fec |
- * remain so until next I/O callback (e.g. bdrv_co_writev) is called.
|
|
|
4a2fec |
+ * bdrv_co_drain is called if implemented in the beginning of a
|
|
|
4a2fec |
+ * drain operation to drain and stop any internal sources of requests in
|
|
|
4a2fec |
+ * the driver.
|
|
|
4a2fec |
+ * bdrv_co_drain_end is called if implemented at the end of the drain.
|
|
|
4a2fec |
+ *
|
|
|
4a2fec |
+ * They should be used by the driver to e.g. manage scheduled I/O
|
|
|
4a2fec |
+ * requests, or toggle an internal state. After the end of the drain new
|
|
|
4a2fec |
+ * requests will continue normally.
|
|
|
4a2fec |
*/
|
|
|
4a2fec |
void coroutine_fn (*bdrv_co_drain)(BlockDriverState *bs);
|
|
|
4a2fec |
+ void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs);
|
|
|
4a2fec |
|
|
|
4a2fec |
void (*bdrv_add_child)(BlockDriverState *parent, BlockDriverState *child,
|
|
|
4a2fec |
Error **errp);
|
|
|
4a2fec |
--
|
|
|
4a2fec |
1.8.3.1
|
|
|
4a2fec |
|