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