|
|
9ae3a8 |
From 7f0500dff4d7da11bda309de3866851f382f6fe8 Mon Sep 17 00:00:00 2001
|
|
|
9ae3a8 |
From: Max Reitz <mreitz@redhat.com>
|
|
|
9ae3a8 |
Date: Mon, 4 Nov 2013 22:32:03 +0100
|
|
|
9ae3a8 |
Subject: [PATCH 10/87] qcow2-refcount: Repair OFLAG_COPIED errors
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
RH-Author: Max Reitz <mreitz@redhat.com>
|
|
|
9ae3a8 |
Message-id: <1383604354-12743-13-git-send-email-mreitz@redhat.com>
|
|
|
9ae3a8 |
Patchwork-id: 55312
|
|
|
9ae3a8 |
O-Subject: [RHEL-7.0 qemu-kvm PATCH 12/43] qcow2-refcount: Repair OFLAG_COPIED errors
|
|
|
9ae3a8 |
Bugzilla: 1004347
|
|
|
9ae3a8 |
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Fam Zheng <famz@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
BZ: 1004347
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Since the OFLAG_COPIED checks are now executed after the refcounts have
|
|
|
9ae3a8 |
been repaired (if repairing), it is safe to assume that they are correct
|
|
|
9ae3a8 |
but the OFLAG_COPIED flag may be not. Therefore, if its value differs
|
|
|
9ae3a8 |
from what it should be (considering the according refcount), that
|
|
|
9ae3a8 |
discrepancy can be repaired by correctly setting (or clearing that flag.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Max Reitz <mreitz@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
|
|
9ae3a8 |
(cherry picked from commit e23e400ec62a03dea58ddb38479b4f1ef86f556d)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Max Reitz <mreitz@redhat.com>
|
|
|
9ae3a8 |
---
|
|
|
9ae3a8 |
block/qcow2-cluster.c | 4 ++--
|
|
|
9ae3a8 |
block/qcow2-refcount.c | 58 ++++++++++++++++++++++++++++++++++++++++++++------
|
|
|
9ae3a8 |
block/qcow2.h | 1 +
|
|
|
9ae3a8 |
3 files changed, 55 insertions(+), 8 deletions(-)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9ae3a8 |
---
|
|
|
9ae3a8 |
block/qcow2-cluster.c | 4 +-
|
|
|
9ae3a8 |
block/qcow2-refcount.c | 58 +++++++++++++++++++++++++++++++++++++++++++-----
|
|
|
9ae3a8 |
block/qcow2.h | 1 +
|
|
|
9ae3a8 |
3 files changed, 55 insertions(+), 8 deletions(-)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
|
|
|
9ae3a8 |
index 7c248aa..2d5aa92 100644
|
|
|
9ae3a8 |
--- a/block/qcow2-cluster.c
|
|
|
9ae3a8 |
+++ b/block/qcow2-cluster.c
|
|
|
9ae3a8 |
@@ -145,7 +145,7 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
|
|
|
9ae3a8 |
* and we really don't want bdrv_pread to perform a read-modify-write)
|
|
|
9ae3a8 |
*/
|
|
|
9ae3a8 |
#define L1_ENTRIES_PER_SECTOR (512 / 8)
|
|
|
9ae3a8 |
-static int write_l1_entry(BlockDriverState *bs, int l1_index)
|
|
|
9ae3a8 |
+int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
BDRVQcowState *s = bs->opaque;
|
|
|
9ae3a8 |
uint64_t buf[L1_ENTRIES_PER_SECTOR];
|
|
|
9ae3a8 |
@@ -254,7 +254,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
|
|
|
9ae3a8 |
/* update the L1 entry */
|
|
|
9ae3a8 |
trace_qcow2_l2_allocate_write_l1(bs, l1_index);
|
|
|
9ae3a8 |
s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
|
|
|
9ae3a8 |
- ret = write_l1_entry(bs, l1_index);
|
|
|
9ae3a8 |
+ ret = qcow2_write_l1_entry(bs, l1_index);
|
|
|
9ae3a8 |
if (ret < 0) {
|
|
|
9ae3a8 |
goto fail;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
|
|
|
9ae3a8 |
index ddc3029..92ecc64 100644
|
|
|
9ae3a8 |
--- a/block/qcow2-refcount.c
|
|
|
9ae3a8 |
+++ b/block/qcow2-refcount.c
|
|
|
9ae3a8 |
@@ -1207,7 +1207,8 @@ fail:
|
|
|
9ae3a8 |
* been already detected and sufficiently signaled by the calling function
|
|
|
9ae3a8 |
* (qcow2_check_refcounts) by the time this function is called).
|
|
|
9ae3a8 |
*/
|
|
|
9ae3a8 |
-static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res)
|
|
|
9ae3a8 |
+static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
|
|
|
9ae3a8 |
+ BdrvCheckMode fix)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
BDRVQcowState *s = bs->opaque;
|
|
|
9ae3a8 |
uint64_t *l2_table = qemu_blockalign(bs, s->cluster_size);
|
|
|
9ae3a8 |
@@ -1218,6 +1219,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res)
|
|
|
9ae3a8 |
for (i = 0; i < s->l1_size; i++) {
|
|
|
9ae3a8 |
uint64_t l1_entry = s->l1_table[i];
|
|
|
9ae3a8 |
uint64_t l2_offset = l1_entry & L1E_OFFSET_MASK;
|
|
|
9ae3a8 |
+ bool l2_dirty = false;
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
if (!l2_offset) {
|
|
|
9ae3a8 |
continue;
|
|
|
9ae3a8 |
@@ -1229,10 +1231,24 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res)
|
|
|
9ae3a8 |
continue;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
if ((refcount == 1) != ((l1_entry & QCOW_OFLAG_COPIED) != 0)) {
|
|
|
9ae3a8 |
- fprintf(stderr, "ERROR OFLAG_COPIED L2 cluster: l1_index=%d "
|
|
|
9ae3a8 |
+ fprintf(stderr, "%s OFLAG_COPIED L2 cluster: l1_index=%d "
|
|
|
9ae3a8 |
"l1_entry=%" PRIx64 " refcount=%d\n",
|
|
|
9ae3a8 |
+ fix & BDRV_FIX_ERRORS ? "Repairing" :
|
|
|
9ae3a8 |
+ "ERROR",
|
|
|
9ae3a8 |
i, l1_entry, refcount);
|
|
|
9ae3a8 |
- res->corruptions++;
|
|
|
9ae3a8 |
+ if (fix & BDRV_FIX_ERRORS) {
|
|
|
9ae3a8 |
+ s->l1_table[i] = refcount == 1
|
|
|
9ae3a8 |
+ ? l1_entry | QCOW_OFLAG_COPIED
|
|
|
9ae3a8 |
+ : l1_entry & ~QCOW_OFLAG_COPIED;
|
|
|
9ae3a8 |
+ ret = qcow2_write_l1_entry(bs, i);
|
|
|
9ae3a8 |
+ if (ret < 0) {
|
|
|
9ae3a8 |
+ res->check_errors++;
|
|
|
9ae3a8 |
+ goto fail;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ res->corruptions_fixed++;
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ res->corruptions++;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
ret = bdrv_pread(bs->file, l2_offset, l2_table,
|
|
|
9ae3a8 |
@@ -1257,13 +1273,43 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res)
|
|
|
9ae3a8 |
continue;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) {
|
|
|
9ae3a8 |
- fprintf(stderr, "ERROR OFLAG_COPIED data cluster: "
|
|
|
9ae3a8 |
+ fprintf(stderr, "%s OFLAG_COPIED data cluster: "
|
|
|
9ae3a8 |
"l2_entry=%" PRIx64 " refcount=%d\n",
|
|
|
9ae3a8 |
+ fix & BDRV_FIX_ERRORS ? "Repairing" :
|
|
|
9ae3a8 |
+ "ERROR",
|
|
|
9ae3a8 |
l2_entry, refcount);
|
|
|
9ae3a8 |
- res->corruptions++;
|
|
|
9ae3a8 |
+ if (fix & BDRV_FIX_ERRORS) {
|
|
|
9ae3a8 |
+ l2_table[j] = cpu_to_be64(refcount == 1
|
|
|
9ae3a8 |
+ ? l2_entry | QCOW_OFLAG_COPIED
|
|
|
9ae3a8 |
+ : l2_entry & ~QCOW_OFLAG_COPIED);
|
|
|
9ae3a8 |
+ l2_dirty = true;
|
|
|
9ae3a8 |
+ res->corruptions_fixed++;
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ res->corruptions++;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (l2_dirty) {
|
|
|
9ae3a8 |
+ ret = qcow2_pre_write_overlap_check(bs,
|
|
|
9ae3a8 |
+ QCOW2_OL_DEFAULT & ~QCOW2_OL_ACTIVE_L2, l2_offset,
|
|
|
9ae3a8 |
+ s->cluster_size);
|
|
|
9ae3a8 |
+ if (ret < 0) {
|
|
|
9ae3a8 |
+ fprintf(stderr, "ERROR: Could not write L2 table; metadata "
|
|
|
9ae3a8 |
+ "overlap check failed: %s\n", strerror(-ret));
|
|
|
9ae3a8 |
+ res->check_errors++;
|
|
|
9ae3a8 |
+ goto fail;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ ret = bdrv_pwrite(bs->file, l2_offset, l2_table, s->cluster_size);
|
|
|
9ae3a8 |
+ if (ret < 0) {
|
|
|
9ae3a8 |
+ fprintf(stderr, "ERROR: Could not write L2 table: %s\n",
|
|
|
9ae3a8 |
+ strerror(-ret));
|
|
|
9ae3a8 |
+ res->check_errors++;
|
|
|
9ae3a8 |
+ goto fail;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
ret = 0;
|
|
|
9ae3a8 |
@@ -1409,7 +1455,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
/* check OFLAG_COPIED */
|
|
|
9ae3a8 |
- ret = check_oflag_copied(bs, res);
|
|
|
9ae3a8 |
+ ret = check_oflag_copied(bs, res, fix);
|
|
|
9ae3a8 |
if (ret < 0) {
|
|
|
9ae3a8 |
goto fail;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
diff --git a/block/qcow2.h b/block/qcow2.h
|
|
|
9ae3a8 |
index 86ddb30..10b7bf4 100644
|
|
|
9ae3a8 |
--- a/block/qcow2.h
|
|
|
9ae3a8 |
+++ b/block/qcow2.h
|
|
|
9ae3a8 |
@@ -432,6 +432,7 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int chk, int64_t offset,
|
|
|
9ae3a8 |
/* qcow2-cluster.c functions */
|
|
|
9ae3a8 |
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|
|
9ae3a8 |
bool exact_size);
|
|
|
9ae3a8 |
+int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
|
|
|
9ae3a8 |
void qcow2_l2_cache_reset(BlockDriverState *bs);
|
|
|
9ae3a8 |
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
|
|
|
9ae3a8 |
void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
|
|
9ae3a8 |
--
|
|
|
9ae3a8 |
1.7.1
|
|
|
9ae3a8 |
|