qcow2: Add qcow2_get_subcluster_range_type()

There are situations in which we want to know how many contiguous
subclusters of the same type there are in a given cluster. This can be
done by simply iterating over the subclusters and repeatedly calling
qcow2_get_subcluster_type() for each one of them.

However once we determined the type of a subcluster we can check the
rest efficiently by counting the number of adjacent ones (or zeroes)
in the bitmap. This is what this function does.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-Id: <db917263d568ec6ffb4a41cac3c9100f96bf6c18.1594396418.git.berto@igalia.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
Alberto Garcia 2020-07-10 18:12:57 +02:00 committed by Max Reitz
parent 34905d8eb1
commit 70d1cbae03

View File

@ -375,6 +375,57 @@ fail:
return ret;
}
/*
* For a given L2 entry, count the number of contiguous subclusters of
* the same type starting from @sc_from. Compressed clusters are
* treated as if they were divided into subclusters of size
* s->subcluster_size.
*
* Return the number of contiguous subclusters and set @type to the
* subcluster type.
*
* If the L2 entry is invalid return -errno and set @type to
* QCOW2_SUBCLUSTER_INVALID.
*/
G_GNUC_UNUSED
static int qcow2_get_subcluster_range_type(BlockDriverState *bs,
uint64_t l2_entry,
uint64_t l2_bitmap,
unsigned sc_from,
QCow2SubclusterType *type)
{
BDRVQcow2State *s = bs->opaque;
uint32_t val;
*type = qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, sc_from);
if (*type == QCOW2_SUBCLUSTER_INVALID) {
return -EINVAL;
} else if (!has_subclusters(s) || *type == QCOW2_SUBCLUSTER_COMPRESSED) {
return s->subclusters_per_cluster - sc_from;
}
switch (*type) {
case QCOW2_SUBCLUSTER_NORMAL:
val = l2_bitmap | QCOW_OFLAG_SUB_ALLOC_RANGE(0, sc_from);
return cto32(val) - sc_from;
case QCOW2_SUBCLUSTER_ZERO_PLAIN:
case QCOW2_SUBCLUSTER_ZERO_ALLOC:
val = (l2_bitmap | QCOW_OFLAG_SUB_ZERO_RANGE(0, sc_from)) >> 32;
return cto32(val) - sc_from;
case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
val = ((l2_bitmap >> 32) | l2_bitmap)
& ~QCOW_OFLAG_SUB_ALLOC_RANGE(0, sc_from);
return ctz32(val) - sc_from;
default:
g_assert_not_reached();
}
}
/*
* Checks how many clusters in a given L2 slice are contiguous in the image
* file. As soon as one of the flags in the bitmask stop_flags changes compared