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