From: Eric Blake <eblake@redhat.com>
To: Stefan Hajnoczi <stefanha@redhat.com>, qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>, John Snow <jsnow@redhat.com>
Subject: Re: [Qemu-devel] [PATCH v2 1/4] block: extract AIO_WAIT_WHILE() from BlockDriverState
Date: Tue, 13 Feb 2018 10:01:06 -0600 [thread overview]
Message-ID: <73eb771d-ddcd-42e6-5895-23e6024ccc80@redhat.com> (raw)
In-Reply-To: <20180213142102.14450-2-stefanha@redhat.com>
On 02/13/2018 08:20 AM, Stefan Hajnoczi wrote:
> BlockDriverState has the BDRV_POLL_WHILE() macro to wait on event loop
> activity while a condition evaluates to true. This is used to implement
> synchronous operations where it acts as a condvar between the IOThread
> running the operation and the main loop waiting for the operation. It
> can also be called from the thread that owns the AioContext and in that
> case it's just a nested event loop.
>
> BlockBackend needs this behavior but doesn't always have a
> BlockDriverState it can use. This patch extracts BDRV_POLL_WHILE() into
> the AioWait abstraction, which can be used with AioContext and isn't
> tied to BlockDriverState anymore.
>
> This feature could be built directly into AioContext but then all users
> would kick the event loop even if they signal different conditions.
> Imagine an AioContext with many BlockDriverStates, each time a request
> completes any waiter would wake up and re-check their condition. It's
> nicer to keep a separate AioWait object for each condition instead.
>
> Please see "block/aio-wait.h" for details on the API.
>
> The name AIO_WAIT_WHILE() avoids the confusion between AIO_POLL_WHILE()
> and AioContext polling.
>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
Trying to understand here:
> +#define AIO_WAIT_WHILE(wait, ctx, cond) ({ \
> + bool waited_ = false; \
> + bool busy_ = true; \
> + AioWait *wait_ = (wait); \
> + AioContext *ctx_ = (ctx); \
> + if (aio_context_in_iothread(ctx_)) { \
> + while ((cond) || busy_) { \
> + busy_ = aio_poll(ctx_, (cond)); \
> + waited_ |= !!(cond) | busy_; \
> + } \
If we are in an iothread already, we never dereference wait,
> + } else { \
> + assert(qemu_get_current_aio_context() == \
> + qemu_get_aio_context()); \
> + assert(!wait_->need_kick); \
but if we are in the main loop, wait must be non-NULL.
> +++ b/include/block/block.h
> @@ -2,6 +2,7 @@
> #define BLOCK_H
>
> #include "block/aio.h"
> +#include "block/aio-wait.h"
> #include "qapi-types.h"
> #include "qemu/iov.h"
> #include "qemu/coroutine.h"
> @@ -367,41 +368,14 @@ void bdrv_drain_all_begin(void);
> void bdrv_drain_all_end(void);
> void bdrv_drain_all(void);
>
> +/* Returns NULL when bs == NULL */
> +AioWait *bdrv_get_aio_wait(BlockDriverState *bs);
This can return NULL, so it is only ever safe to use in an iothread;
because if it is used in the main loop,...
> +
> #define BDRV_POLL_WHILE(bs, cond) ({ \
> + AIO_WAIT_WHILE(bdrv_get_aio_wait(bs_), \
> + bdrv_get_aio_context(bs_), \
> + cond); })
...we can pass NULL as the wait parameter, which will crash.
> +++ b/block.c
> @@ -4716,6 +4716,11 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs)
> return bs->aio_context;
> }
>
> +AioWait *bdrv_get_aio_wait(BlockDriverState *bs)
> +{
> + return bs ? &bs->wait : NULL;
> +}
So, do we need documentation to that fact? Also,
> +++ b/block/io.c
> void bdrv_wakeup(BlockDriverState *bs)
> {
> - /* The barrier (or an atomic op) is in the caller. */
> - if (atomic_read(&bs->wakeup)) {
> - aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL);
> - }
> + aio_wait_kick(bdrv_get_aio_wait(bs));
this is another case where passing NULL...
> +++ b/util/aio-wait.c
> +void aio_wait_kick(AioWait *wait)
> +{
> + /* The barrier (or an atomic op) is in the caller. */
> + if (atomic_read(&wait->need_kick)) {
...is bad. Does that mean bdrv_wakeup() can only be called when bs is
non-NULL? Does that need documentation?
It may be that your patch is correct (as I'm not an expert on the rules
in play here), but more comments may help. Or you may have a NULL
dereference bug lurking. So at this point, I can't give R-b, even
though the refactoring of the BDRV_POLL_WHILE() macro into a separate
helper makes sense from the high level view.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
next prev parent reply other threads:[~2018-02-13 16:01 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-02-13 14:20 [Qemu-devel] [PATCH v2 0/4] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
2018-02-13 14:20 ` [Qemu-devel] [PATCH v2 1/4] block: extract AIO_WAIT_WHILE() from BlockDriverState Stefan Hajnoczi
2018-02-13 16:01 ` Eric Blake [this message]
2018-02-14 14:06 ` Stefan Hajnoczi
2018-02-14 22:31 ` Eric Blake
2018-02-15 9:27 ` Stefan Hajnoczi
2018-02-15 10:12 ` Kevin Wolf
2018-02-15 14:15 ` Eric Blake
2018-02-14 22:33 ` Eric Blake
2018-02-13 14:21 ` [Qemu-devel] [PATCH v2 2/4] block: add BlockBackend->in_flight counter Stefan Hajnoczi
2018-02-13 16:03 ` Eric Blake
2018-02-13 14:21 ` [Qemu-devel] [PATCH v2 3/4] block: test blk_aio_flush() with blk->root == NULL Stefan Hajnoczi
2018-02-13 14:21 ` [Qemu-devel] [PATCH v2 4/4] Revert "IDE: Do not flush empty CDROM drives" Stefan Hajnoczi
2018-02-15 9:28 ` [Qemu-devel] [PATCH v2 0/4] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
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=73eb771d-ddcd-42e6-5895-23e6024ccc80@redhat.com \
--to=eblake@redhat.com \
--cc=jsnow@redhat.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.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).