qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Fam Zheng <famz@redhat.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: kwolf@redhat.com, stefanha@redhat.com, qemu-devel@nongnu.org,
	qemu-block@nongnu.org
Subject: Re: [Qemu-devel] [PATCH 01/18] iothread: release iothread around aio_poll
Date: Wed, 9 Sep 2015 14:06:19 +0800	[thread overview]
Message-ID: <20150909060619.GB21413@ad.nay.redhat.com> (raw)
In-Reply-To: <1438868176-20364-2-git-send-email-pbonzini@redhat.com>

On Thu, 08/06 15:35, Paolo Bonzini wrote:
> This is the first step towards having fine-grained critical sections in
> dataplane threads, which resolves lock ordering problems between
> address_space_* functions (which need the BQL when doing MMIO, even
> after we complete RCU-based dispatch) and the AioContext.
> 
> Because AioContext does not use contention callbacks anymore, the
> unit test has to be changed.
> 
> Previously applied as a0710f7995f914e3044e5899bd8ff6c43c62f916 and
> then reverted.
> 
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  async.c                     | 22 +++-------------------
>  docs/multiple-iothreads.txt | 25 +++++++++++++++----------
>  include/block/aio.h         |  3 ---
>  iothread.c                  | 11 ++---------
>  tests/test-aio.c            | 19 +++++++++++--------
>  5 files changed, 31 insertions(+), 49 deletions(-)
> 
> diff --git a/async.c b/async.c
> index efce14b..f992914 100644
> --- a/async.c
> +++ b/async.c
> @@ -79,8 +79,8 @@ int aio_bh_poll(AioContext *ctx)
>           * aio_notify again if necessary.
>           */
>          if (!bh->deleted && atomic_xchg(&bh->scheduled, 0)) {
> -            /* Idle BHs and the notify BH don't count as progress */
> -            if (!bh->idle && bh != ctx->notify_dummy_bh) {
> +            /* Idle BHs don't count as progress */
> +            if (!bh->idle) {
>                  ret = 1;
>              }
>              bh->idle = 0;
> @@ -232,7 +232,6 @@ aio_ctx_finalize(GSource     *source)
>  {
>      AioContext *ctx = (AioContext *) source;
>  
> -    qemu_bh_delete(ctx->notify_dummy_bh);
>      thread_pool_free(ctx->thread_pool);
>  
>      qemu_mutex_lock(&ctx->bh_lock);
> @@ -299,19 +298,6 @@ static void aio_timerlist_notify(void *opaque)
>      aio_notify(opaque);
>  }
>  
> -static void aio_rfifolock_cb(void *opaque)
> -{
> -    AioContext *ctx = opaque;
> -
> -    /* Kick owner thread in case they are blocked in aio_poll() */
> -    qemu_bh_schedule(ctx->notify_dummy_bh);
> -}
> -
> -static void notify_dummy_bh(void *opaque)
> -{
> -    /* Do nothing, we were invoked just to force the event loop to iterate */
> -}
> -
>  static void event_notifier_dummy_cb(EventNotifier *e)
>  {
>  }
> @@ -333,11 +319,9 @@ AioContext *aio_context_new(Error **errp)
>                             event_notifier_dummy_cb);
>      ctx->thread_pool = NULL;
>      qemu_mutex_init(&ctx->bh_lock);
> -    rfifolock_init(&ctx->lock, aio_rfifolock_cb, ctx);
> +    rfifolock_init(&ctx->lock, NULL, NULL);
>      timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx);
>  
> -    ctx->notify_dummy_bh = aio_bh_new(ctx, notify_dummy_bh, NULL);
> -
>      return ctx;
>  }
>  
> diff --git a/docs/multiple-iothreads.txt b/docs/multiple-iothreads.txt
> index 40b8419..723cc7e 100644
> --- a/docs/multiple-iothreads.txt
> +++ b/docs/multiple-iothreads.txt
> @@ -105,13 +105,10 @@ a BH in the target AioContext beforehand and then call qemu_bh_schedule().  No
>  acquire/release or locking is needed for the qemu_bh_schedule() call.  But be
>  sure to acquire the AioContext for aio_bh_new() if necessary.
>  
> -The relationship between AioContext and the block layer
> --------------------------------------------------------
> -The AioContext originates from the QEMU block layer because it provides a
> -scoped way of running event loop iterations until all work is done.  This
> -feature is used to complete all in-flight block I/O requests (see
> -bdrv_drain_all()).  Nowadays AioContext is a generic event loop that can be
> -used by any QEMU subsystem.
> +AioContext and the block layer
> +------------------------------
> +The AioContext originates from the QEMU block layer, even though nowadays
> +AioContext is a generic event loop that can be used by any QEMU subsystem.
>  
>  The block layer has support for AioContext integrated.  Each BlockDriverState
>  is associated with an AioContext using bdrv_set_aio_context() and
> @@ -122,9 +119,17 @@ Block layer code must therefore expect to run in an IOThread and avoid using
>  old APIs that implicitly use the main loop.  See the "How to program for
>  IOThreads" above for information on how to do that.
>  
> -If main loop code such as a QMP function wishes to access a BlockDriverState it
> -must first call aio_context_acquire(bdrv_get_aio_context(bs)) to ensure the
> -IOThread does not run in parallel.
> +If main loop code such as a QMP function wishes to access a BlockDriverState
> +it must first call aio_context_acquire(bdrv_get_aio_context(bs)) to ensure
> +that callbacks in the IOThread do not run in parallel.
> +
> +Code running in the monitor typically uses bdrv_drain() to ensure that
> +past requests from the guest are completed.  When a block device is
> +running in an IOThread, the IOThread can also process requests from
> +the guest (via ioeventfd).  These requests have to be blocked with
> +aio_disable_clients() before calling bdrv_drain().  You can then reenable
> +guest requests with aio_enable_clients() before finally releasing the
> +AioContext and completing the monitor command.

