]>
Commit | Line | Data |
---|---|---|
e128dc27 DM |
1 | #include "qemu-common.h" |
2 | #include "qerror.h" | |
3 | #include "sysemu.h" | |
4 | #include "qmp-commands.h" | |
5 | #include "blockdev.h" | |
6 | #include "qemu/qom-qobject.h" | |
7 | #include "buffered_file.h" | |
8 | #include "migration.h" | |
9 | ||
10 | //#define DEBUG_SAVEVM_STATE | |
11 | ||
12 | #ifdef DEBUG_SAVEVM_STATE | |
13 | #define DPRINTF(fmt, ...) \ | |
14 | do { printf("savevm-async: " fmt, ## __VA_ARGS__); } while (0) | |
15 | #else | |
16 | #define DPRINTF(fmt, ...) \ | |
17 | do { } while (0) | |
18 | #endif | |
19 | ||
20 | enum { | |
21 | SAVE_STATE_DONE, | |
22 | SAVE_STATE_ERROR, | |
23 | SAVE_STATE_ACTIVE, | |
24 | SAVE_STATE_COMPLETED, | |
25 | }; | |
26 | ||
27 | static struct SnapshotState { | |
28 | BlockDriverState *bs; | |
29 | size_t bs_pos; | |
30 | int state; | |
31 | Error *error; | |
32 | int saved_vm_running; | |
33 | QEMUFile *file; | |
34 | int64_t total_time; | |
35 | } snap_state; | |
36 | ||
37 | SaveVMInfo *qmp_query_savevm(Error **errp) | |
38 | { | |
39 | SaveVMInfo *info = g_malloc0(sizeof(*info)); | |
40 | struct SnapshotState *s = &snap_state; | |
41 | ||
42 | if (s->state != SAVE_STATE_DONE) { | |
43 | info->has_bytes = true; | |
44 | info->bytes = s->bs_pos; | |
45 | switch (s->state) { | |
46 | case SAVE_STATE_ERROR: | |
47 | info->has_status = true; | |
48 | info->status = g_strdup("failed"); | |
49 | info->has_total_time = true; | |
50 | info->total_time = s->total_time; | |
51 | if (s->error) { | |
52 | info->has_error = true; | |
53 | info->error = g_strdup(error_get_pretty(s->error)); | |
54 | } | |
55 | break; | |
56 | case SAVE_STATE_ACTIVE: | |
57 | info->has_status = true; | |
58 | info->status = g_strdup("active"); | |
59 | info->has_total_time = true; | |
60 | info->total_time = qemu_get_clock_ms(rt_clock) | |
61 | - s->total_time; | |
62 | break; | |
63 | case SAVE_STATE_COMPLETED: | |
64 | info->has_status = true; | |
65 | info->status = g_strdup("completed"); | |
66 | info->has_total_time = true; | |
67 | info->total_time = s->total_time; | |
68 | break; | |
69 | } | |
70 | } | |
71 | ||
72 | return info; | |
73 | } | |
74 | ||
75 | static int save_snapshot_cleanup(void) | |
76 | { | |
77 | int ret = 0; | |
78 | ||
79 | DPRINTF("save_snapshot_cleanup\n"); | |
80 | ||
81 | snap_state.total_time = qemu_get_clock_ms(rt_clock) - | |
82 | snap_state.total_time; | |
83 | ||
84 | if (snap_state.file) { | |
85 | ret = qemu_fclose(snap_state.file); | |
86 | } | |
87 | ||
88 | if (snap_state.bs) { | |
89 | // try to truncate, but ignore errors (will fail on block devices). | |
90 | // note: bdrv_read() need whole blocks, so we round up | |
91 | size_t size = (snap_state.bs_pos + BDRV_SECTOR_SIZE) & BDRV_SECTOR_MASK; | |
92 | bdrv_truncate(snap_state.bs, size); | |
93 | ||
94 | bdrv_delete(snap_state.bs); | |
95 | snap_state.bs = NULL; | |
96 | } | |
97 | ||
98 | return ret; | |
99 | } | |
100 | ||
101 | static void save_snapshot_error(const char *fmt, ...) | |
102 | { | |
103 | va_list ap; | |
104 | char *msg; | |
105 | ||
106 | va_start(ap, fmt); | |
107 | msg = g_strdup_vprintf(fmt, ap); | |
108 | va_end(ap); | |
109 | ||
110 | DPRINTF("save_snapshot_error: %s\n", msg); | |
111 | ||
112 | if (!snap_state.error) { | |
113 | error_set(&snap_state.error, ERROR_CLASS_GENERIC_ERROR, "%s", msg); | |
114 | } | |
115 | ||
116 | g_free (msg); | |
117 | ||
118 | snap_state.state = SAVE_STATE_ERROR; | |
119 | ||
120 | save_snapshot_cleanup(); | |
121 | } | |
122 | ||
123 | static void save_snapshot_completed(void) | |
124 | { | |
125 | DPRINTF("save_snapshot_completed\n"); | |
126 | ||
127 | if (save_snapshot_cleanup() < 0) { | |
128 | snap_state.state = SAVE_STATE_ERROR; | |
129 | } else { | |
130 | snap_state.state = SAVE_STATE_COMPLETED; | |
131 | } | |
132 | } | |
133 | ||
134 | static int block_state_close(void *opaque) | |
135 | { | |
136 | snap_state.file = NULL; | |
137 | return bdrv_flush(snap_state.bs); | |
138 | } | |
139 | ||
140 | static ssize_t block_state_put_buffer(void *opaque, const void *buf, | |
141 | size_t size) | |
142 | { | |
143 | int ret; | |
144 | ||
145 | if ((ret = bdrv_pwrite(snap_state.bs, snap_state.bs_pos, buf, size)) > 0) { | |
146 | snap_state.bs_pos += ret; | |
147 | } | |
148 | ||
149 | return ret; | |
150 | } | |
151 | ||
152 | static void block_state_put_ready(void *opaque) | |
153 | { | |
2d58a6b0 DM |
154 | uint64_t remaining; |
155 | int64_t maxlen; | |
e128dc27 DM |
156 | int ret; |
157 | ||
158 | if (snap_state.state != SAVE_STATE_ACTIVE) { | |
159 | save_snapshot_error("put_ready returning because of non-active state"); | |
160 | return; | |
161 | } | |
162 | ||
2d58a6b0 DM |
163 | ret = qemu_savevm_state_iterate(snap_state.file); |
164 | remaining = ram_bytes_remaining(); | |
165 | ||
166 | // stop if we get to the end of available space, | |
167 | // or if remaining is just a few MB | |
168 | maxlen = bdrv_getlength(snap_state.bs) - 30*1024*1024; | |
169 | if ((remaining < 100000) || ((snap_state.bs_pos + remaining) >= maxlen)) { | |
170 | if (runstate_is_running()) { | |
171 | vm_stop(RUN_STATE_SAVE_VM); | |
172 | } | |
e128dc27 DM |
173 | } |
174 | ||
e128dc27 DM |
175 | if (ret < 0) { |
176 | save_snapshot_error("qemu_savevm_state_iterate error %d", ret); | |
177 | return; | |
178 | } else if (ret == 1) { | |
2d58a6b0 DM |
179 | if (runstate_is_running()) { |
180 | vm_stop(RUN_STATE_SAVE_VM); | |
181 | } | |
e128dc27 DM |
182 | DPRINTF("savevm inerate finished\n"); |
183 | if ((ret = qemu_savevm_state_complete(snap_state.file)) < 0) { | |
184 | save_snapshot_error("qemu_savevm_state_complete error %d", ret); | |
185 | return; | |
186 | } else { | |
187 | DPRINTF("save complete\n"); | |
188 | save_snapshot_completed(); | |
189 | return; | |
190 | } | |
191 | } | |
192 | } | |
193 | ||
194 | static void block_state_wait_for_unfreeze(void *opaque) | |
195 | { | |
196 | /* do nothing here - should not be called */ | |
197 | } | |
198 | ||
199 | void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp) | |
200 | { | |
201 | BlockDriver *drv = NULL; | |
202 | int bdrv_oflags = BDRV_O_CACHE_WB | BDRV_O_RDWR; | |
203 | MigrationParams params = { | |
204 | .blk = 0, | |
205 | .shared = 0 | |
206 | }; | |
207 | int ret; | |
208 | ||
209 | if (snap_state.state != SAVE_STATE_DONE) { | |
210 | error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
211 | "VM snapshot already started\n"); | |
212 | return; | |
213 | } | |
214 | ||
215 | /* initialize snapshot info */ | |
216 | snap_state.saved_vm_running = runstate_is_running(); | |
217 | snap_state.bs_pos = 0; | |
218 | snap_state.total_time = qemu_get_clock_ms(rt_clock); | |
219 | ||
220 | if (snap_state.error) { | |
221 | error_free(snap_state.error); | |
222 | snap_state.error = NULL; | |
223 | } | |
224 | ||
e128dc27 | 225 | if (!has_statefile) { |
2d58a6b0 | 226 | vm_stop(RUN_STATE_SAVE_VM); |
e128dc27 DM |
227 | snap_state.state = SAVE_STATE_COMPLETED; |
228 | return; | |
229 | } | |
230 | ||
231 | if (qemu_savevm_state_blocked(errp)) { | |
232 | return; | |
233 | } | |
234 | ||
235 | /* Open the image */ | |
236 | snap_state.bs = bdrv_new("vmstate"); | |
237 | ret = bdrv_open(snap_state.bs, statefile, bdrv_oflags, drv); | |
238 | if (ret < 0) { | |
239 | error_set(errp, QERR_OPEN_FILE_FAILED, statefile); | |
240 | goto restart; | |
241 | } | |
242 | ||
243 | snap_state.file = qemu_fopen_ops_buffered(&snap_state, 1000000000, | |
244 | block_state_put_buffer, | |
245 | block_state_put_ready, | |
246 | block_state_wait_for_unfreeze, | |
247 | block_state_close); | |
248 | ||
249 | if (!snap_state.file) { | |
250 | error_set(errp, QERR_OPEN_FILE_FAILED, statefile); | |
251 | goto restart; | |
252 | } | |
253 | ||
254 | snap_state.state = SAVE_STATE_ACTIVE; | |
255 | ||
256 | ret = qemu_savevm_state_begin(snap_state.file, ¶ms); | |
257 | if (ret < 0) { | |
258 | error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
259 | "qemu_savevm_state_begin failed\n"); | |
260 | goto restart; | |
261 | } | |
262 | ||
263 | block_state_put_ready(&snap_state); | |
264 | ||
265 | return; | |
266 | ||
267 | restart: | |
268 | ||
269 | save_snapshot_error("setup failed"); | |
270 | ||
271 | if (snap_state.saved_vm_running) { | |
272 | vm_start(); | |
273 | } | |
274 | } | |
275 | ||
276 | void qmp_savevm_end(Error **errp) | |
277 | { | |
278 | if (snap_state.state == SAVE_STATE_DONE) { | |
279 | error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
280 | "VM snapshot not started\n"); | |
281 | return; | |
282 | } | |
283 | ||
284 | if (snap_state.saved_vm_running) { | |
285 | vm_start(); | |
286 | } | |
287 | ||
288 | snap_state.state = SAVE_STATE_DONE; | |
289 | } | |
290 | ||
291 | void qmp_snapshot_drive(const char *device, const char *name, Error **errp) | |
292 | { | |
293 | BlockDriverState *bs; | |
294 | QEMUSnapshotInfo sn1, *sn = &sn1; | |
295 | int ret; | |
296 | #ifdef _WIN32 | |
297 | struct _timeb tb; | |
298 | #else | |
299 | struct timeval tv; | |
300 | #endif | |
301 | ||
302 | if (snap_state.state != SAVE_STATE_COMPLETED) { | |
303 | error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
304 | "VM snapshot not ready/started\n"); | |
305 | return; | |
306 | } | |
307 | ||
308 | bs = bdrv_find(device); | |
309 | if (!bs) { | |
310 | error_set(errp, QERR_DEVICE_NOT_FOUND, device); | |
311 | return; | |
312 | } | |
313 | ||
314 | if (!bdrv_is_inserted(bs)) { | |
315 | error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); | |
316 | return; | |
317 | } | |
318 | ||
319 | if (bdrv_is_read_only(bs)) { | |
320 | error_set(errp, QERR_DEVICE_IS_READ_ONLY, device); | |
321 | return; | |
322 | } | |
323 | ||
324 | if (!bdrv_can_snapshot(bs)) { | |
325 | error_set(errp, QERR_NOT_SUPPORTED); | |
326 | return; | |
327 | } | |
328 | ||
329 | if (bdrv_snapshot_find(bs, sn, name) >= 0) { | |
330 | error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
331 | "snapshot '%s' already exists", name); | |
332 | return; | |
333 | } | |
334 | ||
335 | sn = &sn1; | |
336 | memset(sn, 0, sizeof(*sn)); | |
337 | ||
338 | #ifdef _WIN32 | |
339 | _ftime(&tb); | |
340 | sn->date_sec = tb.time; | |
341 | sn->date_nsec = tb.millitm * 1000000; | |
342 | #else | |
343 | gettimeofday(&tv, NULL); | |
344 | sn->date_sec = tv.tv_sec; | |
345 | sn->date_nsec = tv.tv_usec * 1000; | |
346 | #endif | |
347 | sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock); | |
348 | ||
349 | pstrcpy(sn->name, sizeof(sn->name), name); | |
350 | ||
351 | sn->vm_state_size = 0; /* do not save state */ | |
352 | ||
353 | ret = bdrv_snapshot_create(bs, sn); | |
354 | if (ret < 0) { | |
355 | error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
356 | "Error while creating snapshot on '%s'\n", device); | |
357 | return; | |
358 | } | |
359 | } | |
360 | ||
361 | void qmp_delete_drive_snapshot(const char *device, const char *name, | |
362 | Error **errp) | |
363 | { | |
364 | BlockDriverState *bs; | |
365 | QEMUSnapshotInfo sn1, *sn = &sn1; | |
366 | int ret; | |
367 | ||
368 | bs = bdrv_find(device); | |
369 | if (!bs) { | |
370 | error_set(errp, QERR_DEVICE_NOT_FOUND, device); | |
371 | return; | |
372 | } | |
373 | if (bdrv_is_read_only(bs)) { | |
374 | error_set(errp, QERR_DEVICE_IS_READ_ONLY, device); | |
375 | return; | |
376 | } | |
377 | ||
378 | if (!bdrv_can_snapshot(bs)) { | |
379 | error_set(errp, QERR_NOT_SUPPORTED); | |
380 | return; | |
381 | } | |
382 | ||
383 | if (bdrv_snapshot_find(bs, sn, name) < 0) { | |
384 | /* return success if snapshot does not exists */ | |
385 | return; | |
386 | } | |
387 | ||
388 | ret = bdrv_snapshot_delete(bs, name); | |
389 | if (ret < 0) { | |
390 | error_set(errp, ERROR_CLASS_GENERIC_ERROR, | |
391 | "Error while deleting snapshot on '%s'\n", device); | |
392 | return; | |
393 | } | |
394 | } | |
395 | ||
396 | static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) | |
397 | { | |
398 | BlockDriverState *bs = (BlockDriverState *)opaque; | |
399 | int64_t maxlen = bdrv_getlength(bs); | |
400 | if (pos > maxlen) { | |
401 | return -EIO; | |
402 | } | |
403 | if ((pos + size) > maxlen) { | |
404 | size = maxlen - pos - 1; | |
405 | } | |
406 | if (size == 0) { | |
407 | return 0; | |
408 | } | |
409 | return bdrv_pread(bs, pos, buf, size); | |
410 | } | |
411 | ||
412 | int load_state_from_blockdev(const char *filename) | |
413 | { | |
414 | BlockDriverState *bs = NULL; | |
415 | BlockDriver *drv = NULL; | |
416 | QEMUFile *f; | |
417 | int ret = -1; | |
418 | ||
419 | bs = bdrv_new("vmstate"); | |
420 | ret = bdrv_open(bs, filename, BDRV_O_CACHE_WB, drv); | |
421 | if (ret < 0) { | |
422 | error_report("Could not open VM state file"); | |
423 | goto the_end; | |
424 | } | |
425 | ||
426 | /* restore the VM state */ | |
427 | f = qemu_fopen_ops(bs, NULL, loadstate_get_buffer, NULL, NULL, NULL, NULL); | |
428 | if (!f) { | |
429 | error_report("Could not open VM state file"); | |
430 | ret = -EINVAL; | |
431 | goto the_end; | |
432 | } | |
433 | ||
434 | qemu_system_reset(VMRESET_SILENT); | |
435 | ret = qemu_loadvm_state(f); | |
436 | ||
437 | qemu_fclose(f); | |
438 | if (ret < 0) { | |
439 | error_report("Error %d while loading VM state", ret); | |
440 | goto the_end; | |
441 | } | |
442 | ||
443 | ret = 0; | |
444 | ||
445 | the_end: | |
446 | if (bs) { | |
447 | bdrv_delete(bs); | |
448 | } | |
449 | return ret; | |
450 | } |