qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH for-2.1? 0/2] thread-pool: avoid fd usage and fix nested aio_poll() deadlock
@ 2014-07-11 11:20 Stefan Hajnoczi
  2014-07-11 11:20 ` [Qemu-devel] [PATCH for-2.1? 1/2] thread-pool: avoid per-thread-pool EventNotifier Stefan Hajnoczi
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2014-07-11 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Paolo Bonzini, Christian Borntraeger

These patches convert thread-pool.c from EventNotifier to QEMUBH.  They then
solve the deadlock when nested aio_poll() calls are made.

Please speak out whether you want this in QEMU 2.1 or not.  I'm not aware of
the nested aio_poll() deadlock ever having been reported, so maybe we can defer
to QEMU 2.2.

Stefan Hajnoczi (2):
  thread-pool: avoid per-thread-pool EventNotifier
  thread-pool: avoid deadlock in nested aio_poll() calls

 thread-pool.c | 44 +++++++++++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 13 deletions(-)

-- 
1.9.3

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH for-2.1? 1/2] thread-pool: avoid per-thread-pool EventNotifier
  2014-07-11 11:20 [Qemu-devel] [PATCH for-2.1? 0/2] thread-pool: avoid fd usage and fix nested aio_poll() deadlock Stefan Hajnoczi
@ 2014-07-11 11:20 ` Stefan Hajnoczi
  2014-07-11 11:20 ` [Qemu-devel] [PATCH for-2.1? 2/2] thread-pool: avoid deadlock in nested aio_poll() calls Stefan Hajnoczi
  2014-07-11 11:37 ` [Qemu-devel] [PATCH for-2.1? 0/2] thread-pool: avoid fd usage and fix nested aio_poll() deadlock Christian Borntraeger
  2 siblings, 0 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2014-07-11 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Paolo Bonzini, Christian Borntraeger

EventNotifier is implemented using an eventfd or pipe.  It therefore
consumes file descriptors, which can be limited by rlimits and should
therefore be used sparingly.

Switch from EventNotifier to QEMUBH in thread-pool.c.  Originally
EventNotifier was used because qemu_bh_schedule() was not thread-safe
yet.

Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 thread-pool.c | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/thread-pool.c b/thread-pool.c
index dfb699d..4cfd078 100644
--- a/thread-pool.c
+++ b/thread-pool.c
@@ -21,7 +21,6 @@
 #include "block/coroutine.h"
 #include "trace.h"
 #include "block/block_int.h"
-#include "qemu/event_notifier.h"
 #include "block/thread-pool.h"
 #include "qemu/main-loop.h"
 
@@ -57,8 +56,8 @@ struct ThreadPoolElement {
 };
 
 struct ThreadPool {
-    EventNotifier notifier;
     AioContext *ctx;
+    QEMUBH *completion_bh;
     QemuMutex lock;
     QemuCond check_cancel;
     QemuCond worker_stopped;
@@ -119,7 +118,7 @@ static void *worker_thread(void *opaque)
             qemu_cond_broadcast(&pool->check_cancel);
         }
 
-        event_notifier_set(&pool->notifier);
+        qemu_bh_schedule(pool->completion_bh);
     }
 
     pool->cur_threads--;
@@ -168,12 +167,11 @@ static void spawn_thread(ThreadPool *pool)
     }
 }
 
-static void event_notifier_ready(EventNotifier *notifier)
+static void thread_pool_completion_bh(void *opaque)
 {
-    ThreadPool *pool = container_of(notifier, ThreadPool, notifier);
+    ThreadPool *pool = opaque;
     ThreadPoolElement *elem, *next;
 
-    event_notifier_test_and_clear(notifier);
 restart:
     QLIST_FOREACH_SAFE(elem, &pool->head, all, next) {
         if (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) {
@@ -215,7 +213,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb)
         qemu_sem_timedwait(&pool->sem, 0) == 0) {
         QTAILQ_REMOVE(&pool->request_list, elem, reqs);
         elem->state = THREAD_CANCELED;
-        event_notifier_set(&pool->notifier);
+        qemu_bh_schedule(pool->completion_bh);
     } else {
         pool->pending_cancellations++;
         while (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) {
@@ -224,7 +222,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb)
         pool->pending_cancellations--;
     }
     qemu_mutex_unlock(&pool->lock);
-    event_notifier_ready(&pool->notifier);
+    thread_pool_completion_bh(pool);
 }
 
 static const AIOCBInfo thread_pool_aiocb_info = {
@@ -293,8 +291,8 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
     }
 
     memset(pool, 0, sizeof(*pool));
