Fixed that errors had been counted multiple times.

Signed-off-by: Stefan Behrens <sbehr...@giantdisaster.de>
---
 fs/btrfs/ioctl.h |   30 ++++++++------
 fs/btrfs/scrub.c |  115 ++++++++++++++++++++++++++++++++----------------------
 2 files changed, 85 insertions(+), 60 deletions(-)

diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index 4f69028..48b926c 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -49,17 +49,20 @@ struct btrfs_ioctl_vol_args_v2 {
  * result of a finished scrub, a canceled scrub or a progress inquiry
  */
 struct btrfs_scrub_progress {
-       __u64 data_extents_scrubbed;    /* # of data extents scrubbed */
-       __u64 tree_extents_scrubbed;    /* # of tree extents scrubbed */
+       __u64 data_extents_scrubbed;    /* # of 4k data data extents scrubbed */
+       __u64 tree_extents_scrubbed;    /* # of 4k data tree extents scrubbed */
        __u64 data_bytes_scrubbed;      /* # of data bytes scrubbed */
        __u64 tree_bytes_scrubbed;      /* # of tree bytes scrubbed */
-       __u64 read_errors;              /* # of read errors encountered (EIO) */
-       __u64 csum_errors;              /* # of failed csum checks */
-       __u64 verify_errors;            /* # of occurences, where the metadata
-                                        * of a tree block did not match the
-                                        * expected values, like generation or
-                                        * logical */
-       __u64 no_csum;                  /* # of 4k data block for which no csum
+       __u64 read_errors;              /* # of 4k data blocks which encountered
+                                        * read errors (EIO) */
+       __u64 csum_errors;              /* # of 4k data blocks which failed csum
+                                        * checks */
+       __u64 verify_errors;            /* # of 4k data blocks, where the
+                                        * metadata of a tree block did not
+                                        * match the expected values, like
+                                        * generation or logical and the
+                                        * checksum was not incorrect */
+       __u64 no_csum;                  /* # of 4k data blocks for which no csum
                                         * is present, probably the result of
                                         * data written with nodatasum */
        __u64 csum_discards;            /* # of csum for which no data was found
@@ -68,10 +71,11 @@ struct btrfs_scrub_progress {
        __u64 malloc_errors;            /* # of internal kmalloc errors. These
                                         * will likely cause an incomplete
                                         * scrub */
-       __u64 uncorrectable_errors;     /* # of errors where either no intact
-                                        * copy was found or the writeback
-                                        * failed */
-       __u64 corrected_errors;         /* # of errors corrected */
+       __u64 uncorrectable_errors;     /* # of 4k data blocks with errors where
+                                        * either no intact copy was found or
+                                        * the writeback failed */
+       __u64 corrected_errors;         /* # of 4k data blocks with corrected
+                                        * errors */
        __u64 last_physical;            /* last physical address scrubbed. In
                                         * case a scrub was aborted, this can
                                         * be used to restart the scrub */
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 9770cc5..21ea2ab 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -48,10 +48,11 @@ struct scrub_dev;
 static void scrub_bio_end_io(struct bio *bio, int err);
 static void scrub_checksum(struct btrfs_work *work);
 static int scrub_checksum_data(struct scrub_dev *sdev,
-                              struct scrub_page *spag, void *buffer);
+                              struct scrub_page *spag, void *buffer,
+                              int modify_stats);
 static int scrub_checksum_tree_block(struct scrub_dev *sdev,
                                     struct scrub_page *spag, u64 logical,
-                                    void *buffer);
+                                    void *buffer, int modify_stats);
 static int scrub_checksum_super(struct scrub_bio *sbio, void *buffer);
 static int scrub_fixup_check(struct scrub_bio *sbio, int ix);
 static void scrub_fixup_end_io(struct bio *bio, int err);
@@ -555,7 +556,8 @@ out:
  * recheck_error gets called for every page in the bio, even though only
  * one may be bad
  */
-static int scrub_recheck_error(struct scrub_bio *sbio, int ix)
+static int scrub_recheck_error(struct scrub_bio *sbio, int ix,
+                              int modify_stats)
 {
        struct scrub_dev *sdev = sbio->sdev;
        u64 sector = (sbio->physical + ix * PAGE_SIZE) >> 9;
@@ -575,9 +577,11 @@ static int scrub_recheck_error(struct scrub_bio *sbio, int 
ix)
                        scrub_print_warning("checksum error", sbio, ix);
        }
 
