aboutsummaryrefslogtreecommitdiff
path: root/block/qcow2.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/qcow2.c')
-rw-r--r--block/qcow2.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/block/qcow2.c b/block/qcow2.c
index 0edc7f4..3e8b3d0 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -3989,9 +3989,12 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
qemu_co_mutex_lock(&s->lock);
- /* cannot proceed if image has snapshots */
- if (s->nb_snapshots) {
- error_setg(errp, "Can't resize an image which has snapshots");
+ /*
+ * Even though we store snapshot size for all images, it was not
+ * required until v3, so it is not safe to proceed for v2.
+ */
+ if (s->nb_snapshots && s->qcow_version < 3) {
+ error_setg(errp, "Can't resize a v2 image which has snapshots");
ret = -ENOTSUP;
goto fail;
}
@@ -5005,6 +5008,7 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
BDRVQcow2State *s = bs->opaque;
int current_version = s->qcow_version;
int ret;
+ int i;
/* This is qcow2_downgrade(), not qcow2_upgrade() */
assert(target_version < current_version);
@@ -5022,6 +5026,21 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
return -ENOTSUP;
}
+ /*
+ * If any internal snapshot has a different size than the current
+ * image size, or VM state size that exceeds 32 bits, downgrading
+ * is unsafe. Even though we would still use v3-compliant output
+ * to preserve that data, other v2 programs might not realize
+ * those optional fields are important.
+ */
+ for (i = 0; i < s->nb_snapshots; i++) {
+ if (s->snapshots[i].vm_state_size > UINT32_MAX ||
+ s->snapshots[i].disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
+ error_setg(errp, "Internal snapshots prevent downgrade of image");
+ return -ENOTSUP;
+ }
+ }
+
/* clear incompatible features */
if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) {
ret = qcow2_mark_clean(bs);