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.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;
+}
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();
 
