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