* [PATCH] qcow2: Fix preallocation on block devices
@ 2020-05-05 14:18 Max Reitz
2020-05-07 8:39 ` Kevin Wolf
0 siblings, 1 reply; 2+ messages in thread
From: Max Reitz @ 2020-05-05 14:18 UTC (permalink / raw)
To: qemu-block; +Cc: Kevin Wolf, qemu-devel, Max Reitz
Calling bdrv_getlength() to get the pre-truncate file size will not
really work on block devices, because they have always the same length,
and trying to write beyond it will fail with a rather cryptic error
message.
Instead, we should use qcow2_get_last_cluster() and bdrv_getlength()
only as a fallback.
Before this patch:
$ truncate -s 1G test.img
$ sudo losetup -f --show test.img
/dev/loop0
$ sudo qemu-img create -f qcow2 -o preallocation=full /dev/loop0 64M
Formatting '/dev/loop0', fmt=qcow2 size=67108864 cluster_size=65536
preallocation=full lazy_refcounts=off refcount_bits=16
qemu-img: /dev/loop0: Could not resize image: Failed to resize refcount
structures: No space left on device
With this patch:
$ sudo qemu-img create -f qcow2 -o preallocation=full /dev/loop0 64M
Formatting '/dev/loop0', fmt=qcow2 size=67108864 cluster_size=65536
preallocation=full lazy_refcounts=off refcount_bits=16
qemu-img: /dev/loop0: Could not resize image: Failed to resize
underlying file: Preallocation mode 'full' unsupported for this
non-regular file
So as you can see, it still fails, but now the problem is missing
support on the block device level, so we at least get a better error
message.
Note that we cannot preallocate block devices on truncate by design,
because we do not know what area to preallocate. Their length is always
the same, the truncate operation does not change it.
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
block/qcow2.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/block/qcow2.c b/block/qcow2.c
index ad934109a8..c1a9edd6dc 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -4107,7 +4107,7 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
{
int64_t allocation_start, host_offset, guest_offset;
int64_t clusters_allocated;
- int64_t old_file_size, new_file_size;
+ int64_t old_file_size, last_cluster, new_file_size;
uint64_t nb_new_data_clusters, nb_new_l2_tables;
/* With a data file, preallocation means just allocating the metadata
@@ -4127,7 +4127,13 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
ret = old_file_size;
goto fail;
}
- old_file_size = ROUND_UP(old_file_size, s->cluster_size);
+
+ last_cluster = qcow2_get_last_cluster(bs, old_file_size);
+ if (last_cluster >= 0) {
+ old_file_size = (last_cluster + 1) * s->cluster_size;
+ } else {
+ old_file_size = ROUND_UP(old_file_size, s->cluster_size);
+ }
nb_new_data_clusters = DIV_ROUND_UP(offset - old_length,
s->cluster_size);
--
2.26.2
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] qcow2: Fix preallocation on block devices
2020-05-05 14:18 [PATCH] qcow2: Fix preallocation on block devices Max Reitz
@ 2020-05-07 8:39 ` Kevin Wolf
0 siblings, 0 replies; 2+ messages in thread
From: Kevin Wolf @ 2020-05-07 8:39 UTC (permalink / raw)
To: Max Reitz; +Cc: qemu-devel, qemu-block
Am 05.05.2020 um 16:18 hat Max Reitz geschrieben:
> Calling bdrv_getlength() to get the pre-truncate file size will not
> really work on block devices, because they have always the same length,
> and trying to write beyond it will fail with a rather cryptic error
> message.
>
> Instead, we should use qcow2_get_last_cluster() and bdrv_getlength()
> only as a fallback.
>
> Before this patch:
> $ truncate -s 1G test.img
> $ sudo losetup -f --show test.img
> /dev/loop0
> $ sudo qemu-img create -f qcow2 -o preallocation=full /dev/loop0 64M
> Formatting '/dev/loop0', fmt=qcow2 size=67108864 cluster_size=65536
> preallocation=full lazy_refcounts=off refcount_bits=16
> qemu-img: /dev/loop0: Could not resize image: Failed to resize refcount
> structures: No space left on device
>
> With this patch:
> $ sudo qemu-img create -f qcow2 -o preallocation=full /dev/loop0 64M
> Formatting '/dev/loop0', fmt=qcow2 size=67108864 cluster_size=65536
> preallocation=full lazy_refcounts=off refcount_bits=16
> qemu-img: /dev/loop0: Could not resize image: Failed to resize
> underlying file: Preallocation mode 'full' unsupported for this
> non-regular file
>
> So as you can see, it still fails, but now the problem is missing
> support on the block device level, so we at least get a better error
> message.
>
> Note that we cannot preallocate block devices on truncate by design,
> because we do not know what area to preallocate. Their length is always
> the same, the truncate operation does not change it.
>
> Signed-off-by: Max Reitz <mreitz@redhat.com>
Thanks, applied to the block branch.
Kevin
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2020-05-07 8:40 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-05-05 14:18 [PATCH] qcow2: Fix preallocation on block devices Max Reitz
2020-05-07 8:39 ` Kevin Wolf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).