Also don't infer the cluster type directly from the L2 entries, but use qcow2_get_cluster_type() to keep everything in a single place.
Signed-off-by: Kevin Wolf <kw...@redhat.com> --- block/qcow2-refcount.c | 98 ++++++++++++++++++++++++++--------------------- 1 files changed, 54 insertions(+), 44 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 50bf44e..c5d3171 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -934,7 +934,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, int check_copied) { BDRVQcowState *s = bs->opaque; - uint64_t *l2_table, offset; + uint64_t *l2_table, l2_entry; int i, l2_size, nb_csectors, refcount; /* Read L2 table from disk */ @@ -946,54 +946,64 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, /* Do the actual checks */ for(i = 0; i < s->l2_size; i++) { - offset = be64_to_cpu(l2_table[i]); - if (offset != 0) { - if (offset & QCOW_OFLAG_COMPRESSED) { - /* Compressed clusters don't have QCOW_OFLAG_COPIED */ - if (offset & QCOW_OFLAG_COPIED) { - fprintf(stderr, "ERROR: cluster %" PRId64 ": " - "copied flag must never be set for compressed " - "clusters\n", offset >> s->cluster_bits); - offset &= ~QCOW_OFLAG_COPIED; - res->corruptions++; - } + l2_entry = be64_to_cpu(l2_table[i]); + + switch (qcow2_get_cluster_type(l2_entry)) { + case QCOW2_CLUSTER_COMPRESSED: + /* Compressed clusters don't have QCOW_OFLAG_COPIED */ + if (l2_entry & QCOW_OFLAG_COPIED) { + fprintf(stderr, "ERROR: cluster %" PRId64 ": " + "copied flag must never be set for compressed " + "clusters\n", l2_entry >> s->cluster_bits); + l2_entry &= ~QCOW_OFLAG_COPIED; + res->corruptions++; + } - /* Mark cluster as used */ - nb_csectors = ((offset >> s->csize_shift) & - s->csize_mask) + 1; - offset &= s->cluster_offset_mask; - inc_refcounts(bs, res, refcount_table, refcount_table_size, - offset & ~511, nb_csectors * 512); - } else { - /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ - if (check_copied) { - 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)); - goto fail; - } - if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) { - fprintf(stderr, "ERROR OFLAG_COPIED: offset=%" - PRIx64 " refcount=%d\n", entry, refcount); - res->corruptions++; - } - } + /* Mark cluster as used */ + nb_csectors = ((l2_entry >> s->csize_shift) & + s->csize_mask) + 1; + l2_entry &= s->cluster_offset_mask; + inc_refcounts(bs, res, refcount_table, refcount_table_size, + l2_entry & ~511, nb_csectors * 512); + break; - /* Mark cluster as used */ - offset &= ~QCOW_OFLAG_COPIED; - inc_refcounts(bs, res, refcount_table,refcount_table_size, - offset, s->cluster_size); + case QCOW2_CLUSTER_NORMAL: + { + /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ + uint64_t offset = l2_entry & L2E_OFFSET_MASK; - /* Correct offsets are cluster aligned */ - if (offset & (s->cluster_size - 1)) { - fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not " - "properly aligned; L2 entry corrupted.\n", offset); + if (check_copied) { + refcount = get_refcount(bs, offset >> s->cluster_bits); + if (refcount < 0) { + fprintf(stderr, "Can't get refcount for offset %" + PRIx64 ": %s\n", l2_entry, strerror(-refcount)); + goto fail; + } + if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) { + fprintf(stderr, "ERROR OFLAG_COPIED: offset=%" + PRIx64 " refcount=%d\n", l2_entry, refcount); res->corruptions++; } } + + /* Mark cluster as used */ + inc_refcounts(bs, res, refcount_table,refcount_table_size, + offset, s->cluster_size); + + /* Correct offsets are cluster aligned */ + if (offset & (s->cluster_size - 1)) { + fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not " + "properly aligned; L2 entry corrupted.\n", offset); + res->corruptions++; + } + break; + } + + case QCOW2_CLUSTER_UNALLOCATED: + break; + + default: + abort(); } } @@ -1064,7 +1074,7 @@ static int check_refcounts_l1(BlockDriverState *bs, } /* Mark L2 table as used */ - l2_offset &= ~QCOW_OFLAG_COPIED; + l2_offset &= L1E_OFFSET_MASK; inc_refcounts(bs, res, refcount_table, refcount_table_size, l2_offset, s->cluster_size); -- 1.7.6.5