aboutsummaryrefslogtreecommitdiff
path: root/block/qcow2.c
diff options
context:
space:
mode:
authorPavel Butsykin <pbutsykin@virtuozzo.com>2017-09-29 15:16:13 +0300
committerMax Reitz <mreitz@redhat.com>2017-10-06 16:30:48 +0200
commit163bc39d2c2921430e5c23f4d0a0966d62f67a02 (patch)
treed0303bc2a7e3d2d346d8c1d7d361f5a453c8aed4 /block/qcow2.c
parent76a2a30a99c670e9ec1b4a5d976868059c6bc258 (diff)
qcow2: truncate the tail of the image file after shrinking the image
Now after shrinking the image, at the end of the image file, there might be a tail that probably will never be used. So we can find the last used cluster and cut the tail. Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com> Reviewed-by: John Snow <jsnow@redhat.com> Message-id: 20170929121613.25997-3-pbutsykin@virtuozzo.com Signed-off-by: Max Reitz <mreitz@redhat.com>
Diffstat (limited to 'block/qcow2.c')
-rw-r--r--block/qcow2.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/block/qcow2.c b/block/qcow2.c
index 960b3ab977..f63d1831f8 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -3107,6 +3107,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
new_l1_size = size_to_l1(s, offset);
if (offset < old_length) {
+ int64_t last_cluster, old_file_size;
if (prealloc != PREALLOC_MODE_OFF) {
error_setg(errp,
"Preallocation can't be used for shrinking an image");
@@ -3135,6 +3136,28 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
"Failed to discard unused refblocks");
return ret;
}
+
+ old_file_size = bdrv_getlength(bs->file->bs);
+ if (old_file_size < 0) {
+ error_setg_errno(errp, -old_file_size,
+ "Failed to inquire current file length");
+ return old_file_size;
+ }
+ last_cluster = qcow2_get_last_cluster(bs, old_file_size);
+ if (last_cluster < 0) {
+ error_setg_errno(errp, -last_cluster,
+ "Failed to find the last cluster");
+ return last_cluster;
+ }
+ if ((last_cluster + 1) * s->cluster_size < old_file_size) {
+ ret = bdrv_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
+ PREALLOC_MODE_OFF, NULL);
+ if (ret < 0) {
+ warn_report("Failed to truncate the tail of the image: %s",
+ strerror(-ret));
+ ret = 0;
+ }
+ }
} else {
ret = qcow2_grow_l1_table(bs, new_l1_size, true);
if (ret < 0) {