Blame SOURCES/kvm-block-Use-a-single-global-AioWait.patch

1bdc94
From 54d30086f066f1094871c4886f3a6dee51263d76 Mon Sep 17 00:00:00 2001
1bdc94
From: Kevin Wolf <kwolf@redhat.com>
1bdc94
Date: Fri, 21 Sep 2018 12:46:29 +0200
1bdc94
Subject: [PATCH 2/3] block: Use a single global AioWait
1bdc94
1bdc94
RH-Author: Kevin Wolf <kwolf@redhat.com>
1bdc94
Message-id: <20180921124630.29036-3-kwolf@redhat.com>
1bdc94
Patchwork-id: 82231
1bdc94
O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/3] block: Use a single global AioWait
1bdc94
Bugzilla: 1618584
1bdc94
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
1bdc94
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
1bdc94
RH-Acked-by: John Snow <jsnow@redhat.com>
1bdc94
RH-Acked-by: Eric Blake <eblake@redhat.com>
1bdc94
1bdc94
When draining a block node, we recurse to its parent and for subtree
1bdc94
drains also to its children. A single AIO_WAIT_WHILE() is then used to
1bdc94
wait for bdrv_drain_poll() to become true, which depends on all of the
1bdc94
nodes we recursed to. However, if the respective child or parent becomes
1bdc94
quiescent and calls bdrv_wakeup(), only the AioWait of the child/parent
1bdc94
is checked, while AIO_WAIT_WHILE() depends on the AioWait of the
1bdc94
original node.
1bdc94
1bdc94
Fix this by using a single AioWait for all callers of AIO_WAIT_WHILE().
1bdc94
1bdc94
This may mean that the draining thread gets a few more unnecessary
1bdc94
wakeups because an unrelated operation got completed, but we already
1bdc94
wake it up when something _could_ have changed rather than only if it
1bdc94
has certainly changed.
1bdc94
1bdc94
Apart from that, drain is a slow path anyway. In theory it would be
1bdc94
possible to use wakeups more selectively and still correctly, but the
1bdc94
gains are likely not worth the additional complexity. In fact, this
1bdc94
patch is a nice simplification for some places in the code.
1bdc94
1bdc94
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1bdc94
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
1bdc94
---
1bdc94
 block.c                   |  5 -----
1bdc94
 block/block-backend.c     | 11 ++++-------
1bdc94
 block/io.c                |  7 ++-----
1bdc94
 blockjob.c                | 13 +------------
1bdc94
 include/block/aio-wait.h  | 11 +++++------
1bdc94
 include/block/block.h     |  6 +-----
1bdc94
 include/block/block_int.h |  3 ---
1bdc94
 include/block/blockjob.h  | 10 ----------
1bdc94
 job.c                     |  3 +--
1bdc94
 util/aio-wait.c           | 11 ++++++-----
1bdc94
 10 files changed, 20 insertions(+), 60 deletions(-)
1bdc94
1bdc94
diff --git a/block.c b/block.c
1bdc94
index e89b5e3..fbd569c 100644
1bdc94
--- a/block.c
1bdc94
+++ b/block.c
1bdc94
@@ -4847,11 +4847,6 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs)
1bdc94
     return bs ? bs->aio_context : qemu_get_aio_context();
1bdc94
 }
1bdc94
 
1bdc94
-AioWait *bdrv_get_aio_wait(BlockDriverState *bs)
1bdc94
-{
1bdc94
-    return bs ? &bs->wait : NULL;
1bdc94
-}
1bdc94
-
1bdc94
 void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co)
