1 #include "qemu-common.h"
4 #include "qmp-commands.h"
6 #include "qemu/qom-qobject.h"
7 #include "buffered_file.h"
10 //#define DEBUG_SAVEVM_STATE
12 #ifdef DEBUG_SAVEVM_STATE
13 #define DPRINTF(fmt, ...) \
14 do { printf("savevm-async: " fmt, ## __VA_ARGS__); } while (0)
16 #define DPRINTF(fmt, ...) \
27 static struct SnapshotState
{
37 SaveVMInfo
*qmp_query_savevm(Error
**errp
)
39 SaveVMInfo
*info
= g_malloc0(sizeof(*info
));
40 struct SnapshotState
*s
= &snap_state
;
42 if (s
->state
!= SAVE_STATE_DONE
) {
43 info
->has_bytes
= true;
44 info
->bytes
= s
->bs_pos
;
46 case SAVE_STATE_ERROR
:
47 info
->has_status
= true;
48 info
->status
= g_strdup("failed");
49 info
->has_total_time
= true;
50 info
->total_time
= s
->total_time
;
52 info
->has_error
= true;
53 info
->error
= g_strdup(error_get_pretty(s
->error
));
56 case SAVE_STATE_ACTIVE
:
57 info
->has_status
= true;
58 info
->status
= g_strdup("active");
59 info
->has_total_time
= true;
60 info
->total_time
= qemu_get_clock_ms(rt_clock
)
63 case SAVE_STATE_COMPLETED
:
64 info
->has_status
= true;
65 info
->status
= g_strdup("completed");
66 info
->has_total_time
= true;
67 info
->total_time
= s
->total_time
;
75 static int save_snapshot_cleanup(void)
79 DPRINTF("save_snapshot_cleanup\n");
81 snap_state
.total_time
= qemu_get_clock_ms(rt_clock
) -
82 snap_state
.total_time
;
84 if (snap_state
.file
) {
85 ret
= qemu_fclose(snap_state
.file
);
89 // try to truncate, but ignore errors (will fail on block devices).
90 // note: bdrv_read() need whole blocks, so we round up
91 size_t size
= (snap_state
.bs_pos
+ BDRV_SECTOR_SIZE
) & BDRV_SECTOR_MASK
;
92 bdrv_truncate(snap_state
.bs
, size
);
94 bdrv_delete(snap_state
.bs
);
101 static void save_snapshot_error(const char *fmt
, ...)
107 msg
= g_strdup_vprintf(fmt
, ap
);
110 DPRINTF("save_snapshot_error: %s\n", msg
);
112 if (!snap_state
.error
) {
113 error_set(&snap_state
.error
, ERROR_CLASS_GENERIC_ERROR
, "%s", msg
);
118 snap_state
.state
= SAVE_STATE_ERROR
;
120 save_snapshot_cleanup();
123 static void save_snapshot_completed(void)
125 DPRINTF("save_snapshot_completed\n");
127 if (save_snapshot_cleanup() < 0) {
128 snap_state
.state
= SAVE_STATE_ERROR
;
130 snap_state
.state
= SAVE_STATE_COMPLETED
;
134 static int block_state_close(void *opaque
)
136 snap_state
.file
= NULL
;
137 return bdrv_flush(snap_state
.bs
);
140 static ssize_t
block_state_put_buffer(void *opaque
, const void *buf
,
145 if ((ret
= bdrv_pwrite(snap_state
.bs
, snap_state
.bs_pos
, buf
, size
)) > 0) {
146 snap_state
.bs_pos
+= ret
;
152 static void block_state_put_ready(void *opaque
)
158 if (snap_state
.state
!= SAVE_STATE_ACTIVE
) {
159 save_snapshot_error("put_ready returning because of non-active state");
163 ret
= qemu_savevm_state_iterate(snap_state
.file
);
164 remaining
= ram_bytes_remaining();
166 // stop if we get to the end of available space,
167 // or if remaining is just a few MB
168 maxlen
= bdrv_getlength(snap_state
.bs
) - 30*1024*1024;
169 if ((remaining
< 100000) || ((snap_state
.bs_pos
+ remaining
) >= maxlen
)) {
170 if (runstate_is_running()) {
171 vm_stop(RUN_STATE_SAVE_VM
);
176 save_snapshot_error("qemu_savevm_state_iterate error %d", ret
);
178 } else if (ret
== 1) {
179 if (runstate_is_running()) {
180 vm_stop(RUN_STATE_SAVE_VM
);
182 DPRINTF("savevm inerate finished\n");
183 if ((ret
= qemu_savevm_state_complete(snap_state
.file
)) < 0) {
184 save_snapshot_error("qemu_savevm_state_complete error %d", ret
);
187 DPRINTF("save complete\n");
188 save_snapshot_completed();
194 static void block_state_wait_for_unfreeze(void *opaque
)
196 /* do nothing here - should not be called */
199 void qmp_savevm_start(bool has_statefile
, const char *statefile
, Error
**errp
)
201 BlockDriver
*drv
= NULL
;
202 int bdrv_oflags
= BDRV_O_CACHE_WB
| BDRV_O_RDWR
;
203 MigrationParams params
= {
209 if (snap_state
.state
!= SAVE_STATE_DONE
) {
210 error_set(errp
, ERROR_CLASS_GENERIC_ERROR
,
211 "VM snapshot already started\n");
215 /* initialize snapshot info */
216 snap_state
.saved_vm_running
= runstate_is_running();
217 snap_state
.bs_pos
= 0;
218 snap_state
.total_time
= qemu_get_clock_ms(rt_clock
);
220 if (snap_state
.error
) {
221 error_free(snap_state
.error
);
222 snap_state
.error
= NULL
;
225 if (!has_statefile
) {
226 vm_stop(RUN_STATE_SAVE_VM
);
227 snap_state
.state
= SAVE_STATE_COMPLETED
;
231 if (qemu_savevm_state_blocked(errp
)) {
236 snap_state
.bs
= bdrv_new("vmstate");
237 ret
= bdrv_open(snap_state
.bs
, statefile
, bdrv_oflags
, drv
);
239 error_set(errp
, QERR_OPEN_FILE_FAILED
, statefile
);
243 snap_state
.file
= qemu_fopen_ops_buffered(&snap_state
, 1000000000,
244 block_state_put_buffer
,
245 block_state_put_ready
,
246 block_state_wait_for_unfreeze
,
249 if (!snap_state
.file
) {
250 error_set(errp
, QERR_OPEN_FILE_FAILED
, statefile
);
254 snap_state
.state
= SAVE_STATE_ACTIVE
;
256 ret
= qemu_savevm_state_begin(snap_state
.file
, ¶ms
);
258 error_set(errp
, ERROR_CLASS_GENERIC_ERROR
,
259 "qemu_savevm_state_begin failed\n");
263 block_state_put_ready(&snap_state
);
269 save_snapshot_error("setup failed");
271 if (snap_state
.saved_vm_running
) {
276 void qmp_savevm_end(Error
**errp
)
278 if (snap_state
.state
== SAVE_STATE_DONE
) {
279 error_set(errp
, ERROR_CLASS_GENERIC_ERROR
,
280 "VM snapshot not started\n");
284 if (snap_state
.saved_vm_running
) {
288 snap_state
.state
= SAVE_STATE_DONE
;
291 void qmp_snapshot_drive(const char *device
, const char *name
, Error
**errp
)
293 BlockDriverState
*bs
;
294 QEMUSnapshotInfo sn1
, *sn
= &sn1
;
302 if (snap_state
.state
!= SAVE_STATE_COMPLETED
) {
303 error_set(errp
, ERROR_CLASS_GENERIC_ERROR
,
304 "VM snapshot not ready/started\n");
308 bs
= bdrv_find(device
);
310 error_set(errp
, QERR_DEVICE_NOT_FOUND
, device
);
314 if (!bdrv_is_inserted(bs
)) {
315 error_set(errp
, QERR_DEVICE_HAS_NO_MEDIUM
, device
);
319 if (bdrv_is_read_only(bs
)) {
320 error_set(errp
, QERR_DEVICE_IS_READ_ONLY
, device
);
324 if (!bdrv_can_snapshot(bs
)) {
325 error_set(errp
, QERR_NOT_SUPPORTED
);
329 if (bdrv_snapshot_find(bs
, sn
, name
) >= 0) {
330 error_set(errp
, ERROR_CLASS_GENERIC_ERROR
,
331 "snapshot '%s' already exists", name
);
336 memset(sn
, 0, sizeof(*sn
));
340 sn
->date_sec
= tb
.time
;
341 sn
->date_nsec
= tb
.millitm
* 1000000;
343 gettimeofday(&tv
, NULL
);
344 sn
->date_sec
= tv
.tv_sec
;
345 sn
->date_nsec
= tv
.tv_usec
* 1000;
347 sn
->vm_clock_nsec
= qemu_get_clock_ns(vm_clock
);
349 pstrcpy(sn
->name
, sizeof(sn
->name
), name
);
351 sn
->vm_state_size
= 0; /* do not save state */
353 ret
= bdrv_snapshot_create(bs
, sn
);
355 error_set(errp
, ERROR_CLASS_GENERIC_ERROR
,
356 "Error while creating snapshot on '%s'\n", device
);
361 void qmp_delete_drive_snapshot(const char *device
, const char *name
,
364 BlockDriverState
*bs
;
365 QEMUSnapshotInfo sn1
, *sn
= &sn1
;
368 bs
= bdrv_find(device
);
370 error_set(errp
, QERR_DEVICE_NOT_FOUND
, device
);
373 if (bdrv_is_read_only(bs
)) {
374 error_set(errp
, QERR_DEVICE_IS_READ_ONLY
, device
);
378 if (!bdrv_can_snapshot(bs
)) {
379 error_set(errp
, QERR_NOT_SUPPORTED
);
383 if (bdrv_snapshot_find(bs
, sn
, name
) < 0) {
384 /* return success if snapshot does not exists */
388 ret
= bdrv_snapshot_delete(bs
, name
);
390 error_set(errp
, ERROR_CLASS_GENERIC_ERROR
,
391 "Error while deleting snapshot on '%s'\n", device
);
396 static int loadstate_get_buffer(void *opaque
, uint8_t *buf
, int64_t pos
, int size
)
398 BlockDriverState
*bs
= (BlockDriverState
*)opaque
;
399 int64_t maxlen
= bdrv_getlength(bs
);
403 if ((pos
+ size
) > maxlen
) {
404 size
= maxlen
- pos
- 1;
409 return bdrv_pread(bs
, pos
, buf
, size
);
412 int load_state_from_blockdev(const char *filename
)
414 BlockDriverState
*bs
= NULL
;
415 BlockDriver
*drv
= NULL
;
419 bs
= bdrv_new("vmstate");
420 ret
= bdrv_open(bs
, filename
, BDRV_O_CACHE_WB
, drv
);
422 error_report("Could not open VM state file");
426 /* restore the VM state */
427 f
= qemu_fopen_ops(bs
, NULL
, loadstate_get_buffer
, NULL
, NULL
, NULL
, NULL
);
429 error_report("Could not open VM state file");
434 qemu_system_reset(VMRESET_SILENT
);
435 ret
= qemu_loadvm_state(f
);
439 error_report("Error %d while loading VM state", ret
);