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