-    event_notifier_init(&pool->notifier, false);
     pool->ctx = ctx;
+    pool->completion_bh = aio_bh_new(ctx, thread_pool_completion_bh, pool);
     qemu_mutex_init(&pool->lock);
     qemu_cond_init(&pool->check_cancel);
     qemu_cond_init(&pool->worker_stopped);
@@ -304,8 +302,6 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
 
     QLIST_INIT(&pool->head);
     QTAILQ_INIT(&pool->request_list);
-
-    aio_set_event_notifier(ctx, &pool->notifier, event_notifier_ready);
 }
 
 ThreadPool *thread_pool_new(AioContext *ctx)
@@ -339,11 +335,10 @@ void thread_pool_free(ThreadPool *pool)
 
     qemu_mutex_unlock(&pool->lock);
 
-    aio_set_event_notifier(pool->ctx, &pool->notifier, NULL);
+    qemu_bh_delete(pool->completion_bh);
     qemu_sem_destroy(&pool->sem);
     qemu_cond_destroy(&pool->check_cancel);
     qemu_cond_destroy(&pool->worker_stopped);
     qemu_mutex_destroy(&pool->lock);
-    event_notifier_cleanup(&pool->notifier);
     g_free(pool);
 }
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCH for-2.1? 2/2] thread-pool: avoid deadlock in nested aio_poll() calls
  2014-07-11 11:20 [Qemu-devel] [PATCH for-2.1? 0/2] thread-pool: avoid fd usage and fix nested aio_poll() deadlock Stefan Hajnoczi
  2014-07-11 11:20 ` [Qemu-devel] [PATCH for-2.1? 1/2] thread-pool: avoid per-thread-pool EventNotifier Stefan Hajnoczi
@ 2014-07-11 11:20 ` Stefan Hajnoczi
  2014-07-14  8:36   ` Paolo Bonzini
  2014-07-11 11:37 ` [Qemu-devel] [PATCH for-2.1? 0/2] thread-pool: avoid fd usage and fix nested aio_poll() deadlock Christian Borntraeger
  2 siblings, 1 reply; 10+ messages in thread
From: Stefan Hajnoczi @ 2014-07-11 11:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: Paolo Bonzini, Christian Borntraeger

The thread pool has a race condition if two elements complete before
thread_pool_completion_bh() runs:

  If element A's callback waits for element B using aio_poll() it will
  deadlock since pool->completion_bh is not marked scheduled when the
  nested aio_poll() runs.

Fix this by marking the BH scheduled while thread_pool_completion_bh()
is executing.  This way any nested aio_poll() loops will enter
thread_pool_completion_bh() and complete the remaining elements.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 thread-pool.c | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/thread-pool.c b/thread-pool.c
index 4cfd078..0ede168 100644
--- a/thread-pool.c
+++ b/thread-pool.c
@@ -65,6 +65,9 @@ struct ThreadPool {
     int max_threads;
     QEMUBH *new_thread_bh;
 
+    /* Atomic counter to detect completions while completion handler runs */
+    uint32_t completion_token;
+
     /* The following variables are only accessed from one AioContext. */
     QLIST_HEAD(, ThreadPoolElement) head;
 
@@ -118,6 +121,7 @@ static void *worker_thread(void *opaque)
             qemu_cond_broadcast(&pool->check_cancel);
         }
 
+        atomic_inc(&pool->completion_token);
         qemu_bh_schedule(pool->completion_bh);
     }
 
@@ -167,9 +171,8 @@ static void spawn_thread(ThreadPool *pool)
     }
 }
 
-static void thread_pool_completion_bh(void *opaque)
+static void thread_pool_complete_elements(ThreadPool *pool)
 {
-    ThreadPool *pool = opaque;
     ThreadPoolElement *elem, *next;
 
 restart:
@@ -196,6 +199,26 @@ restart:
     }
 }
 
