diff mbox

[10/16] block: explicitly acquire aiocontext in timers that need it

Message ID 20170113131731.1246-11-pbonzini@redhat.com
State New
Headers show

Commit Message

Paolo Bonzini Jan. 13, 2017, 1:17 p.m. UTC
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 aio-posix.c                 |  2 --
 aio-win32.c                 |  2 --
 block/curl.c                |  2 ++
 block/iscsi.c               |  8 ++++++--
 block/null.c                |  4 ++++
 block/qed.c                 | 12 ++++++++++++
 block/qed.h                 |  3 +++
 block/throttle-groups.c     |  2 ++
 util/qemu-coroutine-sleep.c |  2 +-
 9 files changed, 30 insertions(+), 7 deletions(-)

Comments

Fam Zheng Jan. 16, 2017, 1:07 p.m. UTC | #1
On Fri, 01/13 14:17, Paolo Bonzini wrote:
> diff --git a/block/qed.c b/block/qed.c
> index 7f1c508..a21d025 100644
> --- a/block/qed.c
> +++ b/block/qed.c
> @@ -345,10 +345,22 @@ static void qed_need_check_timer_cb(void *opaque)
>  
>      trace_qed_need_check_timer_cb(s);
>  
> +    qed_acquire(s);
>      qed_plug_allocating_write_reqs(s);
>  
>      /* Ensure writes are on disk before clearing flag */
>      bdrv_aio_flush(s->bs->file->bs, qed_clear_need_check, s);
> +    qed_release(s);
> +}
> +
> +void qed_acquire(BDRVQEDState *s)
> +{
> +    aio_context_acquire(bdrv_get_aio_context(s->bs));
> +}
> +
> +void qed_release(BDRVQEDState *s)
> +{
> +    aio_context_release(bdrv_get_aio_context(s->bs));
>  }
>  
>  static void qed_start_need_check_timer(BDRVQEDState *s)
> diff --git a/block/qed.h b/block/qed.h
> index 9676ab9..ce8c314 100644
> --- a/block/qed.h
> +++ b/block/qed.h
> @@ -198,6 +198,9 @@ enum {
>   */
>  typedef void QEDFindClusterFunc(void *opaque, int ret, uint64_t offset, size_t len);
>  
> +void qed_acquire(BDRVQEDState *s);
> +void qed_release(BDRVQEDState *s);
> +

Why cannot these be local (static) functions, in block/qed.c?

>  /**
>   * Generic callback for chaining async callbacks
>   */

Fam
Paolo Bonzini Jan. 16, 2017, 1:32 p.m. UTC | #2
On 16/01/2017 14:07, Fam Zheng wrote:
> On Fri, 01/13 14:17, Paolo Bonzini wrote:
>> diff --git a/block/qed.c b/block/qed.c
>> index 7f1c508..a21d025 100644
>> --- a/block/qed.c
>> +++ b/block/qed.c
>> @@ -345,10 +345,22 @@ static void qed_need_check_timer_cb(void *opaque)
>>  
>>      trace_qed_need_check_timer_cb(s);
>>  
>> +    qed_acquire(s);
>>      qed_plug_allocating_write_reqs(s);
>>  
>>      /* Ensure writes are on disk before clearing flag */
>>      bdrv_aio_flush(s->bs->file->bs, qed_clear_need_check, s);
>> +    qed_release(s);
>> +}
>> +
>> +void qed_acquire(BDRVQEDState *s)
>> +{
>> +    aio_context_acquire(bdrv_get_aio_context(s->bs));
>> +}
>> +
>> +void qed_release(BDRVQEDState *s)
>> +{
>> +    aio_context_release(bdrv_get_aio_context(s->bs));
>>  }
>>  
>>  static void qed_start_need_check_timer(BDRVQEDState *s)
>> diff --git a/block/qed.h b/block/qed.h
>> index 9676ab9..ce8c314 100644
>> --- a/block/qed.h
>> +++ b/block/qed.h
>> @@ -198,6 +198,9 @@ enum {
>>   */
>>  typedef void QEDFindClusterFunc(void *opaque, int ret, uint64_t offset, size_t len);
>>  
>> +void qed_acquire(BDRVQEDState *s);
>> +void qed_release(BDRVQEDState *s);
>> +
> 
> Why cannot these be local (static) functions, in block/qed.c?

Patch 13 uses them elsewhere.  Should I put them in a separate patch?

Paolo

>>  /**
>>   * Generic callback for chaining async callbacks
>>   */
> 
> Fam
> 
>
Fam Zheng Jan. 16, 2017, 1:50 p.m. UTC | #3
On Mon, 01/16 14:32, Paolo Bonzini wrote:
> > Why cannot these be local (static) functions, in block/qed.c?
> 
> Patch 13 uses them elsewhere.  Should I put them in a separate patch?

Thanks, this is fine!

Fam
Stefan Hajnoczi Jan. 18, 2017, 3:43 p.m. UTC | #4
On Fri, Jan 13, 2017 at 02:17:25PM +0100, Paolo Bonzini wrote:
> diff --git a/block/null.c b/block/null.c
> index b300390..356209a 100644
> --- a/block/null.c
> +++ b/block/null.c
> @@ -141,7 +141,11 @@ static void null_bh_cb(void *opaque)
>  static void null_timer_cb(void *opaque)
>  {
>      NullAIOCB *acb = opaque;
> +    AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
> +
> +    aio_context_acquire(ctx);
>      acb->common.cb(acb->common.opaque, 0);
> +    aio_context_release(ctx);
>      timer_deinit(&acb->timer);
>      qemu_aio_unref(acb);

Is qemu_aio_unref() thread-safe?
Paolo Bonzini Jan. 18, 2017, 4:44 p.m. UTC | #5
On 18/01/2017 16:43, Stefan Hajnoczi wrote:
> On Fri, Jan 13, 2017 at 02:17:25PM +0100, Paolo Bonzini wrote:
>> diff --git a/block/null.c b/block/null.c
>> index b300390..356209a 100644
>> --- a/block/null.c
>> +++ b/block/null.c
>> @@ -141,7 +141,11 @@ static void null_bh_cb(void *opaque)
>>  static void null_timer_cb(void *opaque)
>>  {
>>      NullAIOCB *acb = opaque;
>> +    AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
>> +
>> +    aio_context_acquire(ctx);
>>      acb->common.cb(acb->common.opaque, 0);
>> +    aio_context_release(ctx);
>>      timer_deinit(&acb->timer);
>>      qemu_aio_unref(acb);
> 
> Is qemu_aio_unref() thread-safe?

qemu_aio_ref()/qemu_aio_unref() is only used by bdrv_aio_cancel, which
in turn is not used by dataplane.  So in the multithreaded case
qemu_aio_unref() is effectively qemu_aio_free().

Probably needs more documentation, or a different implementation of
bdrv_aio_cancel (e.g. replacing the reference counting with a
NotifierList of some kind).  Let me know what you prefer for v2.

Paolo
Stefan Hajnoczi Jan. 19, 2017, 4:59 p.m. UTC | #6
On Wed, Jan 18, 2017 at 05:44:24PM +0100, Paolo Bonzini wrote:
> On 18/01/2017 16:43, Stefan Hajnoczi wrote:
> > On Fri, Jan 13, 2017 at 02:17:25PM +0100, Paolo Bonzini wrote:
> >> diff --git a/block/null.c b/block/null.c
> >> index b300390..356209a 100644
> >> --- a/block/null.c
> >> +++ b/block/null.c
> >> @@ -141,7 +141,11 @@ static void null_bh_cb(void *opaque)
> >>  static void null_timer_cb(void *opaque)
> >>  {
> >>      NullAIOCB *acb = opaque;
> >> +    AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
> >> +
> >> +    aio_context_acquire(ctx);
> >>      acb->common.cb(acb->common.opaque, 0);
> >> +    aio_context_release(ctx);
> >>      timer_deinit(&acb->timer);
> >>      qemu_aio_unref(acb);
> > 
> > Is qemu_aio_unref() thread-safe?
> 
> qemu_aio_ref()/qemu_aio_unref() is only used by bdrv_aio_cancel, which
> in turn is not used by dataplane.  So in the multithreaded case
> qemu_aio_unref() is effectively qemu_aio_free().
> 
> Probably needs more documentation, or a different implementation of
> bdrv_aio_cancel (e.g. replacing the reference counting with a
> NotifierList of some kind).  Let me know what you prefer for v2.

Documentation is fine.  I just checked and see that virtio-scsi
dataplane uses blk_aio_cancel_async() so the aio refcount is never
touched - no race.

Stefan
diff mbox

Patch

diff --git a/aio-posix.c b/aio-posix.c
index 3fd64fb..8d79cf3 100644
--- a/aio-posix.c
+++ b/aio-posix.c
@@ -454,9 +454,7 @@  bool aio_dispatch(AioContext *ctx, bool dispatch_fds)
     }
 
     /* Run our timers */
-    aio_context_acquire(ctx);
     progress |= timerlistgroup_run_timers(&ctx->tlg);
-    aio_context_release(ctx);
 
     return progress;
 }
diff --git a/aio-win32.c b/aio-win32.c
index ab6d0e5..810e1c6 100644
--- a/aio-win32.c
+++ b/aio-win32.c
@@ -403,9 +403,7 @@  bool aio_poll(AioContext *ctx, bool blocking)
         progress |= aio_dispatch_handlers(ctx, event);
     } while (count > 0);
 
-    aio_context_acquire(ctx);
     progress |= timerlistgroup_run_timers(&ctx->tlg);
-    aio_context_release(ctx);
     return progress;
 }
 
