Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 3160499aacb81f6735941eb4c372d87a > files > 513

kvm-83-164.el5_5.30.src.rpm

From 6e16e19476a1677f748aabd82ff438a93ab56879 Mon Sep 17 00:00:00 2001
From: Kevin Wolf <kwolf@redhat.com>
Date: Thu, 8 Jul 2010 15:34:08 -0300
Subject: [PATCH 4/4] qcow2: Change check to distinguish error cases

RH-Author: Kevin Wolf <kwolf@redhat.com>
Message-id: <patch-10577-clone-for-rhel55-rhel55>
Patchwork-id: 10580
O-Subject: [RHEL-5.6 KVM PATCH 2/2] qcow2: Change check to distinguish error
	cases
Bugzilla: 618206
RH-Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com>
RH-Acked-by: Christoph Hellwig <chellwig@redhat.com>
RH-Acked-by: Juan Quintela <quintela@redhat.com>

Bugzilla: 606651
Upstream commit: 9ac228e02cf16202547e7025ef300369e0db7781

This distinguishes between harmless leaks and real corruption. Hopefully users
better understand what qemu-img check wants to tell them.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qemu/block-qcow2.c |   89 +++++++++++++++++++++++++++++-----------------------
 qemu/block.c       |    3 +-
 qemu/block_int.h   |    7 +++-
 3 files changed, 56 insertions(+), 43 deletions(-)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 qemu/block-qcow2.c |   89 +++++++++++++++++++++++++++++-----------------------
 qemu/block.c       |    3 +-
 qemu/block_int.h   |    7 +++-
 3 files changed, 56 insertions(+), 43 deletions(-)

diff --git a/qemu/block-qcow2.c b/qemu/block-qcow2.c
index 913679f..9501ea1 100644
--- a/qemu/block-qcow2.c
+++ b/qemu/block-qcow2.c
@@ -181,7 +181,7 @@ static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
 static int64_t alloc_bytes(BlockDriverState *bs, int size);
 static void free_clusters(BlockDriverState *bs,
                           int64_t offset, int64_t size);
-static int check_refcounts(BlockDriverState *bs);
+static int check_refcounts(BlockDriverState *bs, BdrvCheckResult *res);
 
 static inline int64_t align_offset(int64_t offset, int n)
 {
@@ -3164,9 +3164,10 @@ fail:
  * This is used to construct a temporary refcount table out of L1 and L2 tables
  * which can be compared the the refcount table saved in the image.
  *
- * Returns the number of errors in the image that were found
+ * Modifies the number of errors in res.
  */
-static int inc_refcounts(BlockDriverState *bs,
+static void inc_refcounts(BlockDriverState *bs,
+                          BdrvCheckResult *res,
                           uint16_t *refcount_table,
                           int refcount_table_size,
                           int64_t offset, int64_t size)
@@ -3174,33 +3175,35 @@ static int inc_refcounts(BlockDriverState *bs,
     BDRVQcowState *s = bs->opaque;
     int64_t start, last, cluster_offset;
     int k;
-    int errors = 0;
 
     if (size <= 0)
-        return 0;
+        return;
 
     start = offset & ~(s->cluster_size - 1);
     last = (offset + size - 1) & ~(s->cluster_size - 1);
     for(cluster_offset = start; cluster_offset <= last;
         cluster_offset += s->cluster_size) {
         k = cluster_offset >> s->cluster_bits;
-        if (k < 0 || k >= refcount_table_size) {
+        if (k < 0) {
             fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
                 cluster_offset);
-            errors++;
+            res->corruptions++;
+        } else if (k >= refcount_table_size) {
+            fprintf(stderr, "Warning: cluster offset=0x%" PRIx64 " is after "
+                "the end of the image file, can't properly check refcounts.\n",
+                cluster_offset);
+            res->check_errors++;
         } else {
             if (++refcount_table[k] == 0) {
                 fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64
                     "\n", cluster_offset);
-                errors++;
+                res->corruptions++;
             }
         }
     }
-
-    return errors;
 }
 
-static int check_refcounts_l1(BlockDriverState *bs,
+static int check_refcounts_l1(BlockDriverState *bs, BdrvCheckResult *res,
                               uint16_t *refcount_table,
                               int refcount_table_size,
                               int64_t l1_table_offset, int l1_size,
@@ -3209,12 +3212,11 @@ static int check_refcounts_l1(BlockDriverState *bs,
     BDRVQcowState *s = bs->opaque;
     uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;
     int l2_size, i, j, nb_csectors, refcount;
-    int errors = 0;
 
     l2_table = NULL;
     l1_size2 = l1_size * sizeof(uint64_t);
 
-    errors += inc_refcounts(bs, refcount_table, refcount_table_size,
+    inc_refcounts(bs, res, refcount_table, refcount_table_size,
                   l1_table_offset, l1_size2);
 
     l1_table = qemu_malloc(l1_size2);
@@ -3242,7 +3244,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
                 if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
                     fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64
                         " refcount=%d\n", l2_offset, refcount);
-                    errors++;
+                    res->corruptions++;
                 }
             }
             l2_offset &= ~QCOW_OFLAG_COPIED;
@@ -3257,12 +3259,12 @@ static int check_refcounts_l1(BlockDriverState *bs,
                                 "copied flag must never be set for compressed "
                                 "clusters\n", offset >> s->cluster_bits);
                             offset &= ~QCOW_OFLAG_COPIED;
-                            errors++;
+                            res->corruptions++;
                         }
                         nb_csectors = ((offset >> s->csize_shift) &
                                        s->csize_mask) + 1;
                         offset &= s->cluster_offset_mask;
-                        errors += inc_refcounts(bs, refcount_table,
+                        inc_refcounts(bs, res, refcount_table,
                                       refcount_table_size,
                                       offset & ~511, nb_csectors * 512);
                     } else {
@@ -3275,11 +3277,11 @@ static int check_refcounts_l1(BlockDriverState *bs,
                             if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) {
                                 fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
                                     PRIx64 " refcount=%d\n", offset, refcount);
-                                errors++;
+                                res->corruptions++;
                             }
                         }
                         offset &= ~QCOW_OFLAG_COPIED;
