From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57141) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VFJQZ-0005GG-Ql for qemu-devel@nongnu.org; Fri, 30 Aug 2013 03:47:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VFJQT-0004Kr-8y for qemu-devel@nongnu.org; Fri, 30 Aug 2013 03:47:31 -0400 Received: from mx1.redhat.com ([209.132.183.28]:34984) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VFJQT-0004Ki-0q for qemu-devel@nongnu.org; Fri, 30 Aug 2013 03:47:25 -0400 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r7U7lOii026831 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 30 Aug 2013 03:47:24 -0400 From: Max Reitz Date: Fri, 30 Aug 2013 09:46:55 +0200 Message-Id: <1377848818-2623-6-git-send-email-mreitz@redhat.com> In-Reply-To: <1377848818-2623-1-git-send-email-mreitz@redhat.com> References: <1377848818-2623-1-git-send-email-mreitz@redhat.com> Subject: [Qemu-devel] [PATCH v3 5/8] qcow2-refcount: Repair OFLAG_COPIED errors List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Kevin Wolf , Stefan Hajnoczi , Max Reitz Since the OFLAG_COPIED checks are now executed after the refcounts have been repaired (if repairing), it is safe to assume that they are correct but the OFLAG_COPIED flag may be not. Therefore, if its value differs from what it should be (considering the according refcount), that discrepancy can be repaired by correctly setting (or clearing that flag. Signed-off-by: Max Reitz --- block/qcow2-cluster.c | 4 ++-- block/qcow2-refcount.c | 44 ++++++++++++++++++++++++++++++++++++++++---- block/qcow2.h | 1 + 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 7c248aa..2d5aa92 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -145,7 +145,7 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset, * and we really don't want bdrv_pread to perform a read-modify-write) */ #define L1_ENTRIES_PER_SECTOR (512 / 8) -static int write_l1_entry(BlockDriverState *bs, int l1_index) +int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index) { BDRVQcowState *s = bs->opaque; uint64_t buf[L1_ENTRIES_PER_SECTOR]; @@ -254,7 +254,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table) /* update the L1 entry */ trace_qcow2_l2_allocate_write_l1(bs, l1_index); s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED; - ret = write_l1_entry(bs, l1_index); + ret = qcow2_write_l1_entry(bs, l1_index); if (ret < 0) { goto fail; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index fdc0f86..30a1bee 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1341,6 +1341,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, for (i = 0; i < s->l1_size; i++) { uint64_t l1_entry = s->l1_table[i]; uint64_t l2_offset = l1_entry & L1E_OFFSET_MASK; + bool l2_dirty = false; int refcount; if (!l2_offset) { @@ -1354,10 +1355,24 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, continue; } if ((refcount == 1) != ((l1_entry & QCOW_OFLAG_COPIED) != 0)) { - fprintf(stderr, "ERROR OFLAG_COPIED L2 cluster: l1_entry=%" PRIx64 + fprintf(stderr, "%s OFLAG_COPIED L2 cluster: l1_entry=%" PRIx64 " refcount=%d\n", + fix & BDRV_FIX_ERRORS ? "Repairing" : + "ERROR", l1_entry, refcount); - res->corruptions++; + if (fix & BDRV_FIX_ERRORS) { + s->l1_table[i] = refcount == 1 + ? l1_entry | QCOW_OFLAG_COPIED + : l1_entry & ~QCOW_OFLAG_COPIED; + ret = qcow2_write_l1_entry(bs, i); + if (ret < 0) { + res->check_errors++; + goto fail; + } + res->corruptions_fixed++; + } else { + res->corruptions++; + } } ret = bdrv_pread(bs->file, l2_offset, l2_table, @@ -1386,10 +1401,31 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, continue; } if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) { - fprintf(stderr, "ERROR OFLAG_COPIED data cluster: l2_entry=%" + fprintf(stderr, "%s OFLAG_COPIED data cluster: l2_entry=%" PRIx64 " refcount=%d\n", + fix & BDRV_FIX_ERRORS ? "Repairing" : + "ERROR", l2_entry, refcount); - res->corruptions++; + if (fix & BDRV_FIX_ERRORS) { + l2_table[j] = cpu_to_be64(refcount == 1 + ? l2_entry | QCOW_OFLAG_COPIED + : l2_entry & ~QCOW_OFLAG_COPIED); + l2_dirty = true; + res->corruptions_fixed++; + } else { + res->corruptions++; + } + } + } + + if (l2_dirty) { + ret = bdrv_pwrite(bs->file, l2_offset, l2_table, + s->l2_size * sizeof(uint64_t)); + if (ret < 0) { + fprintf(stderr, "ERROR: Could not write L2 table: %s\n", + strerror(-ret)); + res->check_errors++; + goto fail; } } } diff --git a/block/qcow2.h b/block/qcow2.h index 86ddb30..10b7bf4 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -432,6 +432,7 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int chk, int64_t offset, /* qcow2-cluster.c functions */ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, bool exact_size); +int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); void qcow2_l2_cache_reset(BlockDriverState *bs); int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, -- 1.8.3.1