-       spin_lock(&sdev->stat_lock);
-       ++sdev->stat.read_errors;
-       spin_unlock(&sdev->stat_lock);
+       if (modify_stats) {
+               spin_lock(&sdev->stat_lock);
+               ++sdev->stat.read_errors;
+               spin_unlock(&sdev->stat_lock);
+       }
 
        scrub_fixup(sbio, ix);
        return 1;
@@ -594,12 +598,12 @@ static int scrub_fixup_check(struct scrub_bio *sbio, int 
ix)
        buffer = kmap_atomic(page, KM_USER0);
        if (flags & BTRFS_EXTENT_FLAG_DATA) {
                ret = scrub_checksum_data(sbio->sdev,
-                                         sbio->spag + ix, buffer);
+                                         sbio->spag + ix, buffer, 0);
        } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
                ret = scrub_checksum_tree_block(sbio->sdev,
                                                sbio->spag + ix,
                                                sbio->logical + ix * PAGE_SIZE,
-                                               buffer);
+                                               buffer, 0);
        } else {
                WARN_ON(1);
        }
@@ -700,15 +704,15 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix)
                        /* I/O-error, writeback failed, give up */
                        goto uncorrectable;
                }
+
+               spin_lock(&sdev->stat_lock);
+               ++sdev->stat.corrected_errors;
+               spin_unlock(&sdev->stat_lock);
+               printk_ratelimited(KERN_ERR "btrfs: fixed up error at logical "
+                                  "%llu\n", (unsigned long long)logical);
        }
 
        kfree(bbio);
-       spin_lock(&sdev->stat_lock);
-       ++sdev->stat.corrected_errors;
-       spin_unlock(&sdev->stat_lock);
-
-       printk_ratelimited(KERN_ERR "btrfs: fixed up error at logical %llu\n",
-                              (unsigned long long)logical);
        return;
 
 uncorrectable:
@@ -766,16 +770,15 @@ static void scrub_checksum(struct btrfs_work *work)
        u64 flags;
        u64 logical;
        int ret;
+       int recheck_succeeded_at_least_once = 0;
+       int recheck_failed_at_least_once = 0;
 
        if (sbio->err) {
-               ret = 0;
                for (i = 0; i < sbio->count; ++i)
-                       ret |= scrub_recheck_error(sbio, i);
-               if (!ret) {
-                       spin_lock(&sdev->stat_lock);
-                       ++sdev->stat.unverified_errors;
-                       spin_unlock(&sdev->stat_lock);
-               }
+                       if (scrub_recheck_error(sbio, i, 1))
+                               recheck_failed_at_least_once = 1;
+                       else
+                               recheck_succeeded_at_least_once = 1;
 
                sbio->bio->bi_flags &= ~(BIO_POOL_MASK - 1);
                sbio->bio->bi_flags |= 1 << BIO_UPTODATE;
@@ -797,10 +800,11 @@ static void scrub_checksum(struct btrfs_work *work)
                logical = sbio->logical + i * PAGE_SIZE;
                ret = 0;
                if (flags & BTRFS_EXTENT_FLAG_DATA) {
-                       ret = scrub_checksum_data(sdev, sbio->spag + i, buffer);
+                       ret = scrub_checksum_data(sdev, sbio->spag + i, buffer,
+                                                 1);
                } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
                        ret = scrub_checksum_tree_block(sdev, sbio->spag + i,
-                                                       logical, buffer);
+                                                       logical, buffer, 1);
                } else if (flags & BTRFS_EXTENT_FLAG_SUPER) {
                        BUG_ON(i);
                        (void)scrub_checksum_super(sbio, buffer);
@@ -809,16 +813,19 @@ static void scrub_checksum(struct btrfs_work *work)
                }
                kunmap_atomic(buffer, KM_USER0);
                if (ret) {
-                       ret = scrub_recheck_error(sbio, i);
-                       if (!ret) {
-                               spin_lock(&sdev->stat_lock);
-                               ++sdev->stat.unverified_errors;
-                               spin_unlock(&sdev->stat_lock);
-                       }
+                       if (scrub_recheck_error(sbio, i, 0))
+                               recheck_failed_at_least_once = 1;
+                       else
+                               recheck_succeeded_at_least_once = 1;
                }
        }
 
 out:
