[RFC,18/24] block/block-copy: add block_copy_cancel
diff mbox series

Message ID 20191115141444.24155-19-vsementsov@virtuozzo.com
State New
Headers show
Series
  • backup performance: block_status + async
Related show

Commit Message

Vladimir Sementsov-Ogievskiy Nov. 15, 2019, 2:14 p.m. UTC
Add function to cancel running async block-copy call. It will be used
in backup.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
 include/block/block-copy.h |  7 +++++++
 block/block-copy.c         | 20 ++++++++++++++++++--
 2 files changed, 25 insertions(+), 2 deletions(-)

Patch
diff mbox series

diff --git a/include/block/block-copy.h b/include/block/block-copy.h
index 3f9cdc5eb2..fbbee094e6 100644
--- a/include/block/block-copy.h
+++ b/include/block/block-copy.h
@@ -67,6 +67,13 @@  BlockCopyCallState *block_copy_async(BlockCopyState *s,
 void block_copy_set_speed(BlockCopyState *s, BlockCopyCallState *call_state,
                           uint64_t speed);
 
+/*
+ * Cancel running block-copy call.
+ * Cancel leaves block-copy state valid: dirty bits are correct and you may use
+ * cancel + <run block_copy with same parameters> to emulate pause/resume.
+ */
+void block_copy_cancel(BlockCopyCallState *call_state);
+
 BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s);
 void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip);
 
diff --git a/block/block-copy.c b/block/block-copy.c
index 091bc044de..d11c744320 100644
--- a/block/block-copy.c
+++ b/block/block-copy.c
@@ -42,6 +42,8 @@  typedef struct BlockCopyCallState {
     bool failed;
     bool finished;
     QemuCoSleepState *sleep_state;
+    bool cancelled;
+    Coroutine *canceller;
 
     /* OUT parameters */
     bool error_is_read;
@@ -553,7 +555,7 @@  block_copy_dirty_clusters(BlockCopyCallState *call_state)
     assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
     assert(QEMU_IS_ALIGNED(bytes, s->cluster_size));
 
-    while (bytes && aio_task_pool_status(aio) == 0) {
+    while (bytes && aio_task_pool_status(aio) == 0 && !call_state->cancelled) {
         BlockCopyTask *task;
         int64_t status_bytes;
 
@@ -639,7 +641,7 @@  static int coroutine_fn block_copy_common(BlockCopyCallState *call_state)
     while (true) {
         ret = block_copy_dirty_clusters(call_state);
 
-        if (ret < 0) {
+        if (ret < 0 || call_state->cancelled) {
             /*
              * IO operation failed, which means the whole block_copy request
              * failed.
@@ -673,6 +675,11 @@  static int coroutine_fn block_copy_common(BlockCopyCallState *call_state)
                        call_state->s->progress_opaque);
     }
 
+    if (call_state->canceller) {
+        aio_co_wake(call_state->canceller);
+        call_state->canceller = NULL;
+    }
+
     call_state->finished = true;
 
     return ret;
@@ -731,6 +738,15 @@  BlockCopyCallState *block_copy_async(BlockCopyState *s,
 
     return call_state;
 }
+
+void block_copy_cancel(BlockCopyCallState *call_state)
+{
+    call_state->cancelled = true;
+    call_state->canceller = qemu_coroutine_self();
+    block_copy_kick(call_state);
+    qemu_coroutine_yield();
+}
+
 BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s)
 {
     return s->copy_bitmap;