From 175dbc6a2217f7a8cf319d8da487fa80ff68eba4 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 2 Jul 2018 15:40:07 +0200 Subject: [PATCH 183/268] qcow2: Free allocated clusters on write error RH-Author: Kevin Wolf Message-id: <20180702154008.15533-3-kwolf@redhat.com> Patchwork-id: 81185 O-Subject: [RHV-7.6 qemu-kvm-rhev PATCH 2/3] qcow2: Free allocated clusters on write error Bugzilla: 1528541 RH-Acked-by: Max Reitz RH-Acked-by: Fam Zheng RH-Acked-by: Stefan Hajnoczi If we managed to allocate the clusters, but then failed to write the data, there's a good chance that we'll still be able to free the clusters again in order to avoid cluster leaks (the refcounts are cached, so even if we can't write them out right now, we may be able to do so when the VM is resumed after a werror=stop/enospc pause). Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz Reviewed-by: Eric Blake Tested-by: Eric Blake (cherry picked from commit 8b24cd141549b5b264baeddd4e72902cfb5de23b) Signed-off-by: Kevin Wolf Signed-off-by: Miroslav Rezanina --- block/qcow2-cluster.c | 11 +++++++++++ block/qcow2.c | 2 ++ block/qcow2.h | 1 + 3 files changed, 14 insertions(+) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 1aee726..c90e2ec 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -994,6 +994,17 @@ err: return ret; } +/** + * Frees the allocated clusters because the request failed and they won't + * actually be linked. + */ +void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m) +{ + BDRVQcow2State *s = bs->opaque; + qcow2_free_clusters(bs, m->alloc_offset, m->nb_clusters << s->cluster_bits, + QCOW2_DISCARD_NEVER); +} + /* * Returns the number of contiguous clusters that can be used for an allocating * write, but require COW to be performed (this includes yet unallocated space, diff --git a/block/qcow2.c b/block/qcow2.c index 4404dc7..da74e2a 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1771,6 +1771,8 @@ static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs, if (ret) { goto out; } + } else { + qcow2_alloc_cluster_abort(bs, l2meta); } /* Take the request off the list of running requests */ diff --git a/block/qcow2.h b/block/qcow2.h index adf5c39..b5e2aa3 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -618,6 +618,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, int compressed_size); int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); +void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, uint64_t bytes, enum qcow2_discard_type type, bool full_discard); -- 1.8.3.1