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

Prepare it for bs > ps cases by:

- Introduce two helpers to calculate the sector number
  Previously we assume one page will contain at least one fs block, thus
  can use something like "sectors_per_page = PAGE_SIZE / sectorsize;",
  but with bs > ps support that above number will be 0.

  Instead introduce two helpers:

  * page_nr_to_sector_nr()
    Returns the sector number of the first sector covered by the page.

  * page_nr_to_num_sectors()
    Return how many sectors are covered by the page.

  And use the returned values for bitmap operations other than
  open-coded "PAGE_SIZE / sectorsize".
  Those helpers also have extra ASSERT()s to catch weird numbers.

- Use above helpers
  The involved functions are:
  * steal_rbio_page()
  * is_data_stripe_page()
  * full_page_sectors_uptodate()

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

index 2b6838380544118835246d10f0093f54d1188b83..5f2843a378e3febb93f679efac870c035fd38f66 100644 (file)
@@ -300,18 +300,47 @@ static int rbio_bucket(struct btrfs_raid_bio *rbio)
        return hash_64(num >> 16, BTRFS_STRIPE_HASH_TABLE_BITS);
 }
 
+/* Get the sector number of the first sector covered by @page_nr. */
+static u32 page_nr_to_sector_nr(struct btrfs_raid_bio *rbio, unsigned int page_nr)
+{
+       u32 sector_nr;
+
+       ASSERT(page_nr < rbio->nr_pages);
+
+       sector_nr = (page_nr << PAGE_SHIFT) >> rbio->bioc->fs_info->sectorsize_bits;
+       ASSERT(sector_nr < rbio->nr_sectors);
+       return sector_nr;
+}
+
+/*
+ * Get the number of sectors covered by @page_nr.
+ *
+ * For bs > ps cases, the result will always be 1.
+ * For bs <= ps cases, the result will be ps / bs.
+ */
+static u32 page_nr_to_num_sectors(struct btrfs_raid_bio *rbio, unsigned int page_nr)
+{
+       struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
+       u32 nr_sectors;
+
+       ASSERT(page_nr < rbio->nr_pages);
+
+       nr_sectors = round_up(PAGE_SIZE, fs_info->sectorsize) >> fs_info->sectorsize_bits;
+       ASSERT(nr_sectors > 0);
+       return nr_sectors;
+}
+
 static __maybe_unused bool full_page_sectors_uptodate(struct btrfs_raid_bio *rbio,
                                                      unsigned int page_nr)
 {
-       const u32 sectorsize = rbio->bioc->fs_info->sectorsize;
-       const u32 sectors_per_page = PAGE_SIZE / sectorsize;
+       const u32 sector_nr = page_nr_to_sector_nr(rbio, page_nr);
+       const u32 nr_bits = page_nr_to_num_sectors(rbio, page_nr);
        int i;
 
        ASSERT(page_nr < rbio->nr_pages);
+       ASSERT(sector_nr + nr_bits < rbio->nr_sectors);
 
-       for (i = sectors_per_page * page_nr;
-            i < sectors_per_page * page_nr + sectors_per_page;
-            i++) {
+       for (i = sector_nr; i < sector_nr + nr_bits; i++) {
                if (!test_bit(i, rbio->stripe_uptodate_bitmap))
                        return false;
        }
@@ -345,8 +374,11 @@ static void index_stripe_sectors(struct btrfs_raid_bio *rbio)
 static void steal_rbio_page(struct btrfs_raid_bio *src,
                            struct btrfs_raid_bio *dest, int page_nr)
 {
-       const u32 sectorsize = src->bioc->fs_info->sectorsize;
-       const u32 sectors_per_page = PAGE_SIZE / sectorsize;
+       const u32 sector_nr = page_nr_to_sector_nr(src, page_nr);
+       const u32 nr_bits = page_nr_to_num_sectors(src, page_nr);
+
+       ASSERT(page_nr < src->nr_pages);
+       ASSERT(sector_nr + nr_bits < src->nr_sectors);
 
        if (dest->stripe_pages[page_nr])
                __free_page(dest->stripe_pages[page_nr]);
@@ -354,13 +386,12 @@ static void steal_rbio_page(struct btrfs_raid_bio *src,
        src->stripe_pages[page_nr] = NULL;
 
        /* Also update the stripe_uptodate_bitmap bits. */
-       bitmap_set(dest->stripe_uptodate_bitmap, sectors_per_page * page_nr, sectors_per_page);
+       bitmap_set(dest->stripe_uptodate_bitmap, sector_nr, nr_bits);
 }
 
 static bool is_data_stripe_page(struct btrfs_raid_bio *rbio, int page_nr)
 {
-       const int sector_nr = (page_nr << PAGE_SHIFT) >>
-                             rbio->bioc->fs_info->sectorsize_bits;
+       const int sector_nr = page_nr_to_sector_nr(rbio, page_nr);
 
        /*
         * We have ensured PAGE_SIZE is aligned with sectorsize, thus