From patchwork Thu Nov 20 17:06:19 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Max Reitz X-Patchwork-Id: 412811 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id DCCCE14017B for ; Fri, 21 Nov 2014 04:08:14 +1100 (AEDT) Received: from localhost ([::1]:36428 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XrVDJ-0005Hh-0q for incoming@patchwork.ozlabs.org; Thu, 20 Nov 2014 12:08:13 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:32919) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XrVC3-0003RN-HQ for qemu-devel@nongnu.org; Thu, 20 Nov 2014 12:07:01 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XrVBw-0000hu-CK for qemu-devel@nongnu.org; Thu, 20 Nov 2014 12:06:55 -0500 Received: from mx1.redhat.com ([209.132.183.28]:44178) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XrVBw-0000hm-52 for qemu-devel@nongnu.org; Thu, 20 Nov 2014 12:06:48 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id sAKH6lbg017863 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Thu, 20 Nov 2014 12:06:47 -0500 Received: from localhost (dhcp-192-247.str.redhat.com [10.33.192.247]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id sAKH6jkY030469 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=NO); Thu, 20 Nov 2014 12:06:46 -0500 From: Max Reitz To: qemu-devel@nongnu.org Date: Thu, 20 Nov 2014 18:06:19 +0100 Message-Id: <1416503198-17031-4-git-send-email-mreitz@redhat.com> In-Reply-To: <1416503198-17031-1-git-send-email-mreitz@redhat.com> References: <1416503198-17031-1-git-send-email-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Kevin Wolf , Stefan Hajnoczi , Max Reitz Subject: [Qemu-devel] [PATCH v3 03/22] qcow2: Use 64 bits for refcount values X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Refcounts may have a width of up to 64 bits, so qemu should use the same width to represent refcount values internally. Since for instance qcow2_get_refcount() signals an error by returning a negative value, refcount values are generally signed to be able to represent those error values correctly. This limits the maximum refcount value supported by qemu to INT64_MAX (= 63 bits), as established in "qcow2: Add two new fields to BDRVQcowState". This limitation should have no implications in practice for normal valid images. If the MSb in a 64 bit refcount value is set, we can safely assume the value to be invalid (because reaching such high refcounts is impossible due to other limitations of the qcow2 format). Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi --- block/qcow2-cluster.c | 9 ++++++--- block/qcow2-refcount.c | 37 ++++++++++++++++++++----------------- block/qcow2.h | 7 ++++--- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index df0b2c9..ab43902 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1640,7 +1640,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, for (i = 0; i < l1_size; i++) { uint64_t l2_offset = l1_table[i] & L1E_OFFSET_MASK; bool l2_dirty = false; - int l2_refcount; + int64_t l2_refcount; if (!l2_offset) { /* unallocated */ @@ -1696,14 +1696,17 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, } if (l2_refcount > 1) { + int64_t ret64; + /* For shared L2 tables, set the refcount accordingly (it is * already 1 and needs to be l2_refcount) */ - ret = qcow2_update_cluster_refcount(bs, + ret64 = qcow2_update_cluster_refcount(bs, offset >> s->cluster_bits, l2_refcount - 1, QCOW2_DISCARD_OTHER); - if (ret < 0) { + if (ret64 < 0) { qcow2_free_clusters(bs, offset, s->cluster_size, QCOW2_DISCARD_OTHER); + ret = ret64; goto fail; } } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 6016211..6e06531 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -91,14 +91,14 @@ static int load_refcount_block(BlockDriverState *bs, * return value is the refcount of the cluster, negative values are -errno * and indicate an error. */ -int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index) +int64_t qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index) { BDRVQcowState *s = bs->opaque; uint64_t refcount_table_index, block_index; int64_t refcount_block_offset; int ret; uint16_t *refcount_block; - uint16_t refcount; + int64_t refcount; refcount_table_index = cluster_index >> s->refcount_block_bits; if (refcount_table_index >= s->refcount_table_size) @@ -556,9 +556,10 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, for(cluster_offset = start; cluster_offset <= last; cluster_offset += s->cluster_size) { - int block_index, refcount; + int block_index; int64_t cluster_index = cluster_offset >> s->cluster_bits; int64_t table_index = cluster_index >> s->refcount_block_bits; + int64_t refcount; /* Load the refcount block and allocate it if needed */ if (table_index != old_table_index) { @@ -634,10 +635,10 @@ fail: * If the return value is non-negative, it is the new refcount of the cluster. * If it is negative, it is -errno and indicates an error. */ -int qcow2_update_cluster_refcount(BlockDriverState *bs, - int64_t cluster_index, - int addend, - enum qcow2_discard_type type) +int64_t qcow2_update_cluster_refcount(BlockDriverState *bs, + int64_t cluster_index, + int addend, + enum qcow2_discard_type type) { BDRVQcowState *s = bs->opaque; int ret; @@ -663,7 +664,7 @@ static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size) { BDRVQcowState *s = bs->opaque; uint64_t i, nb_clusters; - int refcount; + int64_t refcount; nb_clusters = size_to_clusters(s, size); retry: @@ -722,7 +723,8 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, BDRVQcowState *s = bs->opaque; uint64_t cluster_index; uint64_t i; - int refcount, ret; + int64_t refcount; + int ret; assert(nb_clusters >= 0); if (nb_clusters == 0) { @@ -878,8 +880,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, BDRVQcowState *s = bs->opaque; uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2; bool l1_allocated = false; - int64_t old_offset, old_l2_offset; - int i, j, l1_modified = 0, nb_csectors, refcount; + int64_t old_offset, old_l2_offset, refcount; + int i, j, l1_modified = 0, nb_csectors; int ret; l2_table = NULL; @@ -1341,7 +1343,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, BDRVQcowState *s = bs->opaque; uint64_t *l2_table = qemu_blockalign(bs, s->cluster_size); int ret; - int refcount; + int64_t refcount; int i, j; for (i = 0; i < s->l1_size; i++) { @@ -1360,7 +1362,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, } if ((refcount == 1) != ((l1_entry & QCOW_OFLAG_COPIED) != 0)) { fprintf(stderr, "%s OFLAG_COPIED L2 cluster: l1_index=%d " - "l1_entry=%" PRIx64 " refcount=%d\n", + "l1_entry=%" PRIx64 " refcount=%" PRId64 "\n", fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i, l1_entry, refcount); @@ -1403,7 +1405,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, } if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) { fprintf(stderr, "%s OFLAG_COPIED data cluster: " - "l2_entry=%" PRIx64 " refcount=%d\n", + "l2_entry=%" PRIx64 " refcount=%" PRId64 "\n", fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", l2_entry, refcount); @@ -1628,8 +1630,8 @@ static void compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res, uint16_t *refcount_table, int64_t nb_clusters) { BDRVQcowState *s = bs->opaque; - int64_t i; - int refcount1, refcount2, ret; + int64_t i, refcount1, refcount2; + int ret; for (i = 0, *highest_cluster = 0; i < nb_clusters; i++) { refcount1 = qcow2_get_refcount(bs, i); @@ -1657,7 +1659,8 @@ static void compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res, num_fixed = &res->corruptions_fixed; } - fprintf(stderr, "%s cluster %" PRId64 " refcount=%d reference=%d\n", + fprintf(stderr, "%s cluster %" PRId64 " refcount=%" PRId64 + " reference=%" PRId64 "\n", num_fixed != NULL ? "Repairing" : refcount1 < refcount2 ? "ERROR" : "Leaked", diff --git a/block/qcow2.h b/block/qcow2.h index 4d8c902..0f8eb15 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -489,10 +489,11 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, int qcow2_refcount_init(BlockDriverState *bs); void qcow2_refcount_close(BlockDriverState *bs); -int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index); +int64_t qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index); -int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index, - int addend, enum qcow2_discard_type type); +int64_t qcow2_update_cluster_refcount(BlockDriverState *bs, + int64_t cluster_index, int addend, + enum qcow2_discard_type type); int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size); int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,