diff --git a/block/curl.c b/block/curl.c
index 792fef8..65e6da1 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -424,9 +424,11 @@  static void curl_multi_timeout_do(void *arg)
         return;
     }
 
+    aio_context_acquire(s->aio_context);
     curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
 
     curl_multi_check_completion(s);
+    aio_context_release(s->aio_context);
 #else
     abort();
 #endif
diff --git a/block/iscsi.c b/block/iscsi.c
index 6aeeb9e..e1f10d6 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -174,7 +174,7 @@  static void iscsi_retry_timer_expired(void *opaque)
     struct IscsiTask *iTask = opaque;
     iTask->complete = 1;
     if (iTask->co) {
-        qemu_coroutine_enter(iTask->co);
+        aio_co_wake(iTask->co);
     }
 }
 
@@ -1388,16 +1388,20 @@  static void iscsi_nop_timed_event(void *opaque)
 {
     IscsiLun *iscsilun = opaque;
 
+    aio_context_acquire(iscsilun->aio_context);
     if (iscsi_get_nops_in_flight(iscsilun->iscsi) >= MAX_NOP_FAILURES) {
         error_report("iSCSI: NOP timeout. Reconnecting...");
         iscsilun->request_timed_out = true;
     } else if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) {
         error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages.");
-        return;
+        goto out;
     }
 
     timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
     iscsi_set_events(iscsilun);
