From: Stefan Hajnoczi <stefanha@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Coiby Xu" <Coiby.Xu@gmail.com>,
"Marcel Apfelbaum" <marcel.apfelbaum@gmail.com>,
"Michael S. Tsirkin" <mst@redhat.com>,
"Richard W.M. Jones" <rjones@redhat.com>,
"Peter Xu" <peterx@redhat.com>,
xen-devel@lists.xenproject.org, "Kevin Wolf" <kwolf@redhat.com>,
"Ronnie Sahlberg" <ronniesahlberg@gmail.com>,
"Stefano Stabellini" <sstabellini@kernel.org>,
"Richard Henderson" <richard.henderson@linaro.org>,
"Stefan Hajnoczi" <stefanha@redhat.com>,
"Julia Suvorova" <jusual@redhat.com>,
"Hanna Reitz" <hreitz@redhat.com>,
"Leonardo Bras" <leobras@redhat.com>,
eesposit@redhat.com, "Fam Zheng" <fam@euphon.net>,
"Aarushi Mehta" <mehta.aaru20@gmail.com>,
"David Woodhouse" <dwmw2@infradead.org>,
"Xie Yongji" <xieyongji@bytedance.com>,
"Stefano Garzarella" <sgarzare@redhat.com>,
qemu-block@nongnu.org, "Eduardo Habkost" <eduardo@habkost.net>,
"Paul Durrant" <paul@xen.org>, "Stefan Weil" <sw@weilnetz.de>,
"Anthony Perard" <anthony.perard@citrix.com>,
"Daniel P. Berrangé" <berrange@redhat.com>,
"Peter Lieven" <pl@kamp.de>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Philippe Mathieu-Daudé" <philmd@linaro.org>,
"Juan Quintela" <quintela@redhat.com>
Subject: [PATCH v6 10/20] block: drain from main loop thread in bdrv_co_yield_to_drain()
Date: Tue, 16 May 2023 15:02:28 -0400 [thread overview]
Message-ID: <20230516190238.8401-11-stefanha@redhat.com> (raw)
In-Reply-To: <20230516190238.8401-1-stefanha@redhat.com>
For simplicity, always run BlockDevOps .drained_begin/end/poll()
callbacks in the main loop thread. This makes it easier to implement the
callbacks and avoids extra locks.
Move the function pointer declarations from the I/O Code section to the
Global State section for BlockDevOps, BdrvChildClass, and BlockDriver.
Narrow IO_OR_GS_CODE() to GLOBAL_STATE_CODE() where appropriate.
The test-bdrv-drain test case calls bdrv_drain() from an IOThread. This
is now only allowed from coroutine context, so update the test case to
run in a coroutine.
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
---
include/block/block_int-common.h | 90 +++++++++++++--------------
include/sysemu/block-backend-common.h | 25 ++++----
block/io.c | 14 +++--
tests/unit/test-bdrv-drain.c | 14 +++--
4 files changed, 76 insertions(+), 67 deletions(-)
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
index dbec0e3bb4..17eb54edcb 100644
--- a/include/block/block_int-common.h
+++ b/include/block/block_int-common.h
@@ -363,6 +363,21 @@ struct BlockDriver {
void (*bdrv_attach_aio_context)(BlockDriverState *bs,
AioContext *new_context);
+ /**
+ * bdrv_drain_begin is called if implemented in the beginning of a
+ * drain operation to drain and stop any internal sources of requests in
+ * the driver.
+ * bdrv_drain_end is called if implemented at the end of the drain.
+ *
+ * They should be used by the driver to e.g. manage scheduled I/O
+ * requests, or toggle an internal state. After the end of the drain new
+ * requests will continue normally.
+ *
+ * Implementations of both functions must not call aio_poll().
+ */
+ void (*bdrv_drain_begin)(BlockDriverState *bs);
+ void (*bdrv_drain_end)(BlockDriverState *bs);
+
/**
* Try to get @bs's logical and physical block size.
* On success, store them in @bsz and return zero.
@@ -758,21 +773,6 @@ struct BlockDriver {
void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_io_unplug)(
BlockDriverState *bs);
- /**
- * bdrv_drain_begin is called if implemented in the beginning of a
- * drain operation to drain and stop any internal sources of requests in
- * the driver.
- * bdrv_drain_end is called if implemented at the end of the drain.
- *
- * They should be used by the driver to e.g. manage scheduled I/O
- * requests, or toggle an internal state. After the end of the drain new
- * requests will continue normally.
- *
- * Implementations of both functions must not call aio_poll().
- */
- void (*bdrv_drain_begin)(BlockDriverState *bs);
- void (*bdrv_drain_end)(BlockDriverState *bs);
-
bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs);
bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_can_store_new_dirty_bitmap)(
@@ -955,36 +955,6 @@ struct BdrvChildClass {
void GRAPH_WRLOCK_PTR (*attach)(BdrvChild *child);
void GRAPH_WRLOCK_PTR (*detach)(BdrvChild *child);
- /*
- * Notifies the parent that the filename of its child has changed (e.g.
- * because the direct child was removed from the backing chain), so that it
- * can update its reference.
- */
- int (*update_filename)(BdrvChild *child, BlockDriverState *new_base,
- const char *filename, Error **errp);
-
- bool (*change_aio_ctx)(BdrvChild *child, AioContext *ctx,
- GHashTable *visited, Transaction *tran,
- Error **errp);
-
- /*
- * I/O API functions. These functions are thread-safe.
- *
- * See include/block/block-io.h for more information about
- * the I/O API.
- */
-
- void (*resize)(BdrvChild *child);
-
- /*
- * Returns a name that is supposedly more useful for human users than the
- * node name for identifying the node in question (in particular, a BB
- * name), or NULL if the parent can't provide a better name.
- */
- const char *(*get_name)(BdrvChild *child);
-
- AioContext *(*get_parent_aio_context)(BdrvChild *child);
-
/*
* If this pair of functions is implemented, the parent doesn't issue new
* requests after returning from .drained_begin() until .drained_end() is
@@ -1005,6 +975,36 @@ struct BdrvChildClass {
* activity on the child has stopped.
*/
bool (*drained_poll)(BdrvChild *child);
+
+ /*
+ * Notifies the parent that the filename of its child has changed (e.g.
+ * because the direct child was removed from the backing chain), so that it
+ * can update its reference.
+ */
+ int (*update_filename)(BdrvChild *child, BlockDriverState *new_base,
+ const char *filename, Error **errp);
+
+ bool (*change_aio_ctx)(BdrvChild *child, AioContext *ctx,
+ GHashTable *visited, Transaction *tran,
+ Error **errp);
+
+ /*
+ * I/O API functions. These functions are thread-safe.
+ *
+ * See include/block/block-io.h for more information about
+ * the I/O API.
+ */
+
+ void (*resize)(BdrvChild *child);
+
+ /*
+ * Returns a name that is supposedly more useful for human users than the
+ * node name for identifying the node in question (in particular, a BB
+ * name), or NULL if the parent can't provide a better name.
+ */
+ const char *(*get_name)(BdrvChild *child);
+
+ AioContext *(*get_parent_aio_context)(BdrvChild *child);
};
extern const BdrvChildClass child_of_bds;
diff --git a/include/sysemu/block-backend-common.h b/include/sysemu/block-backend-common.h
index 2391679c56..780cea7305 100644
--- a/include/sysemu/block-backend-common.h
+++ b/include/sysemu/block-backend-common.h
@@ -59,6 +59,19 @@ typedef struct BlockDevOps {
*/
bool (*is_medium_locked)(void *opaque);
+ /*
+ * Runs when the backend receives a drain request.
+ */
+ void (*drained_begin)(void *opaque);
+ /*
+ * Runs when the backend's last drain request ends.
+ */
+ void (*drained_end)(void *opaque);
+ /*
+ * Is the device still busy?
+ */
+ bool (*drained_poll)(void *opaque);
+
/*
* I/O API functions. These functions are thread-safe.
*
@@ -76,18 +89,6 @@ typedef struct BlockDevOps {
* Runs when the size changed (e.g. monitor command block_resize)
*/
void (*resize_cb)(void *opaque);
- /*
- * Runs when the backend receives a drain request.
- */
- void (*drained_begin)(void *opaque);
- /*
- * Runs when the backend's last drain request ends.
- */
- void (*drained_end)(void *opaque);
- /*
- * Is the device still busy?
- */
- bool (*drained_poll)(void *opaque);
} BlockDevOps;
/*
diff --git a/block/io.c b/block/io.c
index 4d54fda593..fece938fd0 100644
--- a/block/io.c
+++ b/block/io.c
@@ -60,7 +60,7 @@ static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
void bdrv_parent_drained_end_single(BdrvChild *c)
{
- IO_OR_GS_CODE();
+ GLOBAL_STATE_CODE();
assert(c->quiesced_parent);
c->quiesced_parent = false;
@@ -108,7 +108,7 @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
void bdrv_parent_drained_begin_single(BdrvChild *c)
{
- IO_OR_GS_CODE();
+ GLOBAL_STATE_CODE();
assert(!c->quiesced_parent);
c->quiesced_parent = true;
@@ -247,7 +247,7 @@ typedef struct {
bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
bool ignore_bds_parents)
{
- IO_OR_GS_CODE();
+ GLOBAL_STATE_CODE();
if (bdrv_parent_drained_poll(bs, ignore_parent, ignore_bds_parents)) {
return true;
@@ -334,7 +334,8 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
if (ctx != co_ctx) {
aio_context_release(ctx);
}
- replay_bh_schedule_oneshot_event(ctx, bdrv_co_drain_bh_cb, &data);
+ replay_bh_schedule_oneshot_event(qemu_get_aio_context(),
+ bdrv_co_drain_bh_cb, &data);
qemu_coroutine_yield();
/* If we are resumed from some other event (such as an aio completion or a
@@ -357,6 +358,8 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
return;
}
+ GLOBAL_STATE_CODE();
+
/* Stop things in parent-to-child order */
if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
aio_disable_external(bdrv_get_aio_context(bs));
@@ -399,11 +402,14 @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
{
int old_quiesce_counter;
+ IO_OR_GS_CODE();
+
if (qemu_in_coroutine()) {
bdrv_co_yield_to_drain(bs, false, parent, false);
return;
}
assert(bs->quiesce_counter > 0);
+ GLOBAL_STATE_CODE();
/* Re-enable things in child-to-parent order */
old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
index 9a4c5e59d6..6ad9964f03 100644
--- a/tests/unit/test-bdrv-drain.c
+++ b/tests/unit/test-bdrv-drain.c
@@ -483,19 +483,19 @@ struct test_iothread_data {
BlockDriverState *bs;
enum drain_type drain_type;
int *aio_ret;
+ bool co_done;
};
-static void test_iothread_drain_entry(void *opaque)
+static void coroutine_fn test_iothread_drain_co_entry(void *opaque)
{
struct test_iothread_data *data = opaque;
- aio_context_acquire(bdrv_get_aio_context(data->bs));
do_drain_begin(data->drain_type, data->bs);
g_assert_cmpint(*data->aio_ret, ==, 0);
do_drain_end(data->drain_type, data->bs);
- aio_context_release(bdrv_get_aio_context(data->bs));
- qemu_event_set(&done_event);
+ data->co_done = true;
+ aio_wait_kick();
}
static void test_iothread_aio_cb(void *opaque, int ret)
@@ -531,6 +531,7 @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
BlockDriverState *bs;
BDRVTestState *s;
BlockAIOCB *acb;
+ Coroutine *co;
int aio_ret;
struct test_iothread_data data;
@@ -609,8 +610,9 @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
}
break;
case 1:
- aio_bh_schedule_oneshot(ctx_a, test_iothread_drain_entry, &data);
- qemu_event_wait(&done_event);
+ co = qemu_coroutine_create(test_iothread_drain_co_entry, &data);
+ aio_co_enter(ctx_a, co);
+ AIO_WAIT_WHILE_UNLOCKED(NULL, !data.co_done);
break;
default:
g_assert_not_reached();
--
2.40.1
next prev parent reply other threads:[~2023-05-16 19:05 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-05-16 19:02 [PATCH v6 00/20] block: remove aio_disable_external() API Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 01/20] block-backend: split blk_do_set_aio_context() Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 02/20] hw/qdev: introduce qdev_is_realized() helper Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 03/20] virtio-scsi: avoid race between unplug and transport event Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 04/20] virtio-scsi: stop using aio_disable_external() during unplug Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 05/20] util/vhost-user-server: rename refcount to in_flight counter Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 06/20] block/export: wait for vhost-user-blk requests when draining Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 07/20] block/export: stop using is_external in vhost-user-blk server Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 08/20] hw/xen: do not use aio_set_fd_handler(is_external=true) in xen_xenstore Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 09/20] block: add blk_in_drain() API Stefan Hajnoczi
2023-05-16 19:02 ` Stefan Hajnoczi [this message]
2023-05-16 19:02 ` [PATCH v6 11/20] xen-block: implement BlockDevOps->drained_begin() Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 12/20] hw/xen: do not set is_external=true on evtchn fds Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 13/20] block/export: rewrite vduse-blk drain code Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 14/20] block/export: don't require AioContext lock around blk_exp_ref/unref() Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 15/20] block/fuse: do not set is_external=true on FUSE fd Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 16/20] virtio: make it possible to detach host notifier from any thread Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 17/20] virtio-blk: implement BlockDevOps->drained_begin() Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 18/20] virtio-scsi: " Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 19/20] virtio: do not set is_external=true on host notifiers Stefan Hajnoczi
2023-05-16 19:02 ` [PATCH v6 20/20] aio: remove aio_disable_external() API Stefan Hajnoczi
2023-05-30 16:24 ` [PATCH v6 00/20] block: " Kevin Wolf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230516190238.8401-11-stefanha@redhat.com \
--to=stefanha@redhat.com \
--cc=Coiby.Xu@gmail.com \
--cc=anthony.perard@citrix.com \
--cc=berrange@redhat.com \
--cc=dwmw2@infradead.org \
--cc=eduardo@habkost.net \
--cc=eesposit@redhat.com \
--cc=fam@euphon.net \
--cc=hreitz@redhat.com \
--cc=jusual@redhat.com \
--cc=kwolf@redhat.com \
--cc=leobras@redhat.com \
--cc=marcel.apfelbaum@gmail.com \
--cc=mehta.aaru20@gmail.com \
--cc=mst@redhat.com \
--cc=paul@xen.org \
--cc=pbonzini@redhat.com \
--cc=peterx@redhat.com \
--cc=philmd@linaro.org \
--cc=pl@kamp.de \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=quintela@redhat.com \
--cc=richard.henderson@linaro.org \
--cc=rjones@redhat.com \
--cc=ronniesahlberg@gmail.com \
--cc=sgarzare@redhat.com \
--cc=sstabellini@kernel.org \
--cc=sw@weilnetz.de \
--cc=xen-devel@lists.xenproject.org \
--cc=xieyongji@bytedance.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).