+static void thread_pool_completion_bh(void *opaque)
+{
+    ThreadPool *pool = opaque;
+    uint32_t token;
+
+    do {
+        token = atomic_mb_read(&pool->completion_token);
+
+        /* Stay scheduled in case elem->common.cb() makes a nested aio_poll()
+         * call.  This avoids deadlock if element A's callback waits for
+         * element B and both completed at the same time.
+         */
+        qemu_bh_schedule(pool->completion_bh);
+
+        thread_pool_complete_elements(pool);
+
+        qemu_bh_cancel(pool->completion_bh);
+    } while (token != pool->completion_token);
+}
+
 static void thread_pool_cancel(BlockDriverAIOCB *acb)
 {
     ThreadPoolElement *elem = (ThreadPoolElement *)acb;
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.1? 0/2] thread-pool: avoid fd usage and fix nested aio_poll() deadlock
  2014-07-11 11:20 [Qemu-devel] [PATCH for-2.1? 0/2] thread-pool: avoid fd usage and fix nested aio_poll() deadlock Stefan Hajnoczi
  2014-07-11 11:20 ` [Qemu-devel] [PATCH for-2.1? 1/2] thread-pool: avoid per-thread-pool EventNotifier Stefan Hajnoczi
  2014-07-11 11:20 ` [Qemu-devel] [PATCH for-2.1? 2/2] thread-pool: avoid deadlock in nested aio_poll() calls Stefan Hajnoczi
@ 2014-07-11 11:37 ` Christian Borntraeger
  2 siblings, 0 replies; 10+ messages in thread
From: Christian Borntraeger @ 2014-07-11 11:37 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: Paolo Bonzini

On 11/07/14 13:20, Stefan Hajnoczi wrote:
> These patches convert thread-pool.c from EventNotifier to QEMUBH.  They then
> solve the deadlock when nested aio_poll() calls are made.
> 
> Please speak out whether you want this in QEMU 2.1 or not.  I'm not aware of
> the nested aio_poll() deadlock ever having been reported, so maybe we can defer
> to QEMU 2.2.
> 
> Stefan Hajnoczi (2):
>   thread-pool: avoid per-thread-pool EventNotifier
>   thread-pool: avoid deadlock in nested aio_poll() calls
> 
>  thread-pool.c | 44 +++++++++++++++++++++++++++++++-------------
>  1 file changed, 31 insertions(+), 13 deletions(-)
> 

Seems to work ok and saves an fd. I think its still better scheduled for 2.2

Christian

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.1? 2/2] thread-pool: avoid deadlock in nested aio_poll() calls
  2014-07-11 11:20 ` [Qemu-devel] [PATCH for-2.1? 2/2] thread-pool: avoid deadlock in nested aio_poll() calls Stefan Hajnoczi
