]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
btrfs: raid56: move sector_ptr::uptodate into a dedicated bitmap
authorQu Wenruo <wqu@suse.com>
Thu, 9 Oct 2025 04:40:00 +0000 (15:10 +1030)
committerDavid Sterba <dsterba@suse.com>
Mon, 24 Nov 2025 21:42:22 +0000 (22:42 +0100)
The uptodate boolean member can be extracted into a bitmap, which will
save us some space (1 bit in a byte vs 8 bits in a byte).

Furthermore we do not need to record the uptodate bitmap for bio
sectors, as if bio_sectors[].paddr is valid it means there is a bio and
will be uptodate.

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

index c057491c842b7dcc3d0bfbbb1184f602f4014e7c..3375919f81220a24d13dae6445998196c0ee520c 100644 (file)
@@ -151,7 +151,6 @@ struct sector_ptr {
         * If it's INVALID_PADDR then it's not set.
         */
        phys_addr_t paddr;
-       bool uptodate;
 };
 
 static void rmw_rbio_work(struct work_struct *work);
@@ -277,13 +276,13 @@ static void cache_rbio_pages(struct btrfs_raid_bio *rbio)
                         * read from disk.
                         */
                        if (i < rbio->nr_data * rbio->stripe_nsectors)
-                               ASSERT(rbio->stripe_sectors[i].uptodate);
+                               ASSERT(test_bit(i, rbio->stripe_uptodate_bitmap));
                        continue;
                }
 
                memcpy_sectors(&rbio->stripe_sectors[i], &rbio->bio_sectors[i],
                                rbio->bioc->fs_info->sectorsize);
-               rbio->stripe_sectors[i].uptodate = 1;
+               set_bit(i, rbio->stripe_uptodate_bitmap);
        }
        set_bit(RBIO_CACHE_READY_BIT, &rbio->flags);
 }
@@ -318,7 +317,7 @@ static __maybe_unused bool full_page_sectors_uptodate(struct btrfs_raid_bio *rbi
        for (i = sectors_per_page * page_nr;
             i < sectors_per_page * page_nr + sectors_per_page;
             i++) {
-               if (!rbio->stripe_sectors[i].uptodate)
+               if (!test_bit(i, rbio->stripe_uptodate_bitmap))
                        return false;
        }
        return true;
@@ -353,17 +352,14 @@ static void steal_rbio_page(struct btrfs_raid_bio *src,
 {
        const u32 sectorsize = src->bioc->fs_info->sectorsize;
        const u32 sectors_per_page = PAGE_SIZE / sectorsize;
-       int i;
 
        if (dest->stripe_pages[page_nr])
                __free_page(dest->stripe_pages[page_nr]);
        dest->stripe_pages[page_nr] = src->stripe_pages[page_nr];
        src->stripe_pages[page_nr] = NULL;
 
-       /* Also update the sector->uptodate bits. */
-       for (i = sectors_per_page * page_nr;
-            i < sectors_per_page * page_nr + sectors_per_page; i++)
-               dest->stripe_sectors[i].uptodate = true;
+       /* Also update the stripe_uptodate_bitmap bits. */
+       bitmap_set(dest->stripe_uptodate_bitmap, sectors_per_page * page_nr, sectors_per_page);
 }
 
 static bool is_data_stripe_page(struct btrfs_raid_bio *rbio, int page_nr)
@@ -1031,9 +1027,10 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
                                       GFP_NOFS);
        rbio->finish_pointers = kcalloc(real_stripes, sizeof(void *), GFP_NOFS);
        rbio->error_bitmap = bitmap_zalloc(num_sectors, GFP_NOFS);
+       rbio->stripe_uptodate_bitmap = bitmap_zalloc(num_sectors, GFP_NOFS);
 
        if (!rbio->stripe_pages || !rbio->bio_sectors || !rbio->stripe_sectors ||
-           !rbio->finish_pointers || !rbio->error_bitmap) {
+           !rbio->finish_pointers || !rbio->error_bitmap || !rbio->stripe_uptodate_bitmap) {
                free_raid_bio_pointers(rbio);
                kfree(rbio);
                return ERR_PTR(-ENOMEM);
@@ -1331,7 +1328,8 @@ static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr)
 
        /* Then add the parity stripe */
        sector = rbio_pstripe_sector(rbio, sectornr);
-       sector->uptodate = 1;
+       set_bit(rbio_stripe_sector_index(rbio, rbio->nr_data, sectornr),
+               rbio->stripe_uptodate_bitmap);
        pointers[stripe++] = kmap_local_sector(sector);
 
        if (has_qstripe) {
@@ -1340,7 +1338,8 @@ static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr)
                 * to fill in our p/q
                 */
                sector = rbio_qstripe_sector(rbio, sectornr);
-               sector->uptodate = 1;
+               set_bit(rbio_stripe_sector_index(rbio, rbio->nr_data + 1, sectornr),
+                       rbio->stripe_uptodate_bitmap);
                pointers[stripe++] = kmap_local_sector(sector);
 
                assert_rbio(rbio);
@@ -1496,21 +1495,19 @@ static void set_rbio_range_error(struct btrfs_raid_bio *rbio, struct bio *bio)
 }
 
 /*
- * For subpage case, we can no longer set page Up-to-date directly for
- * stripe_pages[], thus we need to locate the sector.
+ * Return the index inside the rbio->stripe_sectors[] array.
+ *
+ * Return -1 if not found.
  */
