btrfs: scrub: implement calc_sector_number() in a faster way

Currently calc_sector_number() is implemented by comparing the first
bvec of the bbio against all blocks inside a scrub_stripe.

This implementation is a little inefficient, and depends on how the
scrub buffer is implemented.

One of the reason implementing such complex function is that, we do not
save the original bvec_iter inside a write btrfs_bio.
Although a read bbio has btrfs_bio::saved_iter to get the original
logical bytenr, it's not implemented for write bios.

On the other hand, since commit 81cea6cd70 ("btrfs: remove
btrfs_bio::fs_info by extracting it from btrfs_bio::inode"), we always
set the btrfs_bio::file_offset as the logical bytenr for scrub, and that
member will not be modified during IO.

So this means we have a stable way to determine the logical bytenr for a
scrub bio, now calc_sector_number() is just as simple as:

	return (bbio->file_offset - stripe->logical) >> sectorsize_bits;

Since we're here, also add an ASSERT() to make sure the bbio is inside
the stripe, and change the return type to unsigned int to be extra safe.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2026-07-05 21:24:48 +09:30 committed by David Sterba
parent 1462637d55
commit 36c9fddcf8

View File

@ -864,16 +864,19 @@ static void scrub_verify_one_stripe(struct scrub_stripe *stripe, unsigned long b
}
}
static int calc_sector_number(struct scrub_stripe *stripe, struct bio_vec *first_bvec)
static unsigned int calc_sector_number(const struct btrfs_bio *bbio)
{
int i;
const struct scrub_stripe *stripe = bbio->private;
const struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
for (i = 0; i < stripe->nr_sectors; i++) {
if (scrub_stripe_get_kaddr(stripe, i) == bvec_virt(first_bvec))
break;
}
ASSERT(i < stripe->nr_sectors);
return i;
/* Scrub bbios all have their @file_offset set to the logical bytenr. */
ASSERT(bbio->file_offset >= stripe->logical &&
bbio->file_offset < stripe->logical + (stripe->nr_sectors <<
fs_info->sectorsize_bits),
"scrub bio logical=%llu stripe logical=%llu stripe len=%u",
bbio->file_offset, stripe->logical,
stripe->nr_sectors << fs_info->sectorsize_bits);
return (bbio->file_offset - stripe->logical) >> fs_info->sectorsize_bits;
}
/*
@ -885,12 +888,10 @@ static void scrub_read_endio_common(struct btrfs_bio *bbio)
{
struct scrub_stripe *stripe = bbio->private;
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
int sector_nr = calc_sector_number(stripe, bio_first_bvec_all(&bbio->bio));
unsigned int sector_nr = calc_sector_number(bbio);
const u32 bio_size = bio_get_size(&bbio->bio);
const u32 sectors = bio_size >> fs_info->sectorsize_bits;
ASSERT(sector_nr < stripe->nr_sectors);
if (bbio->bio.bi_status) {
scrub_bitmap_set_io_error(stripe, sector_nr, sectors);
scrub_bitmap_set_error(stripe, sector_nr, sectors);
@ -1264,7 +1265,7 @@ static void scrub_write_endio(struct btrfs_bio *bbio)
{
struct scrub_stripe *stripe = bbio->private;
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
int sector_nr = calc_sector_number(stripe, bio_first_bvec_all(&bbio->bio));
unsigned int sector_nr = calc_sector_number(bbio);
const u32 bio_size = bio_get_size(&bbio->bio);
if (bbio->bio.bi_status) {