@@ -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;
@@ -1205,9 +1206,31 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
refcount2 = refcount_table[i];
if (refcount1 != refcount2) {
+
+ /* 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 %d refcount=%d reference=%d\n",
- refcount1 < refcount2 ? "ERROR" : "Leaked",
+ 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);
Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- block/qcow2-refcount.c | 31 +++++++++++++++++++++++++++---- block/qcow2.c | 6 +----- block/qcow2.h | 3 ++- 3 files changed, 30 insertions(+), 10 deletions(-)