[PATCH] Btrfs: fix scrub statistics report

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

 



Fixed that errors had been counted multiple times.

Signed-off-by: Stefan Behrens <sbehrens@xxxxxxxxxxxxxxxx>
---
 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux