mirror of https://github.com/proxmox/mirror_qemu
qcow2: Ignore reserved bits in check_refcounts
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 <kwolf@redhat.com>master
parent
76dc9e0c8f
commit
afdf0abe77
|
@ -940,7 +940,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||||
int check_copied)
|
int check_copied)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint64_t *l2_table, offset;
|
uint64_t *l2_table, l2_entry;
|
||||||
int i, l2_size, nb_csectors, refcount;
|
int i, l2_size, nb_csectors, refcount;
|
||||||
|
|
||||||
/* Read L2 table from disk */
|
/* Read L2 table from disk */
|
||||||
|
@ -952,54 +952,64 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
|
||||||
|
|
||||||
/* Do the actual checks */
|
/* Do the actual checks */
|
||||||
for(i = 0; i < s->l2_size; i++) {
|
for(i = 0; i < s->l2_size; i++) {
|
||||||
offset = be64_to_cpu(l2_table[i]);
|
l2_entry = be64_to_cpu(l2_table[i]);
|
||||||
if (offset != 0) {
|
|
||||||
if (offset & QCOW_OFLAG_COMPRESSED) {
|
switch (qcow2_get_cluster_type(l2_entry)) {
|
||||||
/* Compressed clusters don't have QCOW_OFLAG_COPIED */
|
case QCOW2_CLUSTER_COMPRESSED:
|
||||||
if (offset & QCOW_OFLAG_COPIED) {
|
/* Compressed clusters don't have QCOW_OFLAG_COPIED */
|
||||||
fprintf(stderr, "ERROR: cluster %" PRId64 ": "
|
if (l2_entry & QCOW_OFLAG_COPIED) {
|
||||||
"copied flag must never be set for compressed "
|
fprintf(stderr, "ERROR: cluster %" PRId64 ": "
|
||||||
"clusters\n", offset >> s->cluster_bits);
|
"copied flag must never be set for compressed "
|
||||||
offset &= ~QCOW_OFLAG_COPIED;
|
"clusters\n", l2_entry >> s->cluster_bits);
|
||||||
res->corruptions++;
|
l2_entry &= ~QCOW_OFLAG_COPIED;
|
||||||
|
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;
|
||||||
|
|
||||||
|
case QCOW2_CLUSTER_NORMAL:
|
||||||
|
{
|
||||||
|
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
|
||||||
|
uint64_t offset = l2_entry & L2E_OFFSET_MASK;
|
||||||
|
|
||||||
|
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)) {
|
||||||
/* Mark cluster as used */
|
fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
|
||||||
nb_csectors = ((offset >> s->csize_shift) &
|
PRIx64 " refcount=%d\n", l2_entry, refcount);
|
||||||
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 */
|
|
||||||
offset &= ~QCOW_OFLAG_COPIED;
|
|
||||||
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++;
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1070,7 +1080,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark L2 table as used */
|
/* Mark L2 table as used */
|
||||||
l2_offset &= ~QCOW_OFLAG_COPIED;
|
l2_offset &= L1E_OFFSET_MASK;
|
||||||
inc_refcounts(bs, res, refcount_table, refcount_table_size,
|
inc_refcounts(bs, res, refcount_table, refcount_table_size,
|
||||||
l2_offset, s->cluster_size);
|
l2_offset, s->cluster_size);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue