All of lore.kernel.org
 help / color / mirror / Atom feed
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 v3 15/27] qcow2: Add subcluster support to qcow2_get_cluster_offset()
Date: Sun, 22 Dec 2019 12:36:56 +0100	[thread overview]
Message-ID: <020909580d10ee5b9681961b52b8372ee892d35d.1577014346.git.berto@igalia.com> (raw)
In-Reply-To: <cover.1577014346.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 | 136 ++++++++++++++++++++----------------------
 block/qcow2.h         |  36 +++++------
 2 files changed, 80 insertions(+), 92 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index c6eb480ee8..c10601a828 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -372,66 +372,55 @@ 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. Allocated subclusters are required to be contiguous in
+ * the image file.
+ * At most @nb_clusters are checked (note that this means clusters,
+ * not subclusters).
  */
-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;
+    QCow2SubclusterType type =
+        qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, sc_index);
+
+    assert(type != QCOW2_SUBCLUSTER_INVALID); /* The caller should check this */
+
+    if (type == QCOW2_SUBCLUSTER_COMPRESSED) {
+        /* Compressed clusters are always processed one by one */
+        return s->subclusters_per_cluster - sc_index;
     }
 
-    /* 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_SUBCLUSTER_UNALLOCATED_PLAIN ||
+        type == QCOW2_SUBCLUSTER_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,
@@ -515,12 +504,12 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
                              QCow2SubclusterType *subcluster_type)
 {
     BDRVQcow2State *s = bs->opaque;
-    unsigned int l2_index;
-    uint64_t l1_index, l2_offset, *l2_slice;
-    int c;
+    unsigned int l2_index, sc_index;
+    uint64_t l1_index, l2_offset, *l2_slice, l2_bitmap;
+    int sc;
     unsigned int offset_in_cluster;
     uint64_t bytes_available, bytes_needed, nb_clusters;
-    QCow2ClusterType type;
+    QCow2SubclusterType type;
     int ret;
 
     offset_in_cluster = offset_into_cluster(s, offset);
@@ -570,7 +559,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
@@ -578,9 +569,9 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
      * true */
     assert(nb_clusters <= INT_MAX);
 
-    type = qcow2_get_cluster_type(bs, *cluster_offset);
-    if (s->qcow_version < 3 && (type == QCOW2_CLUSTER_ZERO_PLAIN ||
-                                type == QCOW2_CLUSTER_ZERO_ALLOC)) {
+    type = qcow2_get_subcluster_type(bs, *cluster_offset, l2_bitmap, sc_index);
+    if (s->qcow_version < 3 && (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||
+                                type == QCOW2_SUBCLUSTER_ZERO_ALLOC)) {
         qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found"
                                 " in pre-v3 image (L2 offset: %#" PRIx64
                                 ", L2 index: %#x)", l2_offset, l2_index);
@@ -588,7 +579,13 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
         goto fail;
     }
     switch (type) {
-    case QCOW2_CLUSTER_COMPRESSED:
+    case QCOW2_SUBCLUSTER_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;
+    case QCOW2_SUBCLUSTER_COMPRESSED:
         if (has_data_file(bs)) {
             qcow2_signal_corruption(bs, true, -1, -1, "Compressed cluster "
                                     "entry found in image with external data "
@@ -598,21 +595,20 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
             goto fail;
         }
         /* Compressed clusters can only be processed one by one */
-        c = 1;
+        sc = s->subclusters_per_cluster - sc_index;
         *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
         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);
+    case QCOW2_SUBCLUSTER_ZERO_PLAIN:
+    case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
+        sc = 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_SUBCLUSTER_ZERO_ALLOC:
+    case QCOW2_SUBCLUSTER_NORMAL:
+    case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC:
+        sc = 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,
@@ -641,7 +637,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)sc + sc_index) << s->subcluster_bits;
 
 out:
     if (bytes_available > bytes_needed) {
@@ -654,7 +650,7 @@ out:
     assert(bytes_available - offset_in_cluster <= UINT_MAX);
     *bytes = bytes_available - offset_in_cluster;
 
-    *subcluster_type = qcow2_cluster_to_subcluster_type(type);
+    *subcluster_type = type;
 
     return 0;
 
diff --git a/block/qcow2.h b/block/qcow2.h
index 37b7e25989..ae7973a2c2 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -651,27 +651,6 @@ static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs,
     }
 }
 
