提交 f0aa7a8b 编写于 作者: M Miguel Di Ciurcio Filho 提交者: Kevin Wolf

loadvm: improve tests before bdrv_snapshot_goto()

This patch improves the resilience of the load_vmstate() function, doing
further and better ordered tests.

In load_vmstate(), if there is any error on bdrv_snapshot_goto(), except if the
error is on VM state device, load_vmstate() will return zero and the VM will be
started with major corruption chances.

The current process:
- test if there is any writable device without snapshot support
    - if exists return -error
- get the device that saves the VM state, possible return -error but unlikely
because it was tested earlier
- flush I/O
- run bdrv_snapshot_goto() on devices
    - if fails, give an warning and goes to the next (not good!)
    - if fails on the VM state device, return zero (not good!)
- check if the requested snapshot exists on the device that saves the VM state
and the state is not zero
    - if fails return -error
- open the file with the VM state
    - if fails return -error
- load the VM state
    - if fails return -error
- return zero

New behavior:
- get the device that saves the VM state
    - if fails return -error
- check if the requested snapshot exists on the device that saves the VM state
and the state is not zero
    - if fails return -error
- test if there is any writable device without snapshot support
    - if exists return -error
- test if the devices with snapshot support have the requested snapshot
    - if anyone fails, return -error
- flush I/O
- run snapshot_goto() on devices
    - if anyone fails, return -error
- open the file with the VM state
    - if fails return -error
- load the VM state
    - if fails return -error
- return zero

do_loadvm must not call vm_start if any error has occurred in load_vmstate.
Signed-off-by: NMiguel Di Ciurcio Filho <miguel.filho@gmail.com>
Signed-off-by: NKevin Wolf <kwolf@redhat.com>
上级 8a426614
...@@ -2274,8 +2274,9 @@ static void do_loadvm(Monitor *mon, const QDict *qdict) ...@@ -2274,8 +2274,9 @@ static void do_loadvm(Monitor *mon, const QDict *qdict)
vm_stop(0); vm_stop(0);
if (load_vmstate(name) >= 0 && saved_vm_running) if (load_vmstate(name) == 0 && saved_vm_running) {
vm_start(); vm_start();
}
} }
int monitor_get_fd(Monitor *mon, const char *fdname) int monitor_get_fd(Monitor *mon, const char *fdname)
......
...@@ -1894,12 +1894,27 @@ void do_savevm(Monitor *mon, const QDict *qdict) ...@@ -1894,12 +1894,27 @@ void do_savevm(Monitor *mon, const QDict *qdict)
int load_vmstate(const char *name) int load_vmstate(const char *name)
{ {
BlockDriverState *bs, *bs1; BlockDriverState *bs, *bs_vm_state;
QEMUSnapshotInfo sn; QEMUSnapshotInfo sn;
QEMUFile *f; QEMUFile *f;
int ret; int ret;
/* Verify if there is a device that doesn't support snapshots and is writable */ bs_vm_state = bdrv_snapshots();
if (!bs_vm_state) {
error_report("No block device supports snapshots");
return -ENOTSUP;
}
/* Don't even try to load empty VM states */
ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
if (ret < 0) {
return ret;
} else if (sn.vm_state_size == 0) {
return -EINVAL;
}
/* Verify if there is any device that doesn't support snapshots and is
writable and check if the requested snapshot is available too. */
bs = NULL; bs = NULL;
while ((bs = bdrv_next(bs))) { while ((bs = bdrv_next(bs))) {
...@@ -1912,63 +1927,45 @@ int load_vmstate(const char *name) ...@@ -1912,63 +1927,45 @@ int load_vmstate(const char *name)
bdrv_get_device_name(bs)); bdrv_get_device_name(bs));
return -ENOTSUP; return -ENOTSUP;
} }
}
bs = bdrv_snapshots(); ret = bdrv_snapshot_find(bs, &sn, name);
if (!bs) { if (ret < 0) {
error_report("No block device supports snapshots"); error_report("Device '%s' does not have the requested snapshot '%s'",
return -EINVAL; bdrv_get_device_name(bs), name);
return ret;
}
} }
/* Flush all IO requests so they don't interfere with the new state. */ /* Flush all IO requests so they don't interfere with the new state. */
qemu_aio_flush(); qemu_aio_flush();
bs1 = NULL; bs = NULL;
while ((bs1 = bdrv_next(bs1))) { while ((bs = bdrv_next(bs))) {
if (bdrv_can_snapshot(bs1)) { if (bdrv_can_snapshot(bs)) {
ret = bdrv_snapshot_goto(bs1, name); ret = bdrv_snapshot_goto(bs, name);
if (ret < 0) { if (ret < 0) {
switch(ret) { error_report("Error %d while activating snapshot '%s' on '%s'",
case -ENOTSUP: ret, name, bdrv_get_device_name(bs));
error_report("%sSnapshots not supported on device '%s'", return ret;
bs != bs1 ? "Warning: " : "",
bdrv_get_device_name(bs1));
break;
case -ENOENT:
error_report("%sCould not find snapshot '%s' on device '%s'",
bs != bs1 ? "Warning: " : "",
name, bdrv_get_device_name(bs1));
break;
default:
error_report("%sError %d while activating snapshot on '%s'",
bs != bs1 ? "Warning: " : "",
ret, bdrv_get_device_name(bs1));
break;
}
/* fatal on snapshot block device */
if (bs == bs1)
return 0;
} }
} }
} }
/* Don't even try to load empty VM states */
ret = bdrv_snapshot_find(bs, &sn, name);
if ((ret >= 0) && (sn.vm_state_size == 0))
return -EINVAL;
/* restore the VM state */ /* restore the VM state */
f = qemu_fopen_bdrv(bs, 0); f = qemu_fopen_bdrv(bs_vm_state, 0);
if (!f) { if (!f) {
error_report("Could not open VM state file"); error_report("Could not open VM state file");
return -EINVAL; return -EINVAL;
} }
ret = qemu_loadvm_state(f); ret = qemu_loadvm_state(f);
qemu_fclose(f); qemu_fclose(f);
if (ret < 0) { if (ret < 0) {
error_report("Error %d while loading VM state", ret); error_report("Error %d while loading VM state", ret);
return ret; return ret;
} }
return 0; return 0;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册