Message ID | 20210505065955.13964-7-vsementsov@virtuozzo.com |
---|---|
State | New |
Headers | show |
Series | qcow2 check: check some reserved bits and subcluster bitmaps | expand |
On 05.05.2021 09:59, Vladimir Sementsov-Ogievskiy wrote: > Check subcluster bitmap of the l2 entry for different types of > clusters: > > - for compressed it must be zero > - for allocated check consistency of two parts of the bitmap > - for unallocated all subclusters should be unallocated > (or zero-plain) > > For unallocated clusters we can safely fix the entry by making it > zero-plain. > > Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> > Reviewed-by: Eric Blake <eblake@redhat.com> Tested-by: Kirill Tkhai <ktkhai@virtuozzo.com> > --- > block/qcow2-refcount.c | 30 +++++++++++++++++++++++++++++- > 1 file changed, 29 insertions(+), 1 deletion(-) > > diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c > index f48c5e1b5d..062ec48a15 100644 > --- a/block/qcow2-refcount.c > +++ b/block/qcow2-refcount.c > @@ -1681,6 +1681,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, > uint64_t coffset; > int csize; > l2_entry = get_l2_entry(s, l2_table, i); > + uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, i); > > switch (qcow2_get_cluster_type(bs, l2_entry)) { > case QCOW2_CLUSTER_COMPRESSED: > @@ -1700,6 +1701,14 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, > break; > } > > + if (l2_bitmap) { > + fprintf(stderr, "ERROR compressed cluster %d with non-zero " > + "subcluster allocation bitmap, entry=0x%" PRIx64 "\n", > + i, l2_entry); > + res->corruptions++; > + break; > + } > + > /* Mark cluster as used */ > qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize); > ret = qcow2_inc_refcounts_imrt( > @@ -1727,13 +1736,19 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, > { > uint64_t offset = l2_entry & L2E_OFFSET_MASK; > > + if ((l2_bitmap >> 32) & l2_bitmap) { > + res->corruptions++; > + fprintf(stderr, "ERROR offset=%" PRIx64 ": Allocated " > + "cluster has corrupted subcluster allocation bitmap\n", > + offset); > + } > + > /* Correct offsets are cluster aligned */ > if (offset_into_cluster(s, offset)) { > bool contains_data; > res->corruptions++; > > if (has_subclusters(s)) { > - uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, i); > contains_data = (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC); > } else { > contains_data = !(l2_entry & QCOW_OFLAG_ZERO); > @@ -1800,6 +1815,19 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, > > case QCOW2_CLUSTER_ZERO_PLAIN: > case QCOW2_CLUSTER_UNALLOCATED: > + if (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC) { > + res->corruptions++; > + fprintf(stderr, "%s: Unallocated " > + "cluster has non-zero subcluster allocation map\n", > + fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR"); > + if (fix & BDRV_FIX_ERRORS) { > + ret = fix_l2_entry_by_zero(bs, res, l2_offset, l2_table, i, > + active, &metadata_overlap); > + if (metadata_overlap) { > + return ret; > + } > + } > + } > break; > > default: >
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index f48c5e1b5d..062ec48a15 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1681,6 +1681,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, uint64_t coffset; int csize; l2_entry = get_l2_entry(s, l2_table, i); + uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, i); switch (qcow2_get_cluster_type(bs, l2_entry)) { case QCOW2_CLUSTER_COMPRESSED: @@ -1700,6 +1701,14 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, break; } + if (l2_bitmap) { + fprintf(stderr, "ERROR compressed cluster %d with non-zero " + "subcluster allocation bitmap, entry=0x%" PRIx64 "\n", + i, l2_entry); + res->corruptions++; + break; + } + /* Mark cluster as used */ qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize); ret = qcow2_inc_refcounts_imrt( @@ -1727,13 +1736,19 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, { uint64_t offset = l2_entry & L2E_OFFSET_MASK; + if ((l2_bitmap >> 32) & l2_bitmap) { + res->corruptions++; + fprintf(stderr, "ERROR offset=%" PRIx64 ": Allocated " + "cluster has corrupted subcluster allocation bitmap\n", + offset); + } + /* Correct offsets are cluster aligned */ if (offset_into_cluster(s, offset)) { bool contains_data; res->corruptions++; if (has_subclusters(s)) { - uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, i); contains_data = (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC); } else { contains_data = !(l2_entry & QCOW_OFLAG_ZERO); @@ -1800,6 +1815,19 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, case QCOW2_CLUSTER_ZERO_PLAIN: case QCOW2_CLUSTER_UNALLOCATED: + if (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC) { + res->corruptions++; + fprintf(stderr, "%s: Unallocated " + "cluster has non-zero subcluster allocation map\n", + fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR"); + if (fix & BDRV_FIX_ERRORS) { + ret = fix_l2_entry_by_zero(bs, res, l2_offset, l2_table, i, + active, &metadata_overlap); + if (metadata_overlap) { + return ret; + } + } + } break; default: