From a0bf51672bd6b444cdd7a11c005821bdfc2fddea Mon Sep 17 00:00:00 2001 From: Kevin Wolf <kwolf@redhat.com> Date: Fri, 18 Jun 2010 15:22:32 -0300 Subject: [PATCH 14/18] qcow2: Allow get_refcount to return errors RH-Author: Kevin Wolf <kwolf@redhat.com> Message-id: <1276874554-9820-15-git-send-email-kwolf@redhat.com> Patchwork-id: 9989 O-Subject: [RHEL-5.6 KVM PATCH 14/16] qcow2: Allow get_refcount to return errors Bugzilla: 605701 RH-Acked-by: Juan Quintela <quintela@redhat.com> RH-Acked-by: Eduardo Habkost <ehabkost@redhat.com> RH-Acked-by: Christoph Hellwig <chellwig@redhat.com> RH-Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com> Bugzilla: 605701 Upstream commit: 018faafdbdd88e6212a83126716091ce155e6ff9 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 <kwolf@redhat.com> --- qemu/block-qcow2.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 files changed, 37 insertions(+), 4 deletions(-) Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- qemu/block-qcow2.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 files changed, 37 insertions(+), 4 deletions(-) diff --git a/qemu/block-qcow2.c b/qemu/block-qcow2.c index 9291a2a..d835efd 100644 --- a/qemu/block-qcow2.c +++ b/qemu/block-qcow2.c @@ -2118,6 +2118,10 @@ static int update_snapshot_refcount(BlockDriverState *bs, } else { refcount = get_refcount(bs, offset >> s->cluster_bits); } + + if (refcount < 0) { + goto fail; + } } if (refcount == 1) { @@ -2140,7 +2144,9 @@ static int 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) { @@ -2590,11 +2596,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) @@ -2604,8 +2616,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); @@ -2981,7 +2995,13 @@ fail_block: 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) @@ -3201,6 +3221,10 @@ static int check_refcounts_l1(BlockDriverState *bs, if (l2_offset) { 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); @@ -3230,6 +3254,10 @@ static int check_refcounts_l1(BlockDriverState *bs, } else { if (check_copied) { refcount = get_refcount(bs, (offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits); + if (refcount < 0) { + fprintf(stderr, "Can't get refcount for offset %" + PRIx64 ": %s\n", offset, strerror(-refcount)); + } if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) { fprintf(stderr, "ERROR OFLAG_COPIED: offset=%" PRIx64 " refcount=%d\n", offset, refcount); @@ -3341,6 +3369,11 @@ static int 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", -- 1.7.0.3