Blame SOURCES/kvm-blockjob-do-not-allow-coroutine-double-entry-or-entr.patch

9bac43
From 01dd04dfd1421d041da935e7a22987d0883b4353 Mon Sep 17 00:00:00 2001
9bac43
From: Jeffrey Cody <jcody@redhat.com>
9bac43
Date: Thu, 30 Nov 2017 22:49:07 +0100
9bac43
Subject: [PATCH 03/21] blockjob: do not allow coroutine double entry or
9bac43
 entry-after-completion
9bac43
9bac43
RH-Author: Jeffrey Cody <jcody@redhat.com>
9bac43
Message-id: <36a71db70d56ebdb223c760e682a146ad91d97ad.1511985875.git.jcody@redhat.com>
9bac43
Patchwork-id: 78041
9bac43
O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 03/11] blockjob: do not allow coroutine double entry or entry-after-completion
9bac43
Bugzilla: 1506531
9bac43
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9bac43
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
9bac43
RH-Acked-by: John Snow <jsnow@redhat.com>
9bac43
9bac43
When block_job_sleep_ns() is called, the co-routine is scheduled for
9bac43
future execution.  If we allow the job to be re-entered prior to the
9bac43
scheduled time, we present a race condition in which a coroutine can be
9bac43
entered recursively, or even entered after the coroutine is deleted.
9bac43
9bac43
The job->busy flag is used by blockjobs when a coroutine is busy
9bac43
executing. The function 'block_job_enter()' obeys the busy flag,
9bac43
and will not enter a coroutine if set.  If we sleep a job, we need to
9bac43
leave the busy flag set, so that subsequent calls to block_job_enter()
9bac43
are prevented.
9bac43
9bac43
This changes the prior behavior of block_job_cancel() being able to
9bac43
immediately wake up and cancel a job; in practice, this should not be an
9bac43
issue, as the coroutine sleep times are generally very small, and the
9bac43
cancel will occur the next time the coroutine wakes up.
9bac43
9bac43
This fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1508708
9bac43
9bac43
Signed-off-by: Jeff Cody <jcody@redhat.com>
9bac43
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9bac43
(cherry picked from commit 4afeffc8572f40d8844b946a30c00b10da4442b1)
9bac43
Signed-off-by: Jeff Cody <jcody@redhat.com>
9bac43
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9bac43
---
9bac43
 blockjob.c                   | 7 +++++--
9bac43
 include/block/blockjob_int.h | 3 ++-
9bac43
 2 files changed, 7 insertions(+), 3 deletions(-)
9bac43
9bac43
diff --git a/blockjob.c b/blockjob.c
9bac43
index 70a7818..c3cf9a2 100644
9bac43
--- a/blockjob.c
9bac43
+++ b/blockjob.c
9bac43
@@ -797,11 +797,14 @@ void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns)
9bac43
         return;
9bac43
     }
9bac43
 
9bac43
-    job->busy = false;
9bac43
+    /* We need to leave job->busy set here, because when we have
9bac43
+     * put a coroutine to 'sleep', we have scheduled it to run in
9bac43
+     * the future.  We cannot enter that same coroutine again before
9bac43
+     * it wakes and runs, otherwise we risk double-entry or entry after
9bac43
+     * completion. */
9bac43
     if (!block_job_should_pause(job)) {
9bac43
         co_aio_sleep_ns(blk_get_aio_context(job->blk), type, ns);
9bac43
     }
9bac43
-    job->busy = true;
9bac43
 
9bac43
     block_job_pause_point(job);
9bac43
 }
9bac43
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
9bac43
index f13ad05..43f3be2 100644
9bac43
--- a/include/block/blockjob_int.h
9bac43
+++ b/include/block/blockjob_int.h
9bac43
@@ -143,7 +143,8 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
9bac43
  * @ns: How many nanoseconds to stop for.
9bac43
  *
9bac43
  * Put the job to sleep (assuming that it wasn't canceled) for @ns
9bac43
- * nanoseconds.  Canceling the job will interrupt the wait immediately.
9bac43
+ * nanoseconds.  Canceling the job will not interrupt the wait, so the
9bac43
+ * cancel will not process until the coroutine wakes up.
9bac43
  */
9bac43
 void block_job_sleep_ns(BlockJob *job, QEMUClockType type, int64_t ns);
9bac43
 
9bac43
-- 
9bac43
1.8.3.1
9bac43