With PREALLOC_MODE_OFF, we currently always resize the data file to the right length. This is definitely not necessary if it already has the correct length, and if @exact is false, we also don't need to shrink it.
This is what other preallocation modes already do: preallocate_co() only increases the data file size if it is too small, but never shrinks it. (And note that for raw data files, PREALLOC_MODE_OFF is silently turned into PREALLOC_MODE_METADATA, so this commit only changes behavior for non-raw external data files.) For the next commits, having all preallocation modes behave the same will make it easier to decide when we can skip taking the RESIZE permission on the data-file child. Signed-off-by: Hanna Czenczek <[email protected]> --- block/qcow2.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index e29810d86a..69d621e9bf 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -4515,15 +4515,22 @@ qcow2_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, switch (prealloc) { case PREALLOC_MODE_OFF: if (has_data_file(bs)) { + int64_t data_file_length = bdrv_co_getlength(s->data_file->bs); + /* * If the caller wants an exact resize, the external data * file should be resized to the exact target size, too, * so we pass @exact here. + * Without @exact, we leave it as-is if it is already big enough. + * Implicitly handle bdrv_co_getlength() errors by resizing. */ - ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, 0, - errp); - if (ret < 0) { - goto fail; + if (data_file_length < offset || + (exact && data_file_length != offset)) { + ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, 0, + errp); + if (ret < 0) { + goto fail; + } } } break; -- 2.52.0
