Blame SOURCES/kvm-block-Really-pause-block-jobs-on-drain.patch

357786
From 70365466a45a381ebb54e49cb03579b5fd6c76ef Mon Sep 17 00:00:00 2001
357786
From: Kevin Wolf <kwolf@redhat.com>
357786
Date: Fri, 14 Sep 2018 10:55:05 +0200
357786
Subject: [PATCH 14/49] block: Really pause block jobs on drain
357786
357786
RH-Author: Kevin Wolf <kwolf@redhat.com>
357786
Message-id: <20180914105540.18077-8-kwolf@redhat.com>
357786
Patchwork-id: 82160
357786
O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 07/42] block: Really pause block jobs on drain
357786
Bugzilla: 1601212
357786
RH-Acked-by: John Snow <jsnow@redhat.com>
357786
RH-Acked-by: Max Reitz <mreitz@redhat.com>
357786
RH-Acked-by: Fam Zheng <famz@redhat.com>
357786
357786
We already requested that block jobs be paused in .bdrv_drained_begin,
357786
but no guarantee was made that the job was actually inactive at the
357786
point where bdrv_drained_begin() returned.
357786
357786
This introduces a new callback BdrvChildRole.bdrv_drained_poll() and
357786
uses it to make bdrv_drain_poll() consider block jobs using the node to
357786
be drained.
357786
357786
For the test case to work as expected, we have to switch from
357786
block_job_sleep_ns() to qemu_co_sleep_ns() so that the test job is even
357786
considered active and must be waited for when draining the node.
357786
357786
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
357786
(cherry picked from commit 89bd030533e3592ca0a995450dcfc5d53e459e20)
357786
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
357786
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
357786
---
357786
 block.c                      |  9 +++++++++
357786
 block/io.c                   | 40 ++++++++++++++++++++++++++++++++++------
357786
 block/mirror.c               |  8 ++++++++
357786
 blockjob.c                   | 23 +++++++++++++++++++++++
357786
 include/block/block.h        |  8 ++++++++
357786
 include/block/block_int.h    |  7 +++++++
357786
 include/block/blockjob_int.h |  8 ++++++++
357786
 tests/test-bdrv-drain.c      | 18 ++++++++++--------
357786
 8 files changed, 107 insertions(+), 14 deletions(-)
357786
357786
diff --git a/block.c b/block.c
357786
index 10a1ece..0d9698a 100644
357786
--- a/block.c
357786
+++ b/block.c
357786
@@ -821,6 +821,12 @@ static void bdrv_child_cb_drained_begin(BdrvChild *child)
357786
     bdrv_drained_begin(bs);
357786
 }
357786
 
357786
+static bool bdrv_child_cb_drained_poll(BdrvChild *child)
357786
+{
357786
+    BlockDriverState *bs = child->opaque;
357786
+    return bdrv_drain_poll(bs, NULL);
357786
+}
357786
+
357786
 static void bdrv_child_cb_drained_end(BdrvChild *child)
357786
 {
357786
     BlockDriverState *bs = child->opaque;
357786
@@ -905,6 +911,7 @@ const BdrvChildRole child_file = {
357786
     .get_parent_desc = bdrv_child_get_parent_desc,
357786
     .inherit_options = bdrv_inherited_options,
357786
     .drained_begin   = bdrv_child_cb_drained_begin,
357786
+    .drained_poll    = bdrv_child_cb_drained_poll,
357786
     .drained_end     = bdrv_child_cb_drained_end,
357786
     .attach          = bdrv_child_cb_attach,
357786
     .detach          = bdrv_child_cb_detach,
357786
@@ -929,6 +936,7 @@ const BdrvChildRole child_format = {
357786
     .get_parent_desc = bdrv_child_get_parent_desc,
357786
     .inherit_options = bdrv_inherited_fmt_options,
357786
     .drained_begin   = bdrv_child_cb_drained_begin,
357786
+    .drained_poll    = bdrv_child_cb_drained_poll,
357786
     .drained_end     = bdrv_child_cb_drained_end,
357786
     .attach          = bdrv_child_cb_attach,
357786
     .detach          = bdrv_child_cb_detach,
357786
@@ -1048,6 +1056,7 @@ const BdrvChildRole child_backing = {
357786
     .detach          = bdrv_backing_detach,
357786
     .inherit_options = bdrv_backing_options,
357786
     .drained_begin   = bdrv_child_cb_drained_begin,
357786
+    .drained_poll    = bdrv_child_cb_drained_poll,
357786
     .drained_end     = bdrv_child_cb_drained_end,
357786
     .inactivate      = bdrv_child_cb_inactivate,
357786
     .update_filename = bdrv_backing_update_filename,
357786
diff --git a/block/io.c b/block/io.c
357786
index 4d332c3..e260394 100644
357786
--- a/block/io.c
357786
+++ b/block/io.c
357786
@@ -69,6 +69,23 @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
357786
     }
357786
 }
357786
 
357786
+static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore)
357786
+{
357786
+    BdrvChild *c, *next;
357786
+    bool busy = false;
357786
+
357786
+    QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
357786
+        if (c == ignore) {
357786
+            continue;
357786
+        }
357786
+        if (c->role->drained_poll) {
357786
+            busy |= c->role->drained_poll(c);
357786
+        }
357786
+    }
357786
+
357786
+    return busy;
357786
+}
357786
+
357786
 static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src)