-/* For an image without extended L2 entries, return the
- * QCow2SubclusterType equivalent of a given QCow2ClusterType */
-static inline
-QCow2SubclusterType qcow2_cluster_to_subcluster_type(QCow2ClusterType type)
-{
-    switch (type) {
-    case QCOW2_CLUSTER_COMPRESSED:
-        return QCOW2_SUBCLUSTER_COMPRESSED;
-    case QCOW2_CLUSTER_ZERO_PLAIN:
-        return QCOW2_SUBCLUSTER_ZERO_PLAIN;
-    case QCOW2_CLUSTER_ZERO_ALLOC:
-        return QCOW2_SUBCLUSTER_ZERO_ALLOC;
-    case QCOW2_CLUSTER_NORMAL:
-        return QCOW2_SUBCLUSTER_NORMAL;
-    case QCOW2_CLUSTER_UNALLOCATED:
-        return QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;
-    default:
-        g_assert_not_reached();
-    }
-}
-
 /* In an image without subsclusters @l2_bitmap is ignored and
  * @sc_index must be 0. */
 static inline
@@ -720,7 +699,20 @@ QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs,
             g_assert_not_reached();
         }
     } else {
-        return qcow2_cluster_to_subcluster_type(type);
+        switch (type) {
+        case QCOW2_CLUSTER_COMPRESSED:
+            return QCOW2_SUBCLUSTER_COMPRESSED;
+        case QCOW2_CLUSTER_ZERO_PLAIN:
+            return QCOW2_SUBCLUSTER_ZERO_PLAIN;
+        case QCOW2_CLUSTER_ZERO_ALLOC:
+            return QCOW2_SUBCLUSTER_ZERO_ALLOC;
+        case QCOW2_CLUSTER_NORMAL:
+            return QCOW2_SUBCLUSTER_NORMAL;
+        case QCOW2_CLUSTER_UNALLOCATED:
+            return QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;
+        default:
+            g_assert_not_reached();
+        }
     }
 }
 
-- 
2.20.1



  parent reply	other threads:[~2019-12-22 11:59 UTC|newest]

