--- /dev/null
+Index: new/savevm.c
+===================================================================
+--- new.orig/savevm.c 2012-09-18 07:05:08.000000000 +0200
++++ new/savevm.c 2012-09-18 07:19:31.000000000 +0200
+@@ -387,29 +387,48 @@
+ return NULL;
+ }
+
+-static int block_put_buffer(void *opaque, const uint8_t *buf,
++static int block_state_put_buffer(void *opaque, const uint8_t *buf,
+ int64_t pos, int size)
+ {
+- bdrv_save_vmstate(opaque, buf, pos, size);
+- return size;
++ return bdrv_save_vmstate(opaque, buf, pos, size);
+ }
+
+-static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
++static int block_state_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
++ int size)
+ {
+ return bdrv_load_vmstate(opaque, buf, pos, size);
+ }
+
++static int block_put_buffer(void *opaque, const uint8_t *buf, int64_t pos,
++ int size)
++{
++ return bdrv_pwrite(opaque, pos, buf, size);
++}
++
++static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
++{
++ return bdrv_pread(opaque, pos, buf, size);
++}
++
+ static int bdrv_fclose(void *opaque)
+ {
+ return bdrv_flush(opaque);
+ }
+
+-static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
++QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
++{
++ return qemu_fopen_ops(bs, is_writable ? block_put_buffer : NULL,
++ block_get_buffer, bdrv_fclose,
++ NULL, NULL, NULL);
++}
++
++static QEMUFile *qemu_fopen_bdrv_state(BlockDriverState *bs, int is_writable)
+ {
+ if (is_writable)
+- return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose,
++ return qemu_fopen_ops(bs, block_state_put_buffer, NULL, bdrv_fclose,
+ NULL, NULL, NULL);
+- return qemu_fopen_ops(bs, NULL, block_get_buffer, bdrv_fclose, NULL, NULL, NULL);
++ return qemu_fopen_ops(bs, NULL, block_state_get_buffer, bdrv_fclose,
++ NULL, NULL, NULL);
+ }
+
+ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
+@@ -2145,7 +2164,7 @@
+ }
+
+ /* save the VM state */
+- f = qemu_fopen_bdrv(bs, 1);
++ f = qemu_fopen_bdrv_state(bs, 1);
+ if (!f) {
+ monitor_printf(mon, "Could not open VM state file\n");
+ goto the_end;
+@@ -2266,7 +2285,7 @@
+ }
+
+ /* restore the VM state */
+- f = qemu_fopen_bdrv(bs_vm_state, 0);
++ f = qemu_fopen_bdrv_state(bs_vm_state, 0);
+ if (!f) {
+ error_report("Could not open VM state file");
+ return -EINVAL;
+Index: new/qemu-file.h
+===================================================================
+--- new.orig/qemu-file.h 2012-09-18 07:05:08.000000000 +0200
++++ new/qemu-file.h 2012-09-18 07:07:26.000000000 +0200
+@@ -68,6 +68,7 @@
+ QEMUFile *qemu_fopen(const char *filename, const char *mode);
+ QEMUFile *qemu_fdopen(int fd, const char *mode);
+ QEMUFile *qemu_fopen_socket(int fd);
++QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable);
+ QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
+ QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
+ int qemu_stdio_fd(QEMUFile *f);
Index: new/qapi-schema.json
===================================================================
---- new.orig/qapi-schema.json 2012-09-07 07:41:45.000000000 +0200
-+++ new/qapi-schema.json 2012-09-13 09:22:06.000000000 +0200
+--- new.orig/qapi-schema.json 2012-09-18 06:20:41.000000000 +0200
++++ new/qapi-schema.json 2012-09-18 08:43:25.000000000 +0200
@@ -2493,3 +2493,12 @@
# Since: 1.2.0
##
+{ 'command': 'snapshot-end' }
Index: new/qmp.c
===================================================================
---- new.orig/qmp.c 2012-09-07 07:41:45.000000000 +0200
-+++ new/qmp.c 2012-09-14 14:06:56.000000000 +0200
-@@ -479,3 +479,224 @@
+--- new.orig/qmp.c 2012-09-18 06:20:41.000000000 +0200
++++ new/qmp.c 2012-09-18 08:54:54.000000000 +0200
+@@ -479,3 +479,193 @@
return arch_query_cpu_definitions(errp);
}
+static struct SnapshotState {
-+ int in_progress;
-+ int saved_vm_running;
++ int in_progress;
++ int saved_vm_running;
+} snap_state;
+
-+static int block_put_buffer(void *opaque, const uint8_t *buf,
-+ int64_t pos, int size)
-+{
-+ bdrv_pwrite(opaque, pos, buf, size);
-+ return size;
-+}
-+
-+static int bdrv_fclose(void *opaque)
-+{
-+ return bdrv_flush(opaque);
-+}
-+
+void qmp_snapshot_start(bool has_statefile, const char *statefile, Error **errp)
+{
-+ BlockDriverState *bs = NULL;
-+ BlockDriver *drv = NULL;
-+ int bdrv_oflags = BDRV_O_NOCACHE | BDRV_O_RDWR;
-+ QEMUFile *f;
-+ int ret;
-+
-+ if (snap_state.in_progress) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "VM snapshot already started\n");
-+ return;
-+ }
-+
-+ snap_state.in_progress = 1;
++ BlockDriverState *bs = NULL;
++ BlockDriver *drv = NULL;
++ int bdrv_oflags = BDRV_O_NOCACHE | BDRV_O_RDWR;
++ QEMUFile *f;
++ int ret;
++
++ if (snap_state.in_progress) {
++ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++ "VM snapshot already started\n");
++ return;
++ }
+
-+ snap_state.saved_vm_running = runstate_is_running();
++ snap_state.in_progress = 1;
+
-+ vm_stop(RUN_STATE_SAVE_VM);
++ snap_state.saved_vm_running = runstate_is_running();
+
-+ if (!has_statefile)
-+ return;
++ vm_stop(RUN_STATE_SAVE_VM);
+
-+ /* Open the image */
-+ bs = bdrv_new("vmstate");
-+ ret = bdrv_open(bs, statefile, bdrv_oflags, drv);
-+ if (ret < 0) {
-+ error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
-+ goto restart;
-+ }
++ if (!has_statefile) {
++ return;
++ }
+
-+ f = qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose,
-+ NULL, NULL, NULL);
-+ if (!f) {
-+ error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
-+ goto restart;
-+ }
++ /* Open the image */
++ bs = bdrv_new("vmstate");
++ ret = bdrv_open(bs, statefile, bdrv_oflags, drv);
++ if (ret < 0) {
++ error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
++ goto restart;
++ }
+
-+ ret = qemu_savevm_state(f);
++ f = qemu_fopen_bdrv(bs, 1);
++ if (!f) {
++ error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
++ goto restart;
++ }
+
-+ bdrv_truncate(bs, qemu_ftell(f)); // ignore errors
++ ret = qemu_savevm_state(f);
+
-+ qemu_fclose(f);
++ // try to truncate, but ignore errors (will fail on block devices).
++ bdrv_truncate(bs, qemu_ftell(f));
+
-+ if (ret < 0) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "Error %d while writing VM state\n", ret);
-+ goto restart;
-+ }
-+end:
-+ if (bs)
-+ bdrv_delete(bs);
++ qemu_fclose(f);
+
-+ return;
++ if (ret < 0) {
++ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++ "Error %d while writing VM state\n", ret);
++ goto restart;
++ }
++out:
++ if (bs) {
++ bdrv_delete(bs);
++ }
++ return;
+
+restart:
+
-+ snap_state.in_progress = 0;
++ snap_state.in_progress = 0;
+
-+ if (snap_state.saved_vm_running) {
-+ vm_start();
-+ }
++ if (snap_state.saved_vm_running) {
++ vm_start();
++ }
+
-+ goto end;
++ goto out;
+}
+
+void qmp_snapshot_end(Error **errp)
+{
-+ if (!snap_state.in_progress) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "VM snapshot not started\n");
-+ return;
-+ }
-+ snap_state.in_progress = 0;
-+
-+ if (snap_state.saved_vm_running) {
-+ vm_start();
-+ }
-+}
++ if (!snap_state.in_progress) {
++ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++ "VM snapshot not started\n");
++ return;
++ }
++ snap_state.in_progress = 0;
+
-+/* Fixme: Copied from savevm */
-+static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
-+ const char *name)
-+{
-+ QEMUSnapshotInfo *sn_tab, *sn;
-+ int nb_sns, i, ret;
-+
-+ ret = -ENOENT;
-+ nb_sns = bdrv_snapshot_list(bs, &sn_tab);
-+ if (nb_sns < 0)
-+ return ret;
-+ for(i = 0; i < nb_sns; i++) {
-+ sn = &sn_tab[i];
-+ if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
-+ *sn_info = *sn;
-+ ret = 0;
-+ break;
-+ }
++ if (snap_state.saved_vm_running) {
++ vm_start();
+ }
-+ g_free(sn_tab);
-+ return ret;
+}
+
+void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
+{
-+ BlockDriverState *bs;
-+ QEMUSnapshotInfo sn1, *sn = &sn1;
-+ int ret;
++ BlockDriverState *bs;
++ QEMUSnapshotInfo sn1, *sn = &sn1;
++ int ret;
+#ifdef _WIN32
-+ struct _timeb tb;
++ struct _timeb tb;
+#else
-+ struct timeval tv;
++ struct timeval tv;
+#endif
+
-+ if (!snap_state.in_progress) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "VM snapshot not started\n");
-+ return;
-+ }
-+
-+ bs = bdrv_find(device);
-+ if (!bs) {
-+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
-+ return;
-+ }
-+
-+ if (!bdrv_is_inserted(bs)) {
-+ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
-+ return;
-+ }
-+
-+ if (bdrv_is_read_only(bs)) {
-+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
-+ return;
-+ }
-+
-+ if (!bdrv_can_snapshot(bs)) {
-+ error_set(errp, QERR_NOT_SUPPORTED);
-+ return;
-+ }
-+
-+ if (bdrv_snapshot_find(bs, sn, name) >= 0) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "snapshot '%s' already exists", name);
-+ return;
-+ }
-+
-+ sn = &sn1;
-+ memset(sn, 0, sizeof(*sn));
++ if (!snap_state.in_progress) {
++ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++ "VM snapshot not started\n");
++ return;
++ }
++
++ bs = bdrv_find(device);
++ if (!bs) {
++ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
++ return;
++ }
++
++ if (!bdrv_is_inserted(bs)) {
++ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
++ return;
++ }
++
++ if (bdrv_is_read_only(bs)) {
++ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
++ return;
++ }
++
++ if (!bdrv_can_snapshot(bs)) {
++ error_set(errp, QERR_NOT_SUPPORTED);
++ return;
++ }
++
++ if (bdrv_snapshot_find(bs, sn, name) >= 0) {
++ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++ "snapshot '%s' already exists", name);
++ return;
++ }
++
++ sn = &sn1;
++ memset(sn, 0, sizeof(*sn));
+
+#ifdef _WIN32
-+ _ftime(&tb);
-+ sn->date_sec = tb.time;
-+ sn->date_nsec = tb.millitm * 1000000;
++ _ftime(&tb);
++ sn->date_sec = tb.time;
++ sn->date_nsec = tb.millitm * 1000000;
+#else
-+ gettimeofday(&tv, NULL);
-+ sn->date_sec = tv.tv_sec;
-+ sn->date_nsec = tv.tv_usec * 1000;
++ gettimeofday(&tv, NULL);
++ sn->date_sec = tv.tv_sec;
++ sn->date_nsec = tv.tv_usec * 1000;
+#endif
-+ sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
++ sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
+
-+ pstrcpy(sn->name, sizeof(sn->name), name);
++ pstrcpy(sn->name, sizeof(sn->name), name);
+
-+ sn->vm_state_size = 0; /* do not save state */
++ sn->vm_state_size = 0; /* do not save state */
+
-+ ret = bdrv_snapshot_create(bs, sn);
-+ if (ret < 0) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "Error while creating snapshot on '%s'\n", device);
-+ return;
-+ }
++ ret = bdrv_snapshot_create(bs, sn);
++ if (ret < 0) {
++ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++ "Error while creating snapshot on '%s'\n", device);
++ return;
++ }
+}
+
-+void qmp_delete_drive_snapshot(const char *device, const char *name, Error **errp)
++void qmp_delete_drive_snapshot(const char *device, const char *name,
++ Error **errp)
+{
-+ BlockDriverState *bs;
-+ QEMUSnapshotInfo sn1, *sn = &sn1;
-+ int ret;
-+
-+ bs = bdrv_find(device);
-+ if (!bs) {
-+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
-+ return;
-+ }
-+ if (bdrv_is_read_only(bs)) {
-+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
-+ return;
-+ }
-+
-+ if (!bdrv_can_snapshot(bs)) {
-+ error_set(errp, QERR_NOT_SUPPORTED);
-+ return;
-+ }
-+
-+ if (bdrv_snapshot_find(bs, sn, name) < 0) {
-+ /* return success if snapshot does not exists */
-+ return;
-+ }
-+
-+ ret = bdrv_snapshot_delete(bs, name);
-+ if (ret < 0) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "Error while deleting snapshot on '%s'\n", device);
-+ return;
-+ }
++ BlockDriverState *bs;
++ QEMUSnapshotInfo sn1, *sn = &sn1;
++ int ret;
++
++ bs = bdrv_find(device);
++ if (!bs) {
++ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
++ return;
++ }
++ if (bdrv_is_read_only(bs)) {
++ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
++ return;
++ }
++
++ if (!bdrv_can_snapshot(bs)) {
++ error_set(errp, QERR_NOT_SUPPORTED);
++ return;
++ }
++
++ if (bdrv_snapshot_find(bs, sn, name) < 0) {
++ /* return success if snapshot does not exists */
++ return;
++ }
++
++ ret = bdrv_snapshot_delete(bs, name);
++ if (ret < 0) {
++ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++ "Error while deleting snapshot on '%s'\n", device);
++ return;
++ }
+}
Index: new/qmp-commands.hx
===================================================================
---- new.orig/qmp-commands.hx 2012-09-07 07:41:45.000000000 +0200
-+++ new/qmp-commands.hx 2012-09-13 09:30:33.000000000 +0200
+--- new.orig/qmp-commands.hx 2012-09-18 06:20:41.000000000 +0200
++++ new/qmp-commands.hx 2012-09-18 08:43:25.000000000 +0200
@@ -2514,3 +2514,27 @@
.args_type = "",
.mhandler.cmd_new = qmp_marshal_input_query_target,
+ },
Index: new/hmp.c
===================================================================
---- new.orig/hmp.c 2012-09-07 07:41:45.000000000 +0200
-+++ new/hmp.c 2012-09-13 09:22:06.000000000 +0200
+--- new.orig/hmp.c 2012-09-18 06:20:41.000000000 +0200
++++ new/hmp.c 2012-09-18 08:43:25.000000000 +0200
@@ -1102,3 +1102,40 @@
qmp_closefd(fdname, &errp);
hmp_handle_error(mon, &errp);
+}
Index: new/hmp.h
===================================================================
---- new.orig/hmp.h 2012-09-07 07:41:45.000000000 +0200
-+++ new/hmp.h 2012-09-13 09:22:06.000000000 +0200
+--- new.orig/hmp.h 2012-09-18 06:20:41.000000000 +0200
++++ new/hmp.h 2012-09-18 08:43:25.000000000 +0200
@@ -71,5 +71,9 @@
void hmp_netdev_del(Monitor *mon, const QDict *qdict);
void hmp_getfd(Monitor *mon, const QDict *qdict);
#endif
Index: new/hmp-commands.hx
===================================================================
---- new.orig/hmp-commands.hx 2012-09-07 07:41:45.000000000 +0200
-+++ new/hmp-commands.hx 2012-09-13 09:22:06.000000000 +0200
+--- new.orig/hmp-commands.hx 2012-09-18 06:20:41.000000000 +0200
++++ new/hmp-commands.hx 2012-09-18 08:43:25.000000000 +0200
@@ -1494,3 +1494,35 @@
STEXI
@end table
+ .help = "Resume VM after snaphot.",
+ .mhandler.cmd = hmp_snapshot_end,
+ },
-Index: new/savevm.c
-===================================================================
---- new.orig/savevm.c 2012-09-07 07:41:45.000000000 +0200
-+++ new/savevm.c 2012-09-14 11:32:17.000000000 +0200
-@@ -404,7 +404,7 @@
- return bdrv_flush(opaque);
- }
-
--static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
-+QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
- {
- if (is_writable)
- return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose,
-@@ -1724,7 +1724,7 @@
- }
- }
-
--static int qemu_savevm_state(QEMUFile *f)
-+int qemu_savevm_state(QEMUFile *f)
- {
- int ret;
- MigrationParams params = {
Index: new/sysemu.h
===================================================================
---- new.orig/sysemu.h 2012-09-07 07:41:46.000000000 +0200
-+++ new/sysemu.h 2012-09-13 09:22:06.000000000 +0200
-@@ -83,6 +83,7 @@
+--- new.orig/sysemu.h 2012-09-18 07:35:53.000000000 +0200
++++ new/sysemu.h 2012-09-18 08:43:25.000000000 +0200
+@@ -84,6 +84,7 @@
int qemu_savevm_state_iterate(QEMUFile *f);
int qemu_savevm_state_complete(QEMUFile *f);
void qemu_savevm_state_cancel(QEMUFile *f);
int qemu_loadvm_state(QEMUFile *f);
/* SLIRP */
-Index: new/qemu-file.h
+Index: new/savevm.c
===================================================================
---- new.orig/qemu-file.h 2012-09-14 11:51:31.000000000 +0200
-+++ new/qemu-file.h 2012-09-14 11:51:47.000000000 +0200
-@@ -68,6 +68,7 @@
- QEMUFile *qemu_fopen(const char *filename, const char *mode);
- QEMUFile *qemu_fdopen(int fd, const char *mode);
- QEMUFile *qemu_fopen_socket(int fd);
-+QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable);
- QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
- QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
- int qemu_stdio_fd(QEMUFile *f);
+--- new.orig/savevm.c 2012-09-18 08:53:28.000000000 +0200
++++ new/savevm.c 2012-09-18 08:53:55.000000000 +0200
+@@ -1743,7 +1743,7 @@
+ }
+ }
+
+-static int qemu_savevm_state(QEMUFile *f)
++int qemu_savevm_state(QEMUFile *f)
+ {
+ int ret;
+ MigrationParams params = {
--- /dev/null
+Index: new/savevm.c
+===================================================================
+--- new.orig/savevm.c 2012-09-18 07:20:45.000000000 +0200
++++ new/savevm.c 2012-09-18 07:36:55.000000000 +0200
+@@ -2223,6 +2223,50 @@
+ return;
+ }
+
++int load_state_from_blockdev(const char *filename)
++{
++ BlockDriverState *bs = NULL;
++ BlockDriver *drv = NULL;
++ QEMUFile *f;
++ int bdrv_oflags = BDRV_O_NOCACHE | BDRV_O_RDWR;
++ int ret = -1;
++
++ bs = bdrv_new("vmstate");
++ ret = bdrv_open(bs, filename, bdrv_oflags, drv);
++ if (ret < 0) {
++ error_report("Could not open VM state file");
++ goto the_end;
++ }
++
++ /* Flush all IO requests so they don't interfere with the new state. */
++ bdrv_drain_all();
++
++ /* restore the VM state */
++ f = qemu_fopen_bdrv(bs, 0);
++ if (!f) {
++ error_report("Could not open VM state file");
++ ret = -EINVAL;
++ goto the_end;
++ }
++
++ qemu_system_reset(VMRESET_SILENT);
++ ret = qemu_loadvm_state(f);
++
++ qemu_fclose(f);
++ if (ret < 0) {
++ error_report("Error %d while loading VM state", ret);
++ goto the_end;
++ }
++
++ ret = 0;
++
++ the_end:
++ if (bs) {
++ bdrv_delete(bs);
++ }
++ return ret;
++}
++
+ int load_vmstate(const char *name)
+ {
+ BlockDriverState *bs, *bs_vm_state;
+Index: new/sysemu.h
+===================================================================
+--- new.orig/sysemu.h 2012-09-18 07:35:26.000000000 +0200
++++ new/sysemu.h 2012-09-18 07:35:53.000000000 +0200
+@@ -72,6 +72,7 @@
+
+ void do_savevm(Monitor *mon, const QDict *qdict);
+ int load_vmstate(const char *name);
++int load_state_from_blockdev(const char *filename);
+ void do_delvm(Monitor *mon, const QDict *qdict);
+ void do_info_snapshots(Monitor *mon);
+
+Index: new/qemu-options.hx
+===================================================================
+--- new.orig/qemu-options.hx 2012-09-18 07:39:54.000000000 +0200
++++ new/qemu-options.hx 2012-09-18 07:52:56.000000000 +0200
+@@ -2477,6 +2477,19 @@
+ Start right away with a saved state (@code{loadvm} in monitor)
+ ETEXI
+
++DEF("loadstate", HAS_ARG, QEMU_OPTION_loadstate, \
++ "-loadstate file\n" \
++ " start right away with a saved state\n",
++ QEMU_ARCH_ALL)
++STEXI
++@item -loadstate @var{file}
++@findex -loadstate
++Start right away with a saved state. This option does not rollback
++disk state like @code{loadvm}, so user must make sure that disk
++have correct state. @var{file} can be any valid device URL. See the section
++for "Device URL Syntax" for more information.
++ETEXI
++
+ #ifndef _WIN32
+ DEF("daemonize", 0, QEMU_OPTION_daemonize, \
+ "-daemonize daemonize QEMU after initializing\n", QEMU_ARCH_ALL)
+Index: new/vl.c
+===================================================================
+--- new.orig/vl.c 2012-09-18 07:53:19.000000000 +0200
++++ new/vl.c 2012-09-18 07:55:47.000000000 +0200
+@@ -2364,6 +2364,7 @@
+ int optind;
+ const char *optarg;
+ const char *loadvm = NULL;
++ const char *loadstate = NULL;
+ QEMUMachine *machine;
+ const char *cpu_model;
+ const char *vga_model = "none";
+@@ -2998,6 +2999,9 @@
+ case QEMU_OPTION_loadvm:
+ loadvm = optarg;
+ break;
++ case QEMU_OPTION_loadstate:
++ loadstate = optarg;
++ break;
+ case QEMU_OPTION_full_screen:
+ full_screen = 1;
+ break;
+@@ -3821,6 +3825,10 @@
+ if (load_vmstate(loadvm) < 0) {
+ autostart = 0;
+ }
++ } else if (loadstate) {
++ if (load_state_from_blockdev(loadstate) < 0) {
++ autostart = 0;
++ }
+ }
+
+ if (incoming) {