357786
 {
357786
     dst->opt_transfer = MAX(dst->opt_transfer, src->opt_transfer);
357786
@@ -182,21 +199,32 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
357786
 }
357786
 
357786
 /* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */
357786
-static bool bdrv_drain_poll(BlockDriverState *bs)
357786
+bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent)
357786
+{
357786
+    if (bdrv_parent_drained_poll(bs, ignore_parent)) {
357786
+        return true;
357786
+    }
357786
+
357786
+    return atomic_read(&bs->in_flight);
357786
+}
357786
+
357786
+static bool bdrv_drain_poll_top_level(BlockDriverState *bs,
357786
+                                      BdrvChild *ignore_parent)
357786
 {
357786
     /* Execute pending BHs first and check everything else only after the BHs
357786
      * have executed. */
357786
     while (aio_poll(bs->aio_context, false));
357786
-    return atomic_read(&bs->in_flight);
357786
+
357786
+    return bdrv_drain_poll(bs, ignore_parent);
357786
 }
357786
 
357786
-static bool bdrv_drain_recurse(BlockDriverState *bs)
357786
+static bool bdrv_drain_recurse(BlockDriverState *bs, BdrvChild *parent)
357786
 {
357786
     BdrvChild *child, *tmp;
357786
     bool waited;
357786
 
357786
     /* Wait for drained requests to finish */
357786
-    waited = BDRV_POLL_WHILE(bs, bdrv_drain_poll(bs));
357786
+    waited = BDRV_POLL_WHILE(bs, bdrv_drain_poll_top_level(bs, parent));
357786
 
357786
     QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) {
357786
         BlockDriverState *bs = child->bs;
357786
@@ -213,7 +241,7 @@ static bool bdrv_drain_recurse(BlockDriverState *bs)
357786
              */
357786
             bdrv_ref(bs);
357786
         }
357786
-        waited |= bdrv_drain_recurse(bs);
357786
+        waited |= bdrv_drain_recurse(bs, child);
357786
         if (in_main_loop) {
357786
             bdrv_unref(bs);
357786
         }
357786
@@ -289,7 +317,7 @@ void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
357786
 
357786
     bdrv_parent_drained_begin(bs, parent);
357786
     bdrv_drain_invoke(bs, true);
357786
-    bdrv_drain_recurse(bs);
357786
+    bdrv_drain_recurse(bs, parent);
357786
 
357786
     if (recursive) {
357786
         bs->recursive_quiesce_counter++;
357786
diff --git a/block/mirror.c b/block/mirror.c
357786
index 313e6e9..4b27f71 100644
357786
--- a/block/mirror.c
357786
+++ b/block/mirror.c
357786
@@ -976,6 +976,12 @@ static void mirror_pause(Job *job)
357786
     mirror_wait_for_all_io(s);
357786
 }
357786
 
357786
+static bool mirror_drained_poll(BlockJob *job)
357786
+{
357786
+    MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
357786
+    return !!s->in_flight;
357786
+}
357786
+
357786
 static void mirror_attached_aio_context(BlockJob *job, AioContext *new_context)