@ 2014-07-14  8:36   ` Paolo Bonzini
  2014-07-14 10:49     ` Paolo Bonzini
  2014-07-15 14:23     ` Stefan Hajnoczi
  0 siblings, 2 replies; 10+ messages in thread
From: Paolo Bonzini @ 2014-07-14  8:36 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: Christian Borntraeger

Il 11/07/2014 13:20, Stefan Hajnoczi ha scritto:
> The thread pool has a race condition if two elements complete before
> thread_pool_completion_bh() runs:
>
>   If element A's callback waits for element B using aio_poll() it will
>   deadlock since pool->completion_bh is not marked scheduled when the
>   nested aio_poll() runs.
>
> Fix this by marking the BH scheduled while thread_pool_completion_bh()
> is executing.  This way any nested aio_poll() loops will enter
> thread_pool_completion_bh() and complete the remaining elements.
>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  thread-pool.c | 27 +++++++++++++++++++++++++--
>  1 file changed, 25 insertions(+), 2 deletions(-)
>
> diff --git a/thread-pool.c b/thread-pool.c
> index 4cfd078..0ede168 100644
> --- a/thread-pool.c
> +++ b/thread-pool.c
> @@ -65,6 +65,9 @@ struct ThreadPool {
>      int max_threads;
>      QEMUBH *new_thread_bh;
>
> +    /* Atomic counter to detect completions while completion handler runs */
> +    uint32_t completion_token;
> +
>      /* The following variables are only accessed from one AioContext. */
>      QLIST_HEAD(, ThreadPoolElement) head;
>
> @@ -118,6 +121,7 @@ static void *worker_thread(void *opaque)
>              qemu_cond_broadcast(&pool->check_cancel);
>          }
>
> +        atomic_inc(&pool->completion_token);
>          qemu_bh_schedule(pool->completion_bh);
>      }
>
> @@ -167,9 +171,8 @@ static void spawn_thread(ThreadPool *pool)
>      }
>  }
>
> -static void thread_pool_completion_bh(void *opaque)
> +static void thread_pool_complete_elements(ThreadPool *pool)
>  {
> -    ThreadPool *pool = opaque;
>      ThreadPoolElement *elem, *next;
>
>  restart:
> @@ -196,6 +199,26 @@ restart:
>      }
>  }
>
> +static void thread_pool_completion_bh(void *opaque)
> +{
> +    ThreadPool *pool = opaque;
> +    uint32_t token;
> +
> +    do {
> +        token = atomic_mb_read(&pool->completion_token);
> +
> +        /* Stay scheduled in case elem->common.cb() makes a nested aio_poll()
> +         * call.  This avoids deadlock if element A's callback waits for
> +         * element B and both completed at the same time.
> +         */
> +        qemu_bh_schedule(pool->completion_bh);
> +
> +        thread_pool_complete_elements(pool);
> +
> +        qemu_bh_cancel(pool->completion_bh);
> +    } while (token != pool->completion_token);
> +}
> +
>  static void thread_pool_cancel(BlockDriverAIOCB *acb)
>  {
>      ThreadPoolElement *elem = (ThreadPoolElement *)acb;
>

I am not sure I understand this patch.

The simplest way to fix deadlock is to change this in 
thread_pool_completion_bh:

             elem->common.cb(elem->common.opaque, elem->ret);
             qemu_aio_release(elem);
             goto restart;

to

             /* In case elem->common.cb() makes a nested aio_poll() call,
              * next may become invalid as well.  Instead of just
              * restarting the QLIST_FOREACH_SAFE, go through the BH
              * once more, which also avoids deadlock if element A's
              * callback waits for element B and both completed at the
              * same time.
              */
             qemu_bh_schedule(pool->completion_bh);
             elem->common.cb(elem->common.opaque, elem->ret);
             qemu_aio_release(elem);

There is no change in logic, it's just that the goto is switched to a BH 
representing a continuation.  I am then not sure why 
pool->completion_token is necessary?

Perhaps it is just an optimization to avoid going multiple times around 
aio_poll()?

Paolo

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.1? 2/2] thread-pool: avoid deadlock in nested aio_poll() calls
  2014-07-14  8:36   ` Paolo Bonzini
@ 2014-07-14 10:49     ` Paolo Bonzini
  2014-07-15 14:37       ` Stefan Hajnoczi
  2014-07-15 14:23     ` Stefan Hajnoczi
  1 sibling, 1 reply; 10+ messages in thread
From: Paolo Bonzini @ 2014-07-14 10:49 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: Christian Borntraeger

Il 14/07/2014 10:36, Paolo Bonzini ha scritto:
>
>
> to
>
>             /* In case elem->common.cb() makes a nested aio_poll() call,
>              * next may become invalid as well.  Instead of just
>              * restarting the QLIST_FOREACH_SAFE, go through the BH
>              * once more, which also avoids deadlock if element A's
>              * callback waits for element B and both completed at the
>              * same time.
>              */
>             qemu_bh_schedule(pool->completion_bh);
>             elem->common.cb(elem->common.opaque, elem->ret);
>             qemu_aio_release(elem);

This is of course missing here:

		break;

Paolo

>
> There is no change in logic, it's just that the goto is switched to a BH
> representing a continuation.  I am then not sure why
> pool->completion_token is necessary?

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.1? 2/2] thread-pool: avoid deadlock in nested aio_poll() calls
  2014-07-14  8:36   ` Paolo Bonzini
  2014-07-14 10:49     ` Paolo Bonzini
@ 2014-07-15 14:23     ` Stefan Hajnoczi
  1 sibling, 0 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2014-07-15 14:23 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Christian Borntraeger, qemu-devel, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 4201 bytes --]

