]> git.proxmox.com Git - pve-qemu-kvm.git/blob - debian/patches/internal-snapshot-async.patch
updates for qemu 1.4.0
[pve-qemu-kvm.git] / debian / patches / internal-snapshot-async.patch
1 Index: new/qapi-schema.json
2 ===================================================================
3 --- new.orig/qapi-schema.json 2013-02-12 12:05:14.000000000 +0100
4 +++ new/qapi-schema.json 2013-02-12 12:07:05.000000000 +0100
5 @@ -528,6 +528,40 @@
6 '*downtime': 'int'} }
7
8 ##
9 +# @SaveVMInfo
10 +#
11 +# Information about current migration process.
12 +#
13 +# @status: #optional string describing the current savevm status.
14 +# This can be 'active', 'completed', 'failed'.
15 +# If this field is not returned, no savevm process
16 +# has been initiated
17 +#
18 +# @error: #optional string containing error message is status is failed.
19 +#
20 +# @total-time: #optional total amount of milliseconds since savevm started.
21 +# If savevm has ended, it returns the total save time
22 +#
23 +# @bytes: #optional total amount of data transfered
24 +#
25 +# Since: 1.3
26 +##
27 +{ 'type': 'SaveVMInfo',
28 + 'data': {'*status': 'str', '*error': 'str',
29 + '*total-time': 'int', '*bytes': 'int'} }
30 +
31 +##
32 +# @query-savevm
33 +#
34 +# Returns information about current savevm process.
35 +#
36 +# Returns: @SaveVMInfo
37 +#
38 +# Since: 1.3
39 +##
40 +{ 'command': 'query-savevm', 'returns': 'SaveVMInfo' }
41 +
42 +##
43 # @query-migrate
44 #
45 # Returns information about current migration process.
46 @@ -2965,6 +2999,14 @@
47 ##
48 { 'command': 'query-target', 'returns': 'TargetInfo' }
49
50 +{ 'command': 'savevm-start' 'data': { '*statefile': 'str' } }
51 +
52 +{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
53 +
54 +{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } }
55 +
56 +{ 'command': 'savevm-end' }
57 +
58 ##
59 # @QKeyCode:
60 #
61 Index: new/qmp-commands.hx
62 ===================================================================
63 --- new.orig/qmp-commands.hx 2013-02-12 12:05:14.000000000 +0100
64 +++ new/qmp-commands.hx 2013-02-12 12:07:05.000000000 +0100
65 @@ -2775,3 +2775,34 @@
66 <- { "return": {} }
67
68 EQMP
69 +
70 +
71 + {
72 + .name = "savevm-start",
73 + .args_type = "statefile:s?",
74 + .mhandler.cmd_new = qmp_marshal_input_savevm_start,
75 + },
76 +
77 + {
78 + .name = "snapshot-drive",
79 + .args_type = "device:s,name:s",
80 + .mhandler.cmd_new = qmp_marshal_input_snapshot_drive,
81 + },
82 +
83 + {
84 + .name = "delete-drive-snapshot",
85 + .args_type = "device:s,name:s",
86 + .mhandler.cmd_new = qmp_marshal_input_delete_drive_snapshot,
87 + },
88 +
89 + {
90 + .name = "savevm-end",
91 + .args_type = "",
92 + .mhandler.cmd_new = qmp_marshal_input_savevm_end,
93 + },
94 +
95 + {
96 + .name = "query-savevm",
97 + .args_type = "",
98 + .mhandler.cmd_new = qmp_marshal_input_query_savevm,
99 + },
100 Index: new/hmp.c
101 ===================================================================
102 --- new.orig/hmp.c 2013-02-12 12:05:14.000000000 +0100
103 +++ new/hmp.c 2013-02-12 12:07:05.000000000 +0100
104 @@ -1379,3 +1379,60 @@
105 qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
106 hmp_handle_error(mon, &local_err);
107 }
108 +
109 +void hmp_savevm_start(Monitor *mon, const QDict *qdict)
110 +{
111 + Error *errp = NULL;
112 + const char *statefile = qdict_get_try_str(qdict, "statefile");
113 +
114 + qmp_savevm_start(statefile != NULL, statefile, &errp);
115 + hmp_handle_error(mon, &errp);
116 +}
117 +
118 +void hmp_snapshot_drive(Monitor *mon, const QDict *qdict)
119 +{
120 + Error *errp = NULL;
121 + const char *name = qdict_get_str(qdict, "name");
122 + const char *device = qdict_get_str(qdict, "device");
123 +
124 + qmp_snapshot_drive(device, name, &errp);
125 + hmp_handle_error(mon, &errp);
126 +}
127 +
128 +void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict)
129 +{
130 + Error *errp = NULL;
131 + const char *name = qdict_get_str(qdict, "name");
132 + const char *device = qdict_get_str(qdict, "device");
133 +
134 + qmp_delete_drive_snapshot(device, name, &errp);
135 + hmp_handle_error(mon, &errp);
136 +}
137 +
138 +void hmp_savevm_end(Monitor *mon, const QDict *qdict)
139 +{
140 + Error *errp = NULL;
141 +
142 + qmp_savevm_end(&errp);
143 + hmp_handle_error(mon, &errp);
144 +}
145 +
146 +void hmp_info_savevm(Monitor *mon, const QDict *qdict)
147 +{
148 + SaveVMInfo *info;
149 + info = qmp_query_savevm(NULL);
150 +
151 + if (info->has_status) {
152 + monitor_printf(mon, "savevm status: %s\n", info->status);
153 + monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
154 + info->total_time);
155 + } else {
156 + monitor_printf(mon, "savevm status: not running\n");
157 + }
158 + if (info->has_bytes) {
159 + monitor_printf(mon, "Bytes saved: %"PRIu64"\n", info->bytes);
160 + }
161 + if (info->has_error) {
162 + monitor_printf(mon, "Error: %s\n", info->error);
163 + }
164 +}
165 Index: new/hmp.h
166 ===================================================================
167 --- new.orig/hmp.h 2013-02-12 12:05:14.000000000 +0100
168 +++ new/hmp.h 2013-02-12 12:07:05.000000000 +0100
169 @@ -25,6 +25,7 @@
170 void hmp_info_uuid(Monitor *mon, const QDict *qdict);
171 void hmp_info_chardev(Monitor *mon, const QDict *qdict);
172 void hmp_info_mice(Monitor *mon, const QDict *qdict);
173 +void hmp_info_savevm(Monitor *mon, const QDict *qdict);
174 void hmp_info_migrate(Monitor *mon, const QDict *qdict);
175 void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict);
176 void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict);
177 @@ -77,6 +78,10 @@
178 void hmp_netdev_del(Monitor *mon, const QDict *qdict);
179 void hmp_getfd(Monitor *mon, const QDict *qdict);
180 void hmp_closefd(Monitor *mon, const QDict *qdict);
181 +void hmp_savevm_start(Monitor *mon, const QDict *qdict);
182 +void hmp_snapshot_drive(Monitor *mon, const QDict *qdict);
183 +void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict);
184 +void hmp_savevm_end(Monitor *mon, const QDict *qdict);
185 void hmp_send_key(Monitor *mon, const QDict *qdict);
186 void hmp_screen_dump(Monitor *mon, const QDict *qdict);
187 void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
188 Index: new/hmp-commands.hx
189 ===================================================================
190 --- new.orig/hmp-commands.hx 2013-02-12 12:05:14.000000000 +0100
191 +++ new/hmp-commands.hx 2013-02-12 12:07:05.000000000 +0100
192 @@ -1634,6 +1634,8 @@
193 show current migration capabilities
194 @item info migrate_cache_size
195 show current migration XBZRLE cache size
196 +@item info savevm
197 +show savevm status
198 @item info balloon
199 show balloon information
200 @item info qtree
201 @@ -1653,3 +1655,35 @@
202 STEXI
203 @end table
204 ETEXI
205 +
206 + {
207 + .name = "savevm-start",
208 + .args_type = "statefile:s?",
209 + .params = "[statefile]",
210 + .help = "Prepare for snapshot and halt VM. Save VM state to statefile.",
211 + .mhandler.cmd = hmp_savevm_start,
212 + },
213 +
214 + {
215 + .name = "snapshot-drive",
216 + .args_type = "device:s,name:s",
217 + .params = "device name",
218 + .help = "Create internal snapshot.",
219 + .mhandler.cmd = hmp_snapshot_drive,
220 + },
221 +
222 + {
223 + .name = "delete-drive-snapshot",
224 + .args_type = "device:s,name:s",
225 + .params = "device name",
226 + .help = "Delete internal snapshot.",
227 + .mhandler.cmd = hmp_delete_drive_snapshot,
228 + },
229 +
230 + {
231 + .name = "savevm-end",
232 + .args_type = "",
233 + .params = "",
234 + .help = "Resume VM after snaphot.",
235 + .mhandler.cmd = hmp_savevm_end,
236 + },
237 Index: new/savevm-async.c
238 ===================================================================
239 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
240 +++ new/savevm-async.c 2013-02-12 12:07:05.000000000 +0100
241 @@ -0,0 +1,459 @@
242 +#include "include/qemu-common.h"
243 +#include "include/qapi/qmp/qerror.h"
244 +#include "include/sysemu/sysemu.h"
245 +#include "qmp-commands.h"
246 +#include "include/migration/qemu-file.h"
247 +#include "include/sysemu/blockdev.h"
248 +#include "include/qom/qom-qobject.h"
249 +#include "include/migration/migration.h"
250 +
251 +/* #define DEBUG_SAVEVM_STATE */
252 +
253 +#ifdef DEBUG_SAVEVM_STATE
254 +#define DPRINTF(fmt, ...) \
255 + do { printf("savevm-async: " fmt, ## __VA_ARGS__); } while (0)
256 +#else
257 +#define DPRINTF(fmt, ...) \
258 + do { } while (0)
259 +#endif
260 +
261 +enum {
262 + SAVE_STATE_DONE,
263 + SAVE_STATE_ERROR,
264 + SAVE_STATE_ACTIVE,
265 + SAVE_STATE_COMPLETED,
266 +};
267 +
268 +static struct SnapshotState {
269 + BlockDriverState *bs;
270 + size_t bs_pos;
271 + int state;
272 + Error *error;
273 + int saved_vm_running;
274 + QEMUFile *file;
275 + int64_t total_time;
276 +} snap_state;
277 +
278 +SaveVMInfo *qmp_query_savevm(Error **errp)
279 +{
280 + SaveVMInfo *info = g_malloc0(sizeof(*info));
281 + struct SnapshotState *s = &snap_state;
282 +
283 + if (s->state != SAVE_STATE_DONE) {
284 + info->has_bytes = true;
285 + info->bytes = s->bs_pos;
286 + switch (s->state) {
287 + case SAVE_STATE_ERROR:
288 + info->has_status = true;
289 + info->status = g_strdup("failed");
290 + info->has_total_time = true;
291 + info->total_time = s->total_time;
292 + if (s->error) {
293 + info->has_error = true;
294 + info->error = g_strdup(error_get_pretty(s->error));
295 + }
296 + break;
297 + case SAVE_STATE_ACTIVE:
298 + info->has_status = true;
299 + info->status = g_strdup("active");
300 + info->has_total_time = true;
301 + info->total_time = qemu_get_clock_ms(rt_clock)
302 + - s->total_time;
303 + break;
304 + case SAVE_STATE_COMPLETED:
305 + info->has_status = true;
306 + info->status = g_strdup("completed");
307 + info->has_total_time = true;
308 + info->total_time = s->total_time;
309 + break;
310 + }
311 + }
312 +
313 + return info;
314 +}
315 +
316 +static int save_snapshot_cleanup(void)
317 +{
318 + int ret = 0;
319 +
320 + DPRINTF("save_snapshot_cleanup\n");
321 +
322 + snap_state.total_time = qemu_get_clock_ms(rt_clock) -
323 + snap_state.total_time;
324 +
325 + if (snap_state.file) {
326 + ret = qemu_fclose(snap_state.file);
327 + }
328 +
329 + if (snap_state.bs) {
330 + /* try to truncate, but ignore errors (will fail on block devices).
331 + * note: bdrv_read() need whole blocks, so we round up
332 + */
333 + size_t size = (snap_state.bs_pos + BDRV_SECTOR_SIZE) & BDRV_SECTOR_MASK;
334 + bdrv_truncate(snap_state.bs, size);
335 + bdrv_delete(snap_state.bs);
336 + snap_state.bs = NULL;
337 + }
338 +
339 + return ret;
340 +}
341 +
342 +static void save_snapshot_error(const char *fmt, ...)
343 +{
344 + va_list ap;
345 + char *msg;
346 +
347 + va_start(ap, fmt);
348 + msg = g_strdup_vprintf(fmt, ap);
349 + va_end(ap);
350 +
351 + DPRINTF("save_snapshot_error: %s\n", msg);
352 +
353 + if (!snap_state.error) {
354 + error_set(&snap_state.error, ERROR_CLASS_GENERIC_ERROR, "%s", msg);
355 + }
356 +
357 + g_free (msg);
358 +
359 + snap_state.state = SAVE_STATE_ERROR;
360 +
361 + save_snapshot_cleanup();
362 +}
363 +
364 +static void save_snapshot_completed(void)
365 +{
366 + DPRINTF("save_snapshot_completed\n");
367 +
368 + if (save_snapshot_cleanup() < 0) {
369 + snap_state.state = SAVE_STATE_ERROR;
370 + } else {
371 + snap_state.state = SAVE_STATE_COMPLETED;
372 + }
373 +}
374 +
375 +static int block_state_close(void *opaque)
376 +{
377 + snap_state.file = NULL;
378 + return bdrv_flush(snap_state.bs);
379 +}
380 +
381 +static int block_state_put_buffer(void *opaque, const uint8_t *buf,
382 + int64_t pos, int size)
383 +{
384 + int ret;
385 +
386 + assert(pos == snap_state.bs_pos);
387 +
388 + if ((ret = bdrv_pwrite(snap_state.bs, snap_state.bs_pos, buf, size)) > 0) {
389 + snap_state.bs_pos += ret;
390 + }
391 +
392 + return ret;
393 +}
394 +
395 +static void process_savevm_co(void *opaque)
396 +{
397 + int ret;
398 + int64_t maxlen;
399 + MigrationParams params = {
400 + .blk = 0,
401 + .shared = 0
402 + };
403 +
404 + snap_state.state = SAVE_STATE_ACTIVE;
405 +
406 + ret = qemu_savevm_state_begin(snap_state.file, &params);
407 + if (ret < 0) {
408 + save_snapshot_error("qemu_savevm_state_begin failed");
409 + return;
410 + }
411 +
412 + while (snap_state.state == SAVE_STATE_ACTIVE) {
413 + uint64_t pending_size;
414 +
415 + pending_size = qemu_savevm_state_pending(snap_state.file, 0);
416 +
417 + if (pending_size) {
418 + ret = qemu_savevm_state_iterate(snap_state.file);
419 + if (ret < 0) {
420 + save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
421 + break;
422 + }
423 + DPRINTF("savevm inerate pending size %lu ret %d\n", pending_size, ret);
424 + } else {
425 + DPRINTF("done iterating\n");
426 + if (runstate_is_running()) {
427 + vm_stop(RUN_STATE_SAVE_VM);
428 + }
429 + DPRINTF("savevm inerate finished\n");
430 + ret = qemu_savevm_state_complete(snap_state.file);
431 + if (ret < 0) {
432 + save_snapshot_error("qemu_savevm_state_complete error %d", ret);
433 + break;
434 + } else {
435 + DPRINTF("save complete\n");
436 + save_snapshot_completed();
437 + break;
438 + }
439 + }
440 +
441 + /* stop the VM if we get to the end of available space,
442 + * or if pending_size is just a few MB
443 + */
444 + maxlen = bdrv_getlength(snap_state.bs) - 30*1024*1024;
445 + if ((pending_size < 100000) ||
446 + ((snap_state.bs_pos + pending_size) >= maxlen)) {
447 + if (runstate_is_running()) {
448 + vm_stop(RUN_STATE_SAVE_VM);
449 + }
450 + }
451 + }
452 +}
453 +
454 +static const QEMUFileOps block_file_ops = {
455 + .put_buffer = block_state_put_buffer,
456 + .close = block_state_close,
457 +};
458 +
459 +
460 +void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
461 +{
462 + BlockDriver *drv = NULL;
463 + int bdrv_oflags = BDRV_O_CACHE_WB | BDRV_O_RDWR;
464 + int ret;
465 +
466 + if (snap_state.state != SAVE_STATE_DONE) {
467 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
468 + "VM snapshot already started\n");
469 + return;
470 + }
471 +
472 + /* initialize snapshot info */
473 + snap_state.saved_vm_running = runstate_is_running();
474 + snap_state.bs_pos = 0;
475 + snap_state.total_time = qemu_get_clock_ms(rt_clock);
476 +
477 + if (snap_state.error) {
478 + error_free(snap_state.error);
479 + snap_state.error = NULL;
480 + }
481 +
482 + if (!has_statefile) {
483 + vm_stop(RUN_STATE_SAVE_VM);
484 + snap_state.state = SAVE_STATE_COMPLETED;
485 + return;
486 + }
487 +
488 + if (qemu_savevm_state_blocked(errp)) {
489 + return;
490 + }
491 +
492 + /* Open the image */
493 + snap_state.bs = bdrv_new("vmstate");
494 + ret = bdrv_open(snap_state.bs, statefile, bdrv_oflags, drv);
495 + if (ret < 0) {
496 + error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
497 + goto restart;
498 + }
499 +
500 + snap_state.file = qemu_fopen_ops(&snap_state, &block_file_ops);
501 +
502 + if (!snap_state.file) {
503 + error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
504 + goto restart;
505 + }
506 +
507 + Coroutine *co = qemu_coroutine_create(process_savevm_co);
508 + qemu_coroutine_enter(co, NULL);
509 +
510 + return;
511 +
512 +restart:
513 +
514 + save_snapshot_error("setup failed");
515 +
516 + if (snap_state.saved_vm_running) {
517 + vm_start();
518 + }
519 +}
520 +
521 +void qmp_savevm_end(Error **errp)
522 +{
523 + if (snap_state.state == SAVE_STATE_DONE) {
524 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
525 + "VM snapshot not started\n");
526 + return;
527 + }
528 +
529 + if (snap_state.saved_vm_running) {
530 + vm_start();
531 + }
532 +
533 + snap_state.state = SAVE_STATE_DONE;
534 +}
535 +
536 +void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
537 +{
538 + BlockDriverState *bs;
539 + QEMUSnapshotInfo sn1, *sn = &sn1;
540 + int ret;
541 +#ifdef _WIN32
542 + struct _timeb tb;
543 +#else
544 + struct timeval tv;
545 +#endif
546 +
547 + if (snap_state.state != SAVE_STATE_COMPLETED) {
548 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
549 + "VM snapshot not ready/started\n");
550 + return;
551 + }
552 +
553 + bs = bdrv_find(device);
554 + if (!bs) {
555 + error_set(errp, QERR_DEVICE_NOT_FOUND, device);
556 + return;
557 + }
558 +
559 + if (!bdrv_is_inserted(bs)) {
560 + error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
561 + return;
562 + }
563 +
564 + if (bdrv_is_read_only(bs)) {
565 + error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
566 + return;
567 + }
568 +
569 + if (!bdrv_can_snapshot(bs)) {
570 + error_set(errp, QERR_NOT_SUPPORTED);
571 + return;
572 + }
573 +
574 + if (bdrv_snapshot_find(bs, sn, name) >= 0) {
575 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
576 + "snapshot '%s' already exists", name);
577 + return;
578 + }
579 +
580 + sn = &sn1;
581 + memset(sn, 0, sizeof(*sn));
582 +
583 +#ifdef _WIN32
584 + _ftime(&tb);
585 + sn->date_sec = tb.time;
586 + sn->date_nsec = tb.millitm * 1000000;
587 +#else
588 + gettimeofday(&tv, NULL);
589 + sn->date_sec = tv.tv_sec;
590 + sn->date_nsec = tv.tv_usec * 1000;
591 +#endif
592 + sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
593 +
594 + pstrcpy(sn->name, sizeof(sn->name), name);
595 +
596 + sn->vm_state_size = 0; /* do not save state */
597 +
598 + ret = bdrv_snapshot_create(bs, sn);
599 + if (ret < 0) {
600 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
601 + "Error while creating snapshot on '%s'\n", device);
602 + return;
603 + }
604 +}
605 +
606 +void qmp_delete_drive_snapshot(const char *device, const char *name,
607 + Error **errp)
608 +{
609 + BlockDriverState *bs;
610 + QEMUSnapshotInfo sn1, *sn = &sn1;
611 + int ret;
612 +
613 + bs = bdrv_find(device);
614 + if (!bs) {
615 + error_set(errp, QERR_DEVICE_NOT_FOUND, device);
616 + return;
617 + }
618 + if (bdrv_is_read_only(bs)) {
619 + error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
620 + return;
621 + }
622 +
623 + if (!bdrv_can_snapshot(bs)) {
624 + error_set(errp, QERR_NOT_SUPPORTED);
625 + return;
626 + }
627 +
628 + if (bdrv_snapshot_find(bs, sn, name) < 0) {
629 + /* return success if snapshot does not exists */
630 + return;
631 + }
632 +
633 + ret = bdrv_snapshot_delete(bs, name);
634 + if (ret < 0) {
635 + error_set(errp, ERROR_CLASS_GENERIC_ERROR,
636 + "Error while deleting snapshot on '%s'\n", device);
637 + return;
638 + }
639 +}
640 +
641 +static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
642 + int size)
643 +{
644 + BlockDriverState *bs = (BlockDriverState *)opaque;
645 + int64_t maxlen = bdrv_getlength(bs);
646 + if (pos > maxlen) {
647 + return -EIO;
648 + }
649 + if ((pos + size) > maxlen) {
650 + size = maxlen - pos - 1;
651 + }
652 + if (size == 0) {
653 + return 0;
654 + }
655 + return bdrv_pread(bs, pos, buf, size);
656 +}
657 +
658 +static const QEMUFileOps loadstate_file_ops = {
659 + .get_buffer = loadstate_get_buffer,
660 +};
661 +
662 +int load_state_from_blockdev(const char *filename)
663 +{
664 + BlockDriverState *bs = NULL;
665 + BlockDriver *drv = NULL;
666 + QEMUFile *f;
667 + int ret = -1;
668 +
669 + bs = bdrv_new("vmstate");
670 + ret = bdrv_open(bs, filename, BDRV_O_CACHE_WB, drv);
671 + if (ret < 0) {
672 + error_report("Could not open VM state file");
673 + goto the_end;
674 + }
675 +
676 + /* restore the VM state */
677 + f = qemu_fopen_ops(bs, &loadstate_file_ops);
678 + if (!f) {
679 + error_report("Could not open VM state file");
680 + ret = -EINVAL;
681 + goto the_end;
682 + }
683 +
684 + qemu_system_reset(VMRESET_SILENT);
685 + ret = qemu_loadvm_state(f);
686 +
687 + qemu_fclose(f);
688 + if (ret < 0) {
689 + error_report("Error %d while loading VM state", ret);
690 + goto the_end;
691 + }
692 +
693 + ret = 0;
694 +
695 + the_end:
696 + if (bs) {
697 + bdrv_delete(bs);
698 + }
699 + return ret;
700 +}
701 Index: new/Makefile.objs
702 ===================================================================
703 --- new.orig/Makefile.objs 2013-02-12 12:05:14.000000000 +0100
704 +++ new/Makefile.objs 2013-02-12 12:07:05.000000000 +0100
705 @@ -60,6 +60,7 @@
706 common-obj-y += qemu-char.o #aio.o
707 common-obj-y += block-migration.o
708 common-obj-y += page_cache.o xbzrle.o
709 +common-obj-y += savevm-async.o
710
711 common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
712
713 Index: new/qemu-options.hx
714 ===================================================================
715 --- new.orig/qemu-options.hx 2013-02-12 12:06:20.000000000 +0100
716 +++ new/qemu-options.hx 2013-02-12 12:07:05.000000000 +0100
717 @@ -2605,6 +2605,19 @@
718 Start right away with a saved state (@code{loadvm} in monitor)
719 ETEXI
720
721 +DEF("loadstate", HAS_ARG, QEMU_OPTION_loadstate, \
722 + "-loadstate file\n" \
723 + " start right away with a saved state\n",
724 + QEMU_ARCH_ALL)
725 +STEXI
726 +@item -loadstate @var{file}
727 +@findex -loadstate
728 +Start right away with a saved state. This option does not rollback
729 +disk state like @code{loadvm}, so user must make sure that disk
730 +have correct state. @var{file} can be any valid device URL. See the section
731 +for "Device URL Syntax" for more information.
732 +ETEXI
733 +
734 #ifndef _WIN32
735 DEF("daemonize", 0, QEMU_OPTION_daemonize, \
736 "-daemonize daemonize QEMU after initializing\n", QEMU_ARCH_ALL)
737 Index: new/vl.c
738 ===================================================================
739 --- new.orig/vl.c 2013-02-12 12:06:40.000000000 +0100
740 +++ new/vl.c 2013-02-12 12:07:05.000000000 +0100
741 @@ -2816,6 +2816,7 @@
742 int optind;
743 const char *optarg;
744 const char *loadvm = NULL;
745 + const char *loadstate = NULL;
746 QEMUMachine *machine;
747 const char *cpu_model;
748 const char *vga_model = "none";
749 @@ -3466,6 +3467,9 @@
750 case QEMU_OPTION_loadvm:
751 loadvm = optarg;
752 break;
753 + case QEMU_OPTION_loadstate:
754 + loadstate = optarg;
755 + break;
756 case QEMU_OPTION_full_screen:
757 full_screen = 1;
758 break;
759 @@ -4361,6 +4365,10 @@
760 if (load_vmstate(loadvm) < 0) {
761 autostart = 0;
762 }
763 + } else if (loadstate) {
764 + if (load_state_from_blockdev(loadstate) < 0) {
765 + autostart = 0;
766 + }
767 }
768
769 if (incoming) {
770 Index: new/monitor.c
771 ===================================================================
772 --- new.orig/monitor.c 2013-02-12 12:05:14.000000000 +0100
773 +++ new/monitor.c 2013-02-12 12:07:05.000000000 +0100
774 @@ -2687,6 +2687,13 @@
775 .mhandler.cmd = hmp_info_migrate_cache_size,
776 },
777 {
778 + .name = "savevm",
779 + .args_type = "",
780 + .params = "",
781 + .help = "show savevm status",
782 + .mhandler.cmd = hmp_info_savevm,
783 + },
784 + {
785 .name = "balloon",
786 .args_type = "",
787 .params = "",
788 Index: new/include/sysemu/sysemu.h
789 ===================================================================
790 --- new.orig/include/sysemu/sysemu.h 2013-02-12 12:05:14.000000000 +0100
791 +++ new/include/sysemu/sysemu.h 2013-02-12 12:07:05.000000000 +0100
792 @@ -67,6 +67,7 @@
793
794 void do_savevm(Monitor *mon, const QDict *qdict);
795 int load_vmstate(const char *name);
796 +int load_state_from_blockdev(const char *filename);
797 void do_delvm(Monitor *mon, const QDict *qdict);
798 void do_info_snapshots(Monitor *mon, const QDict *qdict);
799