mirror of
https://github.com/qemu/qemu.git
synced 2024-11-24 19:33:39 +08:00
qcow2: Support for fixing refcount inconsistencies
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
ccf34716ee
commit
166acf546f
@ -1122,11 +1122,12 @@ fail:
|
||||
* Returns 0 if no errors are found, the number of errors in case the image is
|
||||
* detected as corrupted, and -errno when an internal error occurred.
|
||||
*/
|
||||
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
|
||||
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
BdrvCheckMode fix)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int64_t size;
|
||||
int nb_clusters, refcount1, refcount2, i;
|
||||
int64_t size, i;
|
||||
int nb_clusters, refcount1, refcount2;
|
||||
QCowSnapshot *sn;
|
||||
uint16_t *refcount_table;
|
||||
int ret;
|
||||
@ -1170,14 +1171,15 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
|
||||
|
||||
/* Refcount blocks are cluster aligned */
|
||||
if (offset & (s->cluster_size - 1)) {
|
||||
fprintf(stderr, "ERROR refcount block %d is not "
|
||||
fprintf(stderr, "ERROR refcount block %" PRId64 " is not "
|
||||
"cluster aligned; refcount table entry corrupted\n", i);
|
||||
res->corruptions++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cluster >= nb_clusters) {
|
||||
fprintf(stderr, "ERROR refcount block %d is outside image\n", i);
|
||||
fprintf(stderr, "ERROR refcount block %" PRId64
|
||||
" is outside image\n", i);
|
||||
res->corruptions++;
|
||||
continue;
|
||||
}
|
||||
@ -1186,7 +1188,8 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
|
||||
inc_refcounts(bs, res, refcount_table, nb_clusters,
|
||||
offset, s->cluster_size);
|
||||
if (refcount_table[cluster] != 1) {
|
||||
fprintf(stderr, "ERROR refcount block %d refcount=%d\n",
|
||||
fprintf(stderr, "ERROR refcount block %" PRId64
|
||||
" refcount=%d\n",
|
||||
i, refcount_table[cluster]);
|
||||
res->corruptions++;
|
||||
}
|
||||
@ -1197,7 +1200,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
|
||||
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",
|
||||
fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n",
|
||||
i, strerror(-refcount1));
|
||||
res->check_errors++;
|
||||
continue;
|
||||
@ -1205,9 +1208,31 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
|
||||
|
||||
refcount2 = refcount_table[i];
|
||||
if (refcount1 != refcount2) {
|
||||
fprintf(stderr, "%s cluster %d refcount=%d reference=%d\n",
|
||||
refcount1 < refcount2 ? "ERROR" : "Leaked",
|
||||
|
||||
/* Check if we're allowed to fix the mismatch */
|
||||
int *num_fixed = NULL;
|
||||
if (refcount1 > refcount2 && (fix & BDRV_FIX_LEAKS)) {
|
||||
num_fixed = &res->leaks_fixed;
|
||||
} else if (refcount1 < refcount2 && (fix & BDRV_FIX_ERRORS)) {
|
||||
num_fixed = &res->corruptions_fixed;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s cluster %" PRId64 " refcount=%d reference=%d\n",
|
||||
num_fixed != NULL ? "Repairing" :
|
||||
refcount1 < refcount2 ? "ERROR" :
|
||||
"Leaked",
|
||||
i, refcount1, refcount2);
|
||||
|
||||
if (num_fixed) {
|
||||
ret = update_refcount(bs, i << s->cluster_bits, 1,
|
||||
refcount2 - refcount1);
|
||||
if (ret >= 0) {
|
||||
(*num_fixed)++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* And if we couldn't, print an error */
|
||||
if (refcount1 < refcount2) {
|
||||
res->corruptions++;
|
||||
} else {
|
||||
|
@ -1473,11 +1473,7 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
|
||||
BdrvCheckMode fix)
|
||||
{
|
||||
if (fix) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return qcow2_check_refcounts(bs, result);
|
||||
return qcow2_check_refcounts(bs, result, fix);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -261,7 +261,8 @@ void qcow2_free_any_clusters(BlockDriverState *bs,
|
||||
int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
||||
int64_t l1_table_offset, int l1_size, int addend);
|
||||
|
||||
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res);
|
||||
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
BdrvCheckMode fix);
|
||||
|
||||
/* qcow2-cluster.c functions */
|
||||
int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size);
|
||||
|
Loading…
Reference in New Issue
Block a user