On Mon, Jul 14, 2014 at 10:36:21AM +0200, Paolo Bonzini wrote:
> Il 11/07/2014 13:20, Stefan Hajnoczi ha scritto:
> >The thread pool has a race condition if two elements complete before
> >thread_pool_completion_bh() runs:
> >
> >  If element A's callback waits for element B using aio_poll() it will
> >  deadlock since pool->completion_bh is not marked scheduled when the
> >  nested aio_poll() runs.
> >
> >Fix this by marking the BH scheduled while thread_pool_completion_bh()
> >is executing.  This way any nested aio_poll() loops will enter
> >thread_pool_completion_bh() and complete the remaining elements.
> >
> >Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> >---
> > thread-pool.c | 27 +++++++++++++++++++++++++--
> > 1 file changed, 25 insertions(+), 2 deletions(-)
> >
> >diff --git a/thread-pool.c b/thread-pool.c
> >index 4cfd078..0ede168 100644
> >--- a/thread-pool.c
> >+++ b/thread-pool.c
> >@@ -65,6 +65,9 @@ struct ThreadPool {
> >     int max_threads;
> >     QEMUBH *new_thread_bh;
> >
> >+    /* Atomic counter to detect completions while completion handler runs */
> >+    uint32_t completion_token;
> >+
> >     /* The following variables are only accessed from one AioContext. */
> >     QLIST_HEAD(, ThreadPoolElement) head;
> >
> >@@ -118,6 +121,7 @@ static void *worker_thread(void *opaque)
> >             qemu_cond_broadcast(&pool->check_cancel);
> >         }
> >
> >+        atomic_inc(&pool->completion_token);
> >         qemu_bh_schedule(pool->completion_bh);
> >     }
> >
> >@@ -167,9 +171,8 @@ static void spawn_thread(ThreadPool *pool)
> >     }
> > }
> >
> >-static void thread_pool_completion_bh(void *opaque)
> >+static void thread_pool_complete_elements(ThreadPool *pool)
> > {
> >-    ThreadPool *pool = opaque;
> >     ThreadPoolElement *elem, *next;
> >
> > restart:
> >@@ -196,6 +199,26 @@ restart:
> >     }
> > }
> >
> >+static void thread_pool_completion_bh(void *opaque)
> >+{
> >+    ThreadPool *pool = opaque;
> >+    uint32_t token;
> >+
> >+    do {
> >+        token = atomic_mb_read(&pool->completion_token);
> >+
> >+        /* Stay scheduled in case elem->common.cb() makes a nested aio_poll()
> >+         * call.  This avoids deadlock if element A's callback waits for
> >+         * element B and both completed at the same time.
> >+         */
> >+        qemu_bh_schedule(pool->completion_bh);
> >+
> >+        thread_pool_complete_elements(pool);
> >+
> >+        qemu_bh_cancel(pool->completion_bh);
> >+    } while (token != pool->completion_token);
> >+}
> >+
> > static void thread_pool_cancel(BlockDriverAIOCB *acb)
> > {
> >     ThreadPoolElement *elem = (ThreadPoolElement *)acb;
> >
> 
> I am not sure I understand this patch.
> 
> The simplest way to fix deadlock is to change this in
> thread_pool_completion_bh:
> 
>             elem->common.cb(elem->common.opaque, elem->ret);
>             qemu_aio_release(elem);
>             goto restart;
> 
> to
> 
>             /* In case elem->common.cb() makes a nested aio_poll() call,
>              * next may become invalid as well.  Instead of just
>              * restarting the QLIST_FOREACH_SAFE, go through the BH
>              * once more, which also avoids deadlock if element A's
>              * callback waits for element B and both completed at the
>              * same time.
>              */
>             qemu_bh_schedule(pool->completion_bh);
>             elem->common.cb(elem->common.opaque, elem->ret);
>             qemu_aio_release(elem);
> 
> There is no change in logic, it's just that the goto is switched to a BH
> representing a continuation.  I am then not sure why pool->completion_token
> is necessary?
> 
> Perhaps it is just an optimization to avoid going multiple times around
> aio_poll()?

Yes, it's just an optimization.  I wanted to cancel pool->completion_bh
to avoid needlessly entering the BH.  But if we call cancel then we must
watch for worker threads that complete a request while we're invoking
completions - hence the completion_token.

Your approach is simpler and I like that.  I'll send a v2.

Stefan

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.1? 2/2] thread-pool: avoid deadlock in nested aio_poll() calls
  2014-07-14 10:49     ` Paolo Bonzini
@ 2014-07-15 14:37       ` Stefan Hajnoczi
  2014-07-15 15:21         ` Paolo Bonzini
  0 siblings, 1 reply; 10+ messages in thread
From: Stefan Hajnoczi @ 2014-07-15 14:37 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Christian Borntraeger, qemu-devel, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 926 bytes --]

On Mon, Jul 14, 2014 at 12:49:38PM +0200, Paolo Bonzini wrote:
> Il 14/07/2014 10:36, Paolo Bonzini ha scritto:
> >
> >
> >to
> >
> >            /* In case elem->common.cb() makes a nested aio_poll() call,
> >             * next may become invalid as well.  Instead of just
> >             * restarting the QLIST_FOREACH_SAFE, go through the BH
> >             * once more, which also avoids deadlock if element A's
> >             * callback waits for element B and both completed at the
> >             * same time.
> >             */
> >            qemu_bh_schedule(pool->completion_bh);
> >            elem->common.cb(elem->common.opaque, elem->ret);
> >            qemu_aio_release(elem);
> 
> This is of course missing here:
> 
> 		break;

Let's keep goto restart so we don't use the BH for each completion
callback.  We just need the BH scheduled once to protect against the
deadlock.

Stefan

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.1? 2/2] thread-pool: avoid deadlock in nested aio_poll() calls
  2014-07-15 14:37       ` Stefan Hajnoczi