357786
 {
357786
     MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
357786
@@ -1011,6 +1017,7 @@ static const BlockJobDriver mirror_job_driver = {
357786
         .pause                  = mirror_pause,
357786
         .complete               = mirror_complete,
357786
     },
357786
+    .drained_poll           = mirror_drained_poll,
357786
     .attached_aio_context   = mirror_attached_aio_context,
357786
     .drain                  = mirror_drain,
357786
 };
357786
@@ -1028,6 +1035,7 @@ static const BlockJobDriver commit_active_job_driver = {
357786
         .pause                  = mirror_pause,
357786
         .complete               = mirror_complete,
357786
     },
357786
+    .drained_poll           = mirror_drained_poll,
357786
     .attached_aio_context   = mirror_attached_aio_context,
357786
     .drain                  = mirror_drain,
357786
 };
357786
diff --git a/blockjob.c b/blockjob.c
357786
index 0306533..be5903a 100644
357786
--- a/blockjob.c
357786
+++ b/blockjob.c
357786
@@ -155,6 +155,28 @@ static void child_job_drained_begin(BdrvChild *c)
357786
     job_pause(&job->job);
357786
 }
357786
 
357786
+static bool child_job_drained_poll(BdrvChild *c)
357786
+{
357786
+    BlockJob *bjob = c->opaque;
357786
+    Job *job = &bjob->job;
357786
+    const BlockJobDriver *drv = block_job_driver(bjob);
357786
+
357786
+    /* An inactive or completed job doesn't have any pending requests. Jobs
357786
+     * with !job->busy are either already paused or have a pause point after
357786
+     * being reentered, so no job driver code will run before they pause. */
357786
+    if (!job->busy || job_is_completed(job) || job->deferred_to_main_loop) {
357786
+        return false;
357786
+    }
357786
+
357786
+    /* Otherwise, assume that it isn't fully stopped yet, but allow the job to
357786
+     * override this assumption. */
357786
+    if (drv->drained_poll) {
357786
+        return drv->drained_poll(bjob);
357786
+    } else {
357786
+        return true;
357786
+    }
357786
+}
357786
+
357786
 static void child_job_drained_end(BdrvChild *c)
357786
 {
357786
     BlockJob *job = c->opaque;
357786
@@ -164,6 +186,7 @@ static void child_job_drained_end(BdrvChild *c)
357786
 static const BdrvChildRole child_job = {
357786
     .get_parent_desc    = child_job_get_parent_desc,
357786
     .drained_begin      = child_job_drained_begin,
357786
+    .drained_poll       = child_job_drained_poll,
357786
     .drained_end        = child_job_drained_end,
357786
     .stay_at_node       = true,
357786
 };
357786
diff --git a/include/block/block.h b/include/block/block.h
357786
index 8f87eea..8c91d4c 100644
357786
--- a/include/block/block.h
357786
+++ b/include/block/block.h
357786
@@ -596,6 +596,14 @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore);
357786
 void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore);
357786
 
357786
 /**
357786
+ * bdrv_drain_poll:
357786
+ *
357786
+ * Poll for pending requests in @bs and its parents (except for
357786
+ * @ignore_parent). This is part of bdrv_drained_begin.
357786
+ */
357786
+bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent);
357786
+
357786
+/**
357786
  * bdrv_drained_begin:
357786
  *
357786
  * Begin a quiesced section for exclusive access to the BDS, by disabling
357786
diff --git a/include/block/block_int.h b/include/block/block_int.h
357786
index 341cbe8..beeacde 100644
357786
--- a/include/block/block_int.h
357786
+++ b/include/block/block_int.h
357786
@@ -610,6 +610,13 @@ struct BdrvChildRole {
357786
     void (*drained_begin)(BdrvChild *child);
357786
     void (*drained_end)(BdrvChild *child);
357786
 
357786
+    /*
357786
+     * Returns whether the parent has pending requests for the child. This
357786
+     * callback is polled after .drained_begin() has been called until all
357786
+     * activity on the child has stopped.
357786
+     */
357786
+    bool (*drained_poll)(BdrvChild *child);
357786
+
357786
     /* Notifies the parent that the child has been activated/inactivated (e.g.
357786
      * when migration is completing) and it can start/stop requesting
357786
      * permissions and doing I/O on it. */