This patch will probably go in before aio_disable_clients, if any, but I'm not
quite confident about the interface yet: listing a precise set of clients from
monitor is an ugly coupling between modules:

    aio_disable_clients(bdrv_get_aio_context(bs),
                        AIO_CLIENT_NBD | AIO_CLIENT_IOEVENTFD | AIO_CLIENT_FOO);

    ...

    aio_enble_clients(bdrv_get_aio_context(bs),
                      AIO_CLIENT_NBD | AIO_CLIENT_IOEVENTFD | AIO_CLIENT_FOO);

I prefer at least an abstraction:

    bdrv_quiesce_begin(bs);

    ...

    bdrv_quiesce_end(bs);

My point is maybe we should leave documenting this to whichever series that
introduces it?

Fam

>  
>  Long-running jobs (usually in the form of coroutines) are best scheduled in the
>  BlockDriverState's AioContext to avoid the need to acquire/release around each
> diff --git a/include/block/aio.h b/include/block/aio.h
> index 400b1b0..9dd32e0 100644
> --- a/include/block/aio.h
> +++ b/include/block/aio.h
> @@ -114,9 +114,6 @@ struct AioContext {
>      bool notified;
>      EventNotifier notifier;
>  
> -    /* Scheduling this BH forces the event loop it iterate */
> -    QEMUBH *notify_dummy_bh;
> -
>      /* Thread pool for performing work and receiving completion callbacks */
>      struct ThreadPool *thread_pool;
>  
> diff --git a/iothread.c b/iothread.c
> index da6ce7b..8f6d2e4 100644
> --- a/iothread.c
> +++ b/iothread.c
> @@ -30,7 +30,6 @@ typedef ObjectClass IOThreadClass;
>  static void *iothread_run(void *opaque)
>  {
>      IOThread *iothread = opaque;
> -    bool blocking;
>  
>      rcu_register_thread();
>  
> @@ -39,14 +38,8 @@ static void *iothread_run(void *opaque)
>      qemu_cond_signal(&iothread->init_done_cond);
>      qemu_mutex_unlock(&iothread->init_done_lock);
>  
> -    while (!iothread->stopping) {
> -        aio_context_acquire(iothread->ctx);
> -        blocking = true;
> -        while (!iothread->stopping && aio_poll(iothread->ctx, blocking)) {
> -            /* Progress was made, keep going */
> -            blocking = false;
> -        }
> -        aio_context_release(iothread->ctx);
> +    while (!atomic_read(&iothread->stopping)) {
> +        aio_poll(iothread->ctx, true);
>      }
>  
>      rcu_unregister_thread();
> diff --git a/tests/test-aio.c b/tests/test-aio.c
> index 217e337..b4bd3f1 100644
> --- a/tests/test-aio.c
> +++ b/tests/test-aio.c
> @@ -99,6 +99,7 @@ static void event_ready_cb(EventNotifier *e)
>  
>  typedef struct {
>      QemuMutex start_lock;
> +    EventNotifier notifier;
>      bool thread_acquired;
>  } AcquireTestData;
>  
> @@ -110,6 +111,8 @@ static void *test_acquire_thread(void *opaque)
>      qemu_mutex_lock(&data->start_lock);
>      qemu_mutex_unlock(&data->start_lock);
>  
> +    g_usleep(500000);
> +    event_notifier_set(&data->notifier);
>      aio_context_acquire(ctx);
>      aio_context_release(ctx);
>  
> @@ -118,20 +121,19 @@ static void *test_acquire_thread(void *opaque)
>      return NULL;
>  }
>  
> -static void dummy_notifier_read(EventNotifier *unused)
> +static void dummy_notifier_read(EventNotifier *n)
>  {
> -    g_assert(false); /* should never be invoked */
> +    event_notifier_test_and_clear(n);
>  }
>  
>  static void test_acquire(void)
>  {
>      QemuThread thread;
> -    EventNotifier notifier;
>      AcquireTestData data;
>  
>      /* Dummy event notifier ensures aio_poll() will block */
> -    event_notifier_init(&notifier, false);
> -    aio_set_event_notifier(ctx, &notifier, dummy_notifier_read);
> +    event_notifier_init(&data.notifier, false);
> +    aio_set_event_notifier(ctx, &data.notifier, dummy_notifier_read);
>      g_assert(!aio_poll(ctx, false)); /* consume aio_notify() */
>  
>      qemu_mutex_init(&data.start_lock);
> @@ -145,12 +147,13 @@ static void test_acquire(void)
>      /* Block in aio_poll(), let other thread kick us and acquire context */
>      aio_context_acquire(ctx);
>      qemu_mutex_unlock(&data.start_lock); /* let the thread run */
> -    g_assert(!aio_poll(ctx, true));
> +    g_assert(aio_poll(ctx, true));
> +    g_assert(!data.thread_acquired);
>      aio_context_release(ctx);
>  
>      qemu_thread_join(&thread);
> -    aio_set_event_notifier(ctx, &notifier, NULL);
> -    event_notifier_cleanup(&notifier);
> +    aio_set_event_notifier(ctx, &data.notifier, NULL);
> +    event_notifier_cleanup(&data.notifier);
>  
>      g_assert(data.thread_acquired);
>  }
> -- 
> 2.4.3
> 
> 

  reply	other threads:[~2015-09-09  6:06 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-08-06 13:35 [Qemu-devel] [RFC PATCH 00/18] Fine-grained AioContext critical sections Paolo Bonzini
2015-08-06 13:35 ` [Qemu-devel] [PATCH 01/18] iothread: release iothread around aio_poll Paolo Bonzini
2015-09-09  6:06   ` Fam Zheng [this message]
2015-09-09  7:31     ` Paolo Bonzini
2015-09-28  9:50   ` Stefan Hajnoczi
2015-09-28 10:14     ` Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 02/18] aio: rename bh_lock to list_lock Paolo Bonzini
2015-09-09  6:08   ` Fam Zheng
2015-09-28 10:09   ` Stefan Hajnoczi
2015-08-06 13:36 ` [Qemu-devel] [PATCH 03/18] qemu-thread: introduce QemuLockCnt Paolo Bonzini
2015-09-09  8:49   ` Fam Zheng
2015-09-09  9:14     ` Paolo Bonzini
2015-09-28 10:15   ` Stefan Hajnoczi
2015-09-28 10:17     ` Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 04/18] aio: make ctx->list_lock a QemuLockCnt, subsuming ctx->walking_bh Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 05/18] aio: tweak walking in dispatch phase Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 06/18] aio-posix: remove walking_handlers, protecting AioHandler list with list_lock Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 07/18] aio-win32: " Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 08/18] aio: document locking Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 09/18] aio: push aio_context_acquire/release down to dispatching Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 10/18] async: optimize aio_bh_poll Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 11/18] qemu-timer: optimize timerlist_run_timers Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 12/18] block: explicitly acquire aiocontext in callbacks that need it Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 13/18] block: explicitly acquire aiocontext in bottom halves " Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 14/18] block: explicitly acquire aiocontext in timers " Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 15/18] quorum: use atomics for rewrite_count Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 16/18] quorum: split quorum_fifo_aio_cb from quorum_aio_cb Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 17/18] block: explicitly acquire aiocontext in aio callbacks that need it Paolo Bonzini
2015-08-06 13:36 ` [Qemu-devel] [PATCH 18/18] aio: update locking documentation Paolo Bonzini

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=20150909060619.GB21413@ad.nay.redhat.com \
    --to=famz@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-block@nongnu.org \
    --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).