1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2 From: Stefan Reiter <s.reiter@proxmox.com>
3 Date: Wed, 27 May 2020 11:33:19 +0200
4 Subject: [PATCH] savevm-async: move more code to cleanup and rename to
7 process_savevm_cleanup is renamed to process_savevm_finalize to
8 accomodate more code that is not all cleanup related.
10 The benefit of this is that it allows us to call functions which need to
11 run in the main AIOContext directly. It doesn't majorly affect snapshot
12 performance, since the first instruction that is moved stops the VM,
13 so the downtime stays about the same.
15 The target bdrv is additionally moved to the IOHandler context before
16 process_savevm_co to make sure the coroutine can call functions that
17 require it to own the bdrv's context. process_savevm_finalize then moves
18 it back to the main context to run its part.
20 Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
22 savevm-async.c | 87 +++++++++++++++++++++++++++++---------------------
23 1 file changed, 51 insertions(+), 36 deletions(-)
25 diff --git a/savevm-async.c b/savevm-async.c
26 index c3fe741c38..2894c94233 100644
29 @@ -50,7 +50,7 @@ static struct SnapshotState {
34 + QEMUBH *finalize_bh;
38 @@ -196,12 +196,42 @@ static const QEMUFileOps block_file_ops = {
39 .close = block_state_close,
42 -static void process_savevm_cleanup(void *opaque)
43 +static void process_savevm_finalize(void *opaque)
46 - qemu_bh_delete(snap_state.cleanup_bh);
47 - snap_state.cleanup_bh = NULL;
48 + AioContext *iohandler_ctx = iohandler_get_aio_context();
49 + MigrationState *ms = migrate_get_current();
51 + qemu_bh_delete(snap_state.finalize_bh);
52 + snap_state.finalize_bh = NULL;
55 + /* We need to own the target bdrv's context for the following functions,
56 + * so move it back. It can stay in the main context and live out its live
57 + * there, since we're done with it after this method ends anyway.
59 + aio_context_acquire(iohandler_ctx);
60 + blk_set_aio_context(snap_state.target, qemu_get_aio_context(), NULL);
61 + aio_context_release(iohandler_ctx);
63 + ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
65 + save_snapshot_error("vm_stop_force_state error %d", ret);
68 + (void)qemu_savevm_state_complete_precopy(snap_state.file, false, false);
69 + ret = qemu_file_get_error(snap_state.file);
71 + save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
74 + DPRINTF("state saving complete\n");
76 + /* clear migration state */
77 + migrate_set_state(&ms->state, MIGRATION_STATUS_SETUP,
78 + ret ? MIGRATION_STATUS_FAILED : MIGRATION_STATUS_COMPLETED);
79 + ms->to_dst_file = NULL;
81 qemu_savevm_state_cleanup();
83 ret = save_snapshot_cleanup();
84 @@ -219,16 +249,15 @@ static void process_savevm_cleanup(void *opaque)
88 -static void process_savevm_coro(void *opaque)
89 +static void coroutine_fn process_savevm_co(void *opaque)
93 - MigrationState *ms = migrate_get_current();
95 ret = qemu_file_get_error(snap_state.file);
97 save_snapshot_error("qemu_savevm_state_setup failed");
102 while (snap_state.state == SAVE_STATE_ACTIVE) {
103 @@ -245,7 +274,7 @@ static void process_savevm_coro(void *opaque)
104 save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
107 - DPRINTF("savevm inerate pending size %lu ret %d\n", pending_size, ret);
108 + DPRINTF("savevm iterate pending size %lu ret %d\n", pending_size, ret);
110 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
111 ret = global_state_store();
112 @@ -253,40 +282,20 @@ static void process_savevm_coro(void *opaque)
113 save_snapshot_error("global_state_store error %d", ret);
116 - ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
118 - save_snapshot_error("vm_stop_force_state error %d", ret);
121 - DPRINTF("savevm inerate finished\n");
122 - /* upstream made the return value here inconsistent
123 - * (-1 instead of 'ret' in one case and 0 after flush which can
124 - * still set a file error...)
126 - (void)qemu_savevm_state_complete_precopy(snap_state.file, false, false);
127 - ret = qemu_file_get_error(snap_state.file);
129 - save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
132 - DPRINTF("save complete\n");
134 + DPRINTF("savevm iterate complete\n");
139 - qemu_bh_schedule(snap_state.cleanup_bh);
142 - /* set migration state accordingly and clear soon-to-be stale file */
143 - migrate_set_state(&ms->state, MIGRATION_STATUS_SETUP,
144 - ret ? MIGRATION_STATUS_FAILED : MIGRATION_STATUS_COMPLETED);
145 - ms->to_dst_file = NULL;
146 + qemu_bh_schedule(snap_state.finalize_bh);
149 void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
151 Error *local_err = NULL;
152 MigrationState *ms = migrate_get_current();
153 + AioContext *iohandler_ctx = iohandler_get_aio_context();
155 int bdrv_oflags = BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH;
157 @@ -347,7 +356,7 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
160 * qemu_savevm_* paths use migration code and expect a migration state.
161 - * State is cleared in process_savevm_thread, but has to be initialized
162 + * State is cleared in process_savevm_co, but has to be initialized
163 * here (blocking main thread, from QMP) to avoid race conditions.
166 @@ -358,13 +367,19 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
167 blk_op_block_all(snap_state.target, snap_state.blocker);
169 snap_state.state = SAVE_STATE_ACTIVE;
170 - snap_state.cleanup_bh = qemu_bh_new(process_savevm_cleanup, &snap_state);
171 - snap_state.co = qemu_coroutine_create(&process_savevm_coro, NULL);
172 + snap_state.finalize_bh = qemu_bh_new(process_savevm_finalize, &snap_state);
173 + snap_state.co = qemu_coroutine_create(&process_savevm_co, NULL);
174 qemu_mutex_unlock_iothread();
175 qemu_savevm_state_header(snap_state.file);
176 qemu_savevm_state_setup(snap_state.file);
177 qemu_mutex_lock_iothread();
178 - aio_co_schedule(iohandler_get_aio_context(), snap_state.co);
180 + /* Async processing from here on out happens in iohandler context, so let
181 + * the target bdrv have its home there.
183 + blk_set_aio_context(snap_state.target, iohandler_ctx, &local_err);
185 + aio_co_schedule(iohandler_ctx, snap_state.co);