357786
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
357786
index 5cd50c6..e4a318d 100644
357786
--- a/include/block/blockjob_int.h
357786
+++ b/include/block/blockjob_int.h
357786
@@ -39,6 +39,14 @@ struct BlockJobDriver {
357786
     JobDriver job_driver;
357786
 
357786
     /*
357786
+     * Returns whether the job has pending requests for the child or will
357786
+     * submit new requests before the next pause point. This callback is polled
357786
+     * in the context of draining a job node after requesting that the job be
357786
+     * paused, until all activity on the child has stopped.
357786
+     */
357786
+    bool (*drained_poll)(BlockJob *job);
357786
+
357786
+    /*
357786
      * If the callback is not NULL, it will be invoked before the job is
357786
      * resumed in a new AioContext.  This is the place to move any resources
357786
      * besides job->blk to the new AioContext.
357786
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
357786
index f5d85c9..49786ea 100644
357786
--- a/tests/test-bdrv-drain.c
357786
+++ b/tests/test-bdrv-drain.c
357786
@@ -681,7 +681,11 @@ static int coroutine_fn test_job_run(Job *job, Error **errp)
357786
 
357786
     job_transition_to_ready(&s->common.job);
357786
     while (!s->should_complete) {
357786
-        job_sleep_ns(&s->common.job, 100000);
357786
+        /* Avoid block_job_sleep_ns() because it marks the job as !busy. We
357786
+         * want to emulate some actual activity (probably some I/O) here so
357786
+         * that drain has to wait for this acitivity to stop. */
357786
+        qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
357786
+        job_pause_point(&s->common.job);
357786
     }
357786
 
357786
     return 0;
357786
@@ -728,7 +732,7 @@ static void test_blockjob_common(enum drain_type drain_type)
357786
 
357786
     g_assert_cmpint(job->job.pause_count, ==, 0);
357786
     g_assert_false(job->job.paused);
357786
-    g_assert_false(job->job.busy); /* We're in job_sleep_ns() */
357786
+    g_assert_true(job->job.busy); /* We're in job_sleep_ns() */
357786
 
357786
     do_drain_begin(drain_type, src);
357786
 
357786
@@ -738,15 +742,14 @@ static void test_blockjob_common(enum drain_type drain_type)
357786
     } else {
357786
         g_assert_cmpint(job->job.pause_count, ==, 1);
357786
     }
357786
-    /* XXX We don't wait until the job is actually paused. Is this okay? */
357786
-    /* g_assert_true(job->job.paused); */
357786
+    g_assert_true(job->job.paused);
357786
     g_assert_false(job->job.busy); /* The job is paused */
357786
 
357786
     do_drain_end(drain_type, src);
357786
 
357786
     g_assert_cmpint(job->job.pause_count, ==, 0);
357786
     g_assert_false(job->job.paused);
357786
-    g_assert_false(job->job.busy); /* We're in job_sleep_ns() */
357786
+    g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */
357786
 
357786
     do_drain_begin(drain_type, target);
357786
 
357786
@@ -756,15 +759,14 @@ static void test_blockjob_common(enum drain_type drain_type)
357786
     } else {
357786
         g_assert_cmpint(job->job.pause_count, ==, 1);
357786
     }
357786
-    /* XXX We don't wait until the job is actually paused. Is this okay? */
357786
-    /* g_assert_true(job->job.paused); */
357786
+    g_assert_true(job->job.paused);
357786
     g_assert_false(job->job.busy); /* The job is paused */
357786
 
357786
     do_drain_end(drain_type, target);
357786
 
357786
     g_assert_cmpint(job->job.pause_count, ==, 0);
357786
     g_assert_false(job->job.paused);
357786
-    g_assert_false(job->job.busy); /* We're in job_sleep_ns() */
357786
+    g_assert_true(job->job.busy); /* We're in job_sleep_ns() */
357786
 
357786
     ret = job_complete_sync(&job->job, &error_abort);
357786
     g_assert_cmpint(ret, ==, 0);
357786
-- 
357786
1.8.3.1
357786