diff mbox series

[05/14] btrfs: add the ability to read P/Q stripes directly

Message ID 0d54adfb390b3c9ffd8ff8f98db43de51df9c33e.1688368617.git.wqu@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs: scrub: introduce SCRUB_LOGICAL flag | expand

Commit Message

Qu Wenruo July 3, 2023, 7:32 a.m. UTC
Currently there is no way to read P/Q stripes of a RAID56 full stripe
directly.

Normally caller should call btrfs_map_block() directly and fetch the
physical location directly of the P/Q stripes.

But for the recent scrub rework, it's no longer that elegant as the full
scrub code is based on mirror_num based solution, thus this patch would
add two special mirror_num for this usages:

- Mirror -1 for P stripes
- Mirror -2 for Q stripes

Both mirrors only support read for now, and caller should make sure the
range start is stripe aligned.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/scrub.c   |  2 +-
 fs/btrfs/volumes.c | 30 +++++++++++++++++++++++++++++-
 2 files changed, 30 insertions(+), 2 deletions(-)

Comments

Qu Wenruo July 3, 2023, 9:46 a.m. UTC | #1
On 2023/7/3 15:32, Qu Wenruo wrote:
> Currently there is no way to read P/Q stripes of a RAID56 full stripe
> directly.
> 
> Normally caller should call btrfs_map_block() directly and fetch the
> physical location directly of the P/Q stripes.
> 
> But for the recent scrub rework, it's no longer that elegant as the full
> scrub code is based on mirror_num based solution, thus this patch would
> add two special mirror_num for this usages:
> 
> - Mirror -1 for P stripes
> - Mirror -2 for Q stripes
> 
> Both mirrors only support read for now, and caller should make sure the
> range start is stripe aligned.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
>   fs/btrfs/scrub.c   |  2 +-
>   fs/btrfs/volumes.c | 30 +++++++++++++++++++++++++++++-
>   2 files changed, 30 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
> index 1864856abb13..41c514db0793 100644
> --- a/fs/btrfs/scrub.c
> +++ b/fs/btrfs/scrub.c
> @@ -1601,7 +1601,7 @@ static void scrub_submit_initial_read(struct scrub_ctx *sctx,
>   	int mirror = stripe->mirror_num;
>   
>   	ASSERT(stripe->bg);
> -	ASSERT(stripe->mirror_num > 0);
> +	ASSERT(stripe->mirror_num);
>   	ASSERT(test_bit(SCRUB_STRIPE_FLAG_INITIALIZED, &stripe->state));
>   
>   	bbio = btrfs_bio_alloc(SCRUB_STRIPE_PAGES, REQ_OP_READ, fs_info,
> diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
> index cd632b3f579f..c22007bd830b 100644
> --- a/fs/btrfs/volumes.c
> +++ b/fs/btrfs/volumes.c
> @@ -6251,10 +6251,12 @@ static void set_io_stripe(struct btrfs_io_stripe *dst, const struct map_lookup *
>    *
>    *			For RAID56 profile, mirror 1 means rebuild from P and
>    *			the remaining data stripes.
> + *			And mirror -1 means read P stripes directly, -2 means
> + *			read Q stripes directly.
>    *
>    *			For RAID6 profile, mirror > 2 means mark another
>    *			data/P stripe error and rebuild from the remaining
> - *			stripes..
> + *			stripes.
>    *
>    * @need_raid_map:	(Used only for integrity checker) whether the map wants
>    *                      a full stripe map (including all data and P/Q stripes)
> @@ -6297,6 +6299,12 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
>   		goto out_free_em;
>   	}
>   
> +	/* Only allow mirror_num < 0 for RAID56. */
> +	if (mirror_num < 0 && !(map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)) {
> +		free_extent_map(em);
> +		return -EINVAL;
> +	}
> +
>   	data_stripes = nr_data_stripes(map);
>   
>   	map_offset = logical - em->start;
> @@ -6382,6 +6390,26 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
>   				  logical;
>   			stripe_index = 0;
>   			stripe_offset = 0;
> +		} else if (mirror_num < 0) {
> +			/* Only allow READ for direct P/Q operations. */
> +			ASSERT(op == BTRFS_MAP_READ);
> +			/*
> +			 * Caller should make sure the range start is stripe
> +			 * aligned.
> +			 */
> +			ASSERT(stripe_offset == 0);
> +
> +			/*
> +			 * Stripes of @bioc is already sorted, stripes[0] is the
> +			 * first data stripe and stripes[@data_stripes] is the
> +			 * P stripe.
> +			 * So we only need to update the @stripe_index to the
> +			 * specified stripe, and set @stripe_nr/@stripe_offset
> +			 * to 0, so we can return the beginning of the P/Q stripe.
> +			 */
> +			stripe_offset = 0;
> +			stripe_nr = 0;

Oh, the stripe_nr calculation is wrong, it still needs to take full 
stripe number into consideration.

Would update this patch in my branch.

Thanks,
Qu

> +			stripe_index = data_stripes + (-mirror_num - 1);
>   		} else {
>   			/*
>   			 * Mirror #0 or #1 means the original data block.
diff mbox series

Patch

diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 1864856abb13..41c514db0793 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -1601,7 +1601,7 @@  static void scrub_submit_initial_read(struct scrub_ctx *sctx,
 	int mirror = stripe->mirror_num;
 
 	ASSERT(stripe->bg);
-	ASSERT(stripe->mirror_num > 0);
+	ASSERT(stripe->mirror_num);
 	ASSERT(test_bit(SCRUB_STRIPE_FLAG_INITIALIZED, &stripe->state));
 
 	bbio = btrfs_bio_alloc(SCRUB_STRIPE_PAGES, REQ_OP_READ, fs_info,
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index cd632b3f579f..c22007bd830b 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6251,10 +6251,12 @@  static void set_io_stripe(struct btrfs_io_stripe *dst, const struct map_lookup *
  *
  *			For RAID56 profile, mirror 1 means rebuild from P and
  *			the remaining data stripes.
+ *			And mirror -1 means read P stripes directly, -2 means
+ *			read Q stripes directly.
  *
  *			For RAID6 profile, mirror > 2 means mark another
  *			data/P stripe error and rebuild from the remaining
- *			stripes..
+ *			stripes.
  *
  * @need_raid_map:	(Used only for integrity checker) whether the map wants
  *                      a full stripe map (including all data and P/Q stripes)
@@ -6297,6 +6299,12 @@  int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
 		goto out_free_em;
 	}
 
+	/* Only allow mirror_num < 0 for RAID56. */
+	if (mirror_num < 0 && !(map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)) {
+		free_extent_map(em);
+		return -EINVAL;
+	}
+
 	data_stripes = nr_data_stripes(map);
 
 	map_offset = logical - em->start;
@@ -6382,6 +6390,26 @@  int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
 				  logical;
 			stripe_index = 0;
 			stripe_offset = 0;
+		} else if (mirror_num < 0) {
+			/* Only allow READ for direct P/Q operations. */
+			ASSERT(op == BTRFS_MAP_READ);
+			/*
+			 * Caller should make sure the range start is stripe
+			 * aligned.
+			 */
+			ASSERT(stripe_offset == 0);
+
+			/*
+			 * Stripes of @bioc is already sorted, stripes[0] is the
+			 * first data stripe and stripes[@data_stripes] is the
+			 * P stripe.
+			 * So we only need to update the @stripe_index to the
+			 * specified stripe, and set @stripe_nr/@stripe_offset
+			 * to 0, so we can return the beginning of the P/Q stripe.
+			 */
+			stripe_offset = 0;
+			stripe_nr = 0;
+			stripe_index = data_stripes + (-mirror_num - 1);
 		} else {
 			/*
 			 * Mirror #0 or #1 means the original data block.