From 36c9fddcf8b7a6e3c66d7bc12d5b5eed9b9e54d3 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Sun, 5 Jul 2026 21:24:48 +0930 Subject: [PATCH] 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 81cea6cd7041 ("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 Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/scrub.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index f14955c65821..67076d654973 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -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) {