From patchwork Fri Jun 4 10:19:10 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 54561 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 39A3DB7D74 for ; Fri, 4 Jun 2010 20:22:39 +1000 (EST) Received: from localhost ([127.0.0.1]:33015 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OKU2t-0002uh-Hq for incoming@patchwork.ozlabs.org; Fri, 04 Jun 2010 06:22:35 -0400 Received: from [140.186.70.92] (port=44742 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OKU0d-0002go-Q4 for qemu-devel@nongnu.org; Fri, 04 Jun 2010 06:20:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OKU0b-0007gq-RU for qemu-devel@nongnu.org; Fri, 04 Jun 2010 06:20:15 -0400 Received: from mx1.redhat.com ([209.132.183.28]:14647) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OKU0b-0007gd-Hg for qemu-devel@nongnu.org; Fri, 04 Jun 2010 06:20:13 -0400 Received: from int-mx04.intmail.prod.int.phx2.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.17]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o54AKDQK026718 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 4 Jun 2010 06:20:13 -0400 Received: from localhost.localdomain (vpn2-9-152.ams2.redhat.com [10.36.9.152]) by int-mx04.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o54AJZDM002721; Fri, 4 Jun 2010 06:20:06 -0400 From: Kevin Wolf To: qemu-devel@nongnu.org Date: Fri, 4 Jun 2010 12:19:10 +0200 Message-Id: <1275646752-25763-2-git-send-email-kwolf@redhat.com> In-Reply-To: <1275646752-25763-1-git-send-email-kwolf@redhat.com> References: <1275646752-25763-1-git-send-email-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.17 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. Cc: kwolf@redhat.com Subject: [Qemu-devel] [PATCH 1/3] qcow2: Allow get_refcount to return errors X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org get_refcount might need to load a refcount block from disk, so errors may happen. Return the error code instead of assuming a refcount of 1 and change the callers to respect error return values. Signed-off-by: Kevin Wolf --- block/qcow2-refcount.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 files changed, 37 insertions(+), 4 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 22b0b45..ca6b373 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -105,11 +105,17 @@ static int load_refcount_block(BlockDriverState *bs, return 0; } +/* + * Returns the refcount of the cluster given by its index. Any non-negative + * return value is the refcount of the cluster, negative values are -errno + * and indicate an error. + */ static int get_refcount(BlockDriverState *bs, int64_t cluster_index) { BDRVQcowState *s = bs->opaque; int refcount_table_index, block_index; int64_t refcount_block_offset; + int ret; refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); if (refcount_table_index >= s->refcount_table_size) @@ -119,8 +125,10 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index) return 0; if (refcount_block_offset != s->refcount_block_cache_offset) { /* better than nothing: return allocated if read error */ - if (load_refcount_block(bs, refcount_block_offset) < 0) - return 1; + ret = load_refcount_block(bs, refcount_block_offset); + if (ret < 0) { + return ret; + } } block_index = cluster_index & ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); @@ -538,7 +546,13 @@ fail: return ret; } -/* addend must be 1 or -1 */ +/* + * Increases or decreases the refcount of a given cluster by one. + * addend must be 1 or -1. + * + * 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. + */ static int update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index, int addend) @@ -779,6 +793,10 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, } else { refcount = get_refcount(bs, offset >> s->cluster_bits); } + + if (refcount < 0) { + goto fail; + } } if (refcount == 1) { @@ -801,7 +819,9 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, } else { refcount = get_refcount(bs, l2_offset >> s->cluster_bits); } - if (refcount == 1) { + if (refcount < 0) { + goto fail; + } else if (refcount == 1) { l2_offset |= QCOW_OFLAG_COPIED; } if (l2_offset != old_l2_offset) { @@ -934,6 +954,10 @@ static int check_refcounts_l2(BlockDriverState *bs, uint64_t entry = offset; offset &= ~QCOW_OFLAG_COPIED; refcount = get_refcount(bs, offset >> s->cluster_bits); + if (refcount < 0) { + fprintf(stderr, "Can't get refcount for offset %" + PRIx64 ": %s\n", entry, strerror(-refcount)); + } if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) { fprintf(stderr, "ERROR OFLAG_COPIED: offset=%" PRIx64 " refcount=%d\n", entry, refcount); @@ -1011,6 +1035,10 @@ static int check_refcounts_l1(BlockDriverState *bs, if (check_copied) { refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits); + if (refcount < 0) { + fprintf(stderr, "Can't get refcount for l2_offset %" + PRIx64 ": %s\n", l2_offset, strerror(-refcount)); + } if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) { fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64 " refcount=%d\n", l2_offset, refcount); @@ -1118,6 +1146,11 @@ int qcow2_check_refcounts(BlockDriverState *bs) /* compare ref counts */ for(i = 0; i < nb_clusters; i++) { refcount1 = get_refcount(bs, i); + if (refcount1 < 0) { + fprintf(stderr, "Can't get refcount for cluster %d: %s\n", + i, strerror(-refcount1)); + } + refcount2 = refcount_table[i]; if (refcount1 != refcount2) { fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n",