Thread overview: 80+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-12-22 11:36 [RFC PATCH v3 00/27] Add subcluster allocation to qcow2 Alberto Garcia
2019-12-22 11:36 ` [RFC PATCH v3 01/27] qcow2: Add calculate_l2_meta() Alberto Garcia
2020-02-20 13:28   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 02/27] qcow2: Split cluster_needs_cow() out of count_cow_clusters() Alberto Garcia
2020-02-20 13:32   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 03/27] qcow2: Process QCOW2_CLUSTER_ZERO_ALLOC clusters in handle_copied() Alberto Garcia
2020-02-20 14:53   ` Eric Blake
2020-02-20 15:00   ` Max Reitz
2020-02-20 15:19   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 04/27] qcow2: Add get_l2_entry() and set_l2_entry() Alberto Garcia
2020-02-20 15:22   ` Eric Blake
2020-02-20 16:08     ` Alberto Garcia
2020-02-20 15:39   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 05/27] qcow2: Document the Extended L2 Entries feature Alberto Garcia
2020-02-20 14:28   ` Eric Blake
2020-02-20 14:49     ` Alberto Garcia
2020-02-20 15:16       ` Eric Blake
2020-02-26 16:57         ` Alberto Garcia
2020-02-20 14:33   ` Eric Blake
2020-02-20 16:10     ` Alberto Garcia
2020-02-20 15:54   ` Max Reitz
2020-02-20 16:02     ` Eric Blake
2020-02-20 16:04       ` Alberto Garcia
2019-12-22 11:36 ` [RFC PATCH v3 06/27] qcow2: Add dummy has_subclusters() function Alberto Garcia
2020-02-20 15:24   ` Eric Blake
2020-02-20 16:03   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 07/27] qcow2: Add subcluster-related fields to BDRVQcow2State Alberto Garcia
2020-02-20 15:28   ` Eric Blake
2020-02-20 16:34     ` Alberto Garcia
2020-02-20 16:48       ` Eric Blake
2020-02-21 13:14         ` Alberto Garcia
2020-02-20 16:15   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 08/27] qcow2: Add offset_to_sc_index() Alberto Garcia
2020-02-20 16:19   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 09/27] qcow2: Add l2_entry_size() Alberto Garcia
2020-02-20 16:24   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 10/27] qcow2: Update get/set_l2_entry() and add get/set_l2_bitmap() Alberto Garcia
2020-02-20 16:27   ` Max Reitz
2020-02-21 13:57     ` Alberto Garcia
2019-12-22 11:36 ` [RFC PATCH v3 11/27] qcow2: Add QCow2SubclusterType and qcow2_get_subcluster_type() Alberto Garcia
2020-02-20 17:21   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 12/27] qcow2: Replace QCOW2_CLUSTER_* with QCOW2_SUBCLUSTER_* Alberto Garcia
2020-02-21 11:35   ` Max Reitz
2020-02-21 15:14     ` Alberto Garcia
2019-12-22 11:36 ` [RFC PATCH v3 13/27] qcow2: Handle QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC Alberto Garcia
2020-02-21 12:02   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 14/27] qcow2: Add subcluster support to calculate_l2_meta() Alberto Garcia
2020-02-21 13:34   ` Max Reitz
2019-12-22 11:36 ` Alberto Garcia [this message]
2020-02-21 14:21   ` [RFC PATCH v3 15/27] qcow2: Add subcluster support to qcow2_get_cluster_offset() Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 16/27] qcow2: Add subcluster support to zero_in_l2_slice() Alberto Garcia
2020-02-21 14:37   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 17/27] qcow2: Add subcluster support to discard_in_l2_slice() Alberto Garcia
2020-02-21 14:45   ` Max Reitz
2019-12-22 11:36 ` [RFC PATCH v3 18/27] qcow2: Add subcluster support to check_refcounts_l2() Alberto Garcia
2020-02-21 14:47   ` Max Reitz
2019-12-22 11:37 ` [RFC PATCH v3 19/27] qcow2: Add subcluster support to expand_zero_clusters_in_l1() Alberto Garcia
2020-02-21 14:57   ` Max Reitz
2020-02-26 17:19     ` Alberto Garcia
2020-02-27  9:17       ` Max Reitz
2019-12-22 11:37 ` [RFC PATCH v3 20/27] qcow2: Fix offset calculation in handle_dependencies() Alberto Garcia
2020-02-21 15:01   ` Max Reitz
2019-12-22 11:37 ` [RFC PATCH v3 21/27] qcow2: Update L2 bitmap in qcow2_alloc_cluster_link_l2() Alberto Garcia
2020-02-21 15:43   ` Max Reitz
2019-12-22 11:37 ` [RFC PATCH v3 22/27] qcow2: Clear the L2 bitmap when allocating a compressed cluster Alberto Garcia
2020-02-21 15:46   ` Max Reitz
2019-12-22 11:37 ` [RFC PATCH v3 23/27] qcow2: Add subcluster support to handle_alloc_space() Alberto Garcia
2020-02-21 15:56   ` Max Reitz
2019-12-22 11:37 ` [RFC PATCH v3 24/27] qcow2: Restrict qcow2_co_pwrite_zeroes() to full clusters only Alberto Garcia
2020-02-21 16:02   ` Max Reitz
2019-12-22 11:37 ` [RFC PATCH v3 25/27] qcow2: Add the 'extended_l2' option and the QCOW2_INCOMPAT_EXTL2 bit Alberto Garcia
2020-02-20 14:12   ` Eric Blake
2020-02-20 14:16     ` Alberto Garcia
2020-02-21 16:44   ` Max Reitz
2019-12-22 11:37 ` [RFC PATCH v3 26/27] qcow2: Add subcluster support to qcow2_measure() Alberto Garcia
2020-02-21 16:52   ` Max Reitz
2019-12-22 11:37 ` [RFC PATCH v3 27/27] iotests: Add tests for qcow2 images with extended L2 entries Alberto Garcia
2020-02-21 17:04   ` Max Reitz
2020-02-21 17:10 ` [RFC PATCH v3 00/27] Add subcluster allocation to qcow2 Max Reitz
2020-02-22 17:59   ` Alberto Garcia

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=020909580d10ee5b9681961b52b8372ee892d35d.1577014346.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.