]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
btrfs: raid56: prepare verify_bio_data_sectors() to support bs > ps cases
authorQu Wenruo <wqu@suse.com>
Fri, 14 Nov 2025 04:00:25 +0000 (14:30 +1030)
committerDavid Sterba <dsterba@suse.com>
Tue, 25 Nov 2025 00:47:20 +0000 (01:47 +0100)
The function verify_bio_data_sectors() assume each fs block can be mapped by
one page, blocking bs > ps support for raid56.

Prepare it for bs > ps cases by:

- Make get_bio_sector_nr() to consider bs > ps cases
  The function is utilized to calculate the sector number of a device
  bio submitted by btrfs raid56 layer.

- Assemble a local paddrs[] for checksum calculation

- Open code btrfs_check_block_csum()
  btrfs_check_block_csum() only supports fs blocks backed by large
  folios.

  But for raid56 we can have fs blocks backed by multiple non-contiguous
  pages, e.g. direct IO, encoded read/write/send.

  So instead of using btrfs_check_block_csum(), open code it to use
  btrfs_calculate_block_csum_pages().

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

index 1a89cdb80fe42416edfbd036c7679ac41ae3684d..7bc43f1861e644f7c8273f906d2ecf2d0c2bdef1 100644 (file)
@@ -1620,9 +1620,9 @@ static int get_bio_sector_nr(struct btrfs_raid_bio *rbio, struct bio *bio)
        int i;
 
        for (i = 0; i < rbio->nr_sectors; i++) {
-               if (rbio->stripe_paddrs[i] == bvec_paddr)
+               if (rbio->stripe_paddrs[i * rbio->sector_nsteps] == bvec_paddr)
                        break;
-               if (rbio->bio_paddrs[i] == bvec_paddr)
+               if (rbio->bio_paddrs[i * rbio->sector_nsteps] == bvec_paddr)
                        break;
        }
        ASSERT(i < rbio->nr_sectors);
@@ -1655,7 +1655,11 @@ static void verify_bio_data_sectors(struct btrfs_raid_bio *rbio,
                                    struct bio *bio)
 {
        struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
+       const u32 step = min(fs_info->sectorsize, PAGE_SIZE);
+       const u32 nr_steps = rbio->sector_nsteps;
        int total_sector_nr = get_bio_sector_nr(rbio, bio);
+       u32 offset = 0;
+       phys_addr_t paddrs[BTRFS_MAX_BLOCKSIZE / PAGE_SIZE];
        phys_addr_t paddr;
 
        /* No data csum for the whole stripe, no need to verify. */
@@ -1666,18 +1670,24 @@ static void verify_bio_data_sectors(struct btrfs_raid_bio *rbio,
        if (total_sector_nr >= rbio->nr_data * rbio->stripe_nsectors)
                return;
 
-       btrfs_bio_for_each_block_all(paddr, bio, fs_info->sectorsize) {
+       btrfs_bio_for_each_block_all(paddr, bio, step) {
                u8 csum_buf[BTRFS_CSUM_SIZE];
-               u8 *expected_csum = rbio->csum_buf + total_sector_nr * fs_info->csum_size;
-               int ret;
+               u8 *expected_csum;
+
+               paddrs[(offset / step) % nr_steps] = paddr;
+               offset += step;
+
+               /* Not yet covering the full fs block, continue to the next step. */
+               if (!IS_ALIGNED(offset, fs_info->sectorsize))
+                       continue;
 
                /* No csum for this sector, skip to the next sector. */
                if (!test_bit(total_sector_nr, rbio->csum_bitmap))
                        continue;
 
-               ret = btrfs_check_block_csum(fs_info, paddr,
-                                            csum_buf, expected_csum);
-               if (ret < 0)
+               expected_csum = rbio->csum_buf + total_sector_nr * fs_info->csum_size;
+               btrfs_calculate_block_csum_pages(fs_info, paddrs, csum_buf);
+               if (unlikely(memcmp(csum_buf, expected_csum, fs_info->csum_size) != 0))
                        set_bit(total_sector_nr, rbio->error_bitmap);
                total_sector_nr++;
        }