+       if (recheck_succeeded_at_least_once && !recheck_failed_at_least_once) {
+               spin_lock(&sdev->stat_lock);
+               ++sdev->stat.unverified_errors;
+               spin_unlock(&sdev->stat_lock);
+       }
        scrub_free_bio(sbio->bio);
        sbio->bio = NULL;
        spin_lock(&sdev->list_lock);
@@ -830,7 +837,8 @@ out:
 }
 
 static int scrub_checksum_data(struct scrub_dev *sdev,
-                              struct scrub_page *spag, void *buffer)
+                              struct scrub_page *spag, void *buffer,
+                              int modify_stats)
 {
        u8 csum[BTRFS_CSUM_SIZE];
        u32 crc = ~(u32)0;
@@ -842,22 +850,21 @@ static int scrub_checksum_data(struct scrub_dev *sdev,
 
        crc = btrfs_csum_data(root, buffer, crc, PAGE_SIZE);
        btrfs_csum_final(crc, csum);
-       if (memcmp(csum, spag->csum, sdev->csum_size))
+       if (memcmp(csum, spag->csum, sdev->csum_size)) {
                fail = 1;
-
-       spin_lock(&sdev->stat_lock);
-       ++sdev->stat.data_extents_scrubbed;
-       sdev->stat.data_bytes_scrubbed += PAGE_SIZE;
-       if (fail)
-               ++sdev->stat.csum_errors;
-       spin_unlock(&sdev->stat_lock);
+               if (modify_stats) {
+                       spin_lock(&sdev->stat_lock);
+                       ++sdev->stat.csum_errors;
+                       spin_unlock(&sdev->stat_lock);
+               }
+       }
 
        return fail;
 }
 
 static int scrub_checksum_tree_block(struct scrub_dev *sdev,
                                     struct scrub_page *spag, u64 logical,
-                                    void *buffer)
+                                    void *buffer, int modify_stats)
 {
        struct btrfs_header *h;
        struct btrfs_root *root = sdev->dev->dev_root;
@@ -893,14 +900,17 @@ static int scrub_checksum_tree_block(struct scrub_dev 
*sdev,
        if (memcmp(csum, h->csum, sdev->csum_size))
                ++crc_fail;
 
-       spin_lock(&sdev->stat_lock);
-       ++sdev->stat.tree_extents_scrubbed;
-       sdev->stat.tree_bytes_scrubbed += PAGE_SIZE;
-       if (crc_fail)
-               ++sdev->stat.csum_errors;
-       if (fail)
-               ++sdev->stat.verify_errors;
-       spin_unlock(&sdev->stat_lock);
+       if (modify_stats) {
+               if (crc_fail) {
+                       spin_lock(&sdev->stat_lock);
+                       ++sdev->stat.csum_errors;
+                       spin_unlock(&sdev->stat_lock);
+               } else if (fail) {
+                       spin_lock(&sdev->stat_lock);
+                       ++sdev->stat.verify_errors;
+                       spin_unlock(&sdev->stat_lock);
+               }
+       }
 
        return fail || crc_fail;
 }
@@ -1106,6 +1116,17 @@ static int scrub_extent(struct scrub_dev *sdev, u64 
logical, u64 len,
                }
                ret = scrub_page(sdev, logical, l, physical, flags, gen,
                                 mirror_num, have_csum ? csum : NULL, 0);
+               spin_lock(&sdev->stat_lock);
+               if (flags & BTRFS_EXTENT_FLAG_DATA) {
+                       ++sdev->stat.data_extents_scrubbed;
+                       sdev->stat.data_bytes_scrubbed += l;
+               } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
+                       ++sdev->stat.tree_extents_scrubbed;
+                       sdev->stat.tree_bytes_scrubbed += l;
+               } else {
+                       WARN_ON(1);
+               }
+               spin_unlock(&sdev->stat_lock);
                if (ret)
                        return ret;
                len -= l;
-- 
1.7.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to