Add helper to parse compressed l2_entry and use it everywhere instead
of opencoding.
Note, that in most places we move to precise coffset/csize instead of
sector-aligned. Still it should work good enough for updating
refcounts.
Signed-off-by: Vladimir Sementsov-Ogievskiy
---
block/qcow2.h | 3 ++-
block/qcow2-cluster.c | 15 +++
block/qcow2-refcount.c | 36 +---
block/qcow2.c | 9 ++---
4 files changed, 36 insertions(+), 27 deletions(-)
diff --git a/block/qcow2.h b/block/qcow2.h
index 42a0058ab7..c0e1e83796 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -110,7 +110,6 @@
/* Defined in the qcow2 spec (compressed cluster descriptor) */
#define QCOW2_COMPRESSED_SECTOR_SIZE 512U
-#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1ULL))
/* Must be at least 2 to cover COW */
#define MIN_L2_CACHE_SIZE 2 /* cache entries */
@@ -913,6 +912,8 @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState
*bs,
uint64_t offset,
int compressed_size,
uint64_t *host_offset);
+void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
+ uint64_t *coffset, int *csize);
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 04735ee439..70d0570a33 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -2462,3 +2462,18 @@ fail:
g_free(l1_table);
return ret;
}
+
+void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
+ uint64_t *coffset, int *csize)
+{
+BDRVQcow2State *s = bs->opaque;
+int nb_csectors;
+
+assert(qcow2_get_cluster_type(bs, l2_entry) == QCOW2_CLUSTER_COMPRESSED);
+
+*coffset = l2_entry & s->cluster_offset_mask;
+
+nb_csectors = ((l2_entry >> s->csize_shift) & s->csize_mask) + 1;
+*csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
+(*coffset & (QCOW2_COMPRESSED_SECTOR_SIZE - 1));
+}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 2734338625..66cbb94ef9 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1177,11 +1177,11 @@ void qcow2_free_any_cluster(BlockDriverState *bs,
uint64_t l2_entry,
switch (ctype) {
case QCOW2_CLUSTER_COMPRESSED:
{
-int64_t offset = (l2_entry & s->cluster_offset_mask)
-& QCOW2_COMPRESSED_SECTOR_MASK;
-int size = QCOW2_COMPRESSED_SECTOR_SIZE *
-(((l2_entry >> s->csize_shift) & s->csize_mask) + 1);
-qcow2_free_clusters(bs, offset, size, type);
+uint64_t coffset;
+int csize;
+
+qcow2_parse_compressed_l2_entry(bs, l2_entry, , );
+qcow2_free_clusters(bs, coffset, csize, type);
}
break;
case QCOW2_CLUSTER_NORMAL:
@@ -1247,7 +1247,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
bool l1_allocated = false;
int64_t old_entry, old_l2_offset;
unsigned slice, slice_size2, n_slices;
-int i, j, l1_modified = 0, nb_csectors;
+int i, j, l1_modified = 0;
int ret;
assert(addend >= -1 && addend <= 1);
@@ -1318,14 +1318,14 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
switch (qcow2_get_cluster_type(bs, entry)) {
case QCOW2_CLUSTER_COMPRESSED:
-nb_csectors = ((entry >> s->csize_shift) &
- s->csize_mask) + 1;
if (addend != 0) {
-uint64_t coffset = (entry & s->cluster_offset_mask)
-& QCOW2_COMPRESSED_SECTOR_MASK;
+uint64_t coffset;
+int csize;
+
+qcow2_parse_compressed_l2_entry(bs, entry,
+, );
ret = update_refcount(
-bs, coffset,
-nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE,
+bs, coffset, csize,
abs(addend), addend < 0,
QCOW2_DISCARD_SNAPSHOT);
if (ret < 0) {
@@ -1603,7 +1603,7 @@ static int check_refcounts_l2(BlockDriverState *bs,
BdrvCheckResult *res,
BDRVQcow2State *s = bs->opaque;
uint64_t l2_entry;
uint64_t next_contiguous_offset = 0;
-int i, nb_csectors, ret;
+int i, ret;
size_t l2_size_bytes = s->l2_size * l2_entry_size(s);
g_autofree uint64_t *l2_table = g_malloc(l2_size_bytes);
@@ -1617,6 +1617,8 @@ static int