@@ -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 */
@@ -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')
new file mode 100644
@@ -0,0 +1,38 @@
+/*
+ * QEMU External Snapshot Utility
+ *
+ * Copyright Virtuozzo GmbH, 2021
+ *
+ * Authors:
+ * Andrey Gruzdev <andrey.gruzdev@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;
+}
@@ -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();
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.gruzdev@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