@@ -1782,6 +1782,58 @@ static bool stripe_has_metadata_error(struct scrub_stripe *stripe)
return false;
}
+static int submit_raid56_pq_scrub_bio(struct scrub_ctx *sctx,
+ struct map_lookup *map,
+ struct scrub_stripe *first_data_stripe,
+ int group_stripes,
+ struct btrfs_device *scrub_dev,
+ unsigned long extent_bitmap)
+{
+ DECLARE_COMPLETION_ONSTACK(io_done);
+ struct btrfs_fs_info *fs_info = sctx->fs_info;
+ struct btrfs_io_context *bioc = NULL;
+ struct btrfs_raid_bio *rbio;
+ struct bio *bio;
+ const int data_stripes = nr_data_stripes(map);
+ u64 full_stripe_start = first_data_stripe->logical;
+ u64 length = btrfs_stripe_nr_to_offset(data_stripes);
+ int ret;
+
+ bio = bio_alloc(NULL, 1, REQ_OP_READ, GFP_NOFS);
+ bio->bi_iter.bi_sector = full_stripe_start >> SECTOR_SHIFT;
+ bio->bi_private = &io_done;
+ bio->bi_end_io = raid56_scrub_wait_endio;
+
+ btrfs_bio_counter_inc_blocked(fs_info);
+ ret = btrfs_map_block(fs_info, BTRFS_MAP_WRITE, full_stripe_start,
+ &length, &bioc, NULL, NULL, 1);
+ if (ret < 0) {
+ btrfs_put_bioc(bioc);
+ btrfs_bio_counter_dec(fs_info);
+ return ret;
+ }
+ rbio = raid56_parity_alloc_scrub_rbio(bio, bioc, scrub_dev, &extent_bitmap);
+ btrfs_put_bioc(bioc);
+ if (!rbio) {
+ ret = -ENOMEM;
+ btrfs_bio_counter_dec(fs_info);
+ return ret;
+ }
+ /* Use the recovered stripes as cache to avoid read them from disk again. */
+ ASSERT(group_stripes <= map->num_stripes);
+ for (int i = 0; i < group_stripes; i++) {
+ struct scrub_stripe *stripe = first_data_stripe + i;
+
+ raid56_parity_cache_pages(rbio, stripe->pages, i);
+ }
+ raid56_parity_submit_scrub_rbio(rbio);
+ wait_for_completion_io(&io_done);
+ ret = blk_status_to_errno(bio->bi_status);
+ bio_put(bio);
+ btrfs_bio_counter_dec(fs_info);
+ return 0;
+}
+
static int repair_raid56_full_stripe(struct scrub_ctx *sctx, int start_stripe,
int group_stripes)
{
@@ -1853,8 +1905,14 @@ static int repair_raid56_full_stripe(struct scrub_ctx *sctx, int start_stripe,
wait_scrub_stripe_io(stripe);
}
- /* Still need to scrub P/Q stripes. */
- ret = -EOPNOTSUPP;
+ /*
+ * All data stripes repaired, now can generate and verify P/Q stripes.
+ *
+ * Pass NULL as @scrub_dev, so that both P/Q stripes would be verified.
+ */
+ ret = submit_raid56_pq_scrub_bio(sctx, sctx->map, first_stripe,
+ sctx->map->num_stripes, NULL,
+ extents_bitmap);
report:
/*
* Update the accounting for data stripes.
@@ -2141,14 +2199,10 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
{
DECLARE_COMPLETION_ONSTACK(io_done);
struct btrfs_fs_info *fs_info = sctx->fs_info;
- struct btrfs_raid_bio *rbio;
- struct btrfs_io_context *bioc = NULL;
- struct bio *bio;
struct scrub_stripe *stripe;
bool all_empty = true;
const int data_stripes = nr_data_stripes(map);
unsigned long extent_bitmap = 0;
- u64 length = btrfs_stripe_nr_to_offset(data_stripes);
int ret;
ASSERT(sctx->raid56_data_stripes);
@@ -2261,38 +2315,8 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
}
/* Now we can check and regenerate the P/Q stripe. */
- bio = bio_alloc(NULL, 1, REQ_OP_READ, GFP_NOFS);
- bio->bi_iter.bi_sector = full_stripe_start >> SECTOR_SHIFT;
- bio->bi_private = &io_done;
- bio->bi_end_io = raid56_scrub_wait_endio;
-
- btrfs_bio_counter_inc_blocked(fs_info);
- ret = btrfs_map_block(fs_info, BTRFS_MAP_WRITE, full_stripe_start,
- &length, &bioc, NULL, NULL, 1);
- if (ret < 0) {
- btrfs_put_bioc(bioc);
- btrfs_bio_counter_dec(fs_info);
- goto out;
- }
- rbio = raid56_parity_alloc_scrub_rbio(bio, bioc, scrub_dev, &extent_bitmap);
- btrfs_put_bioc(bioc);
- if (!rbio) {
- ret = -ENOMEM;
- btrfs_bio_counter_dec(fs_info);
- goto out;
- }
- /* Use the recovered stripes as cache to avoid read them from disk again. */
- for (int i = 0; i < data_stripes; i++) {
- stripe = &sctx->raid56_data_stripes[i];
-
- raid56_parity_cache_pages(rbio, stripe->pages, i);
- }
- raid56_parity_submit_scrub_rbio(rbio);
- wait_for_completion_io(&io_done);
- ret = blk_status_to_errno(bio->bi_status);
- bio_put(bio);
- btrfs_bio_counter_dec(fs_info);
-
+ ret = submit_raid56_pq_scrub_bio(sctx, map, sctx->raid56_data_stripes,
+ data_stripes, scrub_dev, extent_bitmap);
out:
return ret;
}
@@ -3545,12 +3569,6 @@ static int scrub_logical_one_chunk(struct scrub_ctx *sctx,
scrub_blocked_if_needed(fs_info);
- /* RAID56 not yet supported. */
- if (bg->flags & BTRFS_BLOCK_GROUP_RAID56_MASK) {
- ret = -EOPNOTSUPP;
- goto out;
- }
-
nr_stripes = SCRUB_STRIPES_PER_SCTX * nr_copies;
ret = alloc_scrub_stripes(sctx, nr_stripes);
if (ret < 0)
For RAID56 P/Q stripe verification, we already have an existing path inside scrub_raid56_parity_stripe(). Although the existing path is only to verify one P/Q stripe, with recent changes to scrub_rbio(), we only need to pass a NULL @scrub_dev to raid56_parity_alloc_scrub_rbio(), then we can verify both P/Q stripes in one go. So here we introduce a helper, submit_raid56_pq_scrub_bio(), to do the necessary work of P/Q stripes verification and repair. The new helper would be utilized by both scrub_logical and the existing per-device scrub, and both would use the repaired data stripes to reduce IO for RAID56 scrub. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/scrub.c | 106 +++++++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 44 deletions(-)