mirror of
https://git.proxmox.com/git/qemu
synced 2025-08-14 04:54:36 +00:00
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: Miguel Di Ciurcio Filho <miguel.filho@gmail.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
8a4266144e
commit
f0aa7a8b2d
@ -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)
|
||||||
|
71
savevm.c
71
savevm.c
@ -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)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user