diff options
author | Pavel Butsykin <pbutsykin@virtuozzo.com> | 2017-09-29 15:16:13 +0300 |
---|---|---|
committer | Max Reitz <mreitz@redhat.com> | 2017-10-06 16:30:48 +0200 |
commit | 163bc39d2c2921430e5c23f4d0a0966d62f67a02 (patch) | |
tree | d0303bc2a7e3d2d346d8c1d7d361f5a453c8aed4 /block/qcow2.c | |
parent | 76a2a30a99c670e9ec1b4a5d976868059c6bc258 (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.c | 23 |
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) { |