Blame SOURCES/kvm-blockjob-Lie-better-in-child_job_drained_poll.patch

1bdc94
From a174500971a42552a30d238bf9ec065d27fd4b32 Mon Sep 17 00:00:00 2001
1bdc94
From: Kevin Wolf <kwolf@redhat.com>
1bdc94
Date: Fri, 14 Sep 2018 10:55:36 +0200
1bdc94
Subject: [PATCH 45/49] blockjob: Lie better in child_job_drained_poll()
1bdc94
1bdc94
RH-Author: Kevin Wolf <kwolf@redhat.com>
1bdc94
Message-id: <20180914105540.18077-39-kwolf@redhat.com>
1bdc94
Patchwork-id: 82192
1bdc94
O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 38/42] blockjob: Lie better in child_job_drained_poll()
1bdc94
Bugzilla: 1601212
1bdc94
RH-Acked-by: John Snow <jsnow@redhat.com>
1bdc94
RH-Acked-by: Max Reitz <mreitz@redhat.com>
1bdc94
RH-Acked-by: Fam Zheng <famz@redhat.com>
1bdc94
1bdc94
Block jobs claim in .drained_poll() that they are in a quiescent state
1bdc94
as soon as job->deferred_to_main_loop is true. This is obviously wrong,
1bdc94
they still have a completion BH to run. We only get away with this
1bdc94
because commit 91af091f923 added an unconditional aio_poll(false) to the
1bdc94
drain functions, but this is bypassing the regular drain mechanisms.
1bdc94
1bdc94
However, just removing this and telling that the job is still active
1bdc94
doesn't work either: The completion callbacks themselves call drain
1bdc94
functions (directly, or indirectly with bdrv_reopen), so they would
1bdc94
deadlock then.
1bdc94
1bdc94
As a better lie, tell that the job is active as long as the BH is
1bdc94
pending, but falsely call it quiescent from the point in the BH when the
1bdc94
completion callback is called. At this point, nested drain calls won't
1bdc94
deadlock because they ignore the job, and outer drains will wait for the
1bdc94
job to really reach a quiescent state because the callback is already
1bdc94
running.
1bdc94
1bdc94
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1bdc94
Reviewed-by: Max Reitz <mreitz@redhat.com>
1bdc94
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
1bdc94
---
1bdc94
 blockjob.c         |  2 +-
1bdc94
 include/qemu/job.h |  3 +++
1bdc94
 job.c              | 11 ++++++++++-
1bdc94
 3 files changed, 14 insertions(+), 2 deletions(-)
1bdc94
1bdc94
diff --git a/blockjob.c b/blockjob.c
1bdc94
index 8d27e8e..617d86f 100644
1bdc94
--- a/blockjob.c
1bdc94
+++ b/blockjob.c
1bdc94
@@ -164,7 +164,7 @@ static bool child_job_drained_poll(BdrvChild *c)
1bdc94
     /* An inactive or completed job doesn't have any pending requests. Jobs
1bdc94
      * with !job->busy are either already paused or have a pause point after
1bdc94
      * being reentered, so no job driver code will run before they pause. */
1bdc94
-    if (!job->busy || job_is_completed(job) || job->deferred_to_main_loop) {
1bdc94
+    if (!job->busy || job_is_completed(job)) {
1bdc94
         return false;
1bdc94
     }
1bdc94
 
1bdc94
diff --git a/include/qemu/job.h b/include/qemu/job.h
1bdc94
index 35ac7a9..d1710f3 100644
1bdc94
--- a/include/qemu/job.h
1bdc94
+++ b/include/qemu/job.h
1bdc94
@@ -76,6 +76,9 @@ typedef struct Job {
1bdc94
      * Set to false by the job while the coroutine has yielded and may be
1bdc94
      * re-entered by job_enter(). There may still be I/O or event loop activity
1bdc94
      * pending. Accessed under block_job_mutex (in blockjob.c).
1bdc94
+     *
1bdc94
+     * When the job is deferred to the main loop, busy is true as long as the
1bdc94
+     * bottom half is still pending.
1bdc94
      */
1bdc94
     bool busy;
1bdc94
 
1bdc94
diff --git a/job.c b/job.c
1bdc94
index 47b5a11..42af9e2 100644
1bdc94
--- a/job.c
1bdc94
+++ b/job.c
1bdc94
@@ -852,7 +852,16 @@ static void job_exit(void *opaque)
1bdc94
     AioContext *ctx = job->aio_context;
1bdc94
 
1bdc94
     aio_context_acquire(ctx);
1bdc94
+
1bdc94
+    /* This is a lie, we're not quiescent, but still doing the completion
1bdc94
+     * callbacks. However, completion callbacks tend to involve operations that
1bdc94
+     * drain block nodes, and if .drained_poll still returned true, we would
1bdc94
+     * deadlock. */
1bdc94
+    job->busy = false;
1bdc94
+    job_event_idle(job);
1bdc94
+
1bdc94
     job_completed(job);
1bdc94
+
1bdc94
     aio_context_release(ctx);
1bdc94
 }
1bdc94
 
1bdc94
@@ -867,8 +876,8 @@ static void coroutine_fn job_co_entry(void *opaque)
1bdc94
     assert(job && job->driver && job->driver->run);
1bdc94
     job_pause_point(job);
1bdc94
     job->ret = job->driver->run(job, &job->err);
1bdc94
-    job_event_idle(job);
1bdc94
     job->deferred_to_main_loop = true;
1bdc94
+    job->busy = true;
1bdc94
     aio_bh_schedule_oneshot(qemu_get_aio_context(), job_exit, job);
1bdc94
 }
1bdc94
 
1bdc94
-- 
1bdc94
1.8.3.1
1bdc94