Major part of code is using QEMUFile and block layer routines, thus to take advantage from concurrent I/O operations we need to use coroutines and run in the the main loop context.
Signed-off-by: Andrey Gruzdev <andrey.gruz...@virtuozzo.com> --- include/qemu-snap.h | 3 +++ meson.build | 2 +- qemu-snap-handlers.c | 38 ++++++++++++++++++++++++++ qemu-snap.c | 63 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 qemu-snap-handlers.c diff --git a/include/qemu-snap.h b/include/qemu-snap.h index b8e48bfcbb..b6fd779b13 100644 --- a/include/qemu-snap.h +++ b/include/qemu-snap.h @@ -32,4 +32,7 @@ typedef struct SnapLoadState { SnapSaveState *snap_save_get_state(void); SnapLoadState *snap_load_get_state(void); +int coroutine_fn snap_save_state_main(SnapSaveState *sn); +int coroutine_fn snap_load_state_main(SnapLoadState *sn); + #endif /* QEMU_SNAP_H */ diff --git a/meson.build b/meson.build index 11564165ba..252c55d6a3 100644 --- a/meson.build +++ b/meson.build @@ -2324,7 +2324,7 @@ if have_tools dependencies: [block, qemuutil], install: true) qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'), dependencies: [blockdev, qemuutil, gnutls], install: true) - qemu_snap = executable('qemu-snap', files('qemu-snap.c'), + qemu_snap = executable('qemu-snap', files('qemu-snap.c', 'qemu-snap-handlers.c'), dependencies: [blockdev, qemuutil, migration], install: true) subdir('storage-daemon') diff --git a/qemu-snap-handlers.c b/qemu-snap-handlers.c new file mode 100644 index 0000000000..bdc1911909 --- /dev/null +++ b/qemu-snap-handlers.c @@ -0,0 +1,38 @@ +/* + * QEMU External Snapshot Utility + * + * Copyright Virtuozzo GmbH, 2021 + * + * Authors: + * Andrey Gruzdev <andrey.gruz...@virtuozzo.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "sysemu/block-backend.h" +#include "qemu/coroutine.h" +#include "qemu/cutils.h" +#include "qemu/bitmap.h" +#include "qemu/error-report.h" +#include "io/channel-buffer.h" +#include "migration/qemu-file-channel.h" +#include "migration/qemu-file.h" +#include "migration/savevm.h" +#include "migration/ram.h" +#include "qemu-snap.h" + +/* Save snapshot data from incoming migration stream */ +int coroutine_fn snap_save_state_main(SnapSaveState *sn) +{ + /* TODO: implement */ + return 0; +} + +/* Load snapshot data and send it with outgoing migration stream */ +int coroutine_fn snap_load_state_main(SnapLoadState *sn) +{ + /* TODO: implement */ + return 0; +} diff --git a/qemu-snap.c b/qemu-snap.c index c9f8d7166a..ec56aa55d2 100644 --- a/qemu-snap.c +++ b/qemu-snap.c @@ -44,6 +44,14 @@ #define OPT_CACHE 256 #define OPT_AIO 257 +/* Snapshot task execution state */ +typedef struct SnapTaskState { + QEMUBH *bh; /* BH to enter task's coroutine */ + Coroutine *co; /* Coroutine to execute task */ + + int ret; /* Return code, -EINPROGRESS until complete */ +} SnapTaskState; + /* Parameters for snapshot saving */ typedef struct SnapSaveParams { const char *filename; /* QCOW2 image file name */ @@ -177,6 +185,51 @@ static BlockBackend *snap_open(const char *filename, int flags) return blk; } +static void coroutine_fn do_snap_save_co(void *opaque) +{ + SnapTaskState *task_state = opaque; + SnapSaveState *sn = snap_save_get_state(); + + /* Enter main routine */ + task_state->ret = snap_save_state_main(sn); +} + +static void coroutine_fn do_snap_load_co(void *opaque) +{ + SnapTaskState *task_state = opaque; + SnapLoadState *sn = snap_load_get_state(); + + /* Enter main routine */ + task_state->ret = snap_load_state_main(sn); +} + +/* We use BH to enter coroutine from the main loop context */ +static void enter_co_bh(void *opaque) +{ + SnapTaskState *task_state = opaque; + + qemu_coroutine_enter(task_state->co); + /* Delete BH once we entered coroutine from the main loop */ + qemu_bh_delete(task_state->bh); + task_state->bh = NULL; +} + +static int run_snap_task(CoroutineEntry *entry) +{ + SnapTaskState task_state; + + task_state.bh = qemu_bh_new(enter_co_bh, &task_state); + task_state.co = qemu_coroutine_create(entry, &task_state); + task_state.ret = -EINPROGRESS; + + qemu_bh_schedule(task_state.bh); + while (task_state.ret == -EINPROGRESS) { + main_loop_wait(false); + } + + return task_state.ret; +} + static int snap_save(const SnapSaveParams *params) { SnapSaveState *sn; @@ -191,6 +244,11 @@ static int snap_save(const SnapSaveParams *params) goto fail; } + res = run_snap_task(do_snap_save_co); + if (res) { + error_report("Failed to save snapshot: error=%d", res); + } + fail: snap_save_destroy_state(); @@ -210,6 +268,11 @@ static int snap_load(SnapLoadParams *params) goto fail; } + res = run_snap_task(do_snap_load_co); + if (res) { + error_report("Failed to load snapshot: error=%d", res); + } + fail: snap_load_destroy_state(); -- 2.25.1