1bdc94
 {
1bdc94
     aio_co_enter(bdrv_get_aio_context(bs), co);
1bdc94
diff --git a/block/block-backend.c b/block/block-backend.c
1bdc94
index 466bc27..36922d1 100644
1bdc94
--- a/block/block-backend.c
1bdc94
+++ b/block/block-backend.c
1bdc94
@@ -88,7 +88,6 @@ struct BlockBackend {
1bdc94
      * Accessed with atomic ops.
1bdc94
      */
1bdc94
     unsigned int in_flight;
1bdc94
-    AioWait wait;
1bdc94
 };
1bdc94
 
1bdc94
 typedef struct BlockBackendAIOCB {
1bdc94
@@ -1300,7 +1299,7 @@ static void blk_inc_in_flight(BlockBackend *blk)
1bdc94
 static void blk_dec_in_flight(BlockBackend *blk)
1bdc94
 {
1bdc94
     atomic_dec(&blk->in_flight);
1bdc94
-    aio_wait_kick(&blk->wait);
1bdc94
+    aio_wait_kick();
1bdc94
 }
1bdc94
 
1bdc94
 static void error_callback_bh(void *opaque)
1bdc94
@@ -1609,9 +1608,8 @@ void blk_drain(BlockBackend *blk)
1bdc94
     }
1bdc94
 
1bdc94
     /* We may have -ENOMEDIUM completions in flight */
1bdc94
-    AIO_WAIT_WHILE(&blk->wait,
1bdc94
-            blk_get_aio_context(blk),
1bdc94
-            atomic_mb_read(&blk->in_flight) > 0);
1bdc94
+    AIO_WAIT_WHILE(blk_get_aio_context(blk),
1bdc94
+                   atomic_mb_read(&blk->in_flight) > 0);
1bdc94
 
1bdc94
     if (bs) {
1bdc94
         bdrv_drained_end(bs);
1bdc94
@@ -1630,8 +1628,7 @@ void blk_drain_all(void)
1bdc94
         aio_context_acquire(ctx);
1bdc94
 
1bdc94
         /* We may have -ENOMEDIUM completions in flight */
1bdc94
-        AIO_WAIT_WHILE(&blk->wait, ctx,
1bdc94
-                atomic_mb_read(&blk->in_flight) > 0);
1bdc94
+        AIO_WAIT_WHILE(ctx, atomic_mb_read(&blk->in_flight) > 0);
1bdc94
 
1bdc94
         aio_context_release(ctx);
1bdc94
     }
1bdc94
diff --git a/block/io.c b/block/io.c
1bdc94
index 3313958..7a99f7b 100644
1bdc94
--- a/block/io.c
1bdc94
+++ b/block/io.c
1bdc94
@@ -38,8 +38,6 @@
1bdc94
 /* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */
1bdc94
 #define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
1bdc94
 
1bdc94
-static AioWait drain_all_aio_wait;
1bdc94
-
1bdc94
 static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
1bdc94
     int64_t offset, int bytes, BdrvRequestFlags flags);
1bdc94
 
1bdc94
@@ -555,7 +553,7 @@ void bdrv_drain_all_begin(void)
1bdc94
     }
1bdc94
 
1bdc94
     /* Now poll the in-flight requests */
1bdc94
-    AIO_WAIT_WHILE(&drain_all_aio_wait, NULL, bdrv_drain_all_poll());
1bdc94
+    AIO_WAIT_WHILE(NULL, bdrv_drain_all_poll());
1bdc94
 
1bdc94
     while ((bs = bdrv_next_all_states(bs))) {
1bdc94
         bdrv_drain_assert_idle(bs);
1bdc94
@@ -709,8 +707,7 @@ void bdrv_inc_in_flight(BlockDriverState *bs)
1bdc94
 
1bdc94
 void bdrv_wakeup(BlockDriverState *bs)
1bdc94
 {
1bdc94
-    aio_wait_kick(bdrv_get_aio_wait(bs));
1bdc94
-    aio_wait_kick(&drain_all_aio_wait);
1bdc94
+    aio_wait_kick();
1bdc94
 }
1bdc94
 
1bdc94
 void bdrv_dec_in_flight(BlockDriverState *bs)
1bdc94
diff --git a/blockjob.c b/blockjob.c
1bdc94
index 617d86f..06f2429 100644
1bdc94
--- a/blockjob.c
1bdc94
+++ b/blockjob.c
1bdc94
@@ -221,20 +221,9 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
1bdc94
     return 0;
1bdc94
 }
1bdc94
 
1bdc94
-void block_job_wakeup_all_bdrv(BlockJob *job)
1bdc94
-{
1bdc94
-    GSList *l;
1bdc94
-
1bdc94
-    for (l = job->nodes; l; l = l->next) {
1bdc94
-        BdrvChild *c = l->data;
1bdc94
-        bdrv_wakeup(c->bs);
1bdc94
-    }
1bdc94
-}
1bdc94
-
1bdc94
 static void block_job_on_idle(Notifier *n, void *opaque)
1bdc94
 {
1bdc94
-    BlockJob *job = opaque;
1bdc94
-    block_job_wakeup_all_bdrv(job);
1bdc94
+    aio_wait_kick();
1bdc94
 }
1bdc94
 
1bdc94
 bool block_job_is_internal(BlockJob *job)
