btrfs: scrub: use dedicated super block verification function to scrub one super...
[sfrench/cifs-2.6.git] / fs / btrfs / scrub.c
index 3cdf73277e7e0ad19364d5ea0f0d30b0dc0c42ee..f182a1ba61ea3ece290f1f70c5a8b2cbd5592922 100644 (file)
@@ -4243,18 +4243,62 @@ skip:
        return ret;
 }
 
+static int scrub_one_super(struct scrub_ctx *sctx, struct btrfs_device *dev,
+                          struct page *page, u64 physical, u64 generation)
+{
+       struct btrfs_fs_info *fs_info = sctx->fs_info;
+       struct bio_vec bvec;
+       struct bio bio;
+       struct btrfs_super_block *sb = page_address(page);
+       int ret;
+
+       bio_init(&bio, dev->bdev, &bvec, 1, REQ_OP_READ);
+       bio.bi_iter.bi_sector = physical >> SECTOR_SHIFT;
+       __bio_add_page(&bio, page, BTRFS_SUPER_INFO_SIZE, 0);
+       ret = submit_bio_wait(&bio);
+       bio_uninit(&bio);
+
+       if (ret < 0)
+               return ret;
+       ret = btrfs_check_super_csum(fs_info, sb);
+       if (ret != 0) {
+               btrfs_err_rl(fs_info,
+                       "super block at physical %llu devid %llu has bad csum",
+                       physical, dev->devid);
+               return -EIO;
+       }
+       if (btrfs_super_generation(sb) != generation) {
+               btrfs_err_rl(fs_info,
+"super block at physical %llu devid %llu has bad generation %llu expect %llu",
+                            physical, dev->devid,
+                            btrfs_super_generation(sb), generation);
+               return -EUCLEAN;
+       }
+
+       return btrfs_validate_super(fs_info, sb, -1);
+}
+
 static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
                                           struct btrfs_device *scrub_dev)
 {
        int     i;
        u64     bytenr;
        u64     gen;
-       int     ret;
+       int ret = 0;
+       struct page *page;
        struct btrfs_fs_info *fs_info = sctx->fs_info;
 
        if (BTRFS_FS_ERROR(fs_info))
                return -EROFS;
 
+       page = alloc_page(GFP_KERNEL);
+       if (!page) {
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.malloc_errors++;
+               spin_unlock(&sctx->stat_lock);
+               return -ENOMEM;
+       }
+
        /* Seed devices of a new filesystem has their own generation. */
        if (scrub_dev->fs_devices != fs_info->fs_devices)
                gen = scrub_dev->generation;
@@ -4269,14 +4313,14 @@ static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
                if (!btrfs_check_super_location(scrub_dev, bytenr))
                        continue;
 
-               ret = scrub_sectors(sctx, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr,
-                                   scrub_dev, BTRFS_EXTENT_FLAG_SUPER, gen, i,
-                                   NULL, bytenr);
-               if (ret)
-                       return ret;
+               ret = scrub_one_super(sctx, scrub_dev, page, bytenr, gen);
+               if (ret) {
+                       spin_lock(&sctx->stat_lock);
+                       sctx->stat.super_errors++;
+                       spin_unlock(&sctx->stat_lock);
+               }
        }
-       wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0);
-
+       __free_page(page);
        return 0;
 }