@ 2014-07-15 15:21         ` Paolo Bonzini
  2014-07-17 12:56           ` Stefan Hajnoczi
  0 siblings, 1 reply; 10+ messages in thread
From: Paolo Bonzini @ 2014-07-15 15:21 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: Christian Borntraeger, qemu-devel, Stefan Hajnoczi

Il 15/07/2014 16:37, Stefan Hajnoczi ha scritto:
>> > This is of course missing here:
>> >
>> > 		break;
> Let's keep goto restart so we don't use the BH for each completion
> callback.  We just need the BH scheduled once to protect against the
> deadlock.

Ah, I missed this remark.

Then you could add qemu_bh_cancel at the end of the BH handler.  I do 
find the code a little harder to follow with the "goto" though, as it's 
not clear who will take care of the rest of the list...

Paolo

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.1? 2/2] thread-pool: avoid deadlock in nested aio_poll() calls
  2014-07-15 15:21         ` Paolo Bonzini
@ 2014-07-17 12:56           ` Stefan Hajnoczi
  0 siblings, 0 replies; 10+ messages in thread
From: Stefan Hajnoczi @ 2014-07-17 12:56 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Stefan Hajnoczi, qemu-devel, Christian Borntraeger

[-- Attachment #1: Type: text/plain, Size: 816 bytes --]

On Tue, Jul 15, 2014 at 05:21:21PM +0200, Paolo Bonzini wrote:
> Il 15/07/2014 16:37, Stefan Hajnoczi ha scritto:
> >>> This is of course missing here:
> >>>
> >>> 		break;
> >Let's keep goto restart so we don't use the BH for each completion
> >callback.  We just need the BH scheduled once to protect against the
> >deadlock.
> 
> Ah, I missed this remark.
> 
> Then you could add qemu_bh_cancel at the end of the BH handler.

No, because a worker thread could be completing a work item just as we
leave the BH handler.  Then the BH would be cancelled and the work item
completion would never get executed (until the next work item
completes).

This is why I needed the atomic completion_token.  That way I could
check whether more requests completed while we were in the BH handler.

Stefan

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-07-17 12:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-07-11 11:20 [Qemu-devel] [PATCH for-2.1? 0/2] thread-pool: avoid fd usage and fix nested aio_poll() deadlock Stefan Hajnoczi
2014-07-11 11:20 ` [Qemu-devel] [PATCH for-2.1? 1/2] thread-pool: avoid per-thread-pool EventNotifier Stefan Hajnoczi
2014-07-11 11:20 ` [Qemu-devel] [PATCH for-2.1? 2/2] thread-pool: avoid deadlock in nested aio_poll() calls Stefan Hajnoczi
2014-07-14  8:36   ` Paolo Bonzini
2014-07-14 10:49     ` Paolo Bonzini
2014-07-15 14:37       ` Stefan Hajnoczi
2014-07-15 15:21         ` Paolo Bonzini
2014-07-17 12:56           ` Stefan Hajnoczi
2014-07-15 14:23     ` Stefan Hajnoczi
2014-07-11 11:37 ` [Qemu-devel] [PATCH for-2.1? 0/2] thread-pool: avoid fd usage and fix nested aio_poll() deadlock Christian Borntraeger

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).