]>
Commit | Line | Data |
---|---|---|
87ba737b | 1 | From 190e9321e1657ec0b956ecece21d6a037487cd14 Mon Sep 17 00:00:00 2001 |
712b39fe WB |
2 | From: Wolfgang Bumiller <w.bumiller@proxmox.com> |
3 | Date: Tue, 8 Nov 2016 11:13:06 +0100 | |
adeb0c7a | 4 | Subject: [PATCH 46/48] convert savevm-async to threads |
712b39fe WB |
5 | |
6 | --- | |
4844140a WB |
7 | savevm-async.c | 144 +++++++++++++++++++++++++++++++++++---------------------- |
8 | 1 file changed, 88 insertions(+), 56 deletions(-) | |
712b39fe WB |
9 | |
10 | diff --git a/savevm-async.c b/savevm-async.c | |
1a91ab45 | 11 | index 3adf89f..9f839fa 100644 |
712b39fe WB |
12 | --- a/savevm-async.c |
13 | +++ b/savevm-async.c | |
14 | @@ -48,6 +48,8 @@ static struct SnapshotState { | |
15 | int saved_vm_running; | |
16 | QEMUFile *file; | |
17 | int64_t total_time; | |
18 | + QEMUBH *cleanup_bh; | |
19 | + QemuThread thread; | |
20 | } snap_state; | |
21 | ||
22 | SaveVMInfo *qmp_query_savevm(Error **errp) | |
23 | @@ -135,19 +137,6 @@ static void save_snapshot_error(const char *fmt, ...) | |
24 | g_free (msg); | |
25 | ||
26 | snap_state.state = SAVE_STATE_ERROR; | |
27 | - | |
28 | - save_snapshot_cleanup(); | |
29 | -} | |
30 | - | |
31 | -static void save_snapshot_completed(void) | |
32 | -{ | |
33 | - DPRINTF("save_snapshot_completed\n"); | |
34 | - | |
35 | - if (save_snapshot_cleanup() < 0) { | |
36 | - snap_state.state = SAVE_STATE_ERROR; | |
37 | - } else { | |
38 | - snap_state.state = SAVE_STATE_COMPLETED; | |
39 | - } | |
40 | } | |
41 | ||
42 | static int block_state_close(void *opaque) | |
4844140a | 43 | @@ -156,51 +145,90 @@ static int block_state_close(void *opaque) |
712b39fe WB |
44 | return blk_flush(snap_state.target); |
45 | } | |
46 | ||
47 | +typedef struct BlkRwCo { | |
48 | + int64_t offset; | |
49 | + QEMUIOVector *qiov; | |
50 | + int ret; | |
51 | +} BlkRwCo; | |
52 | + | |
53 | +static void block_state_write_entry(void *opaque) { | |
54 | + BlkRwCo *rwco = opaque; | |
55 | + rwco->ret = blk_co_pwritev(snap_state.target, rwco->offset, rwco->qiov->size, | |
56 | + rwco->qiov, 0); | |
57 | +} | |
58 | + | |
59 | static ssize_t block_state_writev_buffer(void *opaque, struct iovec *iov, | |
60 | int iovcnt, int64_t pos) | |
61 | { | |
62 | - int ret; | |
63 | QEMUIOVector qiov; | |
64 | + AioContext *aio_context; | |
65 | + Coroutine *co; | |
66 | + BlkRwCo rwco; | |
67 | + | |
68 | + assert(pos == snap_state.bs_pos); | |
69 | + rwco = (BlkRwCo) { | |
70 | + .offset = pos, | |
71 | + .qiov = &qiov, | |
72 | + .ret = NOT_DONE, | |
73 | + }; | |
74 | ||
75 | qemu_iovec_init_external(&qiov, iov, iovcnt); | |
76 | - ret = blk_co_pwritev(snap_state.target, pos, qiov.size, &qiov, 0); | |
77 | - if (ret < 0) { | |
78 | - return ret; | |
79 | + | |
d2a6ab5c WB |
80 | + aio_context = blk_get_aio_context(snap_state.target); |
81 | + aio_context_acquire(aio_context); | |
712b39fe WB |
82 | + co = qemu_coroutine_create(&block_state_write_entry, &rwco); |
83 | + qemu_coroutine_enter(co); | |
712b39fe WB |
84 | + while (rwco.ret == NOT_DONE) { |
85 | + aio_poll(aio_context, true); | |
86 | } | |
d2a6ab5c | 87 | + aio_context_release(aio_context); |
712b39fe WB |
88 | + |
89 | snap_state.bs_pos += qiov.size; | |
90 | return qiov.size; | |
91 | } | |
92 | ||
93 | -static int store_and_stop(void) { | |
94 | - if (global_state_store()) { | |
95 | - save_snapshot_error("Error saving global state"); | |
96 | - return 1; | |
97 | +static void process_savevm_cleanup(void *opaque) | |
98 | +{ | |
99 | + int ret; | |
100 | + qemu_bh_delete(snap_state.cleanup_bh); | |
101 | + snap_state.cleanup_bh = NULL; | |
102 | + qemu_mutex_unlock_iothread(); | |
103 | + qemu_thread_join(&snap_state.thread); | |
104 | + qemu_mutex_lock_iothread(); | |
105 | + ret = save_snapshot_cleanup(); | |
106 | + if (ret < 0) { | |
107 | + save_snapshot_error("save_snapshot_cleanup error %d", ret); | |
108 | + } else if (snap_state.state == SAVE_STATE_ACTIVE) { | |
109 | + snap_state.state = SAVE_STATE_COMPLETED; | |
110 | + } else { | |
111 | + save_snapshot_error("process_savevm_cleanup: invalid state: %d", | |
112 | + snap_state.state); | |
113 | } | |
114 | - if (runstate_is_running()) { | |
115 | - vm_stop(RUN_STATE_SAVE_VM); | |
116 | + if (snap_state.saved_vm_running) { | |
117 | + vm_start(); | |
118 | + snap_state.saved_vm_running = false; | |
119 | } | |
120 | - return 0; | |
121 | } | |
122 | ||
123 | -static void process_savevm_co(void *opaque) | |
124 | +static void *process_savevm_thread(void *opaque) | |
125 | { | |
126 | int ret; | |
127 | int64_t maxlen; | |
712b39fe WB |
128 | + |
129 | MigrationParams params = { | |
130 | .blk = 0, | |
131 | .shared = 0 | |
4844140a | 132 | }; |
712b39fe | 133 | |
4844140a WB |
134 | - snap_state.state = SAVE_STATE_ACTIVE; |
135 | + rcu_register_thread(); | |
712b39fe WB |
136 | |
137 | - qemu_mutex_unlock_iothread(); | |
712b39fe WB |
138 | qemu_savevm_state_header(snap_state.file); |
139 | ret = qemu_savevm_state_begin(snap_state.file, ¶ms); | |
140 | - qemu_mutex_lock_iothread(); | |
141 | ||
142 | if (ret < 0) { | |
143 | save_snapshot_error("qemu_savevm_state_begin failed"); | |
144 | - return; | |
145 | + rcu_unregister_thread(); | |
146 | + return NULL; | |
147 | } | |
148 | ||
712b39fe | 149 | while (snap_state.state == SAVE_STATE_ACTIVE) { |
4844140a | 150 | @@ -209,41 +237,43 @@ static void process_savevm_co(void *opaque) |
712b39fe WB |
151 | qemu_savevm_state_pending(snap_state.file, 0, &pend_nonpost, &pend_post); |
152 | pending_size = pend_post + pend_nonpost; | |
153 | ||
154 | - if (pending_size) { | |
155 | - ret = qemu_savevm_state_iterate(snap_state.file, false); | |
156 | - if (ret < 0) { | |
157 | - save_snapshot_error("qemu_savevm_state_iterate error %d", ret); | |
158 | - break; | |
159 | - } | |
160 | - DPRINTF("savevm inerate pending size %lu ret %d\n", pending_size, ret); | |
161 | + maxlen = blk_getlength(snap_state.target) - 30*1024*1024; | |
162 | + | |
163 | + if (pending_size > 400000 && snap_state.bs_pos + pending_size < maxlen) { | |
d2a6ab5c | 164 | + qemu_mutex_lock_iothread(); |
712b39fe WB |
165 | + ret = qemu_savevm_state_iterate(snap_state.file, false); |
166 | + if (ret < 0) { | |
712b39fe WB |
167 | + save_snapshot_error("qemu_savevm_state_iterate error %d", ret); |
168 | + break; | |
169 | + } | |
d2a6ab5c | 170 | + qemu_mutex_unlock_iothread(); |
712b39fe WB |
171 | + DPRINTF("savevm inerate pending size %lu ret %d\n", pending_size, ret); |
172 | } else { | |
173 | - DPRINTF("done iterating\n"); | |
174 | - if (store_and_stop()) | |
712b39fe WB |
175 | + qemu_mutex_lock_iothread(); |
176 | + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); | |
177 | + ret = global_state_store(); | |
178 | + if (ret) { | |
712b39fe WB |
179 | + save_snapshot_error("global_state_store error %d", ret); |
180 | + break; | |
181 | + } | |
182 | + ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); | |
183 | + if (ret < 0) { | |
712b39fe WB |
184 | + save_snapshot_error("vm_stop_force_state error %d", ret); |
185 | break; | |
186 | + } | |
187 | DPRINTF("savevm inerate finished\n"); | |
188 | qemu_savevm_state_complete_precopy(snap_state.file, false); | |
189 | + qemu_savevm_state_cleanup(); | |
190 | DPRINTF("save complete\n"); | |
191 | - save_snapshot_completed(); | |
712b39fe WB |
192 | break; |
193 | } | |
194 | - | |
195 | - /* stop the VM if we get to the end of available space, | |
196 | - * or if pending_size is just a few MB | |
197 | - */ | |
198 | - maxlen = blk_getlength(snap_state.target) - 30*1024*1024; | |
199 | - if ((pending_size < 100000) || | |
200 | - ((snap_state.bs_pos + pending_size) >= maxlen)) { | |
201 | - if (store_and_stop()) | |
202 | - break; | |
203 | - } | |
d2a6ab5c WB |
204 | } |
205 | ||
712b39fe WB |
206 | - if(snap_state.state == SAVE_STATE_CANCELLED) { |
207 | - save_snapshot_completed(); | |
208 | - Error *errp = NULL; | |
209 | - qmp_savevm_end(&errp); | |
d2a6ab5c | 210 | - } |
712b39fe | 211 | + qemu_bh_schedule(snap_state.cleanup_bh); |
d2a6ab5c WB |
212 | + qemu_mutex_unlock_iothread(); |
213 | ||
712b39fe WB |
214 | + rcu_unregister_thread(); |
215 | + return NULL; | |
216 | } | |
217 | ||
218 | static const QEMUFileOps block_file_ops = { | |
4844140a | 219 | @@ -306,8 +336,10 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp) |
712b39fe WB |
220 | error_setg(&snap_state.blocker, "block device is in use by savevm"); |
221 | blk_op_block_all(snap_state.target, snap_state.blocker); | |
222 | ||
223 | - Coroutine *co = qemu_coroutine_create(process_savevm_co, NULL); | |
224 | - qemu_coroutine_enter(co); | |
4844140a | 225 | + snap_state.state = SAVE_STATE_ACTIVE; |
712b39fe WB |
226 | + snap_state.cleanup_bh = qemu_bh_new(process_savevm_cleanup, &snap_state); |
227 | + qemu_thread_create(&snap_state.thread, "savevm-async", process_savevm_thread, | |
228 | + NULL, QEMU_THREAD_JOINABLE); | |
229 | ||
230 | return; | |
231 | ||
232 | -- | |
233 | 2.1.4 | |
234 |