+++ /dev/null
-From 190e9321e1657ec0b956ecece21d6a037487cd14 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Tue, 8 Nov 2016 11:13:06 +0100
-Subject: [PATCH 46/48] convert savevm-async to threads
-
----
- savevm-async.c | 144 +++++++++++++++++++++++++++++++++++----------------------
- 1 file changed, 88 insertions(+), 56 deletions(-)
-
-diff --git a/savevm-async.c b/savevm-async.c
-index 3adf89f..9f839fa 100644
---- a/savevm-async.c
-+++ b/savevm-async.c
-@@ -48,6 +48,8 @@ static struct SnapshotState {
- int saved_vm_running;
- QEMUFile *file;
- int64_t total_time;
-+ QEMUBH *cleanup_bh;
-+ QemuThread thread;
- } snap_state;
-
- SaveVMInfo *qmp_query_savevm(Error **errp)
-@@ -135,19 +137,6 @@ static void save_snapshot_error(const char *fmt, ...)
- g_free (msg);
-
- snap_state.state = SAVE_STATE_ERROR;
--
-- save_snapshot_cleanup();
--}
--
--static void save_snapshot_completed(void)
--{
-- DPRINTF("save_snapshot_completed\n");
--
-- if (save_snapshot_cleanup() < 0) {
-- snap_state.state = SAVE_STATE_ERROR;
-- } else {
-- snap_state.state = SAVE_STATE_COMPLETED;
-- }
- }
-
- static int block_state_close(void *opaque)
-@@ -156,51 +145,90 @@ static int block_state_close(void *opaque)
- return blk_flush(snap_state.target);
- }
-
-+typedef struct BlkRwCo {
-+ int64_t offset;
-+ QEMUIOVector *qiov;
-+ int ret;
-+} BlkRwCo;
-+
-+static void block_state_write_entry(void *opaque) {
-+ BlkRwCo *rwco = opaque;
-+ rwco->ret = blk_co_pwritev(snap_state.target, rwco->offset, rwco->qiov->size,
-+ rwco->qiov, 0);
-+}
-+
- static ssize_t block_state_writev_buffer(void *opaque, struct iovec *iov,
- int iovcnt, int64_t pos)
- {
-- int ret;
- QEMUIOVector qiov;
-+ AioContext *aio_context;
-+ Coroutine *co;
-+ BlkRwCo rwco;
-+
-+ assert(pos == snap_state.bs_pos);
-+ rwco = (BlkRwCo) {
-+ .offset = pos,
-+ .qiov = &qiov,
-+ .ret = NOT_DONE,
-+ };
-
- qemu_iovec_init_external(&qiov, iov, iovcnt);
-- ret = blk_co_pwritev(snap_state.target, pos, qiov.size, &qiov, 0);
-- if (ret < 0) {
-- return ret;
-+
-+ aio_context = blk_get_aio_context(snap_state.target);
-+ aio_context_acquire(aio_context);
-+ co = qemu_coroutine_create(&block_state_write_entry, &rwco);
-+ qemu_coroutine_enter(co);
-+ while (rwco.ret == NOT_DONE) {
-+ aio_poll(aio_context, true);
- }
-+ aio_context_release(aio_context);
-+
- snap_state.bs_pos += qiov.size;
- return qiov.size;
- }
-
--static int store_and_stop(void) {
-- if (global_state_store()) {
-- save_snapshot_error("Error saving global state");
-- return 1;
-+static void process_savevm_cleanup(void *opaque)
-+{
-+ int ret;
-+ qemu_bh_delete(snap_state.cleanup_bh);
-+ snap_state.cleanup_bh = NULL;
-+ qemu_mutex_unlock_iothread();
-+ qemu_thread_join(&snap_state.thread);
-+ qemu_mutex_lock_iothread();
-+ ret = save_snapshot_cleanup();
-+ if (ret < 0) {
-+ save_snapshot_error("save_snapshot_cleanup error %d", ret);
-+ } else if (snap_state.state == SAVE_STATE_ACTIVE) {
-+ snap_state.state = SAVE_STATE_COMPLETED;
-+ } else {
-+ save_snapshot_error("process_savevm_cleanup: invalid state: %d",
-+ snap_state.state);
- }
-- if (runstate_is_running()) {
-- vm_stop(RUN_STATE_SAVE_VM);
-+ if (snap_state.saved_vm_running) {
-+ vm_start();
-+ snap_state.saved_vm_running = false;
- }
-- return 0;
- }
-
--static void process_savevm_co(void *opaque)
-+static void *process_savevm_thread(void *opaque)
- {
- int ret;
- int64_t maxlen;
-+
- MigrationParams params = {
- .blk = 0,
- .shared = 0
- };
-
-- snap_state.state = SAVE_STATE_ACTIVE;
-+ rcu_register_thread();
-
-- qemu_mutex_unlock_iothread();
- qemu_savevm_state_header(snap_state.file);
- ret = qemu_savevm_state_begin(snap_state.file, ¶ms);
-- qemu_mutex_lock_iothread();
-
- if (ret < 0) {
- save_snapshot_error("qemu_savevm_state_begin failed");
-- return;
-+ rcu_unregister_thread();
-+ return NULL;
- }
-
- while (snap_state.state == SAVE_STATE_ACTIVE) {
-@@ -209,41 +237,43 @@ static void process_savevm_co(void *opaque)
- qemu_savevm_state_pending(snap_state.file, 0, &pend_nonpost, &pend_post);
- pending_size = pend_post + pend_nonpost;
-
-- if (pending_size) {
-- ret = qemu_savevm_state_iterate(snap_state.file, false);
-- if (ret < 0) {
-- save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
-- break;
-- }
-- DPRINTF("savevm inerate pending size %lu ret %d\n", pending_size, ret);
-+ maxlen = blk_getlength(snap_state.target) - 30*1024*1024;
-+
-+ if (pending_size > 400000 && snap_state.bs_pos + pending_size < maxlen) {
-+ qemu_mutex_lock_iothread();
-+ ret = qemu_savevm_state_iterate(snap_state.file, false);
-+ if (ret < 0) {
-+ save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
-+ break;
-+ }
-+ qemu_mutex_unlock_iothread();
-+ DPRINTF("savevm inerate pending size %lu ret %d\n", pending_size, ret);
- } else {
-- DPRINTF("done iterating\n");
-- if (store_and_stop())
-+ qemu_mutex_lock_iothread();
-+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
-+ ret = global_state_store();
-+ if (ret) {
-+ save_snapshot_error("global_state_store error %d", ret);
-+ break;
-+ }
-+ ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
-+ if (ret < 0) {
-+ save_snapshot_error("vm_stop_force_state error %d", ret);
- break;
-+ }
- DPRINTF("savevm inerate finished\n");
- qemu_savevm_state_complete_precopy(snap_state.file, false);
-+ qemu_savevm_state_cleanup();
- DPRINTF("save complete\n");
-- save_snapshot_completed();
- break;
- }
--
-- /* stop the VM if we get to the end of available space,
-- * or if pending_size is just a few MB
-- */
-- maxlen = blk_getlength(snap_state.target) - 30*1024*1024;
-- if ((pending_size < 100000) ||
-- ((snap_state.bs_pos + pending_size) >= maxlen)) {
-- if (store_and_stop())
-- break;
-- }
- }
-
-- if(snap_state.state == SAVE_STATE_CANCELLED) {
-- save_snapshot_completed();
-- Error *errp = NULL;
-- qmp_savevm_end(&errp);
-- }
-+ qemu_bh_schedule(snap_state.cleanup_bh);
-+ qemu_mutex_unlock_iothread();
-
-+ rcu_unregister_thread();
-+ return NULL;
- }
-
- static const QEMUFileOps block_file_ops = {
-@@ -306,8 +336,10 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
- error_setg(&snap_state.blocker, "block device is in use by savevm");
- blk_op_block_all(snap_state.target, snap_state.blocker);
-
-- Coroutine *co = qemu_coroutine_create(process_savevm_co, NULL);
-- qemu_coroutine_enter(co);
-+ snap_state.state = SAVE_STATE_ACTIVE;
-+ snap_state.cleanup_bh = qemu_bh_new(process_savevm_cleanup, &snap_state);
-+ qemu_thread_create(&snap_state.thread, "savevm-async", process_savevm_thread,
-+ NULL, QEMU_THREAD_JOINABLE);
-
- return;
-
---
-2.1.4
-