mirror of
https://github.com/qemu/qemu.git
synced 2024-11-24 19:33:39 +08:00
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>
This commit is contained in:
parent
76a2a30a99
commit
163bc39d2c
@ -3181,3 +3181,25 @@ out:
|
||||
g_free(reftable_tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int64_t i;
|
||||
|
||||
for (i = size_to_clusters(s, size) - 1; i >= 0; i--) {
|
||||
uint64_t refcount;
|
||||
int ret = qcow2_get_refcount(bs, i, &refcount);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n",
|
||||
i, strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
if (refcount > 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
qcow2_signal_corruption(bs, true, -1, -1,
|
||||
"There are no references in the refcount table.");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -597,6 +597,7 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
|
||||
BlockDriverAmendStatusCB *status_cb,
|
||||
void *cb_opaque, Error **errp);
|
||||
int qcow2_shrink_reftable(BlockDriverState *bs);
|
||||
int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
|
||||
|
||||
/* qcow2-cluster.c functions */
|
||||
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
||||
|
Loading…
Reference in New Issue
Block a user