From: Qu Wenruo Date: Thu, 9 Oct 2025 04:40:00 +0000 (+1030) Subject: btrfs: raid56: move sector_ptr::uptodate into a dedicated bitmap X-Git-Tag: v6.19-rc1~167^2~51 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1810350b04ef38b375c64304e142de96d90404e1;p=thirdparty%2Fkernel%2Flinux.git btrfs: raid56: move sector_ptr::uptodate into a dedicated bitmap 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 Reviewed-by: David Sterba Signed-off-by: David Sterba --- diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index c057491c842b7..3375919f81220 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -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); } diff --git a/fs/btrfs/raid56.h b/fs/btrfs/raid56.h index 84c4d1d29c7a8..b636de4af7ac6 100644 --- a/fs/btrfs/raid56.h +++ b/fs/btrfs/raid56.h @@ -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;