From: Alberto Garcia <berto@igalia.com>
To: qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>,
Anton Nefedov <anton.nefedov@virtuozzo.com>,
Alberto Garcia <berto@igalia.com>,
qemu-block@nongnu.org, Max Reitz <mreitz@redhat.com>,
Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>,
"Denis V . Lunev" <den@openvz.org>
Subject: [RFC PATCH v2 14/26] qcow2: Add subcluster support to qcow2_get_cluster_offset()
Date: Sun, 27 Oct 2019 00:25:16 +0300 [thread overview]
Message-ID: <6932c2ddfe19a564cad7c54246290e166525fc46.1572125022.git.berto@igalia.com> (raw)
In-Reply-To: <cover.1572125022.git.berto@igalia.com>
The logic of this function remains pretty much the same, except that
it uses count_contiguous_subclusters(), which combines the logic of
count_contiguous_clusters() / count_contiguous_clusters_unallocated()
and checks individual subclusters.
Signed-off-by: Alberto Garcia <berto@igalia.com>
---
block/qcow2-cluster.c | 111 ++++++++++++++++++++----------------------
1 file changed, 52 insertions(+), 59 deletions(-)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 990bc070af..e67559152f 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -372,66 +372,51 @@ fail:
}
/*
- * 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
- * to the first cluster, the search is stopped and the cluster is not counted
- * as contiguous. (This allows it, for example, to stop at the first compressed
- * cluster which may require a different handling)
+ * Return the number of contiguous subclusters of the exact same type
+ * in a given L2 slice, starting from cluster @l2_index, subcluster
+ * @sc_index. At most @nb_clusters are checked. Allocated clusters are
+ * also required to be contiguous in the image file.
*/
-static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters,
- int cluster_size, uint64_t *l2_slice, int l2_index, uint64_t stop_flags)
+static int count_contiguous_subclusters(BlockDriverState *bs, int nb_clusters,
+ unsigned sc_index, uint64_t *l2_slice,
+ int l2_index)
{
BDRVQcow2State *s = bs->opaque;
- int i;
- QCow2ClusterType first_cluster_type;
- uint64_t mask = stop_flags | L2E_OFFSET_MASK | QCOW_OFLAG_COMPRESSED;
- uint64_t first_entry = get_l2_entry(s, l2_slice, l2_index);
- uint64_t offset = first_entry & mask;
-
- first_cluster_type = qcow2_get_cluster_type(bs, first_entry);
- if (first_cluster_type == QCOW2_CLUSTER_UNALLOCATED) {
- return 0;
+ int i, j, count = 0;
+ uint64_t l2_entry = get_l2_entry(s, l2_slice, l2_index);
+ uint64_t l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index);
+ uint64_t expected_offset = l2_entry & L2E_OFFSET_MASK;
+ bool check_offset = true;
+ QCow2ClusterType type =
+ qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, sc_index);
+
+ assert(type != QCOW2_CLUSTER_INVALID); /* The caller should check this */
+
+ if (type == QCOW2_CLUSTER_COMPRESSED) {
+ return 1; /* Compressed clusters are always counted one by one */
}
- /* must be allocated */
- assert(first_cluster_type == QCOW2_CLUSTER_NORMAL ||
- first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC);
-
- for (i = 0; i < nb_clusters; i++) {
- uint64_t l2_entry = get_l2_entry(s, l2_slice, l2_index + i) & mask;
- if (offset + (uint64_t) i * cluster_size != l2_entry) {
- break;
- }
+ if (type == QCOW2_CLUSTER_UNALLOCATED || type == QCOW2_CLUSTER_ZERO_PLAIN) {
+ check_offset = false;
}
- return i;
-}
-
-/*
- * Checks how many consecutive unallocated clusters in a given L2
- * slice have the same cluster type.
- */
-static int count_contiguous_clusters_unallocated(BlockDriverState *bs,
- int nb_clusters,
- uint64_t *l2_slice,
- int l2_index,
- QCow2ClusterType wanted_type)
-{
- BDRVQcow2State *s = bs->opaque;
- int i;
-
- assert(wanted_type == QCOW2_CLUSTER_ZERO_PLAIN ||
- wanted_type == QCOW2_CLUSTER_UNALLOCATED);
for (i = 0; i < nb_clusters; i++) {
- uint64_t entry = get_l2_entry(s, l2_slice, l2_index + i);
- QCow2ClusterType type = qcow2_get_cluster_type(bs, entry);
-
- if (type != wanted_type) {
- break;
+ l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
+ l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
+ if (check_offset && expected_offset != (l2_entry & L2E_OFFSET_MASK)) {
+ goto out;
+ }
+ for (j = (i == 0) ? sc_index : 0; j < s->subclusters_per_cluster; j++) {
+ if (qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, j) != type) {
+ goto out;
+ }
+ count++;
}
+ expected_offset += s->cluster_size;
}
- return i;
+out:
+ return count;
}
static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
@@ -514,8 +499,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *cluster_offset)
{
BDRVQcow2State *s = bs->opaque;
- unsigned int l2_index;
- uint64_t l1_index, l2_offset, *l2_slice;
+ unsigned int l2_index, sc_index;
+ uint64_t l1_index, l2_offset, *l2_slice, l2_bitmap;
int c;
unsigned int offset_in_cluster;
uint64_t bytes_available, bytes_needed, nb_clusters;
@@ -569,7 +554,9 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
/* find the cluster offset for the given disk offset */
l2_index = offset_to_l2_slice_index(s, offset);
+ sc_index = offset_to_sc_index(s, offset);
*cluster_offset = get_l2_entry(s, l2_slice, l2_index);
+ l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index);
nb_clusters = size_to_clusters(s, bytes_needed);
/* bytes_needed <= *bytes + offset_in_cluster, both of which are unsigned
@@ -577,7 +564,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
* true */
assert(nb_clusters <= INT_MAX);
- type = qcow2_get_cluster_type(bs, *cluster_offset);
+ type = qcow2_get_subcluster_type(bs, *cluster_offset, l2_bitmap, sc_index);
if (s->qcow_version < 3 && (type == QCOW2_CLUSTER_ZERO_PLAIN ||
type == QCOW2_CLUSTER_ZERO_ALLOC)) {
qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found"
@@ -587,6 +574,13 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
goto fail;
}
switch (type) {
+ case QCOW2_CLUSTER_INVALID:
+ qcow2_signal_corruption(bs, true, -1, -1, "Invalid cluster entry found "
+ " (L2 offset: %#" PRIx64 ", L2 index: %#x)",
+ l2_offset, l2_index);
+ ret = -EIO;
+ goto fail;
+ break;
case QCOW2_CLUSTER_COMPRESSED:
if (has_data_file(bs)) {
qcow2_signal_corruption(bs, true, -1, -1, "Compressed cluster "
@@ -602,16 +596,15 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
break;
case QCOW2_CLUSTER_ZERO_PLAIN:
case QCOW2_CLUSTER_UNALLOCATED:
- /* how many empty clusters ? */
- c = count_contiguous_clusters_unallocated(bs, nb_clusters,
- l2_slice, l2_index, type);
+ c = count_contiguous_subclusters(bs, nb_clusters, sc_index,
+ l2_slice, l2_index);
*cluster_offset = 0;
break;
case QCOW2_CLUSTER_ZERO_ALLOC:
case QCOW2_CLUSTER_NORMAL:
- /* how many allocated clusters ? */
- c = count_contiguous_clusters(bs, nb_clusters, s->cluster_size,
- l2_slice, l2_index, QCOW_OFLAG_ZERO);
+ case QCOW2_CLUSTER_UNALLOCATED_SUBCLUSTER:
+ c = count_contiguous_subclusters(bs, nb_clusters, sc_index,
+ l2_slice, l2_index);
*cluster_offset &= L2E_OFFSET_MASK;
if (offset_into_cluster(s, *cluster_offset)) {
qcow2_signal_corruption(bs, true, -1, -1,
@@ -640,7 +633,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
- bytes_available = (int64_t)c * s->cluster_size;
+ bytes_available = ((int64_t)c + sc_index) * s->subcluster_size;
out:
if (bytes_available > bytes_needed) {
--
2.20.1
next prev parent reply other threads:[~2019-10-26 21:37 UTC|newest]
Thread overview: 65+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-26 21:25 [RFC PATCH v2 00/26] Add subcluster allocation to qcow2 Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 01/26] qcow2: Add calculate_l2_meta() Alberto Garcia
2019-10-28 12:50 ` Vladimir Sementsov-Ogievskiy
2019-10-30 15:56 ` Alberto Garcia
2019-10-30 12:04 ` Max Reitz
2019-10-30 16:02 ` Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 02/26] qcow2: Split cluster_needs_cow() out of count_cow_clusters() Alberto Garcia
2019-10-28 13:55 ` Vladimir Sementsov-Ogievskiy
2019-10-26 21:25 ` [RFC PATCH v2 03/26] qcow2: Process QCOW2_CLUSTER_ZERO_ALLOC clusters in handle_copied() Alberto Garcia
2019-10-30 14:24 ` Max Reitz
2019-11-13 14:25 ` Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 04/26] qcow2: Add get_l2_entry() and set_l2_entry() Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 05/26] qcow2: Document the Extended L2 Entries feature Alberto Garcia
2019-10-30 16:23 ` Max Reitz
2019-10-30 22:38 ` Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 06/26] qcow2: Add dummy has_subclusters() function Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 07/26] qcow2: Add subcluster-related fields to BDRVQcow2State Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 08/26] qcow2: Add offset_to_sc_index() Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 09/26] qcow2: Add l2_entry_size() Alberto Garcia
2019-10-30 16:47 ` Max Reitz
2019-10-26 21:25 ` [RFC PATCH v2 10/26] qcow2: Update get/set_l2_entry() and add get/set_l2_bitmap() Alberto Garcia
2019-10-30 16:55 ` Max Reitz
2019-11-14 13:57 ` Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 11/26] qcow2: Add qcow2_get_subcluster_type() Alberto Garcia
2019-11-04 12:35 ` Max Reitz
2019-11-04 15:01 ` Max Reitz
2019-10-26 21:25 ` [RFC PATCH v2 12/26] qcow2: Handle QCOW2_CLUSTER_UNALLOCATED_SUBCLUSTER Alberto Garcia
2019-11-04 12:57 ` Max Reitz
2019-11-04 13:03 ` Alberto Garcia
2019-11-04 13:10 ` Max Reitz
2019-11-07 14:44 ` Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 13/26] qcow2: Add subcluster support to calculate_l2_meta() Alberto Garcia
2019-11-04 14:21 ` Max Reitz
2019-11-08 15:18 ` Alberto Garcia
2019-10-26 21:25 ` Alberto Garcia [this message]
2019-11-04 14:58 ` [RFC PATCH v2 14/26] qcow2: Add subcluster support to qcow2_get_cluster_offset() Max Reitz
2019-11-08 15:42 ` Alberto Garcia
2019-11-11 8:42 ` Max Reitz
2019-10-26 21:25 ` [RFC PATCH v2 15/26] qcow2: Add subcluster support to zero_in_l2_slice() Alberto Garcia
2019-11-04 15:04 ` Max Reitz
2019-11-04 15:10 ` Max Reitz
2019-11-14 15:31 ` Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 16/26] qcow2: Add subcluster support to discard_in_l2_slice() Alberto Garcia
2019-11-04 15:07 ` Max Reitz
2019-11-14 15:33 ` Alberto Garcia
2019-11-14 16:22 ` Max Reitz
2019-10-26 21:25 ` [RFC PATCH v2 17/26] qcow2: Add subcluster support to check_refcounts_l2() Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 18/26] qcow2: Add subcluster support to expand_zero_clusters_in_l1() Alberto Garcia
2019-11-05 11:05 ` Max Reitz
2019-11-14 15:43 ` Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 19/26] qcow2: Fix offset calculation in handle_dependencies() Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 20/26] qcow2: Update L2 bitmap in qcow2_alloc_cluster_link_l2() Alberto Garcia
2019-11-05 11:43 ` Max Reitz
2019-11-14 16:30 ` Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 21/26] qcow2: Clear the L2 bitmap when allocating a compressed cluster Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 22/26] qcow2: Add subcluster support to handle_alloc_space() Alberto Garcia
2019-11-05 12:05 ` Max Reitz
2019-10-26 21:25 ` [RFC PATCH v2 23/26] qcow2: Restrict qcow2_co_pwrite_zeroes() to full clusters only Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 24/26] qcow2: Add the 'extended_l2' option and the QCOW2_INCOMPAT_EXTL2 bit Alberto Garcia
2019-11-05 12:47 ` Max Reitz
2019-11-15 13:35 ` Alberto Garcia
2019-10-26 21:25 ` [RFC PATCH v2 25/26] qcow2: Allow preallocation and backing files if extended_l2 is set Alberto Garcia
2019-11-05 13:11 ` Max Reitz
2019-10-26 21:25 ` [RFC PATCH v2 26/26] iotests: Add tests for qcow2 images with extended L2 entries Alberto Garcia
2019-11-05 13:32 ` [RFC PATCH v2 00/26] Add subcluster allocation to qcow2 Max Reitz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=6932c2ddfe19a564cad7c54246290e166525fc46.1572125022.git.berto@igalia.com \
--to=berto@igalia.com \
--cc=anton.nefedov@virtuozzo.com \
--cc=den@openvz.org \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=vsementsov@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).