From: Qu Wenruo Date: Thu, 13 Nov 2025 09:40:38 +0000 (+1030) Subject: btrfs: raid56: prepare generate_pq_vertical() for bs > ps cases X-Git-Tag: v6.19-rc1~167^2~26 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=826325b6d091fdf93cc04fb5e8e462409635a469;p=thirdparty%2Fkernel%2Flinux.git btrfs: raid56: prepare generate_pq_vertical() for bs > ps cases Unlike btrfs_calculate_block_csum_pages(), we cannot handle multiple pages at the same time for P/Q generation. So here we introduce a new @step_nr, and various helpers to grab the sub-block page from the rbio, and generate the P/Q stripe page by page. Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 7f01178be7d8f..209f013e4da94 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -711,20 +711,25 @@ static phys_addr_t rbio_stripe_paddr(const struct btrfs_raid_bio *rbio, return rbio->stripe_paddrs[rbio_paddr_index(rbio, stripe_nr, sector_nr, 0)]; } -/* Grab a paddr inside P stripe */ -static phys_addr_t rbio_pstripe_paddr(const struct btrfs_raid_bio *rbio, - unsigned int sector_nr) +static phys_addr_t rbio_stripe_step_paddr(const struct btrfs_raid_bio *rbio, + unsigned int stripe_nr, unsigned int sector_nr, + unsigned int step_nr) { - return rbio_stripe_paddr(rbio, rbio->nr_data, sector_nr); + return rbio->stripe_paddrs[rbio_paddr_index(rbio, stripe_nr, sector_nr, step_nr)]; } -/* Grab a paddr inside Q stripe, return INVALID_PADDR if not RAID6 */ -static phys_addr_t rbio_qstripe_paddr(const struct btrfs_raid_bio *rbio, - unsigned int sector_nr) +static phys_addr_t rbio_pstripe_step_paddr(const struct btrfs_raid_bio *rbio, + unsigned int sector_nr, unsigned int step_nr) +{ + return rbio_stripe_step_paddr(rbio, rbio->nr_data, sector_nr, step_nr); +} + +static phys_addr_t rbio_qstripe_step_paddr(const struct btrfs_raid_bio *rbio, + unsigned int sector_nr, unsigned int step_nr) { if (rbio->nr_data + 1 == rbio->real_stripes) return INVALID_PADDR; - return rbio_stripe_paddr(rbio, rbio->nr_data + 1, sector_nr); + return rbio_stripe_step_paddr(rbio, rbio->nr_data + 1, sector_nr, step_nr); } /* @@ -998,6 +1003,38 @@ static phys_addr_t sector_paddr_in_rbio(struct btrfs_raid_bio *rbio, return rbio->stripe_paddrs[index]; } +/* + * Similar to sector_paddr_in_rbio(), but with extra consideration for + * bs > ps cases, where we can have multiple steps for a fs block. + */ +static phys_addr_t step_paddr_in_rbio(struct btrfs_raid_bio *rbio, + int stripe_nr, int sector_nr, int step_nr, + bool bio_list_only) +{ + phys_addr_t ret = INVALID_PADDR; + int index; + + ASSERT_RBIO_STRIPE(stripe_nr >= 0 && stripe_nr < rbio->real_stripes, + rbio, stripe_nr); + ASSERT_RBIO_SECTOR(sector_nr >= 0 && sector_nr < rbio->stripe_nsectors, + rbio, sector_nr); + ASSERT_RBIO_SECTOR(step_nr >= 0 && step_nr < rbio->sector_nsteps, + rbio, sector_nr); + + index = (stripe_nr * rbio->stripe_nsectors + sector_nr) * rbio->sector_nsteps + step_nr; + ASSERT(index >= 0 && index < rbio->nr_sectors * rbio->sector_nsteps); + + scoped_guard(spinlock, &rbio->bio_list_lock) { + if (rbio->bio_paddrs[index] != INVALID_PADDR || bio_list_only) { + /* Don't return sector without a valid page pointer */ + if (rbio->bio_paddrs[index] != INVALID_PADDR) + ret = rbio->bio_paddrs[index]; + return ret; + } + } + return rbio->stripe_paddrs[index]; +} + /* * allocation and initial setup for the btrfs_raid_bio. Not * this does not allocate any pages for rbio->pages. @@ -1319,45 +1356,56 @@ static inline void *kmap_local_paddr(phys_addr_t paddr) return kmap_local_page(phys_to_page(paddr)) + offset_in_page(paddr); } -/* Generate PQ for one vertical stripe. */ -static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr) +static void generate_pq_vertical_step(struct btrfs_raid_bio *rbio, unsigned int sector_nr, + unsigned int step_nr) { void **pointers = rbio->finish_pointers; - const u32 sectorsize = rbio->bioc->fs_info->sectorsize; + const u32 step = min(rbio->bioc->fs_info->sectorsize, PAGE_SIZE); int stripe; const bool has_qstripe = rbio->bioc->map_type & BTRFS_BLOCK_GROUP_RAID6; /* First collect one sector from each data stripe */ for (stripe = 0; stripe < rbio->nr_data; stripe++) pointers[stripe] = kmap_local_paddr( - sector_paddr_in_rbio(rbio, stripe, sectornr, 0)); + step_paddr_in_rbio(rbio, stripe, sector_nr, step_nr, 0)); /* Then add the parity stripe */ - set_bit(rbio_sector_index(rbio, rbio->nr_data, sectornr), - rbio->stripe_uptodate_bitmap); - pointers[stripe++] = kmap_local_paddr(rbio_pstripe_paddr(rbio, sectornr)); + pointers[stripe++] = kmap_local_paddr(rbio_pstripe_step_paddr(rbio, sector_nr, step_nr)); if (has_qstripe) { /* * RAID6, add the qstripe and call the library function * to fill in our p/q */ - set_bit(rbio_sector_index(rbio, rbio->nr_data + 1, sectornr), - rbio->stripe_uptodate_bitmap); - pointers[stripe++] = kmap_local_paddr(rbio_qstripe_paddr(rbio, sectornr)); + pointers[stripe++] = kmap_local_paddr( + rbio_qstripe_step_paddr(rbio, sector_nr, step_nr)); assert_rbio(rbio); - raid6_call.gen_syndrome(rbio->real_stripes, sectorsize, - pointers); + raid6_call.gen_syndrome(rbio->real_stripes, step, pointers); } else { /* raid5 */ - memcpy(pointers[rbio->nr_data], pointers[0], sectorsize); - run_xor(pointers + 1, rbio->nr_data - 1, sectorsize); + memcpy(pointers[rbio->nr_data], pointers[0], step); + run_xor(pointers + 1, rbio->nr_data - 1, step); } for (stripe = stripe - 1; stripe >= 0; stripe--) kunmap_local(pointers[stripe]); } +/* Generate PQ for one vertical stripe. */ +static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr) +{ + const bool has_qstripe = (rbio->bioc->map_type & BTRFS_BLOCK_GROUP_RAID6); + + for (int i = 0; i < rbio->sector_nsteps; i++) + generate_pq_vertical_step(rbio, sectornr, i); + + set_bit(rbio_sector_index(rbio, rbio->nr_data, sectornr), + rbio->stripe_uptodate_bitmap); + if (has_qstripe) + set_bit(rbio_sector_index(rbio, rbio->nr_data + 1, sectornr), + rbio->stripe_uptodate_bitmap); +} + static int rmw_assemble_write_bios(struct btrfs_raid_bio *rbio, struct bio_list *bio_list) {