Skip to content

Commit

Permalink
qcow2: simple case support for downgrading of qcow2 images with zstd
Browse files Browse the repository at this point in the history
If image doesn't have any compressed cluster we can easily switch to
zlib compression, which may allow to downgrade the image.

That's mostly needed to support IMGOPTS='compression_type=zstd' in some
iotests which do qcow2 downgrade.

While being here also fix checkpatch complain against '#' in printf
formatting.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-Id: <20211223160144.1097696-13-vsementsov@virtuozzo.com>
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
  • Loading branch information
Vladimir Sementsov-Ogievskiy authored and XanClic committed Feb 1, 2022
1 parent c30175d commit 083c245
Showing 1 changed file with 56 additions and 2 deletions.
58 changes: 56 additions & 2 deletions block/qcow2.c
Expand Up @@ -5279,6 +5279,38 @@ static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0);
}

static int qcow2_has_compressed_clusters(BlockDriverState *bs)
{
int64_t offset = 0;
int64_t bytes = bdrv_getlength(bs);

if (bytes < 0) {
return bytes;
}

while (bytes != 0) {
int ret;
QCow2SubclusterType type;
unsigned int cur_bytes = MIN(INT_MAX, bytes);
uint64_t host_offset;

ret = qcow2_get_host_offset(bs, offset, &cur_bytes, &host_offset,
&type);
if (ret < 0) {
return ret;
}

if (type == QCOW2_SUBCLUSTER_COMPRESSED) {
return 1;
}

offset += cur_bytes;
bytes -= cur_bytes;
}

return 0;
}

/*
* Downgrades an image's version. To achieve this, any incompatible features
* have to be removed.
Expand Down Expand Up @@ -5336,9 +5368,10 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
* the first place; if that happens nonetheless, returning -ENOTSUP is the
* best thing to do anyway */

if (s->incompatible_features) {
if (s->incompatible_features & ~QCOW2_INCOMPAT_COMPRESSION) {
error_setg(errp, "Cannot downgrade an image with incompatible features "
"%#" PRIx64 " set", s->incompatible_features);
"0x%" PRIx64 " set",
s->incompatible_features & ~QCOW2_INCOMPAT_COMPRESSION);
return -ENOTSUP;
}

Expand All @@ -5356,6 +5389,27 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
return ret;
}

if (s->incompatible_features & QCOW2_INCOMPAT_COMPRESSION) {
ret = qcow2_has_compressed_clusters(bs);
if (ret < 0) {
error_setg(errp, "Failed to check block status");
return -EINVAL;
}
if (ret) {
error_setg(errp, "Cannot downgrade an image with zstd compression "
"type and existing compressed clusters");
return -ENOTSUP;
}
/*
* No compressed clusters for now, so just chose default zlib
* compression.
*/
s->incompatible_features &= ~QCOW2_INCOMPAT_COMPRESSION;
s->compression_type = QCOW2_COMPRESSION_TYPE_ZLIB;
}

assert(s->incompatible_features == 0);

s->qcow_version = target_version;
ret = qcow2_update_header(bs);
if (ret < 0) {
Expand Down

0 comments on commit 083c245

Please sign in to comment.