diff options
author | Vincent Vanlaer <libvirt-e6954efa@volkihar.be> | 2024-10-26 18:30:08 +0200 |
---|---|---|
committer | Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | 2025-05-01 12:12:19 +0300 |
commit | 6f3199f99600fe75f32f78574e507f347de80854 (patch) | |
tree | a92da05a341938734993f83626d9563ffffdc956 | |
parent | 0648c76ad198e91515771fbbeaac3a3807669a4a (diff) | |
download | qemu-6f3199f99600fe75f32f78574e507f347de80854.zip qemu-6f3199f99600fe75f32f78574e507f347de80854.tar.gz qemu-6f3199f99600fe75f32f78574e507f347de80854.tar.bz2 |
block: allow commit to unmap zero blocks
Non-active block commits do not discard blocks only containing zeros,
causing images to lose sparseness after the commit. This commit fixes
that by writing zero blocks using blk_co_pwrite_zeroes rather than
writing them out as any other arbitrary data.
Signed-off-by: Vincent Vanlaer <libvirt-e6954efa@volkihar.be>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Message-Id: <20241026163010.2865002-5-libvirt-e6954efa@volkihar.be>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
-rw-r--r-- | block/commit.c | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/block/commit.c b/block/commit.c index 5c6596a..7cc8c0f 100644 --- a/block/commit.c +++ b/block/commit.c @@ -150,19 +150,39 @@ static int commit_iteration(CommitBlockJob *s, int64_t offset, } if (ret & BDRV_BLOCK_ALLOCATED) { - assert(bytes < SIZE_MAX); + if (ret & BDRV_BLOCK_ZERO) { + /* + * If the top (sub)clusters are smaller than the base + * (sub)clusters, this will not unmap unless the underlying device + * does some tracking of these requests. Ideally, we would find + * the maximal extent of the zero clusters. + */ + ret = blk_co_pwrite_zeroes(s->base, offset, bytes, + BDRV_REQ_MAY_UNMAP); + if (ret < 0) { + error_in_source = false; + goto fail; + } + } else { + assert(bytes < SIZE_MAX); - ret = blk_co_pread(s->top, offset, bytes, buf, 0); - if (ret < 0) { - goto fail; - } + ret = blk_co_pread(s->top, offset, bytes, buf, 0); + if (ret < 0) { + goto fail; + } - ret = blk_co_pwrite(s->base, offset, bytes, buf, 0); - if (ret < 0) { - error_in_source = false; - goto fail; + ret = blk_co_pwrite(s->base, offset, bytes, buf, 0); + if (ret < 0) { + error_in_source = false; + goto fail; + } } + /* + * Whether zeroes actually end up on disk depends on the details of + * the underlying driver. Therefore, this might rate limit more than + * is necessary. + */ block_job_ratelimit_processed_bytes(&s->common, bytes); } |