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

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