qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 3/8] block: allow doing I/O in a job after cancellat


From: Paolo Bonzini
Subject: [Qemu-devel] [PATCH 3/8] block: allow doing I/O in a job after cancellation
Date: Fri, 13 Apr 2012 18:23:13 +0200

Track the coroutine that executes the job, so that the wait can be
cancelled before block_job_cancel restarts.  This also gives to the
coroutine an opportunity to flip job->busy to true, and submit new
I/O before exiting.  block_job_cancel_sync will wait for job->busy
to become false again.

Also drain the I/O *before* canceling the job, so that all I/O from
the guest is visible to the job.

This is needed for mirroring.  Once mirroring reaches "steady state"
(i.e. all data from the source is also in the target, except for new
writes coming in from the guest), cancellation of the job will keep
the disks synchronized.  The job thus requires to handle cancellation
with care, and this patch provides the infrastructure.

Signed-off-by: Paolo Bonzini <address@hidden>
---
 block.c        |    8 ++++++++
 block/stream.c |    7 +++----
 block_int.h    |   12 ++++++++----
 3 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/block.c b/block.c
index 1eb82f2..c272421 100644
--- a/block.c
+++ b/block.c
@@ -4255,7 +4255,15 @@ int block_job_set_speed(BlockJob *job, int64_t value)
 
 void block_job_cancel(BlockJob *job)
 {
+    /* Complete all guest I/O before cancelling the job, so that if the
+     * job chooses to complete itself it will do so with a consistent
+     * view of the disk.
+     */
+    bdrv_drain_all();
     job->cancelled = true;
+    if (job->co && !job->busy) {
+        qemu_coroutine_enter(job->co, NULL);
+    }
 }
 
 bool block_job_is_cancelled(BlockJob *job)
diff --git a/block/stream.c b/block/stream.c
index 0116450..d38f30a 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -191,7 +191,6 @@ int stream_start(BlockDriverState *bs, BlockDriverState 
*base,
                  void *opaque)
 {
     StreamBlockJob *s;
-    Coroutine *co;
 
     s = block_job_create(&stream_job_type, bs, cb, opaque);
     if (!s) {
@@ -203,8 +202,8 @@ int stream_start(BlockDriverState *bs, BlockDriverState 
*base,
         pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id);
     }
 
-    co = qemu_coroutine_create(stream_run);
-    trace_stream_start(bs, base, s, co, opaque);
-    qemu_coroutine_enter(co, s);
+    s->common.co = qemu_coroutine_create(stream_run);
+    trace_stream_start(bs, base, s, s->common.co, opaque);
+    qemu_coroutine_enter(s->common.co, s);
     return 0;
 }
diff --git a/block_int.h b/block_int.h
index 58e3eea..eae24d2 100644
--- a/block_int.h
+++ b/block_int.h
@@ -94,6 +94,12 @@ struct BlockJob {
     BlockDriverState *bs;
 
     /**
+     * The coroutine that executes the job.  If not NULL, it is
+     * reentered when busy is false and the job is cancelled.
+     */
+    Coroutine *co;
+
+    /**
      * Set to true if the job should cancel itself.  The flag must
      * always be tested just before toggling the busy flag from false
      * to true.  After a job has detected that the cancelled flag is
@@ -104,10 +110,8 @@ struct BlockJob {
 
     /**
      * Set to false by the job while it is in a quiescent state, where
-     * no I/O is pending and cancellation can be processed without
-     * issuing new I/O.  The busy flag must be set to false when the
-     * job goes to sleep on any condition that is not detected by
-     * #qemu_aio_wait, such as a timer.
+     * no I/O is pending and the job goes to sleep on any condition
+     * that is not detected by #qemu_aio_wait, such as a timer.
      */
     bool busy;
 
-- 
1.7.9.3





reply via email to

[Prev in Thread] Current Thread [Next in Thread]