]> git.proxmox.com Git - pve-qemu-kvm.git/blame - debian/patches/internal-snapshot-async.patch
part 1 of 2.4 patch update series
[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+##
271+{ 'type': 'SaveVMInfo',
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
58117ea6 379@@ -0,0 +1,503 @@
fb40cdcd
AD
380+#include "qemu-common.h"
381+#include "qapi/qmp/qerror.h"
382+#include "sysemu/sysemu.h"
cd983153 383+#include "qmp-commands.h"
fb40cdcd
AD
384+#include "qemu-options.h"
385+#include "migration/qemu-file.h"
386+#include "qom/qom-qobject.h"
387+#include "migration/migration.h"
388+#include "block/snapshot.h"
389+#include "block/qapi.h"
390+#include "block/block.h"
391+#include "qemu/timer.h"
58117ea6 392+#include "sysemu/block-backend.h"
cd983153 393+
b84aa9c4 394+/* #define DEBUG_SAVEVM_STATE */
cd983153
DM
395+
396+#ifdef DEBUG_SAVEVM_STATE
397+#define DPRINTF(fmt, ...) \
398+ do { printf("savevm-async: " fmt, ## __VA_ARGS__); } while (0)
399+#else
400+#define DPRINTF(fmt, ...) \
401+ do { } while (0)
402+#endif
403+
404+enum {
405+ SAVE_STATE_DONE,
406+ SAVE_STATE_ERROR,
407+ SAVE_STATE_ACTIVE,
408+ SAVE_STATE_COMPLETED,
23261368 409+ SAVE_STATE_CANCELLED
cd983153
DM
410+};
411+
fb40cdcd 412+
cd983153
DM
413+static struct SnapshotState {
414+ BlockDriverState *bs;
415+ size_t bs_pos;
416+ int state;
417+ Error *error;
fbe817e2 418+ Error *blocker;
cd983153
DM
419+ int saved_vm_running;
420+ QEMUFile *file;
421+ int64_t total_time;
422+} snap_state;
423+
424+SaveVMInfo *qmp_query_savevm(Error **errp)
425+{
426+ SaveVMInfo *info = g_malloc0(sizeof(*info));
427+ struct SnapshotState *s = &snap_state;
428+
429+ if (s->state != SAVE_STATE_DONE) {
430+ info->has_bytes = true;
431+ info->bytes = s->bs_pos;
432+ switch (s->state) {
433+ case SAVE_STATE_ERROR:
434+ info->has_status = true;
435+ info->status = g_strdup("failed");
436+ info->has_total_time = true;
437+ info->total_time = s->total_time;
438+ if (s->error) {
439+ info->has_error = true;
440+ info->error = g_strdup(error_get_pretty(s->error));
441+ }
442+ break;
443+ case SAVE_STATE_ACTIVE:
444+ info->has_status = true;
445+ info->status = g_strdup("active");
446+ info->has_total_time = true;
fb40cdcd 447+ info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
cd983153
DM
448+ - s->total_time;
449+ break;
450+ case SAVE_STATE_COMPLETED:
451+ info->has_status = true;
452+ info->status = g_strdup("completed");
453+ info->has_total_time = true;
454+ info->total_time = s->total_time;
455+ break;
456+ }
457+ }
458+
459+ return info;
460+}
461+
462+static int save_snapshot_cleanup(void)
463+{
464+ int ret = 0;
465+
466+ DPRINTF("save_snapshot_cleanup\n");
467+
fb40cdcd 468+ snap_state.total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) -
cd983153
DM
469+ snap_state.total_time;
470+
471+ if (snap_state.file) {
472+ ret = qemu_fclose(snap_state.file);
473+ }
474+
475+ if (snap_state.bs) {
b84aa9c4
DM
476+ /* try to truncate, but ignore errors (will fail on block devices).
477+ * note: bdrv_read() need whole blocks, so we round up
478+ */
cd983153
DM
479+ size_t size = (snap_state.bs_pos + BDRV_SECTOR_SIZE) & BDRV_SECTOR_MASK;
480+ bdrv_truncate(snap_state.bs, size);
fbe817e2
DM
481+ bdrv_op_unblock_all(snap_state.bs, snap_state.blocker);
482+ error_free(snap_state.blocker);
483+ snap_state.blocker = NULL;
fb40cdcd 484+ bdrv_unref(snap_state.bs);
cd983153
DM
485+ snap_state.bs = NULL;
486+ }
487+
488+ return ret;
489+}
490+
491+static void save_snapshot_error(const char *fmt, ...)
492+{
493+ va_list ap;
494+ char *msg;
495+
496+ va_start(ap, fmt);
497+ msg = g_strdup_vprintf(fmt, ap);
498+ va_end(ap);
499+
500+ DPRINTF("save_snapshot_error: %s\n", msg);
501+
502+ if (!snap_state.error) {
503+ error_set(&snap_state.error, ERROR_CLASS_GENERIC_ERROR, "%s", msg);
504+ }
505+
506+ g_free (msg);
507+
508+ snap_state.state = SAVE_STATE_ERROR;
509+
510+ save_snapshot_cleanup();
511+}
512+
513+static void save_snapshot_completed(void)
514+{
515+ DPRINTF("save_snapshot_completed\n");
516+
517+ if (save_snapshot_cleanup() < 0) {
518+ snap_state.state = SAVE_STATE_ERROR;
519+ } else {
520+ snap_state.state = SAVE_STATE_COMPLETED;
521+ }
522+}
523+
524+static int block_state_close(void *opaque)
525+{
526+ snap_state.file = NULL;
527+ return bdrv_flush(snap_state.bs);
528+}
529+
b84aa9c4
DM
530+static int block_state_put_buffer(void *opaque, const uint8_t *buf,
531+ int64_t pos, int size)
cd983153
DM
532+{
533+ int ret;
534+
b84aa9c4
DM
535+ assert(pos == snap_state.bs_pos);
536+
cd983153
DM
537+ if ((ret = bdrv_pwrite(snap_state.bs, snap_state.bs_pos, buf, size)) > 0) {
538+ snap_state.bs_pos += ret;
539+ }
540+
541+ return ret;
542+}
543+
b84aa9c4 544+static void process_savevm_co(void *opaque)
cd983153
DM
545+{
546+ int ret;
b84aa9c4
DM
547+ int64_t maxlen;
548+ MigrationParams params = {
549+ .blk = 0,
550+ .shared = 0
551+ };
cd983153 552+
b84aa9c4 553+ snap_state.state = SAVE_STATE_ACTIVE;
cd983153 554+
fb40cdcd 555+ qemu_mutex_unlock_iothread();
b84aa9c4 556+ ret = qemu_savevm_state_begin(snap_state.file, &params);
fb40cdcd
AD
557+ qemu_mutex_lock_iothread();
558+
b84aa9c4
DM
559+ if (ret < 0) {
560+ save_snapshot_error("qemu_savevm_state_begin failed");
cd983153
DM
561+ return;
562+ }
563+
b84aa9c4 564+ while (snap_state.state == SAVE_STATE_ACTIVE) {
92bf040c
DM
565+ uint64_t pending_size;
566+
567+ pending_size = qemu_savevm_state_pending(snap_state.file, 0);
568+
569+ if (pending_size) {
570+ ret = qemu_savevm_state_iterate(snap_state.file);
571+ if (ret < 0) {
572+ save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
573+ break;
574+ }
575+ DPRINTF("savevm inerate pending size %lu ret %d\n", pending_size, ret);
576+ } else {
577+ DPRINTF("done iterating\n");
b84aa9c4
DM
578+ if (runstate_is_running()) {
579+ vm_stop(RUN_STATE_SAVE_VM);
580+ }
581+ DPRINTF("savevm inerate finished\n");
fb40cdcd
AD
582+ qemu_savevm_state_complete(snap_state.file);
583+ DPRINTF("save complete\n");
584+ save_snapshot_completed();
585+ break;
92bf040c
DM
586+ }
587+
588+ /* stop the VM if we get to the end of available space,
589+ * or if pending_size is just a few MB
590+ */
591+ maxlen = bdrv_getlength(snap_state.bs) - 30*1024*1024;
592+ if ((pending_size < 100000) ||
593+ ((snap_state.bs_pos + pending_size) >= maxlen)) {
594+ if (runstate_is_running()) {
595+ vm_stop(RUN_STATE_SAVE_VM);
b84aa9c4
DM
596+ }
597+ }
cd983153 598+ }
23261368
AD
599+
600+ if(snap_state.state == SAVE_STATE_CANCELLED) {
601+ save_snapshot_completed();
602+ Error *errp = NULL;
603+ qmp_savevm_end(&errp);
604+ }
605+
cd983153
DM
606+}
607+
b84aa9c4
DM
608+static const QEMUFileOps block_file_ops = {
609+ .put_buffer = block_state_put_buffer,
610+ .close = block_state_close,
611+};
612+
cd983153 613+
1f416f3a 614+void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
cd983153
DM
615+{
616+ BlockDriver *drv = NULL;
fb40cdcd
AD
617+ Error *local_err = NULL;
618+
cd983153 619+ int bdrv_oflags = BDRV_O_CACHE_WB | BDRV_O_RDWR;
cd983153
DM
620+ int ret;
621+
622+ if (snap_state.state != SAVE_STATE_DONE) {
623+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
624+ "VM snapshot already started\n");
625+ return;
626+ }
627+
628+ /* initialize snapshot info */
629+ snap_state.saved_vm_running = runstate_is_running();
630+ snap_state.bs_pos = 0;
fb40cdcd 631+ snap_state.total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
fbe817e2 632+ snap_state.blocker = NULL;
cd983153
DM
633+
634+ if (snap_state.error) {
635+ error_free(snap_state.error);
636+ snap_state.error = NULL;
637+ }
638+
cd983153 639+ if (!has_statefile) {
b84aa9c4 640+ vm_stop(RUN_STATE_SAVE_VM);
cd983153
DM
641+ snap_state.state = SAVE_STATE_COMPLETED;
642+ return;
643+ }
644+
645+ if (qemu_savevm_state_blocked(errp)) {
646+ return;
647+ }
648+
649+ /* Open the image */
24bb7da3
DM
650+ snap_state.bs = bdrv_new();
651+
62d638ff 652+ ret = bdrv_open(&snap_state.bs, statefile, NULL, NULL, bdrv_oflags, drv, &local_err);
cd983153 653+ if (ret < 0) {
fb40cdcd 654+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile);
cd983153
DM
655+ goto restart;
656+ }
657+
b84aa9c4 658+ snap_state.file = qemu_fopen_ops(&snap_state, &block_file_ops);
cd983153
DM
659+
660+ if (!snap_state.file) {
fb40cdcd 661+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile);
cd983153
DM
662+ goto restart;
663+ }
664+
fb40cdcd 665+
fbe817e2
DM
666+ error_setg(&snap_state.blocker, "block device is in use by savevm");
667+ bdrv_op_block_all(snap_state.bs, snap_state.blocker);
fb40cdcd 668+
b84aa9c4
DM
669+ Coroutine *co = qemu_coroutine_create(process_savevm_co);
670+ qemu_coroutine_enter(co, NULL);
cd983153
DM
671+
672+ return;
673+
674+restart:
675+
676+ save_snapshot_error("setup failed");
677+
678+ if (snap_state.saved_vm_running) {
679+ vm_start();
680+ }
681+}
682+
1f416f3a 683+void qmp_savevm_end(Error **errp)
cd983153
DM
684+{
685+ if (snap_state.state == SAVE_STATE_DONE) {
686+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
687+ "VM snapshot not started\n");
688+ return;
689+ }
690+
23261368
AD
691+ if (snap_state.state == SAVE_STATE_ACTIVE) {
692+ snap_state.state = SAVE_STATE_CANCELLED;
693+ return;
694+ }
695+
cd983153
DM
696+ if (snap_state.saved_vm_running) {
697+ vm_start();
698+ }
699+
700+ snap_state.state = SAVE_STATE_DONE;
701+}
702+
703+void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
704+{
58117ea6 705+ BlockBackend *blk;
cd983153
DM
706+ BlockDriverState *bs;
707+ QEMUSnapshotInfo sn1, *sn = &sn1;
708+ int ret;
709+#ifdef _WIN32
710+ struct _timeb tb;
711+#else
712+ struct timeval tv;
713+#endif
714+
715+ if (snap_state.state != SAVE_STATE_COMPLETED) {
716+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
717+ "VM snapshot not ready/started\n");
718+ return;
719+ }
720+
58117ea6
WB
721+ blk = blk_by_name(device);
722+ if (!blk) {
cd983153
DM
723+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
724+ return;
725+ }
726+
58117ea6 727+ bs = blk_bs(blk);
cd983153
DM
728+ if (!bdrv_is_inserted(bs)) {
729+ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
730+ return;
731+ }
732+
733+ if (bdrv_is_read_only(bs)) {
734+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
735+ return;
736+ }
737+
738+ if (!bdrv_can_snapshot(bs)) {
fbe817e2 739+ error_set(errp, QERR_UNSUPPORTED);
cd983153
DM
740+ return;
741+ }
742+
743+ if (bdrv_snapshot_find(bs, sn, name) >= 0) {
744+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
745+ "snapshot '%s' already exists", name);
746+ return;
747+ }
748+
749+ sn = &sn1;
750+ memset(sn, 0, sizeof(*sn));
751+
752+#ifdef _WIN32
753+ _ftime(&tb);
754+ sn->date_sec = tb.time;
755+ sn->date_nsec = tb.millitm * 1000000;
756+#else
757+ gettimeofday(&tv, NULL);
758+ sn->date_sec = tv.tv_sec;
759+ sn->date_nsec = tv.tv_usec * 1000;
760+#endif
fb40cdcd 761+ sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
cd983153
DM
762+
763+ pstrcpy(sn->name, sizeof(sn->name), name);
764+
765+ sn->vm_state_size = 0; /* do not save state */
766+
767+ ret = bdrv_snapshot_create(bs, sn);
768+ if (ret < 0) {
769+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
770+ "Error while creating snapshot on '%s'\n", device);
771+ return;
772+ }
773+}
774+
775+void qmp_delete_drive_snapshot(const char *device, const char *name,
776+ Error **errp)
777+{
58117ea6 778+ BlockBackend *blk;
cd983153
DM
779+ BlockDriverState *bs;
780+ QEMUSnapshotInfo sn1, *sn = &sn1;
fb40cdcd
AD
781+ Error *local_err = NULL;
782+
cd983153
DM
783+ int ret;
784+
58117ea6
WB
785+ blk = blk_by_name(device);
786+ if (!blk) {
cd983153
DM
787+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
788+ return;
789+ }
58117ea6
WB
790+
791+ bs = blk_bs(blk);
cd983153
DM
792+ if (bdrv_is_read_only(bs)) {
793+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
794+ return;
795+ }
796+
797+ if (!bdrv_can_snapshot(bs)) {
fbe817e2 798+ error_set(errp, QERR_UNSUPPORTED);
cd983153
DM
799+ return;
800+ }
801+
802+ if (bdrv_snapshot_find(bs, sn, name) < 0) {
803+ /* return success if snapshot does not exists */
804+ return;
805+ }
806+
fb40cdcd 807+ ret = bdrv_snapshot_delete(bs, NULL, name, &local_err);
cd983153
DM
808+ if (ret < 0) {
809+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
810+ "Error while deleting snapshot on '%s'\n", device);
811+ return;
812+ }
813+}
814+
b84aa9c4
DM
815+static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
816+ int size)
cd983153
DM
817+{
818+ BlockDriverState *bs = (BlockDriverState *)opaque;
819+ int64_t maxlen = bdrv_getlength(bs);
820+ if (pos > maxlen) {
821+ return -EIO;
822+ }
823+ if ((pos + size) > maxlen) {
824+ size = maxlen - pos - 1;
825+ }
826+ if (size == 0) {
827+ return 0;
828+ }
829+ return bdrv_pread(bs, pos, buf, size);
830+}
831+
b84aa9c4
DM
832+static const QEMUFileOps loadstate_file_ops = {
833+ .get_buffer = loadstate_get_buffer,
834+};
835+
cd983153
DM
836+int load_state_from_blockdev(const char *filename)
837+{
838+ BlockDriverState *bs = NULL;
839+ BlockDriver *drv = NULL;
fb40cdcd 840+ Error *local_err = NULL;
fbe817e2 841+ Error *blocker = NULL;
fb40cdcd 842+
cd983153
DM
843+ QEMUFile *f;
844+ int ret = -1;
845+
24bb7da3 846+ bs = bdrv_new();
c1de5992 847+ ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_CACHE_WB, drv, &local_err);
fbe817e2
DM
848+ error_setg(&blocker, "block device is in use by load state");
849+ bdrv_op_block_all(bs, blocker);
fb40cdcd 850+
cd983153
DM
851+ if (ret < 0) {
852+ error_report("Could not open VM state file");
853+ goto the_end;
854+ }
855+
856+ /* restore the VM state */
b84aa9c4 857+ f = qemu_fopen_ops(bs, &loadstate_file_ops);
cd983153
DM
858+ if (!f) {
859+ error_report("Could not open VM state file");
860+ ret = -EINVAL;
861+ goto the_end;
862+ }
863+
864+ qemu_system_reset(VMRESET_SILENT);
865+ ret = qemu_loadvm_state(f);
866+
867+ qemu_fclose(f);
868+ if (ret < 0) {
869+ error_report("Error %d while loading VM state", ret);
870+ goto the_end;
871+ }
872+
873+ ret = 0;
874+
875+ the_end:
876+ if (bs) {
fbe817e2
DM
877+ bdrv_op_unblock_all(bs, blocker);
878+ error_free(blocker);
fb40cdcd 879+ bdrv_unref(bs);
cd983153
DM
880+ }
881+ return ret;
882+}
b08067ba
DM
883Index: new/savevm.c
884===================================================================
432a6eb5
WB
885--- new.orig/migration/savevm.c 2014-11-20 09:13:01.000000000 +0100
886+++ new/migration/savevm.c 2014-11-20 09:16:47.000000000 +0100
887@@ -718,11 +718,11 @@
888 qemu_put_be32(f, QEMU_VM_FILE_VERSION);
fb40cdcd 889 }
cd983153 890
fb40cdcd
AD
891-void qemu_savevm_state_begin(QEMUFile *f,
892+int qemu_savevm_state_begin(QEMUFile *f,
893 const MigrationParams *params)
894 {
895 SaveStateEntry *se;
896- int ret;
897+ int ret = 0;
cd983153 898
c1de5992 899 trace_savevm_state_begin();
432a6eb5 900 QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
3fe80761 901@@ -642,6 +642,7 @@
fb40cdcd
AD
902 break;
903 }
904 }
905+ return ret;
906 }
907
908 /*
3fe80761 909@@ -690,7 +691,7 @@
58117ea6 910 return !machine->suppress_vmdesc;
fb40cdcd
AD
911 }
912
913-void qemu_savevm_state_complete(QEMUFile *f)
914+int qemu_savevm_state_complete(QEMUFile *f)
915 {
58117ea6
WB
916 QJSON *vmdesc;
917 int vmdesc_len;
432a6eb5
WB
918@@ -838,7 +839,7 @@
919 save_section_footer(f, se);
fb40cdcd
AD
920 if (ret < 0) {
921 qemu_file_set_error(f, ret);
922- return;
923+ return ret;
924 }
925 }
926
3fe80761 927@@ -746,6 +747,7 @@
58117ea6 928 object_unref(OBJECT(vmdesc));
fb40cdcd 929
fb40cdcd
AD
930 qemu_fflush(f);
931+ return qemu_file_get_error(f);
932 }
933
934 uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size)
b08067ba
DM
935Index: new/vl.c
936===================================================================
24bb7da3
DM
937--- new.orig/vl.c 2014-11-20 09:13:01.000000000 +0100
938+++ new/vl.c 2014-11-20 09:16:47.000000000 +0100
939@@ -2760,6 +2760,7 @@
cd983153
DM
940 int optind;
941 const char *optarg;
942 const char *loadvm = NULL;
943+ const char *loadstate = NULL;
c1de5992 944 MachineClass *machine_class;
cd983153 945 const char *cpu_model;
fbe817e2 946 const char *vga_model = NULL;
24bb7da3 947@@ -3457,6 +3458,9 @@
58117ea6
WB
948 case QEMU_OPTION_loadvm:
949 loadvm = optarg;
950 break;
cd983153
DM
951+ case QEMU_OPTION_loadstate:
952+ loadstate = optarg;
953+ break;
954 case QEMU_OPTION_full_screen:
955 full_screen = 1;
956 break;
24bb7da3 957@@ -4428,6 +4432,10 @@
cd983153
DM
958 if (load_vmstate(loadvm) < 0) {
959 autostart = 0;
960 }
961+ } else if (loadstate) {
962+ if (load_state_from_blockdev(loadstate) < 0) {
963+ autostart = 0;
964+ }
965 }
966
24bb7da3 967 qdev_prop_check_globals();