diff --git a/block.c b/block.c index cacf11bd99cf73bca926a85146f50f534062e31d..29a6f393df61b97478cb9f6f358b8540bdf42227 100644 --- a/block.c +++ b/block.c @@ -1666,6 +1666,23 @@ void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event) /**************************************************************/ /* handling of snapshots */ +int bdrv_can_snapshot(BlockDriverState *bs) +{ + BlockDriver *drv = bs->drv; + if (!drv || bdrv_is_removable(bs) || bdrv_is_read_only(bs)) { + return 0; + } + + if (!drv->bdrv_snapshot_create) { + if (bs->file != NULL) { + return bdrv_can_snapshot(bs->file); + } + return 0; + } + + return 1; +} + int bdrv_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) { diff --git a/block.h b/block.h index 25744b134fde45579f87ba93c6f2958d5340bb64..a340ffdaf3f383b0d7b797d47d2776b6fc92a632 100644 --- a/block.h +++ b/block.h @@ -175,6 +175,7 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); const char *bdrv_get_encrypted_filename(BlockDriverState *bs); void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size); +int bdrv_can_snapshot(BlockDriverState *bs); int bdrv_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); int bdrv_snapshot_goto(BlockDriverState *bs, diff --git a/savevm.c b/savevm.c index 1173a22e65c5ebc4aeb9bda3ea089938899e0edb..ab58d63c85e7b6e4eabf3a07923c8ae3b3175ec7 100644 --- a/savevm.c +++ b/savevm.c @@ -1575,22 +1575,6 @@ out: return ret; } -/* device can contain snapshots */ -static int bdrv_can_snapshot(BlockDriverState *bs) -{ - return (bs && - !bdrv_is_removable(bs) && - !bdrv_is_read_only(bs)); -} - -/* device must be snapshots in order to have a reliable snapshot */ -static int bdrv_has_snapshot(BlockDriverState *bs) -{ - return (bs && - !bdrv_is_removable(bs) && - !bdrv_is_read_only(bs)); -} - static BlockDriverState *get_bs_snapshots(void) { BlockDriverState *bs; @@ -1600,8 +1584,9 @@ static BlockDriverState *get_bs_snapshots(void) return bs_snapshots; QTAILQ_FOREACH(dinfo, &drives, next) { bs = dinfo->bdrv; - if (bdrv_can_snapshot(bs)) + if (bdrv_can_snapshot(bs)) { goto ok; + } } return NULL; ok: @@ -1675,12 +1660,26 @@ void do_savevm(Monitor *mon, const QDict *qdict) #endif const char *name = qdict_get_try_str(qdict, "name"); + /* Verify if there is a device that doesn't support snapshots and is writable */ + QTAILQ_FOREACH(dinfo, &drives, next) { + bs = dinfo->bdrv; + + if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) { + continue; + } + + if (!bdrv_can_snapshot(bs)) { + monitor_printf(mon, "Device '%s' is writable but does not support snapshots.\n", + bdrv_get_device_name(bs)); + return; + } + } + bs = get_bs_snapshots(); if (!bs) { monitor_printf(mon, "No block device can accept snapshots\n"); return; } - /* ??? Should this occur after vm_stop? */ qemu_aio_flush(); @@ -1733,7 +1732,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) QTAILQ_FOREACH(dinfo, &drives, next) { bs1 = dinfo->bdrv; - if (bdrv_has_snapshot(bs1)) { + if (bdrv_can_snapshot(bs1)) { /* Write VM state size only to the image that contains the state */ sn->vm_state_size = (bs == bs1 ? vm_state_size : 0); ret = bdrv_snapshot_create(bs1, sn); @@ -1757,6 +1756,21 @@ int load_vmstate(const char *name) QEMUFile *f; int ret; + /* Verify if there is a device that doesn't support snapshots and is writable */ + QTAILQ_FOREACH(dinfo, &drives, next) { + bs = dinfo->bdrv; + + if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) { + continue; + } + + if (!bdrv_can_snapshot(bs)) { + error_report("Device '%s' is writable but does not support snapshots.", + bdrv_get_device_name(bs)); + return -ENOTSUP; + } + } + bs = get_bs_snapshots(); if (!bs) { error_report("No block device supports snapshots"); @@ -1768,7 +1782,7 @@ int load_vmstate(const char *name) QTAILQ_FOREACH(dinfo, &drives, next) { bs1 = dinfo->bdrv; - if (bdrv_has_snapshot(bs1)) { + if (bdrv_can_snapshot(bs1)) { ret = bdrv_snapshot_goto(bs1, name); if (ret < 0) { switch(ret) { @@ -1830,7 +1844,7 @@ void do_delvm(Monitor *mon, const QDict *qdict) QTAILQ_FOREACH(dinfo, &drives, next) { bs1 = dinfo->bdrv; - if (bdrv_has_snapshot(bs1)) { + if (bdrv_can_snapshot(bs1)) { ret = bdrv_snapshot_delete(bs1, name); if (ret < 0) { if (ret == -ENOTSUP) @@ -1861,7 +1875,7 @@ void do_info_snapshots(Monitor *mon) monitor_printf(mon, "Snapshot devices:"); QTAILQ_FOREACH(dinfo, &drives, next) { bs1 = dinfo->bdrv; - if (bdrv_has_snapshot(bs1)) { + if (bdrv_can_snapshot(bs1)) { if (bs == bs1) monitor_printf(mon, " %s", bdrv_get_device_name(bs1)); }