]> git.baikalelectronics.ru Git - kernel.git/commitdiff
btrfs: scrub: properly report super block errors in system log
authorQu Wenruo <wqu@suse.com>
Tue, 2 Aug 2022 06:53:02 +0000 (14:53 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 26 Sep 2022 10:27:53 +0000 (12:27 +0200)
[PROBLEM]

Unlike data/metadata corruption, if scrub detected some error in the
super block, the only error message is from the updated device status:

  BTRFS info (device dm-1): scrub: started on devid 2
  BTRFS error (device dm-1): bdev /dev/mapper/test-scratch2 errs: wr 0, rd 0, flush 0, corrupt 1, gen 0
  BTRFS info (device dm-1): scrub: finished on devid 2 with status: 0

This is not helpful at all.

[CAUSE]
Unlike data/metadata error reporting, there is no visible report in
kernel dmesg to report supper block errors.

In fact, return value of scrub_checksum_super() is intentionally
skipped, thus scrub_handle_errored_block() will never be called for
super blocks.

[FIX]
Make super block errors to output an error message, now the full
dmesg would looks like this:

  BTRFS info (device dm-1): scrub: started on devid 2
  BTRFS warning (device dm-1): super block error on device /dev/mapper/test-scratch2, physical 67108864
  BTRFS error (device dm-1): bdev /dev/mapper/test-scratch2 errs: wr 0, rd 0, flush 0, corrupt 1, gen 0
  BTRFS info (device dm-1): scrub: finished on devid 2 with status: 0
  BTRFS info (device dm-1): scrub: started on devid 2

This fix involves:

- Move the super_errors reporting to scrub_handle_errored_block()
  This allows the device status message to show after the super block
  error message.
  But now we no longer distinguish super block corruption and generation
  mismatch, now all counted as corruption.

- Properly check the return value from scrub_checksum_super()
- Add extra super block error reporting for scrub_print_warning().

Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/scrub.c

index 3afe5fa50a631f9f55286cb24e89c9c06ea1c830..0fe7c4882e1fd95f841fdd0522862db4ea98cba8 100644 (file)
@@ -729,6 +729,13 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
        dev = sblock->sectors[0]->dev;
        fs_info = sblock->sctx->fs_info;
 
+       /* Super block error, no need to search extent tree. */
+       if (sblock->sectors[0]->flags & BTRFS_EXTENT_FLAG_SUPER) {
+               btrfs_warn_in_rcu(fs_info, "%s on device %s, physical %llu",
+                       errstr, rcu_str_deref(dev->name),
+                       sblock->sectors[0]->physical);
+               return;
+       }
        path = btrfs_alloc_path();
        if (!path)
                return;
@@ -804,7 +811,7 @@ static inline void scrub_put_recover(struct btrfs_fs_info *fs_info,
 static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
 {
        struct scrub_ctx *sctx = sblock_to_check->sctx;
-       struct btrfs_device *dev;
+       struct btrfs_device *dev = sblock_to_check->sectors[0]->dev;
        struct btrfs_fs_info *fs_info;
        u64 logical;
        unsigned int failed_mirror_index;
@@ -825,13 +832,15 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
        fs_info = sctx->fs_info;
        if (sblock_to_check->sectors[0]->flags & BTRFS_EXTENT_FLAG_SUPER) {
                /*
-                * if we find an error in a super block, we just report it.
+                * If we find an error in a super block, we just report it.
                 * They will get written with the next transaction commit
                 * anyway
                 */
+               scrub_print_warning("super block error", sblock_to_check);
                spin_lock(&sctx->stat_lock);
                ++sctx->stat.super_errors;
                spin_unlock(&sctx->stat_lock);
+               btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_CORRUPTION_ERRS);
                return 0;
        }
        logical = sblock_to_check->sectors[0]->logical;
@@ -840,7 +849,6 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
        is_metadata = !(sblock_to_check->sectors[0]->flags &
                        BTRFS_EXTENT_FLAG_DATA);
        have_csum = sblock_to_check->sectors[0]->have_csum;
-       dev = sblock_to_check->sectors[0]->dev;
 
        if (!sctx->is_dev_replace && btrfs_repair_one_zone(fs_info, logical))
                return 0;
@@ -1762,7 +1770,7 @@ static int scrub_checksum(struct scrub_block *sblock)
        else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
                ret = scrub_checksum_tree_block(sblock);
        else if (flags & BTRFS_EXTENT_FLAG_SUPER)
-               (void)scrub_checksum_super(sblock);
+               ret = scrub_checksum_super(sblock);
        else
                WARN_ON(1);
        if (ret)
@@ -1901,23 +1909,6 @@ static int scrub_checksum_super(struct scrub_block *sblock)
        if (memcmp(calculated_csum, s->csum, sctx->fs_info->csum_size))
                ++fail_cor;
 
-       if (fail_cor + fail_gen) {
-               /*
-                * if we find an error in a super block, we just report it.
-                * They will get written with the next transaction commit
-                * anyway
-                */
-               spin_lock(&sctx->stat_lock);
-               ++sctx->stat.super_errors;
-               spin_unlock(&sctx->stat_lock);
-               if (fail_cor)
-                       btrfs_dev_stat_inc_and_print(sector->dev,
-                               BTRFS_DEV_STAT_CORRUPTION_ERRS);
-               else
-                       btrfs_dev_stat_inc_and_print(sector->dev,
-                               BTRFS_DEV_STAT_GENERATION_ERRS);
-       }
-
        return fail_cor + fail_gen;
 }