-static struct sector_ptr *find_stripe_sector(struct btrfs_raid_bio *rbio,
-                                            phys_addr_t paddr)
+static int find_stripe_sector_nr(struct btrfs_raid_bio *rbio, phys_addr_t paddr)
 {
-       int i;
-
-       for (i = 0; i < rbio->nr_sectors; i++) {
+       for (int i = 0; i < rbio->nr_sectors; i++) {
                struct sector_ptr *sector = &rbio->stripe_sectors[i];
 
                if (sector->paddr == paddr)
-                       return sector;
+                       return i;
        }
-       return NULL;
+       return -1;
 }
 
 /*
@@ -1525,11 +1522,11 @@ static void set_bio_pages_uptodate(struct btrfs_raid_bio *rbio, struct bio *bio)
        ASSERT(!bio_flagged(bio, BIO_CLONED));
 
        btrfs_bio_for_each_block_all(paddr, bio, blocksize) {
-               struct sector_ptr *sector = find_stripe_sector(rbio, paddr);
+               int sector_nr = find_stripe_sector_nr(rbio, paddr);
 
-               ASSERT(sector);
-               if (sector)
-                       sector->uptodate = 1;
+               ASSERT(sector_nr >= 0);
+               if (sector_nr >= 0)
+                       set_bit(sector_nr, rbio->stripe_uptodate_bitmap);
        }
 }
 
@@ -1963,7 +1960,8 @@ pstripe:
                        goto cleanup;
 
                sector = rbio_stripe_sector(rbio, faila, sector_nr);
-               sector->uptodate = 1;
+               set_bit(rbio_stripe_sector_index(rbio, faila, sector_nr),
+                       rbio->stripe_uptodate_bitmap);
        }
        if (failb >= 0) {
                ret = verify_one_sector(rbio, failb, sector_nr);
@@ -1971,7 +1969,8 @@ pstripe:
                        goto cleanup;
 
                sector = rbio_stripe_sector(rbio, failb, sector_nr);
-               sector->uptodate = 1;
+               set_bit(rbio_stripe_sector_index(rbio, failb, sector_nr),
+                       rbio->stripe_uptodate_bitmap);
        }
 
 cleanup:
@@ -2325,7 +2324,8 @@ static bool need_read_stripe_sectors(struct btrfs_raid_bio *rbio)
                 * thus this rbio can not be cached one, as cached one must
                 * have all its data sectors present and uptodate.
                 */
-               if (sector->paddr == INVALID_PADDR || !sector->uptodate)
+               if (sector->paddr == INVALID_PADDR ||
+                   !test_bit(i, rbio->stripe_uptodate_bitmap))
                        return true;
        }
        return false;
@@ -2551,7 +2551,6 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
        if (!page)
                return -ENOMEM;
        p_sector.paddr = page_to_phys(page);
-       p_sector.uptodate = 1;
        page = NULL;
 
        if (has_qstripe) {
@@ -2563,7 +2562,6 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
                        return -ENOMEM;
                }
                q_sector.paddr = page_to_phys(page);
-               q_sector.uptodate = 1;
                page = NULL;
                pointers[rbio->real_stripes - 1] = kmap_local_sector(&q_sector);
        }
@@ -2781,7 +2779,8 @@ static int scrub_assemble_read_bios(struct btrfs_raid_bio *rbio)
                 * The bio cache may have handed us an uptodate sector.  If so,
                 * use it.
                 */
-               if (sector->uptodate)
+               if (test_bit(rbio_stripe_sector_index(rbio, stripe, sectornr),
+                            rbio->stripe_uptodate_bitmap))
                        continue;
 
                ret = rbio_add_io_sector(rbio, &bio_list, sector, stripe,
@@ -2899,8 +2898,7 @@ void raid56_parity_cache_data_folios(struct btrfs_raid_bio *rbio,
                        foffset = 0;
                }
        }
-       for (unsigned int sector_nr = offset_in_full_stripe >> fs_info->sectorsize_bits;
-            sector_nr < (offset_in_full_stripe + BTRFS_STRIPE_LEN) >> fs_info->sectorsize_bits;
-            sector_nr++)
-               rbio->stripe_sectors[sector_nr].uptodate = true;
+       bitmap_set(rbio->stripe_uptodate_bitmap,
+                  offset_in_full_stripe >> fs_info->sectorsize_bits,
+                  BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits);
 }
index 84c4d1d29c7a88031bf38e9196d86aeb254235a3..b636de4af7ac6f53044e24f476c8ebab43364de2 100644 (file)
@@ -124,6 +124,9 @@ struct btrfs_raid_bio {
         */
        struct sector_ptr *stripe_sectors;
 
+       /* Each set bit means the corresponding sector in stripe_sectors[] is uptodate. */
+       unsigned long *stripe_uptodate_bitmap;
+
        /* Allocated with real_stripes-many pointers for finish_*() calls */
        void **finish_pointers;