summaryrefslogtreecommitdiffstats
path: root/block/block-copy.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/block-copy.c')
-rw-r--r--block/block-copy.c81
1 files changed, 77 insertions, 4 deletions
diff --git a/block/block-copy.c b/block/block-copy.c
index 6ea55f1f9a..74655b86f8 100644
--- a/block/block-copy.c
+++ b/block/block-copy.c
@@ -30,13 +30,19 @@
static coroutine_fn int block_copy_task_entry(AioTask *task);
typedef struct BlockCopyCallState {
- /* IN parameters */
+ /* IN parameters. Initialized in block_copy_async() and never changed. */
BlockCopyState *s;
int64_t offset;
int64_t bytes;
+ BlockCopyAsyncCallbackFunc cb;
+ void *cb_opaque;
+
+ /* Coroutine where async block-copy is running */
+ Coroutine *co;
/* State */
- bool failed;
+ int ret;
+ bool finished;
/* OUT parameters */
bool error_is_read;
@@ -428,8 +434,8 @@ static coroutine_fn int block_copy_task_entry(AioTask *task)
ret = block_copy_do_copy(t->s, t->offset, t->bytes, t->zeroes,
&error_is_read);
- if (ret < 0 && !t->call_state->failed) {
- t->call_state->failed = true;
+ if (ret < 0 && !t->call_state->ret) {
+ t->call_state->ret = ret;
t->call_state->error_is_read = error_is_read;
} else {
progress_work_done(t->s->progress, t->bytes);
@@ -679,6 +685,12 @@ static int coroutine_fn block_copy_common(BlockCopyCallState *call_state)
*/
} while (ret > 0);
+ call_state->finished = true;
+
+ if (call_state->cb) {
+ call_state->cb(call_state->cb_opaque);
+ }
+
return ret;
}
@@ -700,6 +712,67 @@ int coroutine_fn block_copy(BlockCopyState *s, int64_t start, int64_t bytes,
return ret;
}
+static void coroutine_fn block_copy_async_co_entry(void *opaque)
+{
+ block_copy_common(opaque);
+}
+
+BlockCopyCallState *block_copy_async(BlockCopyState *s,
+ int64_t offset, int64_t bytes,
+ BlockCopyAsyncCallbackFunc cb,
+ void *cb_opaque)
+{
+ BlockCopyCallState *call_state = g_new(BlockCopyCallState, 1);
+
+ *call_state = (BlockCopyCallState) {
+ .s = s,
+ .offset = offset,
+ .bytes = bytes,
+ .cb = cb,
+ .cb_opaque = cb_opaque,
+
+ .co = qemu_coroutine_create(block_copy_async_co_entry, call_state),
+ };
+
+ qemu_coroutine_enter(call_state->co);
+
+ return call_state;
+}
+
+void block_copy_call_free(BlockCopyCallState *call_state)
+{
+ if (!call_state) {
+ return;
+ }
+
+ assert(call_state->finished);
+ g_free(call_state);
+}
+
+bool block_copy_call_finished(BlockCopyCallState *call_state)
+{
+ return call_state->finished;
+}
+
+bool block_copy_call_succeeded(BlockCopyCallState *call_state)
+{
+ return call_state->finished && call_state->ret == 0;
+}
+
+bool block_copy_call_failed(BlockCopyCallState *call_state)
+{
+ return call_state->finished && call_state->ret < 0;
+}
+
+int block_copy_call_status(BlockCopyCallState *call_state, bool *error_is_read)
+{
+ assert(call_state->finished);
+ if (error_is_read) {
+ *error_is_read = call_state->error_is_read;
+ }
+ return call_state->ret;
+}
+
BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s)
{
return s->copy_bitmap;