]> git.proxmox.com Git - pve-qemu-kvm.git/blame - debian/patches/internal-snapshot-async.patch
add fix for alarm timer setup
[pve-qemu-kvm.git] / debian / patches / internal-snapshot-async.patch
CommitLineData
cd983153
DM
1Index: new/qapi-schema.json
2===================================================================
b84aa9c4
DM
3--- new.orig/qapi-schema.json 2012-11-23 07:30:15.000000000 +0100
4+++ new/qapi-schema.json 2012-11-23 07:31:44.000000000 +0100
e96de165
DM
5@@ -461,6 +461,40 @@
6 '*downtime': 'int'} }
cd983153
DM
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.
e96de165 46@@ -2902,6 +2936,14 @@
cd983153
DM
47 ##
48 { 'command': 'query-target', 'returns': 'TargetInfo' }
e96de165 49
1f416f3a 50+{ 'command': 'savevm-start' 'data': { '*statefile': 'str' } }
cd983153
DM
51+
52+{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
53+
54+{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } }
55+
1f416f3a 56+{ 'command': 'savevm-end' }
e96de165
DM
57+
58 ##
59 # @QKeyCode:
60 #
cd983153
DM
61Index: new/qmp-commands.hx
62===================================================================
b84aa9c4
DM
63--- new.orig/qmp-commands.hx 2012-11-23 07:30:15.000000000 +0100
64+++ new/qmp-commands.hx 2012-11-23 07:31:44.000000000 +0100
e96de165 65@@ -2654,3 +2654,34 @@
cd983153
DM
66 .args_type = "",
67 .mhandler.cmd_new = qmp_marshal_input_query_target,
68 },
69+
70+ {
1f416f3a 71+ .name = "savevm-start",
cd983153 72+ .args_type = "statefile:s?",
1f416f3a 73+ .mhandler.cmd_new = qmp_marshal_input_savevm_start,
cd983153
DM
74+ },
75+
76+ {
77+ .name = "snapshot-drive",
78+ .args_type = "device:s,name:s",
79+ .mhandler.cmd_new = qmp_marshal_input_snapshot_drive,
80+ },
81+
82+ {
83+ .name = "delete-drive-snapshot",
84+ .args_type = "device:s,name:s",
85+ .mhandler.cmd_new = qmp_marshal_input_delete_drive_snapshot,
86+ },
87+
88+ {
1f416f3a 89+ .name = "savevm-end",
cd983153 90+ .args_type = "",
1f416f3a 91+ .mhandler.cmd_new = qmp_marshal_input_savevm_end,
cd983153 92+ },
629cf2f4
DM
93+
94+ {
95+ .name = "query-savevm",
96+ .args_type = "",
97+ .mhandler.cmd_new = qmp_marshal_input_query_savevm,
98+ },
99+
cd983153
DM
100Index: new/hmp.c
101===================================================================
b84aa9c4
DM
102--- new.orig/hmp.c 2012-11-23 07:30:15.000000000 +0100
103+++ new/hmp.c 2012-11-23 07:31:44.000000000 +0100
e96de165
DM
104@@ -1335,3 +1335,60 @@
105 qmp_nbd_server_stop(&errp);
cd983153
DM
106 hmp_handle_error(mon, &errp);
107 }
108+
1f416f3a 109+void hmp_savevm_start(Monitor *mon, const QDict *qdict)
cd983153
DM
110+{
111+ Error *errp = NULL;
112+ const char *statefile = qdict_get_try_str(qdict, "statefile");
113+
1f416f3a 114+ qmp_savevm_start(statefile != NULL, statefile, &errp);
cd983153
DM
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+
1f416f3a 138+void hmp_savevm_end(Monitor *mon, const QDict *qdict)
cd983153
DM
139+{
140+ Error *errp = NULL;
141+
1f416f3a 142+ qmp_savevm_end(&errp);
cd983153
DM
143+ hmp_handle_error(mon, &errp);
144+}
145+
146+void hmp_info_savevm(Monitor *mon)
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+}
165Index: new/hmp.h
166===================================================================
b84aa9c4
DM
167--- new.orig/hmp.h 2012-11-23 07:30:15.000000000 +0100
168+++ new/hmp.h 2012-11-23 07:31:44.000000000 +0100
cd983153
DM
169@@ -25,6 +25,7 @@
170 void hmp_info_uuid(Monitor *mon);
171 void hmp_info_chardev(Monitor *mon);
172 void hmp_info_mice(Monitor *mon);
173+void hmp_info_savevm(Monitor *mon);
174 void hmp_info_migrate(Monitor *mon);
175 void hmp_info_migrate_capabilities(Monitor *mon);
176 void hmp_info_migrate_cache_size(Monitor *mon);
e96de165 177@@ -75,6 +76,10 @@
cd983153
DM
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);
1f416f3a 181+void hmp_savevm_start(Monitor *mon, const QDict *qdict);
cd983153
DM
182+void hmp_snapshot_drive(Monitor *mon, const QDict *qdict);
183+void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict);
1f416f3a 184+void hmp_savevm_end(Monitor *mon, const QDict *qdict);
e96de165
DM
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);
cd983153
DM
188Index: new/hmp-commands.hx
189===================================================================
b84aa9c4
DM
190--- new.orig/hmp-commands.hx 2012-11-23 07:30:15.000000000 +0100
191+++ new/hmp-commands.hx 2012-11-23 07:31:44.000000000 +0100
e96de165 192@@ -1562,6 +1562,8 @@
cd983153
DM
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
e96de165 201@@ -1581,3 +1583,35 @@
cd983153
DM
202 STEXI
203 @end table
204 ETEXI
205+
206+ {
1f416f3a 207+ .name = "savevm-start",
cd983153
DM
208+ .args_type = "statefile:s?",
209+ .params = "[statefile]",
210+ .help = "Prepare for snapshot and halt VM. Save VM state to statefile.",
1f416f3a 211+ .mhandler.cmd = hmp_savevm_start,
cd983153
DM
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+ {
1f416f3a 231+ .name = "savevm-end",
cd983153
DM
232+ .args_type = "",
233+ .params = "",
234+ .help = "Resume VM after snaphot.",
1f416f3a 235+ .mhandler.cmd = hmp_savevm_end,
cd983153
DM
236+ },
237Index: new/savevm-async.c
238===================================================================
239--- /dev/null 1970-01-01 00:00:00.000000000 +0000
b84aa9c4
DM
240+++ new/savevm-async.c 2012-11-23 07:32:48.000000000 +0100
241@@ -0,0 +1,458 @@
cd983153
DM
242+#include "qemu-common.h"
243+#include "qerror.h"
244+#include "sysemu.h"
245+#include "qmp-commands.h"
246+#include "blockdev.h"
247+#include "qemu/qom-qobject.h"
248+#include "buffered_file.h"
249+#include "migration.h"
250+
b84aa9c4 251+/* #define DEBUG_SAVEVM_STATE */
cd983153
DM
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) {
b84aa9c4
DM
330+ /* try to truncate, but ignore errors (will fail on block devices).
331+ * note: bdrv_read() need whole blocks, so we round up
332+ */
cd983153
DM
333+ size_t size = (snap_state.bs_pos + BDRV_SECTOR_SIZE) & BDRV_SECTOR_MASK;
334+ bdrv_truncate(snap_state.bs, size);
cd983153
DM
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+
b84aa9c4
DM
381+static int block_state_put_buffer(void *opaque, const uint8_t *buf,
382+ int64_t pos, int size)
cd983153
DM
383+{
384+ int ret;
385+
b84aa9c4
DM
386+ assert(pos == snap_state.bs_pos);
387+
cd983153
DM
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+
b84aa9c4 395+static void process_savevm_co(void *opaque)
cd983153
DM
396+{
397+ int ret;
b84aa9c4
DM
398+ uint64_t remaining;
399+ int64_t maxlen;
400+ MigrationParams params = {
401+ .blk = 0,
402+ .shared = 0
403+ };
cd983153 404+
b84aa9c4 405+ snap_state.state = SAVE_STATE_ACTIVE;
cd983153 406+
b84aa9c4
DM
407+ ret = qemu_savevm_state_begin(snap_state.file, &params);
408+ if (ret < 0) {
409+ save_snapshot_error("qemu_savevm_state_begin failed");
cd983153
DM
410+ return;
411+ }
412+
b84aa9c4
DM
413+ while (snap_state.state == SAVE_STATE_ACTIVE) {
414+
415+ ret = qemu_savevm_state_iterate(snap_state.file);
416+ remaining = ram_bytes_remaining();
417+
418+ DPRINTF("savevm inerate %zd %d\n", remaining, ret);
419+
420+ if (ret < 0) {
421+ save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
cd983153
DM
422+ return;
423+ }
b84aa9c4
DM
424+
425+ /* stop the VM if we get to the end of available space,
426+ * or if remaining is just a few MB
427+ */
428+ maxlen = bdrv_getlength(snap_state.bs) - 30*1024*1024;
429+ if ((remaining < 100000) ||
430+ ((snap_state.bs_pos + remaining) >= maxlen)) {
431+ if (runstate_is_running()) {
432+ vm_stop(RUN_STATE_SAVE_VM);
433+ }
434+ }
435+
436+ if (ret == 1) { /* finished */
437+ if (runstate_is_running()) {
438+ vm_stop(RUN_STATE_SAVE_VM);
439+ }
440+ DPRINTF("savevm inerate finished\n");
441+ if ((ret = qemu_savevm_state_complete(snap_state.file)) < 0) {
442+ save_snapshot_error("qemu_savevm_state_complete error %d", ret);
443+ return;
444+ } else {
445+ DPRINTF("save complete\n");
446+ save_snapshot_completed();
447+ return;
448+ }
449+ }
cd983153
DM
450+ }
451+}
452+
b84aa9c4
DM
453+static const QEMUFileOps block_file_ops = {
454+ .put_buffer = block_state_put_buffer,
455+ .close = block_state_close,
456+};
457+
cd983153 458+
1f416f3a 459+void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
cd983153
DM
460+{
461+ BlockDriver *drv = NULL;
462+ int bdrv_oflags = BDRV_O_CACHE_WB | BDRV_O_RDWR;
cd983153
DM
463+ int ret;
464+
465+ if (snap_state.state != SAVE_STATE_DONE) {
466+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
467+ "VM snapshot already started\n");
468+ return;
469+ }
470+
471+ /* initialize snapshot info */
472+ snap_state.saved_vm_running = runstate_is_running();
473+ snap_state.bs_pos = 0;
474+ snap_state.total_time = qemu_get_clock_ms(rt_clock);
475+
476+ if (snap_state.error) {
477+ error_free(snap_state.error);
478+ snap_state.error = NULL;
479+ }
480+
cd983153 481+ if (!has_statefile) {
b84aa9c4 482+ vm_stop(RUN_STATE_SAVE_VM);
cd983153
DM
483+ snap_state.state = SAVE_STATE_COMPLETED;
484+ return;
485+ }
486+
487+ if (qemu_savevm_state_blocked(errp)) {
488+ return;
489+ }
490+
491+ /* Open the image */
492+ snap_state.bs = bdrv_new("vmstate");
493+ ret = bdrv_open(snap_state.bs, statefile, bdrv_oflags, drv);
494+ if (ret < 0) {
495+ error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
496+ goto restart;
497+ }
498+
b84aa9c4 499+ snap_state.file = qemu_fopen_ops(&snap_state, &block_file_ops);
cd983153
DM
500+
501+ if (!snap_state.file) {
502+ error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
503+ goto restart;
504+ }
505+
b84aa9c4
DM
506+ Coroutine *co = qemu_coroutine_create(process_savevm_co);
507+ qemu_coroutine_enter(co, NULL);
cd983153
DM
508+
509+ return;
510+
511+restart:
512+
513+ save_snapshot_error("setup failed");
514+
515+ if (snap_state.saved_vm_running) {
516+ vm_start();
517+ }
518+}
519+
1f416f3a 520+void qmp_savevm_end(Error **errp)
cd983153
DM
521+{
522+ if (snap_state.state == SAVE_STATE_DONE) {
523+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
524+ "VM snapshot not started\n");
525+ return;
526+ }
527+
528+ if (snap_state.saved_vm_running) {
529+ vm_start();
530+ }
531+
532+ snap_state.state = SAVE_STATE_DONE;
533+}
534+
535+void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
536+{
537+ BlockDriverState *bs;
538+ QEMUSnapshotInfo sn1, *sn = &sn1;
539+ int ret;
540+#ifdef _WIN32
541+ struct _timeb tb;
542+#else
543+ struct timeval tv;
544+#endif
545+
546+ if (snap_state.state != SAVE_STATE_COMPLETED) {
547+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
548+ "VM snapshot not ready/started\n");
549+ return;
550+ }
551+
552+ bs = bdrv_find(device);
553+ if (!bs) {
554+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
555+ return;
556+ }
557+
558+ if (!bdrv_is_inserted(bs)) {
559+ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
560+ return;
561+ }
562+
563+ if (bdrv_is_read_only(bs)) {
564+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
565+ return;
566+ }
567+
568+ if (!bdrv_can_snapshot(bs)) {
569+ error_set(errp, QERR_NOT_SUPPORTED);
570+ return;
571+ }
572+
573+ if (bdrv_snapshot_find(bs, sn, name) >= 0) {
574+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
575+ "snapshot '%s' already exists", name);
576+ return;
577+ }
578+
579+ sn = &sn1;
580+ memset(sn, 0, sizeof(*sn));
581+
582+#ifdef _WIN32
583+ _ftime(&tb);
584+ sn->date_sec = tb.time;
585+ sn->date_nsec = tb.millitm * 1000000;
586+#else
587+ gettimeofday(&tv, NULL);
588+ sn->date_sec = tv.tv_sec;
589+ sn->date_nsec = tv.tv_usec * 1000;
590+#endif
591+ sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
592+
593+ pstrcpy(sn->name, sizeof(sn->name), name);
594+
595+ sn->vm_state_size = 0; /* do not save state */
596+
597+ ret = bdrv_snapshot_create(bs, sn);
598+ if (ret < 0) {
599+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
600+ "Error while creating snapshot on '%s'\n", device);
601+ return;
602+ }
603+}
604+
605+void qmp_delete_drive_snapshot(const char *device, const char *name,
606+ Error **errp)
607+{
608+ BlockDriverState *bs;
609+ QEMUSnapshotInfo sn1, *sn = &sn1;
610+ int ret;
611+
612+ bs = bdrv_find(device);
613+ if (!bs) {
614+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
615+ return;
616+ }
617+ if (bdrv_is_read_only(bs)) {
618+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
619+ return;
620+ }
621+
622+ if (!bdrv_can_snapshot(bs)) {
623+ error_set(errp, QERR_NOT_SUPPORTED);
624+ return;
625+ }
626+
627+ if (bdrv_snapshot_find(bs, sn, name) < 0) {
628+ /* return success if snapshot does not exists */
629+ return;
630+ }
631+
632+ ret = bdrv_snapshot_delete(bs, name);
633+ if (ret < 0) {
634+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
635+ "Error while deleting snapshot on '%s'\n", device);
636+ return;
637+ }
638+}
639+
b84aa9c4
DM
640+static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
641+ int size)
cd983153
DM
642+{
643+ BlockDriverState *bs = (BlockDriverState *)opaque;
644+ int64_t maxlen = bdrv_getlength(bs);
645+ if (pos > maxlen) {
646+ return -EIO;
647+ }
648+ if ((pos + size) > maxlen) {
649+ size = maxlen - pos - 1;
650+ }
651+ if (size == 0) {
652+ return 0;
653+ }
654+ return bdrv_pread(bs, pos, buf, size);
655+}
656+
b84aa9c4
DM
657+static const QEMUFileOps loadstate_file_ops = {
658+ .get_buffer = loadstate_get_buffer,
659+};
660+
cd983153
DM
661+int load_state_from_blockdev(const char *filename)
662+{
663+ BlockDriverState *bs = NULL;
664+ BlockDriver *drv = NULL;
665+ QEMUFile *f;
666+ int ret = -1;
667+
668+ bs = bdrv_new("vmstate");
669+ ret = bdrv_open(bs, filename, BDRV_O_CACHE_WB, drv);
670+ if (ret < 0) {
671+ error_report("Could not open VM state file");
672+ goto the_end;
673+ }
674+
675+ /* restore the VM state */
b84aa9c4 676+ f = qemu_fopen_ops(bs, &loadstate_file_ops);
cd983153
DM
677+ if (!f) {
678+ error_report("Could not open VM state file");
679+ ret = -EINVAL;
680+ goto the_end;
681+ }
682+
683+ qemu_system_reset(VMRESET_SILENT);
684+ ret = qemu_loadvm_state(f);
685+
686+ qemu_fclose(f);
687+ if (ret < 0) {
688+ error_report("Error %d while loading VM state", ret);
689+ goto the_end;
690+ }
691+
692+ ret = 0;
693+
694+ the_end:
695+ if (bs) {
696+ bdrv_delete(bs);
697+ }
698+ return ret;
699+}
700Index: new/Makefile.objs
701===================================================================
b84aa9c4
DM
702--- new.orig/Makefile.objs 2012-11-23 07:30:15.000000000 +0100
703+++ new/Makefile.objs 2012-11-23 07:31:44.000000000 +0100
e96de165
DM
704@@ -84,6 +84,7 @@
705 common-obj-y += block-migration.o iohandler.o
cd983153
DM
706 common-obj-y += bitmap.o bitops.o
707 common-obj-y += page_cache.o
708+common-obj-y += savevm-async.o
709
710 common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
711 common-obj-$(CONFIG_WIN32) += version.o
712Index: new/sysemu.h
713===================================================================
b84aa9c4
DM
714--- new.orig/sysemu.h 2012-11-23 07:30:15.000000000 +0100
715+++ new/sysemu.h 2012-11-23 07:31:44.000000000 +0100
e96de165 716@@ -67,6 +67,7 @@
cd983153
DM
717
718 void do_savevm(Monitor *mon, const QDict *qdict);
719 int load_vmstate(const char *name);
720+int load_state_from_blockdev(const char *filename);
721 void do_delvm(Monitor *mon, const QDict *qdict);
722 void do_info_snapshots(Monitor *mon);
723
724Index: new/qemu-options.hx
725===================================================================
b84aa9c4
DM
726--- new.orig/qemu-options.hx 2012-11-23 07:31:24.000000000 +0100
727+++ new/qemu-options.hx 2012-11-23 07:31:44.000000000 +0100
e96de165 728@@ -2575,6 +2575,19 @@
cd983153
DM
729 Start right away with a saved state (@code{loadvm} in monitor)
730 ETEXI
731
732+DEF("loadstate", HAS_ARG, QEMU_OPTION_loadstate, \
733+ "-loadstate file\n" \
734+ " start right away with a saved state\n",
735+ QEMU_ARCH_ALL)
736+STEXI
737+@item -loadstate @var{file}
738+@findex -loadstate
739+Start right away with a saved state. This option does not rollback
740+disk state like @code{loadvm}, so user must make sure that disk
741+have correct state. @var{file} can be any valid device URL. See the section
742+for "Device URL Syntax" for more information.
743+ETEXI
744+
745 #ifndef _WIN32
746 DEF("daemonize", 0, QEMU_OPTION_daemonize, \
747 "-daemonize daemonize QEMU after initializing\n", QEMU_ARCH_ALL)
748Index: new/vl.c
749===================================================================
b84aa9c4
DM
750--- new.orig/vl.c 2012-11-23 07:31:29.000000000 +0100
751+++ new/vl.c 2012-11-23 07:31:44.000000000 +0100
e96de165 752@@ -2545,6 +2545,7 @@
cd983153
DM
753 int optind;
754 const char *optarg;
755 const char *loadvm = NULL;
756+ const char *loadstate = NULL;
757 QEMUMachine *machine;
758 const char *cpu_model;
759 const char *vga_model = "none";
e96de165 760@@ -3185,6 +3186,9 @@
cd983153
DM
761 case QEMU_OPTION_loadvm:
762 loadvm = optarg;
763 break;
764+ case QEMU_OPTION_loadstate:
765+ loadstate = optarg;
766+ break;
767 case QEMU_OPTION_full_screen:
768 full_screen = 1;
769 break;
e96de165 770@@ -4038,6 +4042,10 @@
cd983153
DM
771 if (load_vmstate(loadvm) < 0) {
772 autostart = 0;
773 }
774+ } else if (loadstate) {
775+ if (load_state_from_blockdev(loadstate) < 0) {
776+ autostart = 0;
777+ }
778 }
779
780 if (incoming) {
629cf2f4
DM
781Index: new/monitor.c
782===================================================================
b84aa9c4
DM
783--- new.orig/monitor.c 2012-11-23 07:30:15.000000000 +0100
784+++ new/monitor.c 2012-11-23 07:31:44.000000000 +0100
e96de165 785@@ -2701,6 +2701,13 @@
629cf2f4
DM
786 .mhandler.info = hmp_info_migrate_cache_size,
787 },
788 {
789+ .name = "savevm",
790+ .args_type = "",
791+ .params = "",
792+ .help = "show savevm status",
793+ .mhandler.info = hmp_info_savevm,
794+ },
795+ {
796 .name = "balloon",
797 .args_type = "",
798 .params = "",