Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/1307033/?format=api
{ "id": 1307033, "url": "http://patchwork.ozlabs.org/api/patches/1307033/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/e5e12a2aec11aa344aa331b5f418529368d45e12.1591801197.git.berto@igalia.com/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api", "name": "QEMU Development", "link_name": "qemu-devel", "list_id": "qemu-devel.nongnu.org", "list_email": "qemu-devel@nongnu.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<e5e12a2aec11aa344aa331b5f418529368d45e12.1591801197.git.berto@igalia.com>", "list_archive_url": null, "date": "2020-06-10T15:02:59", "name": "[v8,21/34] qcow2: Add subcluster support to qcow2_get_host_offset()", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "a3ec7696a9f18f5a33b66dabe161a54630411ee3", "submitter": { "id": 65704, "url": "http://patchwork.ozlabs.org/api/people/65704/?format=api", "name": "Alberto Garcia", "email": "berto@igalia.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/e5e12a2aec11aa344aa331b5f418529368d45e12.1591801197.git.berto@igalia.com/mbox/", "series": [ { "id": 182563, "url": "http://patchwork.ozlabs.org/api/series/182563/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=182563", "date": "2020-06-10T15:02:49", "name": "Add subcluster allocation to qcow2", "version": 8, "mbox": "http://patchwork.ozlabs.org/series/182563/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/1307033/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/1307033/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": [ "ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=<UNKNOWN>)", "ozlabs.org;\n dmarc=none (p=none dis=none) header.from=igalia.com", "ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n unprotected) header.d=igalia.com header.i=@igalia.com header.a=rsa-sha256\n header.s=20170329 header.b=dXV4Stkl;\n\tdkim-atps=neutral" ], "Received": [ "from lists.gnu.org (lists.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 49hrT61Vp0z9sQx\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 11 Jun 2020 01:27:22 +1000 (AEST)", "from localhost ([::1]:38292 helo=lists1p.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1jj2dL-0002ur-PM\n\tfor incoming@patchwork.ozlabs.org; Wed, 10 Jun 2020 11:27:19 -0400", "from eggs.gnu.org ([2001:470:142:3::10]:36188)\n by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <berto@igalia.com>)\n id 1jj2H4-0002ot-6D; Wed, 10 Jun 2020 11:04:18 -0400", "from fanzine.igalia.com ([178.60.130.6]:58237)\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.90_1) (envelope-from <berto@igalia.com>)\n id 1jj2Gs-0006wV-LU; Wed, 10 Jun 2020 11:04:15 -0400", "from [81.0.38.199] (helo=perseus.local)\n by fanzine.igalia.com with esmtpsa\n (Cipher TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim)\n id 1jj2GR-0007h1-MX; Wed, 10 Jun 2020 17:03:39 +0200", "from berto by perseus.local with local (Exim 4.92)\n (envelope-from <berto@igalia.com>)\n id 1jj2GC-0007NN-9Q; Wed, 10 Jun 2020 17:03:24 +0200" ], "DKIM-Signature": "v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com;\n s=20170329;\n h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From;\n bh=HX/BNY9+fnF3/IdpMYeBixighVMLrzZ1bFMk4+G70IU=;\n b=dXV4Stkl/KnM30XvDXpUp6kg1kb89n4EaV7fpGcVRzqOgupcTDnLLZfMlZ9QOb6w/Evzl+z34qu8Yb1tKAnyNQDShm5dZaKamA8cBaqtCLAh4oKlPPBtuMdaxUKabj7Zkbvviyflq0NG/znvNJ0vC7rqfx8I77WF8/fYaje2old+2ibiOTBrBuq9/qMy9aeqv2RLledLrMgXGVBcs99SLZkQhXM5jGYrBkPVrnscwuIy1qcoR+pvuHaUlesNfAl5MZnKM4Nbxak65s36BhW1RMVzxY3X1vKXFSZm7pmNSYMbcW0ZiM1st7XBj7H6r3owybR+4+WzZk2kiEJ/L6j4Tg==;", "From": "Alberto Garcia <berto@igalia.com>", "To": "qemu-devel@nongnu.org", "Subject": "[PATCH v8 21/34] qcow2: Add subcluster support to\n qcow2_get_host_offset()", "Date": "Wed, 10 Jun 2020 17:02:59 +0200", "Message-Id": "\n <e5e12a2aec11aa344aa331b5f418529368d45e12.1591801197.git.berto@igalia.com>", "X-Mailer": "git-send-email 2.20.1", "In-Reply-To": "<cover.1591801197.git.berto@igalia.com>", "References": "<cover.1591801197.git.berto@igalia.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Received-SPF": "pass client-ip=178.60.130.6; envelope-from=berto@igalia.com;\n helo=fanzine.igalia.com", "X-detected-operating-system": "by eggs.gnu.org: First seen = 2020/06/10 11:03:39", "X-ACL-Warn": "Detected OS = Linux 2.2.x-3.x (no timestamps) [generic] [fuzzy]", "X-Spam_score_int": "-20", "X-Spam_score": "-2.1", "X-Spam_bar": "--", "X-Spam_report": "(-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,\n DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001,\n SPF_PASS=-0.001 autolearn=_AUTOLEARN", "X-Spam_action": "no action", "X-BeenThere": "qemu-devel@nongnu.org", "X-Mailman-Version": "2.1.23", "Precedence": "list", "List-Id": "<qemu-devel.nongnu.org>", "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>", "List-Archive": "<https://lists.nongnu.org/archive/html/qemu-devel>", "List-Post": "<mailto:qemu-devel@nongnu.org>", "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>", "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>", "Cc": "Kevin Wolf <kwolf@redhat.com>,\n Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>,\n Alberto Garcia <berto@igalia.com>, qemu-block@nongnu.org,\n Derek Su <dereksu@qnap.com>, Max Reitz <mreitz@redhat.com>", "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org", "Sender": "\"Qemu-devel\"\n <qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>" }, "content": "The logic of this function remains pretty much the same, except that\nit uses count_contiguous_subclusters(), which combines the logic of\ncount_contiguous_clusters() / count_contiguous_clusters_unallocated()\nand checks individual subclusters.\n\nqcow2_cluster_to_subcluster_type() is not necessary as a separate\nfunction anymore so it's inlined into its caller.\n\nSigned-off-by: Alberto Garcia <berto@igalia.com>\nReviewed-by: Eric Blake <eblake@redhat.com>\n---\n block/qcow2.h | 38 ++++-------\n block/qcow2-cluster.c | 150 ++++++++++++++++++++++--------------------\n 2 files changed, 92 insertions(+), 96 deletions(-)", "diff": "diff --git a/block/qcow2.h b/block/qcow2.h\nindex 5df761edc3..4fad40b96b 100644\n--- a/block/qcow2.h\n+++ b/block/qcow2.h\n@@ -710,29 +710,6 @@ static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs,\n }\n }\n \n-/*\n- * For an image without extended L2 entries, return the\n- * QCow2SubclusterType equivalent of a given QCow2ClusterType.\n- */\n-static inline\n-QCow2SubclusterType qcow2_cluster_to_subcluster_type(QCow2ClusterType type)\n-{\n- switch (type) {\n- case QCOW2_CLUSTER_COMPRESSED:\n- return QCOW2_SUBCLUSTER_COMPRESSED;\n- case QCOW2_CLUSTER_ZERO_PLAIN:\n- return QCOW2_SUBCLUSTER_ZERO_PLAIN;\n- case QCOW2_CLUSTER_ZERO_ALLOC:\n- return QCOW2_SUBCLUSTER_ZERO_ALLOC;\n- case QCOW2_CLUSTER_NORMAL:\n- return QCOW2_SUBCLUSTER_NORMAL;\n- case QCOW2_CLUSTER_UNALLOCATED:\n- return QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;\n- default:\n- g_assert_not_reached();\n- }\n-}\n-\n /*\n * In an image without subsclusters @l2_bitmap is ignored and\n * @sc_index must be 0.\n@@ -776,7 +753,20 @@ QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs,\n g_assert_not_reached();\n }\n } else {\n- return qcow2_cluster_to_subcluster_type(type);\n+ switch (type) {\n+ case QCOW2_CLUSTER_COMPRESSED:\n+ return QCOW2_SUBCLUSTER_COMPRESSED;\n+ case QCOW2_CLUSTER_ZERO_PLAIN:\n+ return QCOW2_SUBCLUSTER_ZERO_PLAIN;\n+ case QCOW2_CLUSTER_ZERO_ALLOC:\n+ return QCOW2_SUBCLUSTER_ZERO_ALLOC;\n+ case QCOW2_CLUSTER_NORMAL:\n+ return QCOW2_SUBCLUSTER_NORMAL;\n+ case QCOW2_CLUSTER_UNALLOCATED:\n+ return QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;\n+ default:\n+ g_assert_not_reached();\n+ }\n }\n }\n \ndiff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c\nindex 59dd9bda29..2f3bd3a882 100644\n--- a/block/qcow2-cluster.c\n+++ b/block/qcow2-cluster.c\n@@ -426,66 +426,66 @@ static int qcow2_get_subcluster_range_type(BlockDriverState *bs,\n }\n \n /*\n- * Checks how many clusters in a given L2 slice are contiguous in the image\n- * file. As soon as one of the flags in the bitmask stop_flags changes compared\n- * to the first cluster, the search is stopped and the cluster is not counted\n- * as contiguous. (This allows it, for example, to stop at the first compressed\n- * cluster which may require a different handling)\n+ * Return the number of contiguous subclusters of the exact same type\n+ * in a given L2 slice, starting from cluster @l2_index, subcluster\n+ * @sc_index. Allocated subclusters are required to be contiguous in\n+ * the image file.\n+ * At most @nb_clusters are checked (note that this means clusters,\n+ * not subclusters).\n+ * Compressed clusters are always processed one by one but for the\n+ * purpose of this count they are treated as if they were divided into\n+ * subclusters of size s->subcluster_size.\n+ * On failure return -errno and update @l2_index to point to the\n+ * invalid entry.\n */\n-static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters,\n- int cluster_size, uint64_t *l2_slice, int l2_index, uint64_t stop_flags)\n+static int count_contiguous_subclusters(BlockDriverState *bs, int nb_clusters,\n+ unsigned sc_index, uint64_t *l2_slice,\n+ unsigned *l2_index)\n {\n BDRVQcow2State *s = bs->opaque;\n- int i;\n- QCow2ClusterType first_cluster_type;\n- uint64_t mask = stop_flags | L2E_OFFSET_MASK | QCOW_OFLAG_COMPRESSED;\n- uint64_t first_entry = get_l2_entry(s, l2_slice, l2_index);\n- uint64_t offset = first_entry & mask;\n+ int i, count = 0;\n+ bool check_offset;\n+ uint64_t expected_offset;\n+ QCow2SubclusterType expected_type, type;\n \n- first_cluster_type = qcow2_get_cluster_type(bs, first_entry);\n- if (first_cluster_type == QCOW2_CLUSTER_UNALLOCATED) {\n- return 0;\n- }\n-\n- /* must be allocated */\n- assert(first_cluster_type == QCOW2_CLUSTER_NORMAL ||\n- first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC);\n+ assert(*l2_index + nb_clusters <= s->l2_size);\n \n for (i = 0; i < nb_clusters; i++) {\n- uint64_t l2_entry = get_l2_entry(s, l2_slice, l2_index + i) & mask;\n- if (offset + (uint64_t) i * cluster_size != l2_entry) {\n+ unsigned first_sc = (i == 0) ? sc_index : 0;\n+ uint64_t l2_entry = get_l2_entry(s, l2_slice, *l2_index + i);\n+ uint64_t l2_bitmap = get_l2_bitmap(s, l2_slice, *l2_index + i);\n+ int ret = qcow2_get_subcluster_range_type(bs, l2_entry, l2_bitmap,\n+ first_sc, &type);\n+ if (ret < 0) {\n+ *l2_index += i; /* Point to the invalid entry */\n+ return -EIO;\n+ }\n+ if (i == 0) {\n+ if (type == QCOW2_SUBCLUSTER_COMPRESSED) {\n+ /* Compressed clusters are always processed one by one */\n+ return ret;\n+ }\n+ expected_type = type;\n+ expected_offset = l2_entry & L2E_OFFSET_MASK;\n+ check_offset = (type == QCOW2_SUBCLUSTER_NORMAL ||\n+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC ||\n+ type == QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC);\n+ } else if (type != expected_type) {\n break;\n+ } else if (check_offset) {\n+ expected_offset += s->cluster_size;\n+ if (expected_offset != (l2_entry & L2E_OFFSET_MASK)) {\n+ break;\n+ }\n }\n- }\n-\n- return i;\n-}\n-\n-/*\n- * Checks how many consecutive unallocated clusters in a given L2\n- * slice have the same cluster type.\n- */\n-static int count_contiguous_clusters_unallocated(BlockDriverState *bs,\n- int nb_clusters,\n- uint64_t *l2_slice,\n- int l2_index,\n- QCow2ClusterType wanted_type)\n-{\n- BDRVQcow2State *s = bs->opaque;\n- int i;\n-\n- assert(wanted_type == QCOW2_CLUSTER_ZERO_PLAIN ||\n- wanted_type == QCOW2_CLUSTER_UNALLOCATED);\n- for (i = 0; i < nb_clusters; i++) {\n- uint64_t entry = get_l2_entry(s, l2_slice, l2_index + i);\n- QCow2ClusterType type = qcow2_get_cluster_type(bs, entry);\n-\n- if (type != wanted_type) {\n+ count += ret;\n+ /* Stop if there are type changes before the end of the cluster */\n+ if (first_sc + ret < s->subclusters_per_cluster) {\n break;\n }\n }\n \n- return i;\n+ return count;\n }\n \n static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,\n@@ -574,12 +574,12 @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,\n QCow2SubclusterType *subcluster_type)\n {\n BDRVQcow2State *s = bs->opaque;\n- unsigned int l2_index;\n- uint64_t l1_index, l2_offset, *l2_slice, l2_entry;\n- int c;\n+ unsigned int l2_index, sc_index;\n+ uint64_t l1_index, l2_offset, *l2_slice, l2_entry, l2_bitmap;\n+ int sc;\n unsigned int offset_in_cluster;\n uint64_t bytes_available, bytes_needed, nb_clusters;\n- QCow2ClusterType type;\n+ QCow2SubclusterType type;\n int ret;\n \n offset_in_cluster = offset_into_cluster(s, offset);\n@@ -600,13 +600,13 @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,\n \n l1_index = offset_to_l1_index(s, offset);\n if (l1_index >= s->l1_size) {\n- type = QCOW2_CLUSTER_UNALLOCATED;\n+ type = QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;\n goto out;\n }\n \n l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;\n if (!l2_offset) {\n- type = QCOW2_CLUSTER_UNALLOCATED;\n+ type = QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN;\n goto out;\n }\n \n@@ -627,7 +627,9 @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,\n /* find the cluster offset for the given disk offset */\n \n l2_index = offset_to_l2_slice_index(s, offset);\n+ sc_index = offset_to_sc_index(s, offset);\n l2_entry = get_l2_entry(s, l2_slice, l2_index);\n+ l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index);\n \n nb_clusters = size_to_clusters(s, bytes_needed);\n /* bytes_needed <= *bytes + offset_in_cluster, both of which are unsigned\n@@ -635,9 +637,9 @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,\n * true */\n assert(nb_clusters <= INT_MAX);\n \n- type = qcow2_get_cluster_type(bs, l2_entry);\n- if (s->qcow_version < 3 && (type == QCOW2_CLUSTER_ZERO_PLAIN ||\n- type == QCOW2_CLUSTER_ZERO_ALLOC)) {\n+ type = qcow2_get_subcluster_type(bs, l2_entry, l2_bitmap, sc_index);\n+ if (s->qcow_version < 3 && (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||\n+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC)) {\n qcow2_signal_corruption(bs, true, -1, -1, \"Zero cluster entry found\"\n \" in pre-v3 image (L2 offset: %#\" PRIx64\n \", L2 index: %#x)\", l2_offset, l2_index);\n@@ -645,7 +647,9 @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,\n goto fail;\n }\n switch (type) {\n- case QCOW2_CLUSTER_COMPRESSED:\n+ case QCOW2_SUBCLUSTER_INVALID:\n+ break; /* This is handled by count_contiguous_subclusters() below */\n+ case QCOW2_SUBCLUSTER_COMPRESSED:\n if (has_data_file(bs)) {\n qcow2_signal_corruption(bs, true, -1, -1, \"Compressed cluster \"\n \"entry found in image with external data \"\n@@ -654,24 +658,17 @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,\n ret = -EIO;\n goto fail;\n }\n- /* Compressed clusters can only be processed one by one */\n- c = 1;\n *host_offset = l2_entry & L2E_COMPRESSED_OFFSET_SIZE_MASK;\n break;\n- case QCOW2_CLUSTER_ZERO_PLAIN:\n- case QCOW2_CLUSTER_UNALLOCATED:\n- /* how many empty clusters ? */\n- c = count_contiguous_clusters_unallocated(bs, nb_clusters,\n- l2_slice, l2_index, type);\n+ case QCOW2_SUBCLUSTER_ZERO_PLAIN:\n+ case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:\n *host_offset = 0;\n break;\n- case QCOW2_CLUSTER_ZERO_ALLOC:\n- case QCOW2_CLUSTER_NORMAL: {\n+ case QCOW2_SUBCLUSTER_ZERO_ALLOC:\n+ case QCOW2_SUBCLUSTER_NORMAL:\n+ case QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC: {\n uint64_t host_cluster_offset = l2_entry & L2E_OFFSET_MASK;\n *host_offset = host_cluster_offset + offset_in_cluster;\n- /* how many allocated clusters ? */\n- c = count_contiguous_clusters(bs, nb_clusters, s->cluster_size,\n- l2_slice, l2_index, QCOW_OFLAG_ZERO);\n if (offset_into_cluster(s, host_cluster_offset)) {\n qcow2_signal_corruption(bs, true, -1, -1,\n \"Cluster allocation offset %#\"\n@@ -697,9 +694,18 @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,\n abort();\n }\n \n+ sc = count_contiguous_subclusters(bs, nb_clusters, sc_index,\n+ l2_slice, &l2_index);\n+ if (sc < 0) {\n+ qcow2_signal_corruption(bs, true, -1, -1, \"Invalid cluster entry found \"\n+ \" (L2 offset: %#\" PRIx64 \", L2 index: %#x)\",\n+ l2_offset, l2_index);\n+ ret = -EIO;\n+ goto fail;\n+ }\n qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);\n \n- bytes_available = (int64_t)c * s->cluster_size;\n+ bytes_available = ((int64_t)sc + sc_index) << s->subcluster_bits;\n \n out:\n if (bytes_available > bytes_needed) {\n@@ -712,7 +718,7 @@ out:\n assert(bytes_available - offset_in_cluster <= UINT_MAX);\n *bytes = bytes_available - offset_in_cluster;\n \n- *subcluster_type = qcow2_cluster_to_subcluster_type(type);\n+ *subcluster_type = type;\n \n return 0;\n \n", "prefixes": [ "v8", "21/34" ] }