qemu-block
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-block] [RFC PATCH 1/2] qcow2: Allow checking and repairing corrupt


From: Alberto Garcia
Subject: [Qemu-block] [RFC PATCH 1/2] qcow2: Allow checking and repairing corrupted internal snapshots
Date: Thu, 15 Feb 2018 18:30:54 +0200

The L1 table parameters of internal snapshots are generally not
checked by QEMU. This patch allows 'qemu-img check' to detect broken
snapshots and to skip them when doing the refcount consistency check.

Since without an L1 table we don't have a reliable way to recover the
data from the snapshot, when 'qemu-img check' runs in repair mode this
patch simply removes the corrupted snapshots.

Signed-off-by: Alberto Garcia <address@hidden>
---
 block/qcow2-snapshot.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
 block/qcow2.c          |  7 ++++++-
 block/qcow2.h          |  2 ++
 3 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index cee25f582b..7a36073e3e 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -736,3 +736,56 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
 
     return 0;
 }
+
+/* Check the snapshot table and optionally delete the corrupted entries */
+int qcow2_snapshot_table_check(BlockDriverState *bs, BdrvCheckResult *result,
+                               BdrvCheckMode fix)
+{
+    BDRVQcow2State *s = bs->opaque;
+    bool keep_checking;
+    int ret, i;
+
+    do {
+        keep_checking = false;
+
+        for (i = 0; i < s->nb_snapshots; i++) {
+            QCowSnapshot *sn = s->snapshots + i;
+            bool found_corruption = false;
+
+            if (offset_into_cluster(s, sn->l1_table_offset)) {
+                fprintf(stderr, "%s snapshot %s (%s) l1_offset=%#" PRIx64 ": "
+                        "L1 table is not cluster aligned; snapshot table entry 
"
+                        "corrupted\n",
+                        (fix & BDRV_FIX_ERRORS) ? "Deleting" : "ERROR",
+                        sn->id_str, sn->name, sn->l1_table_offset);
+                found_corruption = true;
+            } else if (sn->l1_size > QCOW_MAX_L1_SIZE / sizeof(uint64_t)) {
+                fprintf(stderr, "%s snapshot %s (%s) l1_size=%#" PRIx32 ": "
+                        "L1 table is too large; snapshot table entry 
corrupted\n",
+                        (fix & BDRV_FIX_ERRORS) ? "Deleting" : "ERROR",
+                        sn->id_str, sn->name, sn->l1_size);
+                found_corruption = true;
+            }
+
+            if (found_corruption) {
+                result->corruptions++;
+                sn->l1_size = 0; /* Prevent this L1 table from being used */
+                if (fix & BDRV_FIX_ERRORS) {
+                    ret = qcow2_snapshot_delete(bs, sn->id_str, sn->name, 
NULL);
+                    if (ret < 0) {
+                        return ret;
+                    }
+                    result->corruptions_fixed++;
+                    /* If we modified the snapshot table we can't keep
+                     * iterating. We have to start again from the
+                     * beginning instead. */
+                    keep_checking = true;
+                    break;
+                }
+            }
+        }
+
+    } while (keep_checking);
+
+    return 0;
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index 2c6c33b67c..20e16ea602 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -546,7 +546,12 @@ int qcow2_mark_consistent(BlockDriverState *bs)
 static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
                        BdrvCheckMode fix)
 {
-    int ret = qcow2_check_refcounts(bs, result, fix);
+    int ret = qcow2_snapshot_table_check(bs, result, fix);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = qcow2_check_refcounts(bs, result, fix);
     if (ret < 0) {
         return ret;
     }
diff --git a/block/qcow2.h b/block/qcow2.h
index 1a84cc77b0..19f14bfc1e 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -637,6 +637,8 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
                             const char *snapshot_id,
                             const char *name,
                             Error **errp);
+int qcow2_snapshot_table_check(BlockDriverState *bs, BdrvCheckResult *result,
+                               BdrvCheckMode fix);
 
 void qcow2_free_snapshots(BlockDriverState *bs);
 int qcow2_read_snapshots(BlockDriverState *bs);
-- 
2.11.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]