Commit 2a2dc22f authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba
Browse files

btrfs: scrub: use dedicated super block verification function to scrub one super block



There is really no need to go through the super complex scrub_sectors()
to just handle super blocks.  Introduce a dedicated function to handle
super block scrubbing.

This new function will introduce a behavior change, instead of using the
complex but concurrent scrub_bio system, here we just go submit-and-wait.

There is really not much sense to care the performance of super block
scrubbing. It only has 3 super blocks at most, and they are all
scattered around the devices already.

Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarAnand Jain <anand.jain@oracle.com>
Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent f0bb5474
Loading
Loading
Loading
Loading
+52 −8
Original line number Original line Diff line number Diff line
@@ -4243,18 +4243,62 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
	return ret;
	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,
static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
					   struct btrfs_device *scrub_dev)
					   struct btrfs_device *scrub_dev)
{
{
	int	i;
	int	i;
	u64	bytenr;
	u64	bytenr;
	u64	gen;
	u64	gen;
	int	ret;
	int ret = 0;
	struct page *page;
	struct btrfs_fs_info *fs_info = sctx->fs_info;
	struct btrfs_fs_info *fs_info = sctx->fs_info;


	if (BTRFS_FS_ERROR(fs_info))
	if (BTRFS_FS_ERROR(fs_info))
		return -EROFS;
		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. */
	/* Seed devices of a new filesystem has their own generation. */
	if (scrub_dev->fs_devices != fs_info->fs_devices)
	if (scrub_dev->fs_devices != fs_info->fs_devices)
		gen = scrub_dev->generation;
		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))
		if (!btrfs_check_super_location(scrub_dev, bytenr))
			continue;
			continue;


		ret = scrub_sectors(sctx, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr,
		ret = scrub_one_super(sctx, scrub_dev, page, bytenr, gen);
				    scrub_dev, BTRFS_EXTENT_FLAG_SUPER, gen, i,
		if (ret) {
				    NULL, bytenr);
			spin_lock(&sctx->stat_lock);
		if (ret)
			sctx->stat.super_errors++;
			return ret;
			spin_unlock(&sctx->stat_lock);
		}
		}
	wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0);
	}

	__free_page(page);
	return 0;
	return 0;
}
}