+
+out:
+    aio_context_release(iscsilun->aio_context);
 }
 
 static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
diff --git a/block/null.c b/block/null.c
index b300390..356209a 100644
--- a/block/null.c
+++ b/block/null.c
@@ -141,7 +141,11 @@  static void null_bh_cb(void *opaque)
 static void null_timer_cb(void *opaque)
 {
     NullAIOCB *acb = opaque;
+    AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
+
+    aio_context_acquire(ctx);
     acb->common.cb(acb->common.opaque, 0);
+    aio_context_release(ctx);
     timer_deinit(&acb->timer);
     qemu_aio_unref(acb);
 }
diff --git a/block/qed.c b/block/qed.c
index 7f1c508..a21d025 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -345,10 +345,22 @@  static void qed_need_check_timer_cb(void *opaque)
 
     trace_qed_need_check_timer_cb(s);
 
+    qed_acquire(s);
     qed_plug_allocating_write_reqs(s);
 
     /* Ensure writes are on disk before clearing flag */
     bdrv_aio_flush(s->bs->file->bs, qed_clear_need_check, s);
+    qed_release(s);
+}
+
+void qed_acquire(BDRVQEDState *s)
+{
+    aio_context_acquire(bdrv_get_aio_context(s->bs));
+}
+
+void qed_release(BDRVQEDState *s)
+{
+    aio_context_release(bdrv_get_aio_context(s->bs));
 }
 
 static void qed_start_need_check_timer(BDRVQEDState *s)
diff --git a/block/qed.h b/block/qed.h
index 9676ab9..ce8c314 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -198,6 +198,9 @@  enum {
  */
 typedef void QEDFindClusterFunc(void *opaque, int ret, uint64_t offset, size_t len);
 
+void qed_acquire(BDRVQEDState *s);
+void qed_release(BDRVQEDState *s);
+
 /**
  * Generic callback for chaining async callbacks
  */
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
index 17b2efb..aade5de 100644
--- a/block/throttle-groups.c
+++ b/block/throttle-groups.c
@@ -416,7 +416,9 @@  static void timer_cb(BlockBackend *blk, bool is_write)
     qemu_mutex_unlock(&tg->lock);
 
     /* Run the request that was waiting for this timer */
+    aio_context_acquire(blk_get_aio_context(blk));
     empty_queue = !qemu_co_enter_next(&blkp->throttled_reqs[is_write]);
+    aio_context_release(blk_get_aio_context(blk));
 
     /* If the request queue was empty then we have to take care of
      * scheduling the next one */
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
index 25de3ed..9c56550 100644
--- a/util/qemu-coroutine-sleep.c
+++ b/util/qemu-coroutine-sleep.c
@@ -25,7 +25,7 @@  static void co_sleep_cb(void *opaque)
 {
     CoSleepCB *sleep_cb = opaque;
 
-    qemu_coroutine_enter(sleep_cb->co);
+    aio_co_wake(sleep_cb->co);
 }
 
 void coroutine_fn co_aio_sleep_ns(AioContext *ctx, QEMUClockType type,