1bdc94
diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h
1bdc94
index 600fad1..46f86f9 100644
1bdc94
--- a/include/block/aio-wait.h
1bdc94
+++ b/include/block/aio-wait.h
1bdc94
@@ -54,9 +54,10 @@ typedef struct {
1bdc94
     unsigned num_waiters;
1bdc94
 } AioWait;
1bdc94
 
1bdc94
+extern AioWait global_aio_wait;
1bdc94
+
1bdc94
 /**
1bdc94
  * AIO_WAIT_WHILE:
1bdc94
- * @wait: the aio wait object
1bdc94
  * @ctx: the aio context, or NULL if multiple aio contexts (for which the
1bdc94
  *       caller does not hold a lock) are involved in the polling condition.
1bdc94
  * @cond: wait while this conditional expression is true
1bdc94
@@ -72,9 +73,9 @@ typedef struct {
1bdc94
  * wait on conditions between two IOThreads since that could lead to deadlock,
1bdc94
  * go via the main loop instead.
1bdc94
  */
1bdc94
-#define AIO_WAIT_WHILE(wait, ctx, cond) ({                         \
1bdc94
+#define AIO_WAIT_WHILE(ctx, cond) ({                               \
1bdc94
     bool waited_ = false;                                          \
1bdc94
-    AioWait *wait_ = (wait);                                       \
1bdc94
+    AioWait *wait_ = &global_aio_wait;                             \
1bdc94
     AioContext *ctx_ = (ctx);                                      \
1bdc94
     /* Increment wait_->num_waiters before evaluating cond. */     \
1bdc94
     atomic_inc(&wait_->num_waiters);                               \
1bdc94
@@ -102,14 +103,12 @@ typedef struct {
1bdc94
 
1bdc94
 /**
1bdc94
  * aio_wait_kick:
1bdc94
- * @wait: the aio wait object that should re-evaluate its condition
1bdc94
- *
1bdc94
  * Wake up the main thread if it is waiting on AIO_WAIT_WHILE().  During
1bdc94
  * synchronous operations performed in an IOThread, the main thread lets the
1bdc94
  * IOThread's event loop run, waiting for the operation to complete.  A
1bdc94
  * aio_wait_kick() call will wake up the main thread.
1bdc94
  */
1bdc94
-void aio_wait_kick(AioWait *wait);
1bdc94
+void aio_wait_kick(void);
1bdc94
 
1bdc94
 /**
1bdc94
  * aio_wait_bh_oneshot:
1bdc94
diff --git a/include/block/block.h b/include/block/block.h
1bdc94
index 356712c..8e78daf 100644
1bdc94
--- a/include/block/block.h
1bdc94
+++ b/include/block/block.h
1bdc94
@@ -406,13 +406,9 @@ void bdrv_drain_all_begin(void);
1bdc94
 void bdrv_drain_all_end(void);
1bdc94
 void bdrv_drain_all(void);
1bdc94
 
1bdc94
-/* Returns NULL when bs == NULL */
1bdc94
-AioWait *bdrv_get_aio_wait(BlockDriverState *bs);
1bdc94
-
1bdc94
 #define BDRV_POLL_WHILE(bs, cond) ({                       \
1bdc94
     BlockDriverState *bs_ = (bs);                          \
1bdc94
-    AIO_WAIT_WHILE(bdrv_get_aio_wait(bs_),                 \
1bdc94
-                   bdrv_get_aio_context(bs_),              \
1bdc94
+    AIO_WAIT_WHILE(bdrv_get_aio_context(bs_),              \
1bdc94
                    cond); })
1bdc94
 
1bdc94
 int bdrv_pdiscard(BlockDriverState *bs, int64_t offset, int bytes);