-                        errors += inc_refcounts(bs, refcount_table,
+                        inc_refcounts(bs, res, refcount_table,
                                       refcount_table_size,
                                       offset, s->cluster_size);
 
@@ -3287,12 +3289,12 @@ static int check_refcounts_l1(BlockDriverState *bs,
                         if (offset & (s->cluster_size - 1)) {
                             fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
                                 "properly aligned; L2 entry corrupted.\n", offset);
-                            errors++;
+                            res->corruptions++;
                         }
                     }
                 }
             }
-            errors += inc_refcounts(bs, refcount_table,
+            inc_refcounts(bs, res, refcount_table,
                           refcount_table_size,
                           l2_offset,
                           s->cluster_size);
@@ -3301,16 +3303,17 @@ static int check_refcounts_l1(BlockDriverState *bs,
             if (l2_offset & (s->cluster_size - 1)) {
                 fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
                     "cluster aligned; L1 entry corrupted\n", l2_offset);
-                errors++;
+                res->corruptions++;
             }
 
         }
     }
     qemu_free(l1_table);
     qemu_free(l2_table);
-    return errors;
+    return 0;
  fail:
     fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
+    res->check_errors++;
     qemu_free(l1_table);
     qemu_free(l2_table);
     return -EIO;
@@ -3322,41 +3325,43 @@ static int check_refcounts_l1(BlockDriverState *bs,
  * 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 occured.
  */
-static int check_refcounts(BlockDriverState *bs)
+static int check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
 {
     BDRVQcowState *s = bs->opaque;
     int64_t size;
     int nb_clusters, refcount1, refcount2, i;
     QCowSnapshot *sn;
     uint16_t *refcount_table;
-    int ret, errors = 0;
+    int ret;
 
     size = bdrv_getlength(s->hd);
     nb_clusters = size_to_clusters(s, size);
     refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
 
     /* header */
-    errors += inc_refcounts(bs, refcount_table, nb_clusters,
+    inc_refcounts(bs, res, refcount_table, nb_clusters,
                   0, s->cluster_size);
 
-    ret = check_refcounts_l1(bs, refcount_table, nb_clusters,
+    ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
                        s->l1_table_offset, s->l1_size, 1);
     if (ret < 0) {
         return ret;
     }
-    errors += ret;
 
     /* snapshots */
     for(i = 0; i < s->nb_snapshots; i++) {
         sn = s->snapshots + i;
-        check_refcounts_l1(bs, refcount_table, nb_clusters,
-                           sn->l1_table_offset, sn->l1_size, 0);
+        ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
+            sn->l1_table_offset, sn->l1_size, 0);
+        if (ret < 0) {
+            return ret;
+        }
     }
-    errors += inc_refcounts(bs, refcount_table, nb_clusters,
+    inc_refcounts(bs, res, refcount_table, nb_clusters,
                   s->snapshots_offset, s->snapshots_size);
 
     /* refcount data */
-    errors += inc_refcounts(bs, refcount_table, nb_clusters,
+    inc_refcounts(bs, res, refcount_table, nb_clusters,
                   s->refcount_table_offset,
                   s->refcount_table_size * sizeof(uint64_t));
     for(i = 0; i < s->refcount_table_size; i++) {
@@ -3368,22 +3373,23 @@ static int check_refcounts(BlockDriverState *bs)
         if (offset & (s->cluster_size - 1)) {
             fprintf(stderr, "ERROR refcount block %d is not "
                 "cluster aligned; refcount table entry corrupted\n", i);
-            errors++;
+            res->corruptions++;
             continue;
         }
 
         if (cluster >= nb_clusters) {
             fprintf(stderr, "ERROR refcount block %d is outside image\n", i);
-            errors++;
+            res->corruptions++;
             continue;
         }
 
         if (offset != 0) {
-            errors += inc_refcounts(bs, refcount_table, nb_clusters,
+            inc_refcounts(bs, res, refcount_table, nb_clusters,
                           offset, s->cluster_size);
             if (refcount_table[cluster] != 1) {
                 fprintf(stderr, "ERROR refcount block %d refcount=%d\n",
                     i, refcount_table[cluster]);
+                res->corruptions++;
             }
         }
     }
@@ -3399,20 +3405,25 @@ static int check_refcounts(BlockDriverState *bs)
 
         refcount2 = refcount_table[i];
         if (refcount1 != refcount2) {
-            fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n",
+            fprintf(stderr, "%s cluster %d refcount=%d reference=%d\n",
+                   refcount1 < refcount2 ? "ERROR" : "Leaked",
                    i, refcount1, refcount2);
-            errors++;
+            if (refcount1 < refcount2) {
+                res->corruptions++;
+            } else {
+                res->leaks++;
+            }
         }
     }
 
     qemu_free(refcount_table);
 
-    return errors;
+    return 0;
 }
 
-static int qcow_check(BlockDriverState *bs)
+static int qcow_check(BlockDriverState *bs, BdrvCheckResult *result)
 {
-    return check_refcounts(bs);
+    return check_refcounts(bs, result);
 }
 
 #if 0
diff --git a/qemu/block.c b/qemu/block.c
index 9ed7b91..585204e 100644
--- a/qemu/block.c
+++ b/qemu/block.c
@@ -600,8 +600,7 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res)
     }
 
     memset(res, 0, sizeof(*res));
-    res->corruptions = bs->drv->bdrv_check(bs);
-    return res->corruptions < 0 ? res->corruptions : 0;
+    return bs->drv->bdrv_check(bs, res);
 }
 
 /* commit COW file into the raw image */
diff --git a/qemu/block_int.h b/qemu/block_int.h
index 43a4e6a..dbb5534 100644
--- a/qemu/block_int.h
+++ b/qemu/block_int.h
@@ -102,8 +102,11 @@ struct BlockDriver {
                         const char *backing_file, const char *backing_format,
                         int flags);
 
-    /* Returns number of errors in image, -errno for internal errors */
-    int (*bdrv_check)(BlockDriverState* bs);
+    /*
+     * Returns 0 for completed check, -errno for internal errors.
+     * The check results are stored in result.
+     */
+    int (*bdrv_check)(BlockDriverState* bs, BdrvCheckResult *result);
 
     struct BlockDriver *next;
 };
-- 
1.7.0.3