]> git.proxmox.com Git - pve-qemu-kvm.git/blame - debian/patches/internal-snapshot-async.patch
fix snapshot/rollback of running vm
[pve-qemu-kvm.git] / debian / patches / internal-snapshot-async.patch
CommitLineData
fb40cdcd
AD
1From 46fd4bb673a91d40352c95e9d3f62f63b5021053 Mon Sep 17 00:00:00 2001
2From: Stefan Priebe <s.priebe@profihost.ag>
3Date: Fri, 29 Nov 2013 22:17:03 +0100
4Subject: [PATCH] internal-snapshot-async-qemu1.7.patch
5
6---
7 Makefile.objs | 1 +
8 block.c | 2 +-
9 hmp-commands.hx | 34 ++++
10 hmp.c | 57 ++++++
11 hmp.h | 5 +
12 include/block/block.h | 1 +
13 include/sysemu/sysemu.h | 5 +-
14 monitor.c | 7 +
15 qapi-schema.json | 46 +++++
16 qemu-options.hx | 13 ++
17 qmp-commands.hx | 31 +++
18 savevm-async.c | 478 +++++++++++++++++++++++++++++++++++++++++++++++
19 savevm.c | 10 +-
20 vl.c | 9 +
21 14 files changed, 692 insertions(+), 7 deletions(-)
22 create mode 100644 savevm-async.c
23
b08067ba
DM
24Index: new/Makefile.objs
25===================================================================
24bb7da3
DM
26--- new.orig/Makefile.objs 2014-11-20 09:13:01.000000000 +0100
27+++ new/Makefile.objs 2014-11-20 09:16:47.000000000 +0100
58117ea6 28@@ -53,6 +53,7 @@
fb40cdcd 29 common-obj-y += qemu-char.o #aio.o
58117ea6
WB
30 common-obj-y += page_cache.o
31 common-obj-y += qjson.o
fb40cdcd 32+common-obj-y += savevm-async.o
cd983153 33
58117ea6 34 common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
e96de165 35
b08067ba
DM
36Index: new/block.c
37===================================================================
24bb7da3
DM
38--- new.orig/block.c 2014-11-20 09:13:01.000000000 +0100
39+++ new/block.c 2014-11-20 09:16:47.000000000 +0100
58117ea6 40@@ -2202,7 +2202,7 @@
432a6eb5 41 bdrv_attach_child(bs_top, bs_new, &child_backing);
fb40cdcd 42 }
92bf040c 43
fb40cdcd
AD
44-static void bdrv_delete(BlockDriverState *bs)
45+void bdrv_delete(BlockDriverState *bs)
46 {
fb40cdcd 47 assert(!bs->job);
24bb7da3 48 assert(bdrv_op_blocker_is_empty(bs));
b08067ba
DM
49Index: new/hmp-commands.hx
50===================================================================
24bb7da3
DM
51--- new.orig/hmp-commands.hx 2014-11-20 09:13:01.000000000 +0100
52+++ new/hmp-commands.hx 2014-11-20 09:16:47.000000000 +0100
432a6eb5
WB
53@@ -1809,6 +1809,8 @@
54 show current migration parameters
fb40cdcd
AD
55 @item info migrate_cache_size
56 show current migration XBZRLE cache size
57+@item info savevm
58+show savevm status
59 @item info balloon
60 show balloon information
61 @item info qtree
432a6eb5 62@@ -1857,3 +1859,35 @@
fb40cdcd
AD
63 STEXI
64 @end table
65 ETEXI
cd983153
DM
66+
67+ {
1f416f3a 68+ .name = "savevm-start",
cd983153 69+ .args_type = "statefile:s?",
fb40cdcd
AD
70+ .params = "[statefile]",
71+ .help = "Prepare for snapshot and halt VM. Save VM state to statefile.",
72+ .mhandler.cmd = hmp_savevm_start,
cd983153
DM
73+ },
74+
75+ {
76+ .name = "snapshot-drive",
77+ .args_type = "device:s,name:s",
fb40cdcd
AD
78+ .params = "device name",
79+ .help = "Create internal snapshot.",
80+ .mhandler.cmd = hmp_snapshot_drive,
cd983153
DM
81+ },
82+
83+ {
84+ .name = "delete-drive-snapshot",
85+ .args_type = "device:s,name:s",
fb40cdcd
AD
86+ .params = "device name",
87+ .help = "Delete internal snapshot.",
88+ .mhandler.cmd = hmp_delete_drive_snapshot,
cd983153
DM
89+ },
90+
91+ {
1f416f3a 92+ .name = "savevm-end",
cd983153 93+ .args_type = "",
fb40cdcd
AD
94+ .params = "",
95+ .help = "Resume VM after snaphot.",
96+ .mhandler.cmd = hmp_savevm_end,
629cf2f4 97+ },
b08067ba
DM
98Index: new/hmp.c
99===================================================================
24bb7da3
DM
100--- new.orig/hmp.c 2014-11-20 09:13:01.000000000 +0100
101+++ new/hmp.c 2014-11-20 09:16:47.000000000 +0100
58117ea6 102@@ -1849,6 +1849,63 @@
3fe80761 103
24bb7da3 104 qapi_free_MemoryDeviceInfoList(info_list);
cd983153
DM
105 }
106+
1f416f3a 107+void hmp_savevm_start(Monitor *mon, const QDict *qdict)
cd983153
DM
108+{
109+ Error *errp = NULL;
110+ const char *statefile = qdict_get_try_str(qdict, "statefile");
111+
1f416f3a 112+ qmp_savevm_start(statefile != NULL, statefile, &errp);
cd983153
DM
113+ hmp_handle_error(mon, &errp);
114+}
115+
116+void hmp_snapshot_drive(Monitor *mon, const QDict *qdict)
117+{
118+ Error *errp = NULL;
119+ const char *name = qdict_get_str(qdict, "name");
120+ const char *device = qdict_get_str(qdict, "device");
121+
122+ qmp_snapshot_drive(device, name, &errp);
123+ hmp_handle_error(mon, &errp);
124+}
125+
126+void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict)
127+{
128+ Error *errp = NULL;
129+ const char *name = qdict_get_str(qdict, "name");
130+ const char *device = qdict_get_str(qdict, "device");
131+
132+ qmp_delete_drive_snapshot(device, name, &errp);
133+ hmp_handle_error(mon, &errp);
134+}
135+
1f416f3a 136+void hmp_savevm_end(Monitor *mon, const QDict *qdict)
cd983153
DM
137+{
138+ Error *errp = NULL;
139+
1f416f3a 140+ qmp_savevm_end(&errp);
cd983153
DM
141+ hmp_handle_error(mon, &errp);
142+}
143+
92bf040c 144+void hmp_info_savevm(Monitor *mon, const QDict *qdict)
cd983153
DM
145+{
146+ SaveVMInfo *info;
147+ info = qmp_query_savevm(NULL);
148+
149+ if (info->has_status) {
150+ monitor_printf(mon, "savevm status: %s\n", info->status);
151+ monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
152+ info->total_time);
153+ } else {
154+ monitor_printf(mon, "savevm status: not running\n");
155+ }
156+ if (info->has_bytes) {
157+ monitor_printf(mon, "Bytes saved: %"PRIu64"\n", info->bytes);
158+ }
159+ if (info->has_error) {
160+ monitor_printf(mon, "Error: %s\n", info->error);
161+ }
162+}
58117ea6
WB
163
164 void hmp_qom_list(Monitor *mon, const QDict *qdict)
165 {
b08067ba
DM
166Index: new/hmp.h
167===================================================================
24bb7da3
DM
168--- new.orig/hmp.h 2014-11-20 09:13:01.000000000 +0100
169+++ new/hmp.h 2014-11-20 09:16:47.000000000 +0100
fbe817e2 170@@ -26,6 +26,7 @@
92bf040c
DM
171 void hmp_info_uuid(Monitor *mon, const QDict *qdict);
172 void hmp_info_chardev(Monitor *mon, const QDict *qdict);
173 void hmp_info_mice(Monitor *mon, const QDict *qdict);
174+void hmp_info_savevm(Monitor *mon, const QDict *qdict);
175 void hmp_info_migrate(Monitor *mon, const QDict *qdict);
176 void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict);
432a6eb5 177 void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict);
fbe817e2 178@@ -85,6 +86,10 @@
cd983153
DM
179 void hmp_netdev_del(Monitor *mon, const QDict *qdict);
180 void hmp_getfd(Monitor *mon, const QDict *qdict);
181 void hmp_closefd(Monitor *mon, const QDict *qdict);
1f416f3a 182+void hmp_savevm_start(Monitor *mon, const QDict *qdict);
cd983153
DM
183+void hmp_snapshot_drive(Monitor *mon, const QDict *qdict);
184+void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict);
1f416f3a 185+void hmp_savevm_end(Monitor *mon, const QDict *qdict);
58117ea6
WB
186 void hmp_sendkey(Monitor *mon, const QDict *qdict);
187 void hmp_screendump(Monitor *mon, const QDict *qdict);
e96de165 188 void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
b08067ba
DM
189Index: new/include/block/block.h
190===================================================================
24bb7da3
DM
191--- new.orig/include/block/block.h 2014-11-20 09:13:01.000000000 +0100
192+++ new/include/block/block.h 2014-11-20 09:16:47.000000000 +0100
193@@ -235,6 +235,7 @@
fb40cdcd 194 int bdrv_get_backing_file_depth(BlockDriverState *bs);
24bb7da3 195 void bdrv_refresh_filename(BlockDriverState *bs);
fb40cdcd
AD
196 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
197+void bdrv_delete(BlockDriverState *bs);
24bb7da3 198 int64_t bdrv_nb_sectors(BlockDriverState *bs);
fb40cdcd
AD
199 int64_t bdrv_getlength(BlockDriverState *bs);
200 int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
b08067ba
DM
201Index: new/include/sysemu/sysemu.h
202===================================================================
24bb7da3
DM
203--- new.orig/include/sysemu/sysemu.h 2014-11-20 09:13:01.000000000 +0100
204+++ new/include/sysemu/sysemu.h 2014-11-20 09:16:47.000000000 +0100
432a6eb5 205@@ -76,17 +76,18 @@
fb40cdcd 206
58117ea6 207 void hmp_savevm(Monitor *mon, const QDict *qdict);
fb40cdcd
AD
208 int load_vmstate(const char *name);
209+int load_state_from_blockdev(const char *filename);
58117ea6
WB
210 void hmp_delvm(Monitor *mon, const QDict *qdict);
211 void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
fb40cdcd
AD
212
213 void qemu_announce_self(void);
214
215 bool qemu_savevm_state_blocked(Error **errp);
216-void qemu_savevm_state_begin(QEMUFile *f,
217+int qemu_savevm_state_begin(QEMUFile *f,
218 const MigrationParams *params);
432a6eb5 219 void qemu_savevm_state_header(QEMUFile *f);
fb40cdcd
AD
220 int qemu_savevm_state_iterate(QEMUFile *f);
221-void qemu_savevm_state_complete(QEMUFile *f);
222+int qemu_savevm_state_complete(QEMUFile *f);
223 void qemu_savevm_state_cancel(void);
224 uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size);
225 int qemu_loadvm_state(QEMUFile *f);
b08067ba
DM
226Index: new/monitor.c
227===================================================================
24bb7da3
DM
228--- new.orig/monitor.c 2014-11-20 09:13:01.000000000 +0100
229+++ new/monitor.c 2014-11-20 09:16:47.000000000 +0100
3fe80761 230@@ -2876,6 +2876,13 @@
fb40cdcd
AD
231 .mhandler.cmd = hmp_info_migrate_cache_size,
232 },
233 {
234+ .name = "savevm",
235+ .args_type = "",
236+ .params = "",
237+ .help = "show savevm status",
238+ .mhandler.cmd = hmp_info_savevm,
239+ },
240+ {
241 .name = "balloon",
242 .args_type = "",
243 .params = "",
b08067ba
DM
244Index: new/qapi-schema.json
245===================================================================
24bb7da3
DM
246--- new.orig/qapi-schema.json 2014-11-20 09:13:01.000000000 +0100
247+++ new/qapi-schema.json 2014-11-20 09:16:47.000000000 +0100
248@@ -550,6 +550,42 @@
fb40cdcd
AD
249 '*downtime': 'int',
250 '*setup-time': 'int'} }
251
252+
253+# @SaveVMInfo
254+#
255+# Information about current migration process.
256+#
257+# @status: #optional string describing the current savevm status.
258+# This can be 'active', 'completed', 'failed'.
259+# If this field is not returned, no savevm process
260+# has been initiated
261+#
262+# @error: #optional string containing error message is status is failed.
263+#
264+# @total-time: #optional total amount of milliseconds since savevm started.
265+# If savevm has ended, it returns the total save time
266+#
267+# @bytes: #optional total amount of data transfered
268+#
269+# Since: 1.3
270+##
047e4448 271+{ 'struct': 'SaveVMInfo',
fb40cdcd
AD
272+ 'data': {'*status': 'str', '*error': 'str',
273+ '*total-time': 'int', '*bytes': 'int'} }
274+
275+##
276+# @query-savevm
277+#
278+# Returns information about current savevm process.
279+#
280+# Returns: @SaveVMInfo
281+#
282+# Since: 1.3
283+##
284+{ 'command': 'query-savevm', 'returns': 'SaveVMInfo' }
285+
286+##
287+
288 ##
289 # @query-migrate
290 #
24bb7da3 291@@ -2649,8 +2685,18 @@
fb40cdcd
AD
292 #
293 # Since: 1.2.0
294 ##
295+
296 { 'command': 'query-target', 'returns': 'TargetInfo' }
297
298+{ 'command': 'savevm-start', 'data': { '*statefile': 'str' } }
299+
300+{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
301+
302+{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } }
303+
304+{ 'command': 'savevm-end' }
305+
306+
307 ##
308 # @QKeyCode:
309 #
b08067ba
DM
310Index: new/qemu-options.hx
311===================================================================
24bb7da3
DM
312--- new.orig/qemu-options.hx 2014-11-20 09:13:01.000000000 +0100
313+++ new/qemu-options.hx 2014-11-20 09:16:47.000000000 +0100
314@@ -2975,6 +2975,19 @@
fb40cdcd 315 Start right away with a saved state (@code{loadvm} in monitor)
cd983153 316 ETEXI
fb40cdcd
AD
317
318+DEF("loadstate", HAS_ARG, QEMU_OPTION_loadstate, \
319+ "-loadstate file\n" \
320+ " start right away with a saved state\n",
321+ QEMU_ARCH_ALL)
322+STEXI
323+@item -loadstate @var{file}
324+@findex -loadstate
325+Start right away with a saved state. This option does not rollback
326+disk state like @code{loadvm}, so user must make sure that disk
327+have correct state. @var{file} can be any valid device URL. See the section
328+for "Device URL Syntax" for more information.
329+ETEXI
330+
331 #ifndef _WIN32
332 DEF("daemonize", 0, QEMU_OPTION_daemonize, \
333 "-daemonize daemonize QEMU after initializing\n", QEMU_ARCH_ALL)
b08067ba
DM
334Index: new/qmp-commands.hx
335===================================================================
24bb7da3
DM
336--- new.orig/qmp-commands.hx 2014-11-20 09:13:01.000000000 +0100
337+++ new/qmp-commands.hx 2014-11-20 09:16:47.000000000 +0100
432a6eb5 338@@ -4200,6 +4200,36 @@
3fe80761 339 <- { "return": {} }
fb40cdcd
AD
340
341 EQMP
342+
cd983153 343+ {
1f416f3a 344+ .name = "savevm-start",
cd983153 345+ .args_type = "statefile:s?",
fb40cdcd 346+ .mhandler.cmd_new = qmp_marshal_input_savevm_start,
cd983153
DM
347+ },
348+
349+ {
350+ .name = "snapshot-drive",
351+ .args_type = "device:s,name:s",
fb40cdcd 352+ .mhandler.cmd_new = qmp_marshal_input_snapshot_drive,
cd983153
DM
353+ },
354+
355+ {
356+ .name = "delete-drive-snapshot",
357+ .args_type = "device:s,name:s",
fb40cdcd 358+ .mhandler.cmd_new = qmp_marshal_input_delete_drive_snapshot,
cd983153
DM
359+ },
360+
361+ {
1f416f3a 362+ .name = "savevm-end",
cd983153 363+ .args_type = "",
fb40cdcd
AD
364+ .mhandler.cmd_new = qmp_marshal_input_savevm_end,
365+ },
366+
367+ {
368+ .name = "query-savevm",
369+ .args_type = "",
370+ .mhandler.cmd_new = qmp_marshal_input_query_savevm,
cd983153 371+ },
432a6eb5
WB
372
373 {
374 .name = "query-rocker",
b08067ba
DM
375Index: new/savevm-async.c
376===================================================================
377--- /dev/null 1970-01-01 00:00:00.000000000 +0000
24bb7da3 378+++ new/savevm-async.c 2014-11-20 09:17:48.000000000 +0100
3a007690 379@@ -0,0 +1,515 @@
fb40cdcd
AD
380+#include "qemu-common.h"
381+#include "qapi/qmp/qerror.h"
e647d55d 382+#include "qemu/error-report.h"
fb40cdcd 383+#include "sysemu/sysemu.h"
cd983153 384+#include "qmp-commands.h"
fb40cdcd
AD
385+#include "qemu-options.h"
386+#include "migration/qemu-file.h"
387+#include "qom/qom-qobject.h"
388+#include "migration/migration.h"
389+#include "block/snapshot.h"
390+#include "block/qapi.h"
391+#include "block/block.h"
392+#include "qemu/timer.h"
58117ea6 393+#include "sysemu/block-backend.h"
cd983153 394+
b84aa9c4 395+/* #define DEBUG_SAVEVM_STATE */
cd983153
DM
396+
397+#ifdef DEBUG_SAVEVM_STATE
398+#define DPRINTF(fmt, ...) \
399+ do { printf("savevm-async: " fmt, ## __VA_ARGS__); } while (0)
400+#else
401+#define DPRINTF(fmt, ...) \
402+ do { } while (0)
403+#endif
404+
405+enum {
406+ SAVE_STATE_DONE,
407+ SAVE_STATE_ERROR,
408+ SAVE_STATE_ACTIVE,
409+ SAVE_STATE_COMPLETED,
23261368 410+ SAVE_STATE_CANCELLED
cd983153
DM
411+};
412+
fb40cdcd 413+
cd983153
DM
414+static struct SnapshotState {
415+ BlockDriverState *bs;
416+ size_t bs_pos;
417+ int state;
418+ Error *error;
fbe817e2 419+ Error *blocker;
cd983153
DM
420+ int saved_vm_running;
421+ QEMUFile *file;
422+ int64_t total_time;
423+} snap_state;
424+
425+SaveVMInfo *qmp_query_savevm(Error **errp)
426+{
427+ SaveVMInfo *info = g_malloc0(sizeof(*info));
428+ struct SnapshotState *s = &snap_state;
429+
430+ if (s->state != SAVE_STATE_DONE) {
431+ info->has_bytes = true;
432+ info->bytes = s->bs_pos;
433+ switch (s->state) {
434+ case SAVE_STATE_ERROR:
435+ info->has_status = true;
436+ info->status = g_strdup("failed");
437+ info->has_total_time = true;
438+ info->total_time = s->total_time;
439+ if (s->error) {
440+ info->has_error = true;
441+ info->error = g_strdup(error_get_pretty(s->error));
442+ }
443+ break;
444+ case SAVE_STATE_ACTIVE:
445+ info->has_status = true;
446+ info->status = g_strdup("active");
447+ info->has_total_time = true;
fb40cdcd 448+ info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
cd983153
DM
449+ - s->total_time;
450+ break;
451+ case SAVE_STATE_COMPLETED:
452+ info->has_status = true;
453+ info->status = g_strdup("completed");
454+ info->has_total_time = true;
455+ info->total_time = s->total_time;
456+ break;
457+ }
458+ }
459+
460+ return info;
461+}
462+
463+static int save_snapshot_cleanup(void)
464+{
465+ int ret = 0;
466+
467+ DPRINTF("save_snapshot_cleanup\n");
468+
fb40cdcd 469+ snap_state.total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) -
cd983153
DM
470+ snap_state.total_time;
471+
472+ if (snap_state.file) {
473+ ret = qemu_fclose(snap_state.file);
474+ }
475+
476+ if (snap_state.bs) {
b84aa9c4
DM
477+ /* try to truncate, but ignore errors (will fail on block devices).
478+ * note: bdrv_read() need whole blocks, so we round up
479+ */
cd983153
DM
480+ size_t size = (snap_state.bs_pos + BDRV_SECTOR_SIZE) & BDRV_SECTOR_MASK;
481+ bdrv_truncate(snap_state.bs, size);
fbe817e2
DM
482+ bdrv_op_unblock_all(snap_state.bs, snap_state.blocker);
483+ error_free(snap_state.blocker);
484+ snap_state.blocker = NULL;
fb40cdcd 485+ bdrv_unref(snap_state.bs);
cd983153
DM
486+ snap_state.bs = NULL;
487+ }
488+
489+ return ret;
490+}
491+
492+static void save_snapshot_error(const char *fmt, ...)
493+{
494+ va_list ap;
495+ char *msg;
496+
497+ va_start(ap, fmt);
498+ msg = g_strdup_vprintf(fmt, ap);
499+ va_end(ap);
500+
501+ DPRINTF("save_snapshot_error: %s\n", msg);
502+
503+ if (!snap_state.error) {
504+ error_set(&snap_state.error, ERROR_CLASS_GENERIC_ERROR, "%s", msg);
505+ }
506+
507+ g_free (msg);
508+
509+ snap_state.state = SAVE_STATE_ERROR;
510+
511+ save_snapshot_cleanup();
512+}
513+
514+static void save_snapshot_completed(void)
515+{
516+ DPRINTF("save_snapshot_completed\n");
517+
518+ if (save_snapshot_cleanup() < 0) {
519+ snap_state.state = SAVE_STATE_ERROR;
520+ } else {
521+ snap_state.state = SAVE_STATE_COMPLETED;
522+ }
523+}
524+
525+static int block_state_close(void *opaque)
526+{
527+ snap_state.file = NULL;
528+ return bdrv_flush(snap_state.bs);
529+}
530+
b84aa9c4
DM
531+static int block_state_put_buffer(void *opaque, const uint8_t *buf,
532+ int64_t pos, int size)
cd983153
DM
533+{
534+ int ret;
535+
b84aa9c4
DM
536+ assert(pos == snap_state.bs_pos);
537+
cd983153
DM
538+ if ((ret = bdrv_pwrite(snap_state.bs, snap_state.bs_pos, buf, size)) > 0) {
539+ snap_state.bs_pos += ret;
540+ }
541+
542+ return ret;
543+}
544+
b84aa9c4 545+static void process_savevm_co(void *opaque)
cd983153
DM
546+{
547+ int ret;
b84aa9c4
DM
548+ int64_t maxlen;
549+ MigrationParams params = {
550+ .blk = 0,
551+ .shared = 0
552+ };
cd983153 553+
b84aa9c4 554+ snap_state.state = SAVE_STATE_ACTIVE;
cd983153 555+
fb40cdcd 556+ qemu_mutex_unlock_iothread();
3a007690 557+ qemu_savevm_state_header(snap_state.file);
b84aa9c4 558+ ret = qemu_savevm_state_begin(snap_state.file, &params);
fb40cdcd
AD
559+ qemu_mutex_lock_iothread();
560+
b84aa9c4
DM
561+ if (ret < 0) {
562+ save_snapshot_error("qemu_savevm_state_begin failed");
cd983153
DM
563+ return;
564+ }
565+
b84aa9c4 566+ while (snap_state.state == SAVE_STATE_ACTIVE) {
92bf040c
DM
567+ uint64_t pending_size;
568+
569+ pending_size = qemu_savevm_state_pending(snap_state.file, 0);
570+
571+ if (pending_size) {
572+ ret = qemu_savevm_state_iterate(snap_state.file);
573+ if (ret < 0) {
574+ save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
575+ break;
576+ }
577+ DPRINTF("savevm inerate pending size %lu ret %d\n", pending_size, ret);
578+ } else {
579+ DPRINTF("done iterating\n");
b84aa9c4
DM
580+ if (runstate_is_running()) {
581+ vm_stop(RUN_STATE_SAVE_VM);
582+ }
583+ DPRINTF("savevm inerate finished\n");
fb40cdcd
AD
584+ qemu_savevm_state_complete(snap_state.file);
585+ DPRINTF("save complete\n");
586+ save_snapshot_completed();
587+ break;
92bf040c
DM
588+ }
589+
590+ /* stop the VM if we get to the end of available space,
591+ * or if pending_size is just a few MB
592+ */
593+ maxlen = bdrv_getlength(snap_state.bs) - 30*1024*1024;
594+ if ((pending_size < 100000) ||
595+ ((snap_state.bs_pos + pending_size) >= maxlen)) {
596+ if (runstate_is_running()) {
597+ vm_stop(RUN_STATE_SAVE_VM);
b84aa9c4
DM
598+ }
599+ }
cd983153 600+ }
23261368
AD
601+
602+ if(snap_state.state == SAVE_STATE_CANCELLED) {
603+ save_snapshot_completed();
604+ Error *errp = NULL;
605+ qmp_savevm_end(&errp);
606+ }
607+
cd983153
DM
608+}
609+
b84aa9c4
DM
610+static const QEMUFileOps block_file_ops = {
611+ .put_buffer = block_state_put_buffer,
612+ .close = block_state_close,
613+};
614+
cd983153 615+
1f416f3a 616+void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
cd983153
DM
617+{
618+ BlockDriver *drv = NULL;
fb40cdcd
AD
619+ Error *local_err = NULL;
620+
cd983153 621+ int bdrv_oflags = BDRV_O_CACHE_WB | BDRV_O_RDWR;
cd983153
DM
622+ int ret;
623+
624+ if (snap_state.state != SAVE_STATE_DONE) {
625+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
626+ "VM snapshot already started\n");
627+ return;
628+ }
629+
630+ /* initialize snapshot info */
631+ snap_state.saved_vm_running = runstate_is_running();
632+ snap_state.bs_pos = 0;
fb40cdcd 633+ snap_state.total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
fbe817e2 634+ snap_state.blocker = NULL;
cd983153
DM
635+
636+ if (snap_state.error) {
637+ error_free(snap_state.error);
638+ snap_state.error = NULL;
639+ }
640+
cd983153 641+ if (!has_statefile) {
b84aa9c4 642+ vm_stop(RUN_STATE_SAVE_VM);
cd983153
DM
643+ snap_state.state = SAVE_STATE_COMPLETED;
644+ return;
645+ }
646+
647+ if (qemu_savevm_state_blocked(errp)) {
648+ return;
649+ }
650+
651+ /* Open the image */
24bb7da3
DM
652+ snap_state.bs = bdrv_new();
653+
62d638ff 654+ ret = bdrv_open(&snap_state.bs, statefile, NULL, NULL, bdrv_oflags, drv, &local_err);
cd983153 655+ if (ret < 0) {
fb40cdcd 656+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile);
cd983153
DM
657+ goto restart;
658+ }
659+
b84aa9c4 660+ snap_state.file = qemu_fopen_ops(&snap_state, &block_file_ops);
cd983153
DM
661+
662+ if (!snap_state.file) {
fb40cdcd 663+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile);
cd983153
DM
664+ goto restart;
665+ }
666+
fb40cdcd 667+
fbe817e2
DM
668+ error_setg(&snap_state.blocker, "block device is in use by savevm");
669+ bdrv_op_block_all(snap_state.bs, snap_state.blocker);
fb40cdcd 670+
b84aa9c4
DM
671+ Coroutine *co = qemu_coroutine_create(process_savevm_co);
672+ qemu_coroutine_enter(co, NULL);
cd983153
DM
673+
674+ return;
675+
676+restart:
677+
678+ save_snapshot_error("setup failed");
679+
680+ if (snap_state.saved_vm_running) {
681+ vm_start();
682+ }
683+}
684+
1f416f3a 685+void qmp_savevm_end(Error **errp)
cd983153
DM
686+{
687+ if (snap_state.state == SAVE_STATE_DONE) {
688+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
689+ "VM snapshot not started\n");
690+ return;
691+ }
692+
23261368
AD
693+ if (snap_state.state == SAVE_STATE_ACTIVE) {
694+ snap_state.state = SAVE_STATE_CANCELLED;
695+ return;
696+ }
697+
cd983153
DM
698+ if (snap_state.saved_vm_running) {
699+ vm_start();
700+ }
701+
702+ snap_state.state = SAVE_STATE_DONE;
703+}
704+
705+void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
706+{
58117ea6 707+ BlockBackend *blk;
cd983153
DM
708+ BlockDriverState *bs;
709+ QEMUSnapshotInfo sn1, *sn = &sn1;
710+ int ret;
711+#ifdef _WIN32
712+ struct _timeb tb;
713+#else
714+ struct timeval tv;
715+#endif
716+
717+ if (snap_state.state != SAVE_STATE_COMPLETED) {
718+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
719+ "VM snapshot not ready/started\n");
720+ return;
721+ }
722+
58117ea6
WB
723+ blk = blk_by_name(device);
724+ if (!blk) {
e647d55d
WB
725+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
726+ "Device '%s' not found", device);
cd983153
DM
727+ return;
728+ }
729+
58117ea6 730+ bs = blk_bs(blk);
cd983153 731+ if (!bdrv_is_inserted(bs)) {
e647d55d 732+ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
cd983153
DM
733+ return;
734+ }
735+
736+ if (bdrv_is_read_only(bs)) {
e647d55d 737+ error_setg(errp, "Node '%s' is read only", device);
cd983153
DM
738+ return;
739+ }
740+
741+ if (!bdrv_can_snapshot(bs)) {
e647d55d 742+ error_setg(errp, QERR_UNSUPPORTED);
cd983153
DM
743+ return;
744+ }
745+
746+ if (bdrv_snapshot_find(bs, sn, name) >= 0) {
747+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
748+ "snapshot '%s' already exists", name);
749+ return;
750+ }
751+
752+ sn = &sn1;
753+ memset(sn, 0, sizeof(*sn));
754+
755+#ifdef _WIN32
756+ _ftime(&tb);
757+ sn->date_sec = tb.time;
758+ sn->date_nsec = tb.millitm * 1000000;
759+#else
760+ gettimeofday(&tv, NULL);
761+ sn->date_sec = tv.tv_sec;
762+ sn->date_nsec = tv.tv_usec * 1000;
763+#endif
fb40cdcd 764+ sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
cd983153
DM
765+
766+ pstrcpy(sn->name, sizeof(sn->name), name);
767+
768+ sn->vm_state_size = 0; /* do not save state */
769+
770+ ret = bdrv_snapshot_create(bs, sn);
771+ if (ret < 0) {
772+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
773+ "Error while creating snapshot on '%s'\n", device);
774+ return;
775+ }
776+}
777+
778+void qmp_delete_drive_snapshot(const char *device, const char *name,
779+ Error **errp)
780+{
58117ea6 781+ BlockBackend *blk;
cd983153
DM
782+ BlockDriverState *bs;
783+ QEMUSnapshotInfo sn1, *sn = &sn1;
fb40cdcd
AD
784+ Error *local_err = NULL;
785+
cd983153
DM
786+ int ret;
787+
58117ea6
WB
788+ blk = blk_by_name(device);
789+ if (!blk) {
e647d55d
WB
790+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
791+ "Device '%s' not found", device);
cd983153
DM
792+ return;
793+ }
58117ea6
WB
794+
795+ bs = blk_bs(blk);
cd983153 796+ if (bdrv_is_read_only(bs)) {
e647d55d 797+ error_setg(errp, "Node '%s' is read only", device);
cd983153
DM
798+ return;
799+ }
800+
801+ if (!bdrv_can_snapshot(bs)) {
e647d55d 802+ error_setg(errp, QERR_UNSUPPORTED);
cd983153
DM
803+ return;
804+ }
805+
806+ if (bdrv_snapshot_find(bs, sn, name) < 0) {
807+ /* return success if snapshot does not exists */
808+ return;
809+ }
810+
fb40cdcd 811+ ret = bdrv_snapshot_delete(bs, NULL, name, &local_err);
cd983153
DM
812+ if (ret < 0) {
813+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
814+ "Error while deleting snapshot on '%s'\n", device);
815+ return;
816+ }
817+}
818+
b84aa9c4
DM
819+static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
820+ int size)
cd983153
DM
821+{
822+ BlockDriverState *bs = (BlockDriverState *)opaque;
823+ int64_t maxlen = bdrv_getlength(bs);
824+ if (pos > maxlen) {
825+ return -EIO;
826+ }
827+ if ((pos + size) > maxlen) {
828+ size = maxlen - pos - 1;
829+ }
830+ if (size == 0) {
831+ return 0;
832+ }
833+ return bdrv_pread(bs, pos, buf, size);
834+}
835+
b84aa9c4
DM
836+static const QEMUFileOps loadstate_file_ops = {
837+ .get_buffer = loadstate_get_buffer,
838+};
839+
cd983153
DM
840+int load_state_from_blockdev(const char *filename)
841+{
842+ BlockDriverState *bs = NULL;
843+ BlockDriver *drv = NULL;
fb40cdcd 844+ Error *local_err = NULL;
fbe817e2 845+ Error *blocker = NULL;
fb40cdcd 846+
cd983153 847+ QEMUFile *f;
3a007690
WB
848+ int ret;
849+
850+ ret = global_state_store();
851+ if (ret) {
852+ error_report("Error saving global state");
853+ goto the_end;
854+ }
cd983153 855+
24bb7da3 856+ bs = bdrv_new();
c1de5992 857+ ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_CACHE_WB, drv, &local_err);
fbe817e2
DM
858+ error_setg(&blocker, "block device is in use by load state");
859+ bdrv_op_block_all(bs, blocker);
fb40cdcd 860+
cd983153
DM
861+ if (ret < 0) {
862+ error_report("Could not open VM state file");
863+ goto the_end;
864+ }
865+
866+ /* restore the VM state */
b84aa9c4 867+ f = qemu_fopen_ops(bs, &loadstate_file_ops);
cd983153
DM
868+ if (!f) {
869+ error_report("Could not open VM state file");
870+ ret = -EINVAL;
871+ goto the_end;
872+ }
873+
874+ qemu_system_reset(VMRESET_SILENT);
3a007690 875+ migration_incoming_state_new(f);
cd983153
DM
876+ ret = qemu_loadvm_state(f);
877+
878+ qemu_fclose(f);
3a007690 879+ migration_incoming_state_destroy();
cd983153
DM
880+ if (ret < 0) {
881+ error_report("Error %d while loading VM state", ret);
882+ goto the_end;
883+ }
884+
885+ ret = 0;
886+
887+ the_end:
888+ if (bs) {
fbe817e2
DM
889+ bdrv_op_unblock_all(bs, blocker);
890+ error_free(blocker);
fb40cdcd 891+ bdrv_unref(bs);
cd983153
DM
892+ }
893+ return ret;
894+}
b08067ba
DM
895Index: new/savevm.c
896===================================================================
432a6eb5
WB
897--- new.orig/migration/savevm.c 2014-11-20 09:13:01.000000000 +0100
898+++ new/migration/savevm.c 2014-11-20 09:16:47.000000000 +0100
899@@ -718,11 +718,11 @@
900 qemu_put_be32(f, QEMU_VM_FILE_VERSION);
fb40cdcd 901 }
cd983153 902
fb40cdcd
AD
903-void qemu_savevm_state_begin(QEMUFile *f,
904+int qemu_savevm_state_begin(QEMUFile *f,
905 const MigrationParams *params)
906 {
907 SaveStateEntry *se;
908- int ret;
909+ int ret = 0;
cd983153 910
c1de5992 911 trace_savevm_state_begin();
432a6eb5 912 QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
3fe80761 913@@ -642,6 +642,7 @@
fb40cdcd
AD
914 break;
915 }
916 }
917+ return ret;
918 }
919
920 /*
3fe80761 921@@ -690,7 +691,7 @@
58117ea6 922 return !machine->suppress_vmdesc;
fb40cdcd
AD
923 }
924
925-void qemu_savevm_state_complete(QEMUFile *f)
926+int qemu_savevm_state_complete(QEMUFile *f)
927 {
58117ea6
WB
928 QJSON *vmdesc;
929 int vmdesc_len;
432a6eb5
WB
930@@ -838,7 +839,7 @@
931 save_section_footer(f, se);
fb40cdcd
AD
932 if (ret < 0) {
933 qemu_file_set_error(f, ret);
934- return;
935+ return ret;
936 }
937 }
938
3fe80761 939@@ -746,6 +747,7 @@
58117ea6 940 object_unref(OBJECT(vmdesc));
fb40cdcd 941
fb40cdcd
AD
942 qemu_fflush(f);
943+ return qemu_file_get_error(f);
944 }
945
946 uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size)
b08067ba
DM
947Index: new/vl.c
948===================================================================
24bb7da3
DM
949--- new.orig/vl.c 2014-11-20 09:13:01.000000000 +0100
950+++ new/vl.c 2014-11-20 09:16:47.000000000 +0100
951@@ -2760,6 +2760,7 @@
cd983153
DM
952 int optind;
953 const char *optarg;
954 const char *loadvm = NULL;
955+ const char *loadstate = NULL;
c1de5992 956 MachineClass *machine_class;
cd983153 957 const char *cpu_model;
fbe817e2 958 const char *vga_model = NULL;
24bb7da3 959@@ -3457,6 +3458,9 @@
58117ea6
WB
960 case QEMU_OPTION_loadvm:
961 loadvm = optarg;
962 break;
cd983153
DM
963+ case QEMU_OPTION_loadstate:
964+ loadstate = optarg;
965+ break;
966 case QEMU_OPTION_full_screen:
967 full_screen = 1;
968 break;
24bb7da3 969@@ -4428,6 +4432,10 @@
cd983153
DM
970 if (load_vmstate(loadvm) < 0) {
971 autostart = 0;
972 }
973+ } else if (loadstate) {
974+ if (load_state_from_blockdev(loadstate) < 0) {
975+ autostart = 0;
976+ }
977 }
978
24bb7da3 979 qdev_prop_check_globals();