1bdc94
diff --git a/include/block/block_int.h b/include/block/block_int.h
1bdc94
index b7806e3..ff923b7 100644
1bdc94
--- a/include/block/block_int.h
1bdc94
+++ b/include/block/block_int.h
1bdc94
@@ -782,9 +782,6 @@ struct BlockDriverState {
1bdc94
     unsigned int in_flight;
1bdc94
     unsigned int serialising_in_flight;
1bdc94
 
1bdc94
-    /* Kicked to signal main loop when a request completes. */
1bdc94
-    AioWait wait;
1bdc94
-
1bdc94
     /* counter for nested bdrv_io_plug.
1bdc94
      * Accessed with atomic ops.
1bdc94
     */
1bdc94
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
1bdc94
index 2290bbb..ede0bd8 100644
1bdc94
--- a/include/block/blockjob.h
1bdc94
+++ b/include/block/blockjob.h
1bdc94
@@ -122,16 +122,6 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
1bdc94
 void block_job_remove_all_bdrv(BlockJob *job);
1bdc94
 
1bdc94
 /**
1bdc94
- * block_job_wakeup_all_bdrv:
1bdc94
- * @job: The block job
1bdc94
- *
1bdc94
- * Calls bdrv_wakeup() for all BlockDriverStates that have been added to the
1bdc94
- * job. This function is to be called whenever child_job_drained_poll() would
1bdc94
- * go from true to false to notify waiting drain requests.
1bdc94
- */
1bdc94
-void block_job_wakeup_all_bdrv(BlockJob *job);
1bdc94
-
1bdc94
-/**
1bdc94
  * block_job_set_speed:
1bdc94
  * @job: The job to set the speed for.
1bdc94
  * @speed: The new value
1bdc94
diff --git a/job.c b/job.c
1bdc94
index 5b53e43..3a7db59 100644
1bdc94
--- a/job.c
1bdc94
+++ b/job.c
1bdc94
@@ -973,7 +973,6 @@ void job_complete(Job *job, Error **errp)
1bdc94
 int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp)
1bdc94
 {
1bdc94
     Error *local_err = NULL;
1bdc94
-    AioWait dummy_wait = {};
1bdc94
     int ret;
1bdc94
 
1bdc94
     job_ref(job);
1bdc94
@@ -987,7 +986,7 @@ int job_finish_sync(Job *job, void (*finish)(Job *, Error **errp), Error **errp)
1bdc94
         return -EBUSY;
1bdc94
     }
1bdc94
 
1bdc94
-    AIO_WAIT_WHILE(&dummy_wait, job->aio_context,
1bdc94
+    AIO_WAIT_WHILE(job->aio_context,
1bdc94
                    (job_drain(job), !job_is_completed(job)));
1bdc94
 
1bdc94
     ret = (job_is_cancelled(job) && job->ret == 0) ? -ECANCELED : job->ret;
1bdc94
diff --git a/util/aio-wait.c b/util/aio-wait.c
1bdc94
index b8a8f86..b487749 100644
1bdc94
--- a/util/aio-wait.c
1bdc94
+++ b/util/aio-wait.c
1bdc94
@@ -26,21 +26,22 @@
1bdc94
 #include "qemu/main-loop.h"
1bdc94
 #include "block/aio-wait.h"
1bdc94
 
1bdc94
+AioWait global_aio_wait;
1bdc94
+
1bdc94
 static void dummy_bh_cb(void *opaque)
1bdc94
 {
1bdc94
     /* The point is to make AIO_WAIT_WHILE()'s aio_poll() return */
1bdc94
 }
1bdc94
 
1bdc94
-void aio_wait_kick(AioWait *wait)
1bdc94
+void aio_wait_kick(void)
1bdc94
 {
1bdc94
     /* The barrier (or an atomic op) is in the caller.  */
1bdc94
-    if (atomic_read(&wait->num_waiters)) {
1bdc94
+    if (atomic_read(&global_aio_wait.num_waiters)) {
1bdc94
         aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL);
1bdc94
     }
1bdc94
 }
1bdc94
 
1bdc94
 typedef struct {
1bdc94
-    AioWait wait;
1bdc94
     bool done;
1bdc94
     QEMUBHFunc *cb;
1bdc94
     void *opaque;
1bdc94
@@ -54,7 +55,7 @@ static void aio_wait_bh(void *opaque)
1bdc94
     data->cb(data->opaque);
1bdc94
 
1bdc94
     data->done = true;
1bdc94
-    aio_wait_kick(&data->wait);
1bdc94
+    aio_wait_kick();
1bdc94
 }
1bdc94
 
1bdc94
 void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
1bdc94
@@ -67,5 +68,5 @@ void aio_wait_bh_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
1bdc94
     assert(qemu_get_current_aio_context() == qemu_get_aio_context());
1bdc94
 
1bdc94
     aio_bh_schedule_oneshot(ctx, aio_wait_bh, &data);
1bdc94
-    AIO_WAIT_WHILE(&data.wait, ctx, !data.done);
1bdc94
+    AIO_WAIT_WHILE(ctx, !data.done);
1bdc94
 }
1bdc94
-- 
1bdc94
1.8.3.1
1bdc94