qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v3 14/15] blockjob: add AioContext attach/detach cal


From: Stefan Hajnoczi
Subject: [Qemu-devel] [PATCH v3 14/15] blockjob: add AioContext attach/detach callbacks
Date: Mon, 13 Jun 2016 18:05:34 +0100

Block jobs need callbacks to get their affairs in order when the
AioContext is switched.  Simple block jobs can get away without
implementing these callbacks.

The callbacks are needed if the block job accesses other
BlockDriverStates.  Other BDSes need to be moved to the new AioContext
in the attach callback.

The detach callback must be used to quiesce asynchronous I/O.  Although
bdrv_set_aio_context() internally calls bdrv_drain(), this isn't enough
when multiple BDSes are accessed by the job:

When completing requests on one BDS submits new requests on another BDS,
especially if this is cyclical, then a custom detach callback is needed.

Signed-off-by: Stefan Hajnoczi <address@hidden>
---
 blockjob.c               | 33 +++++++++++++++++++++++++++++++++
 include/block/blockjob.h | 14 ++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/blockjob.c b/blockjob.c
index b810d73..dd384fe 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -60,6 +60,33 @@ BlockJob *block_job_next(BlockJob *job)
     return QLIST_NEXT(job, job_list);
 }
 
+static void block_job_attached_aio_context(AioContext *new_context,
+                                           void *opaque)
+{
+    BlockJob *job = opaque;
+
+    if (job->driver->attached_aio_context) {
+        job->driver->attached_aio_context(job, new_context);
+    }
+
+    block_job_resume(job);
+}
+
+static void block_job_detach_aio_context(void *opaque)
+{
+    BlockJob *job = opaque;
+
+    block_job_pause(job);
+
+    if (job->driver->detach_aio_context) {
+        job->driver->detach_aio_context(job);
+    }
+
+    while (job->busy) {
+        aio_poll(blk_get_aio_context(job->blk), true);
+    }
+}
+
 void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
                        int64_t speed, BlockCompletionFunc *cb,
                        void *opaque, Error **errp)
@@ -92,6 +119,9 @@ void *block_job_create(const BlockJobDriver *driver, 
BlockDriverState *bs,
 
     QLIST_INSERT_HEAD(&block_jobs, job, job_list);
 
+    blk_add_aio_context_notifier(blk, block_job_attached_aio_context,
+                                 block_job_detach_aio_context, job);
+
     /* Only set speed when necessary to avoid NotSupported error */
     if (speed != 0) {
         Error *local_err = NULL;
@@ -117,6 +147,9 @@ void block_job_unref(BlockJob *job)
         BlockDriverState *bs = blk_bs(job->blk);
         bs->job = NULL;
         bdrv_op_unblock_all(bs, job->blocker);
+        blk_remove_aio_context_notifier(job->blk,
+                                        block_job_attached_aio_context,
+                                        block_job_detach_aio_context, job);
         blk_unref(job->blk);
         error_free(job->blocker);
         g_free(job->id);
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
index f83a4f0..604aff8 100644
--- a/include/block/blockjob.h
+++ b/include/block/blockjob.h
@@ -70,6 +70,20 @@ typedef struct BlockJobDriver {
      * never both.
      */
     void (*abort)(BlockJob *job);
+
+    /**
+     * If the callback is not NULL, it will be invoked before the job is
+     * resumed in a new AioContext.  This is the place to move any resources
+     * besides job->blk to the new AioContext.
+     */
+    void (*attached_aio_context)(BlockJob *job, AioContext *new_context);
+
+    /**
+     * If the callback is not NULL, it will be invoked after the job is paused
+     * but before job->blk is detached from the old AioContext.  This is the
+     * place to complete all asynchronous I/O that is in flight.
+     */
+    void (*detach_aio_context)(BlockJob *job);
 } BlockJobDriver;
 
 /**
-- 
2.5.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]