public inbox for linux-btrfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants
@ 2023-02-05  8:53 Qu Wenruo
  2023-02-05  8:53 ` [PATCH 1/2] btrfs: remove map_lookup->stripe_len Qu Wenruo
                   ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Qu Wenruo @ 2023-02-05  8:53 UTC (permalink / raw)
  To: linux-btrfs

Div64 is much slower than 32 bit division, and only get improved in
the most recent CPUs, that's why we have dedicated div64* helpers.

One usage of div64 is in __btrfs_map_block() and its variants, where we
got @stripe_nr as u64, and all later division has to go the div64
helpers.

But the truth is, with our current chunk size limit (10G) and fixed
stripe length (64K), we can have at most 160K stripes in a chunk, which
is small enough for u32 already.

So this patchset would reduce div64 calls by:

- Remove map_lookup::stripe_len first
  So now we don't need to call div64 to calculate @stripe_nr, just a
  simple right shift, then truncate to u32.

  This is a prerequisite for the 2nd patch, without the fixed stripe
  length, we have to rely on div64.

- Reduce the width of various @stripe_nr to 32

- Use regular divitsion and module to do the calculation
  Now we can get rid of the fear that we missed some div64 helpers.
  

Qu Wenruo (2):
  btrfs: remove map_lookup->stripe_len
  btrfs: reduce div64 calls by limiting the number of stripes of a chunk
    to u32

 fs/btrfs/block-group.c            |  18 ++---
 fs/btrfs/scrub.c                  |  43 ++++++------
 fs/btrfs/tests/extent-map-tests.c |   1 -
 fs/btrfs/tree-checker.c           |  14 ++++
 fs/btrfs/volumes.c                | 110 +++++++++++++++---------------
 fs/btrfs/volumes.h                |   7 +-
 6 files changed, 104 insertions(+), 89 deletions(-)

-- 
2.39.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/2] btrfs: remove map_lookup->stripe_len
  2023-02-05  8:53 [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants Qu Wenruo
@ 2023-02-05  8:53 ` Qu Wenruo
  2023-02-06  6:39   ` Christoph Hellwig
  2023-02-06  8:28   ` Johannes Thumshirn
  2023-02-05  8:53 ` [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32 Qu Wenruo
  2023-02-06  6:38 ` [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants Christoph Hellwig
  2 siblings, 2 replies; 14+ messages in thread
From: Qu Wenruo @ 2023-02-05  8:53 UTC (permalink / raw)
  To: linux-btrfs

Currently btrfs doesn't support stripe lengths other than 64KiB.
This is already in the tree-checker.

Thus there is really no meaning to record that fixed value in
map_lookup, and can all be replaced with BTRFS_STRIPE_LEN.

Furthermore we can introduce BTRFS_STRIPE_LEN_SHIFT to change a lot of
multiplication to shift.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/block-group.c            |  6 ++---
 fs/btrfs/scrub.c                  | 43 +++++++++++++++----------------
 fs/btrfs/tests/extent-map-tests.c |  1 -
 fs/btrfs/volumes.c                | 39 ++++++++++++----------------
 fs/btrfs/volumes.h                |  5 +++-
 5 files changed, 44 insertions(+), 50 deletions(-)

diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index 45ccb25c5b1f..1c74af23f54c 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -1994,12 +1994,12 @@ int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start,
 
 	map = em->map_lookup;
 	data_stripe_length = em->orig_block_len;
-	io_stripe_size = map->stripe_len;
+	io_stripe_size = BTRFS_STRIPE_LEN;
 	chunk_start = em->start;
 
 	/* For RAID5/6 adjust to a full IO stripe length */
 	if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
-		io_stripe_size = map->stripe_len * nr_data_stripes(map);
+		io_stripe_size = nr_data_stripes(map) << BTRFS_STRIPE_LEN_SHIFT;
 
 	buf = kcalloc(map->num_stripes, sizeof(u64), GFP_NOFS);
 	if (!buf) {
@@ -2021,7 +2021,7 @@ int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start,
 			continue;
 
 		stripe_nr = physical - map->stripes[i].physical;
-		stripe_nr = div64_u64_rem(stripe_nr, map->stripe_len, &offset);
+		stripe_nr = div64_u64_rem(stripe_nr, BTRFS_STRIPE_LEN, &offset);
 
 		if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
 				 BTRFS_BLOCK_GROUP_RAID10)) {
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 69c93ae333f6..db0ee9354fda 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -2722,7 +2722,7 @@ static int scrub_extent(struct scrub_ctx *sctx, struct map_lookup *map,
 
 	if (flags & BTRFS_EXTENT_FLAG_DATA) {
 		if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
-			blocksize = map->stripe_len;
+			blocksize = BTRFS_STRIPE_LEN;
 		else
 			blocksize = sctx->fs_info->sectorsize;
 		spin_lock(&sctx->stat_lock);
@@ -2731,7 +2731,7 @@ static int scrub_extent(struct scrub_ctx *sctx, struct map_lookup *map,
 		spin_unlock(&sctx->stat_lock);
 	} else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
 		if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
-			blocksize = map->stripe_len;
+			blocksize = BTRFS_STRIPE_LEN;
 		else
 			blocksize = sctx->fs_info->nodesize;
 		spin_lock(&sctx->stat_lock);
@@ -2920,9 +2920,9 @@ static int get_raid56_logic_offset(u64 physical, int num,
 
 	*offset = last_offset;
 	for (i = 0; i < data_stripes; i++) {
-		*offset = last_offset + i * map->stripe_len;
+		*offset = last_offset + (i << BTRFS_STRIPE_LEN_SHIFT);
 
-		stripe_nr = div64_u64(*offset, map->stripe_len);
+		stripe_nr = div64_u64(*offset, BTRFS_STRIPE_LEN);
 		stripe_nr = div_u64(stripe_nr, data_stripes);
 
 		/* Work out the disk rotation on this stripe-set */
@@ -2935,7 +2935,7 @@ static int get_raid56_logic_offset(u64 physical, int num,
 		if (stripe_index < num)
 			j++;
 	}
-	*offset = last_offset + j * map->stripe_len;
+	*offset = last_offset + (j << BTRFS_STRIPE_LEN_SHIFT);
 	return 1;
 }
 
@@ -3205,7 +3205,7 @@ static int scrub_raid56_data_stripe_for_parity(struct scrub_ctx *sctx,
 	/* Path must not be populated */
 	ASSERT(!path->nodes[0]);
 
-	while (cur_logical < logical + map->stripe_len) {
+	while (cur_logical < logical + BTRFS_STRIPE_LEN) {
 		struct btrfs_io_context *bioc = NULL;
 		struct btrfs_device *extent_dev;
 		u64 extent_start;
@@ -3217,7 +3217,7 @@ static int scrub_raid56_data_stripe_for_parity(struct scrub_ctx *sctx,
 		u64 extent_mirror_num;
 
 		ret = find_first_extent_item(extent_root, path, cur_logical,
-					     logical + map->stripe_len - cur_logical);
+					     logical + BTRFS_STRIPE_LEN - cur_logical);
 		/* No more extent item in this data stripe */
 		if (ret > 0) {
 			ret = 0;
@@ -3231,7 +3231,7 @@ static int scrub_raid56_data_stripe_for_parity(struct scrub_ctx *sctx,
 		/* Metadata should not cross stripe boundaries */
 		if ((extent_flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) &&
 		    does_range_cross_boundary(extent_start, extent_size,
-					      logical, map->stripe_len)) {
+					      logical, BTRFS_STRIPE_LEN)) {
 			btrfs_err(fs_info,
 	"scrub: tree block %llu spanning stripes, ignored. logical=%llu",
 				  extent_start, logical);
@@ -3247,7 +3247,7 @@ static int scrub_raid56_data_stripe_for_parity(struct scrub_ctx *sctx,
 
 		/* Truncate the range inside this data stripe */
 		extent_size = min(extent_start + extent_size,
-				  logical + map->stripe_len) - cur_logical;
+				  logical + BTRFS_STRIPE_LEN) - cur_logical;
 		extent_start = cur_logical;
 		ASSERT(extent_size <= U32_MAX);
 
@@ -3320,8 +3320,7 @@ static noinline_for_stack int scrub_raid56_parity(struct scrub_ctx *sctx,
 	path->search_commit_root = 1;
 	path->skip_locking = 1;
 
-	ASSERT(map->stripe_len <= U32_MAX);
-	nsectors = map->stripe_len >> fs_info->sectorsize_bits;
+	nsectors = BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits;
 	ASSERT(nsectors <= BITS_PER_LONG);
 	sparity = kzalloc(sizeof(struct scrub_parity), GFP_NOFS);
 	if (!sparity) {
@@ -3332,8 +3331,7 @@ static noinline_for_stack int scrub_raid56_parity(struct scrub_ctx *sctx,
 		return -ENOMEM;
 	}
 
-	ASSERT(map->stripe_len <= U32_MAX);
-	sparity->stripe_len = map->stripe_len;
+	sparity->stripe_len = BTRFS_STRIPE_LEN;
 	sparity->nsectors = nsectors;
 	sparity->sctx = sctx;
 	sparity->scrub_dev = sdev;
@@ -3344,7 +3342,7 @@ static noinline_for_stack int scrub_raid56_parity(struct scrub_ctx *sctx,
 
 	ret = 0;
 	for (cur_logical = logic_start; cur_logical < logic_end;
-	     cur_logical += map->stripe_len) {
+	     cur_logical += BTRFS_STRIPE_LEN) {
 		ret = scrub_raid56_data_stripe_for_parity(sctx, sparity, map,
 							  sdev, path, cur_logical);
 		if (ret < 0)
@@ -3536,7 +3534,7 @@ static u64 simple_stripe_full_stripe_len(const struct map_lookup *map)
 	ASSERT(map->type & (BTRFS_BLOCK_GROUP_RAID0 |
 			    BTRFS_BLOCK_GROUP_RAID10));
 
-	return map->num_stripes / map->sub_stripes * map->stripe_len;
+	return (map->num_stripes / map->sub_stripes) << BTRFS_STRIPE_LEN_SHIFT;
 }
 
 /* Get the logical bytenr for the stripe */
@@ -3552,7 +3550,8 @@ static u64 simple_stripe_get_logical(struct map_lookup *map,
 	 * (stripe_index / sub_stripes) gives how many data stripes we need to
 	 * skip.
 	 */
-	return (stripe_index / map->sub_stripes) * map->stripe_len + bg->start;
+	return ((stripe_index / map->sub_stripes) << BTRFS_STRIPE_LEN_SHIFT) +
+	       bg->start;
 }
 
 /* Get the mirror number for the stripe */
@@ -3589,14 +3588,14 @@ static int scrub_simple_stripe(struct scrub_ctx *sctx,
 		 * this stripe.
 		 */
 		ret = scrub_simple_mirror(sctx, extent_root, csum_root, bg, map,
-					  cur_logical, map->stripe_len, device,
+					  cur_logical, BTRFS_STRIPE_LEN, device,
 					  cur_physical, mirror_num);
 		if (ret)
 			return ret;
 		/* Skip to next stripe which belongs to the target device */
 		cur_logical += logical_increment;
 		/* For physical offset, we just go to next stripe */
-		cur_physical += map->stripe_len;
+		cur_physical += BTRFS_STRIPE_LEN;
 	}
 	return ret;
 }
@@ -3690,7 +3689,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
 	if (profile & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) {
 		ret = scrub_simple_stripe(sctx, root, csum_root, bg, map,
 					  scrub_dev, stripe_index);
-		offset = map->stripe_len * (stripe_index / map->sub_stripes);
+		offset = (stripe_index / map->sub_stripes) << BTRFS_STRIPE_LEN_SHIFT;
 		goto out;
 	}
 
@@ -3705,7 +3704,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
 
 	/* Initialize @offset in case we need to go to out: label */
 	get_raid56_logic_offset(physical, stripe_index, map, &offset, NULL);
-	increment = map->stripe_len * nr_data_stripes(map);
+	increment = nr_data_stripes(map) << BTRFS_STRIPE_LEN_SHIFT;
 
 	/*
 	 * Due to the rotation, for RAID56 it's better to iterate each stripe
@@ -3736,13 +3735,13 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
 		 * is still based on @mirror_num.
 		 */
 		ret = scrub_simple_mirror(sctx, root, csum_root, bg, map,
-					  logical, map->stripe_len,
+					  logical, BTRFS_STRIPE_LEN,
 					  scrub_dev, physical, 1);
 		if (ret < 0)
 			goto out;
 next:
 		logical += increment;
-		physical += map->stripe_len;
+		physical += BTRFS_STRIPE_LEN;
 		spin_lock(&sctx->stat_lock);
 		if (stop_loop)
 			sctx->stat.last_physical =
diff --git a/fs/btrfs/tests/extent-map-tests.c b/fs/btrfs/tests/extent-map-tests.c
index c5b3a631bf4f..5d09fc4e1c3c 100644
--- a/fs/btrfs/tests/extent-map-tests.c
+++ b/fs/btrfs/tests/extent-map-tests.c
@@ -486,7 +486,6 @@ static int test_rmap_block(struct btrfs_fs_info *fs_info,
 	em->map_lookup = map;
 
 	map->num_stripes = test->num_stripes;
-	map->stripe_len = BTRFS_STRIPE_LEN;
 	map->type = test->raid_type;
 
 	for (i = 0; i < map->num_stripes; i++) {
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 883e5d2a23b6..4c91cc6471c3 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -5095,7 +5095,7 @@ static void init_alloc_chunk_ctl_policy_regular(
 	/* We don't want a chunk larger than 10% of writable space */
 	ctl->max_chunk_size = min(mult_perc(fs_devices->total_rw_bytes, 10),
 				  ctl->max_chunk_size);
-	ctl->dev_extent_min = BTRFS_STRIPE_LEN * ctl->dev_stripes;
+	ctl->dev_extent_min = ctl->dev_stripes << BTRFS_STRIPE_LEN_SHIFT;
 }
 
 static void init_alloc_chunk_ctl_policy_zoned(
@@ -5377,7 +5377,6 @@ static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans,
 						   j * ctl->stripe_size;
 		}
 	}
-	map->stripe_len = BTRFS_STRIPE_LEN;
 	map->io_align = BTRFS_STRIPE_LEN;
 	map->io_width = BTRFS_STRIPE_LEN;
 	map->type = type;
@@ -5585,11 +5584,11 @@ int btrfs_chunk_alloc_add_chunk_item(struct btrfs_trans_handle *trans,
 
 	btrfs_set_stack_chunk_length(chunk, bg->length);
 	btrfs_set_stack_chunk_owner(chunk, BTRFS_EXTENT_TREE_OBJECTID);
-	btrfs_set_stack_chunk_stripe_len(chunk, map->stripe_len);
+	btrfs_set_stack_chunk_stripe_len(chunk, BTRFS_STRIPE_LEN);
 	btrfs_set_stack_chunk_type(chunk, map->type);
 	btrfs_set_stack_chunk_num_stripes(chunk, map->num_stripes);
-	btrfs_set_stack_chunk_io_align(chunk, map->stripe_len);
-	btrfs_set_stack_chunk_io_width(chunk, map->stripe_len);
+	btrfs_set_stack_chunk_io_align(chunk, BTRFS_STRIPE_LEN);
+	btrfs_set_stack_chunk_io_width(chunk, BTRFS_STRIPE_LEN);
 	btrfs_set_stack_chunk_sector_size(chunk, fs_info->sectorsize);
 	btrfs_set_stack_chunk_sub_stripes(chunk, map->sub_stripes);
 
@@ -5779,7 +5778,7 @@ unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info,
 	if (!WARN_ON(IS_ERR(em))) {
 		map = em->map_lookup;
 		if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
-			len = map->stripe_len * nr_data_stripes(map);
+			len = nr_data_stripes(map) << BTRFS_STRIPE_LEN_SHIFT;
 		free_extent_map(em);
 	}
 	return len;
@@ -5945,7 +5944,6 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
 	u64 stripe_nr_end;
 	u64 stripe_end_offset;
 	u64 stripe_cnt;
-	u64 stripe_len;
 	u64 stripe_offset;
 	u32 stripe_index;
 	u32 factor = 0;
@@ -5972,20 +5970,19 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
 	length = min_t(u64, em->start + em->len - logical, length);
 	*length_ret = length;
 
-	stripe_len = map->stripe_len;
 	/*
 	 * stripe_nr counts the total number of stripes we have to stride
 	 * to get to this block
 	 */
-	stripe_nr = div64_u64(offset, stripe_len);
+	stripe_nr = div64_u64(offset, BTRFS_STRIPE_LEN);
 
 	/* stripe_offset is the offset of this block in its stripe */
-	stripe_offset = offset - stripe_nr * stripe_len;
+	stripe_offset = offset - (stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
 
-	stripe_nr_end = round_up(offset + length, map->stripe_len);
-	stripe_nr_end = div64_u64(stripe_nr_end, map->stripe_len);
+	stripe_nr_end = round_up(offset + length, BTRFS_STRIPE_LEN);
+	stripe_nr_end = div64_u64(stripe_nr_end, BTRFS_STRIPE_LEN);
 	stripe_cnt = stripe_nr_end - stripe_nr;
-	stripe_end_offset = stripe_nr_end * map->stripe_len -
+	stripe_end_offset = (stripe_nr_end << BTRFS_STRIPE_LEN_SHIFT) -
 			    (offset + length);
 	/*
 	 * after this, stripe_nr is the number of stripes on this
@@ -6027,15 +6024,15 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
 	for (i = 0; i < *num_stripes; i++) {
 		stripes[i].physical =
 			map->stripes[stripe_index].physical +
-			stripe_offset + stripe_nr * map->stripe_len;
+			stripe_offset + (stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
 		stripes[i].dev = map->stripes[stripe_index].dev;
 
 		if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
 				 BTRFS_BLOCK_GROUP_RAID10)) {
-			stripes[i].length = stripes_per_dev * map->stripe_len;
+			stripes[i].length = stripes_per_dev << BTRFS_STRIPE_LEN_SHIFT;
 
 			if (i / sub_stripes < remaining_stripes)
-				stripes[i].length += map->stripe_len;
+				stripes[i].length += BTRFS_STRIPE_LEN;
 
 			/*
 			 * Special for the first stripe and
@@ -6289,11 +6286,11 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em,
 			  struct btrfs_io_geometry *io_geom)
 {
 	struct map_lookup *map;
+	const u32 stripe_len = BTRFS_STRIPE_LEN;
 	u64 len;
 	u64 offset;
 	u64 stripe_offset;
 	u64 stripe_nr;
-	u32 stripe_len;
 	u64 raid56_full_stripe_start = (u64)-1;
 	int data_stripes;
 
@@ -6302,8 +6299,6 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em,
 	map = em->map_lookup;
 	/* Offset of this logical address in the chunk */
 	offset = logical - em->start;
-	/* Len of a stripe in a chunk */
-	stripe_len = map->stripe_len;
 	/*
 	 * Stripe_nr is where this block falls in
 	 * stripe_offset is the offset of this block in its stripe.
@@ -6362,7 +6357,7 @@ static void set_io_stripe(struct btrfs_io_stripe *dst, const struct map_lookup *
 {
 	dst->dev = map->stripes[stripe_index].dev;
 	dst->physical = map->stripes[stripe_index].physical +
-			stripe_offset + stripe_nr * map->stripe_len;
+			stripe_offset + (stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
 }
 
 int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
@@ -6481,7 +6476,6 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
 		}
 
 	} else if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
-		ASSERT(map->stripe_len == BTRFS_STRIPE_LEN);
 		if (need_raid_map && (need_full_stripe(op) || mirror_num > 1)) {
 			/* push stripe_nr back to the start of the full stripe */
 			stripe_nr = div64_u64(raid56_full_stripe_start,
@@ -6589,7 +6583,7 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
 		tmp = stripe_nr * data_stripes;
 		for (i = 0; i < data_stripes; i++)
 			bioc->raid_map[(i + rot) % num_stripes] =
-				em->start + (tmp + i) * map->stripe_len;
+				em->start + ((tmp + i) << BTRFS_STRIPE_LEN_SHIFT);
 
 		bioc->raid_map[(i + rot) % map->num_stripes] = RAID5_P_STRIPE;
 		if (map->type & BTRFS_BLOCK_GROUP_RAID6)
@@ -6962,7 +6956,6 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
 	map->num_stripes = num_stripes;
 	map->io_width = btrfs_chunk_io_width(leaf, chunk);
 	map->io_align = btrfs_chunk_io_align(leaf, chunk);
-	map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
 	map->type = type;
 	/*
 	 * We can't use the sub_stripes value, as for profiles other than
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 6b7a05f6cf82..7d0d9f25864c 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -19,6 +19,10 @@ extern struct mutex uuid_mutex;
 
 #define BTRFS_STRIPE_LEN	SZ_64K
 
+#define BTRFS_STRIPE_LEN_SHIFT	(16)
+
+static_assert((1 << BTRFS_STRIPE_LEN_SHIFT) == BTRFS_STRIPE_LEN);
+
 /* Used by sanity check for btrfs_raid_types. */
 #define const_ffs(n) (__builtin_ctzll(n) + 1)
 
@@ -461,7 +465,6 @@ struct map_lookup {
 	u64 type;
 	int io_align;
 	int io_width;
-	u32 stripe_len;
 	int num_stripes;
 	int sub_stripes;
 	int verified_stripes; /* For mount time dev extent verification */
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32
  2023-02-05  8:53 [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants Qu Wenruo
  2023-02-05  8:53 ` [PATCH 1/2] btrfs: remove map_lookup->stripe_len Qu Wenruo
@ 2023-02-05  8:53 ` Qu Wenruo
  2023-02-05 12:09   ` kernel test robot
                     ` (2 more replies)
  2023-02-06  6:38 ` [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants Christoph Hellwig
  2 siblings, 3 replies; 14+ messages in thread
From: Qu Wenruo @ 2023-02-05  8:53 UTC (permalink / raw)
  To: linux-btrfs

There are quite some div64 calls inside btrfs_map_block() and its
variants.

One of such calls are for @stripe_nr, where @stripe_nr is the number of
stripes before our logical bytenr inside a chunk.

However we can eliminate such div64 calls by just reducing the width of
@stripe_nr from 64 to 32.

This can be done because our chunk size limit is already 10G, with fixed
stripe length 64K.
Thus a U32 is definitely enough to contain the number of stripes.

With such width reduction, we can get rid of slower div64, and extra
warning for certain 32bit arch.

This patch would do:

- Reduce the width of various stripe_nr variables

- Add a new tree-checker chunk validation on chunk length
  Make sure no chunk can reach 256G, which can also act as a bitflip
  checker.

- Replace unnecessary div64 calls with regular modulo and division
  32bit division and modulo are much faster than 64bit operations, and
  we are finally free of the div64 fear at least in those involved
  functions.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/block-group.c  | 14 ++++----
 fs/btrfs/tree-checker.c | 14 ++++++++
 fs/btrfs/volumes.c      | 79 ++++++++++++++++++++++-------------------
 fs/btrfs/volumes.h      |  2 +-
 4 files changed, 65 insertions(+), 44 deletions(-)

diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index 1c74af23f54c..4d7c62e5a4d8 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -2020,20 +2020,20 @@ int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start,
 		if (bdev && map->stripes[i].dev->bdev != bdev)
 			continue;
 
-		stripe_nr = physical - map->stripes[i].physical;
-		stripe_nr = div64_u64_rem(stripe_nr, BTRFS_STRIPE_LEN, &offset);
+		stripe_nr = (physical - map->stripes[i].physical) >>
+			     BTRFS_STRIPE_LEN_SHIFT;
+		offset = (physical - map->stripes[i].physical) &
+			 ((1 << BTRFS_STRIPE_LEN_SHIFT) - 1);
 
 		if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
-				 BTRFS_BLOCK_GROUP_RAID10)) {
-			stripe_nr = stripe_nr * map->num_stripes + i;
-			stripe_nr = div_u64(stripe_nr, map->sub_stripes);
-		}
+				 BTRFS_BLOCK_GROUP_RAID10))
+			stripe_nr = (stripe_nr * map->num_stripes + i) /
+				     map->sub_stripes;
 		/*
 		 * The remaining case would be for RAID56, multiply by
 		 * nr_data_stripes().  Alternatively, just use rmap_len below
 		 * instead of map->stripe_len
 		 */
-
 		bytenr = chunk_start + stripe_nr * io_stripe_size + offset;
 
 		/* Ensure we don't add duplicate addresses */
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index baad1ed7e111..7968fc89f278 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -849,6 +849,20 @@ int btrfs_check_chunk_valid(struct extent_buffer *leaf,
 			  stripe_len);
 		return -EUCLEAN;
 	}
+	/*
+	 * We artificially limit the chunk size, so that the number of stripes
+	 * inside a chunk can be fit into a U32.
+	 * The current limit (256G) would be way too large for real world usage
+	 * anyway, and it's already way larger than our existing limit (10G).
+	 *
+	 * Thus it should be a good way to catch obvious bitflip.
+	 */
+	if (unlikely(((u64)U32_MAX << BTRFS_STRIPE_LEN_SHIFT) <= length)) {
+		chunk_err(leaf, chunk, logical,
+			  "chunk length too large: have %llu limit %llu",
+			  length, (u64)U32_MAX << BTRFS_STRIPE_LEN_SHIFT);
+		return -EUCLEAN;
+	}
 	if (unlikely(type & ~(BTRFS_BLOCK_GROUP_TYPE_MASK |
 			      BTRFS_BLOCK_GROUP_PROFILE_MASK))) {
 		chunk_err(leaf, chunk, logical,
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 4c91cc6471c3..ce073083b0dc 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -5940,15 +5940,15 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
 	struct btrfs_discard_stripe *stripes;
 	u64 length = *length_ret;
 	u64 offset;
-	u64 stripe_nr;
-	u64 stripe_nr_end;
+	u32 stripe_nr;
+	u32 stripe_nr_end;
+	u32 stripe_cnt;
 	u64 stripe_end_offset;
-	u64 stripe_cnt;
 	u64 stripe_offset;
 	u32 stripe_index;
 	u32 factor = 0;
 	u32 sub_stripes = 0;
-	u64 stripes_per_dev = 0;
+	u32 stripes_per_dev = 0;
 	u32 remaining_stripes = 0;
 	u32 last_stripe = 0;
 	int ret;
@@ -5974,13 +5974,13 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
 	 * stripe_nr counts the total number of stripes we have to stride
 	 * to get to this block
 	 */
-	stripe_nr = div64_u64(offset, BTRFS_STRIPE_LEN);
+	stripe_nr = offset >> BTRFS_STRIPE_LEN_SHIFT;
 
 	/* stripe_offset is the offset of this block in its stripe */
 	stripe_offset = offset - (stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
 
-	stripe_nr_end = round_up(offset + length, BTRFS_STRIPE_LEN);
-	stripe_nr_end = div64_u64(stripe_nr_end, BTRFS_STRIPE_LEN);
+	stripe_nr_end = round_up(offset + length, BTRFS_STRIPE_LEN) >>
+			BTRFS_STRIPE_LEN_SHIFT;
 	stripe_cnt = stripe_nr_end - stripe_nr;
 	stripe_end_offset = (stripe_nr_end << BTRFS_STRIPE_LEN_SHIFT) -
 			    (offset + length);
@@ -6001,18 +6001,18 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
 		factor = map->num_stripes / sub_stripes;
 		*num_stripes = min_t(u64, map->num_stripes,
 				    sub_stripes * stripe_cnt);
-		stripe_nr = div_u64_rem(stripe_nr, factor, &stripe_index);
+		stripe_index = stripe_nr % factor;
+		stripe_nr /= factor;
 		stripe_index *= sub_stripes;
 		stripes_per_dev = div_u64_rem(stripe_cnt, factor,
 					      &remaining_stripes);
-		div_u64_rem(stripe_nr_end - 1, factor, &last_stripe);
-		last_stripe *= sub_stripes;
+		last_stripe = (stripe_nr_end - 1) % factor * sub_stripes;
 	} else if (map->type & (BTRFS_BLOCK_GROUP_RAID1_MASK |
 				BTRFS_BLOCK_GROUP_DUP)) {
 		*num_stripes = map->num_stripes;
 	} else {
-		stripe_nr = div_u64_rem(stripe_nr, map->num_stripes,
-					&stripe_index);
+		stripe_index = stripe_nr % map->num_stripes;
+		stripe_nr /= map->num_stripes;
 	}
 
 	stripes = kcalloc(*num_stripes, sizeof(*stripes), GFP_NOFS);
@@ -6286,11 +6286,10 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em,
 			  struct btrfs_io_geometry *io_geom)
 {
 	struct map_lookup *map;
-	const u32 stripe_len = BTRFS_STRIPE_LEN;
 	u64 len;
 	u64 offset;
 	u64 stripe_offset;
-	u64 stripe_nr;
+	u32 stripe_nr;
 	u64 raid56_full_stripe_start = (u64)-1;
 	int data_stripes;
 
@@ -6303,20 +6302,22 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em,
 	 * Stripe_nr is where this block falls in
 	 * stripe_offset is the offset of this block in its stripe.
 	 */
-	stripe_nr = div64_u64_rem(offset, stripe_len, &stripe_offset);
+	stripe_offset = offset & ((1 << BTRFS_STRIPE_LEN_SHIFT) - 1);
+	stripe_nr = offset >> BTRFS_STRIPE_LEN_SHIFT;
 	ASSERT(stripe_offset < U32_MAX);
 
 	data_stripes = nr_data_stripes(map);
 
 	/* Only stripe based profiles needs to check against stripe length. */
 	if (map->type & BTRFS_BLOCK_GROUP_STRIPE_MASK) {
-		u64 max_len = stripe_len - stripe_offset;
+		u64 max_len = BTRFS_STRIPE_LEN - stripe_offset;
 
 		/*
 		 * In case of raid56, we need to know the stripe aligned start
 		 */
 		if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
-			unsigned long full_stripe_len = stripe_len * data_stripes;
+			unsigned long full_stripe_len = data_stripes <<
+							BTRFS_STRIPE_LEN_SHIFT;
 			raid56_full_stripe_start = offset;
 
 			/*
@@ -6333,7 +6334,7 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em,
 			 * reads, just allow a single stripe (on a single disk).
 			 */
 			if (op == BTRFS_MAP_WRITE) {
-				max_len = stripe_len * data_stripes -
+				max_len = (data_stripes << BTRFS_STRIPE_LEN_SHIFT) -
 					  (offset - raid56_full_stripe_start);
 			}
 		}
@@ -6344,7 +6345,7 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em,
 
 	io_geom->len = len;
 	io_geom->offset = offset;
-	io_geom->stripe_len = stripe_len;
+	io_geom->stripe_len = BTRFS_STRIPE_LEN;
 	io_geom->stripe_nr = stripe_nr;
 	io_geom->stripe_offset = stripe_offset;
 	io_geom->raid56_stripe_offset = raid56_full_stripe_start;
@@ -6353,7 +6354,7 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em,
 }
 
 static void set_io_stripe(struct btrfs_io_stripe *dst, const struct map_lookup *map,
-		          u32 stripe_index, u64 stripe_offset, u64 stripe_nr)
+			  u32 stripe_index, u64 stripe_offset, u32 stripe_nr)
 {
 	dst->dev = map->stripes[stripe_index].dev;
 	dst->physical = map->stripes[stripe_index].physical +
@@ -6369,8 +6370,8 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
 	struct extent_map *em;
 	struct map_lookup *map;
 	u64 stripe_offset;
-	u64 stripe_nr;
 	u64 stripe_len;
+	u32 stripe_nr;
 	u32 stripe_index;
 	int data_stripes;
 	int i;
@@ -6433,8 +6434,8 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
 	num_stripes = 1;
 	stripe_index = 0;
 	if (map->type & BTRFS_BLOCK_GROUP_RAID0) {
-		stripe_nr = div_u64_rem(stripe_nr, map->num_stripes,
-				&stripe_index);
+		stripe_index = stripe_nr % map->num_stripes;
+		stripe_nr /= map->num_stripes;
 		if (!need_full_stripe(op))
 			mirror_num = 1;
 	} else if (map->type & BTRFS_BLOCK_GROUP_RAID1_MASK) {
@@ -6460,8 +6461,8 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
 	} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
 		u32 factor = map->num_stripes / map->sub_stripes;
 
-		stripe_nr = div_u64_rem(stripe_nr, factor, &stripe_index);
-		stripe_index *= map->sub_stripes;
+		stripe_index = stripe_nr % factor * map->sub_stripes;
+		stripe_nr /= factor;
 
 		if (need_full_stripe(op))
 			num_stripes = map->sub_stripes;
@@ -6477,9 +6478,16 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
 
 	} else if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
 		if (need_raid_map && (need_full_stripe(op) || mirror_num > 1)) {
-			/* push stripe_nr back to the start of the full stripe */
-			stripe_nr = div64_u64(raid56_full_stripe_start,
-					stripe_len * data_stripes);
+			/*
+			 * Push stripe_nr back to the start of the full stripe
+			 * For those cases needing a full stripe, @stripe_nr
+			 * is the full stripe number.
+			 *
+			 * Original we go raid56_full_stripe_start / full_stripe_len,
+			 * but that can be expensive.
+			 * Here we just divide @stripe_nr with @data_stripes.
+			 */
+			stripe_nr /= data_stripes;
 
 			/* RAID[56] write or recovery. Return all stripes */
 			num_stripes = map->num_stripes;
@@ -6497,25 +6505,24 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
 			 * Mirror #2 is RAID5 parity block.
 			 * Mirror #3 is RAID6 Q block.
 			 */
-			stripe_nr = div_u64_rem(stripe_nr,
-					data_stripes, &stripe_index);
+			stripe_index = stripe_nr % data_stripes;
+			stripe_nr /= data_stripes;
 			if (mirror_num > 1)
 				stripe_index = data_stripes + mirror_num - 2;
 
 			/* We distribute the parity blocks across stripes */
-			div_u64_rem(stripe_nr + stripe_index, map->num_stripes,
-					&stripe_index);
+			stripe_index = (stripe_nr + stripe_index) % map->num_stripes;
 			if (!need_full_stripe(op) && mirror_num <= 1)
 				mirror_num = 1;
 		}
 	} else {
 		/*
-		 * after this, stripe_nr is the number of stripes on this
+		 * After this, stripe_nr is the number of stripes on this
 		 * device we have to walk to find the data, and stripe_index is
 		 * the number of our device in the stripe array
 		 */
-		stripe_nr = div_u64_rem(stripe_nr, map->num_stripes,
-				&stripe_index);
+		stripe_index = stripe_nr % map->num_stripes;
+		stripe_nr /= map->num_stripes;
 		mirror_num = stripe_index + 1;
 	}
 	if (stripe_index >= map->num_stripes) {
@@ -6577,7 +6584,7 @@ int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
 		unsigned rot;
 
 		/* Work out the disk rotation on this stripe-set */
-		div_u64_rem(stripe_nr, num_stripes, &rot);
+		rot = stripe_nr % num_stripes;
 
 		/* Fill in the logical address of each stripe */
 		tmp = stripe_nr * data_stripes;
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 7d0d9f25864c..96dda0f4c564 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -67,7 +67,7 @@ struct btrfs_io_geometry {
 	/* offset of address in stripe */
 	u32 stripe_offset;
 	/* number of stripe where address falls */
-	u64 stripe_nr;
+	u32 stripe_nr;
 	/* offset of raid56 stripe into the chunk */
 	u64 raid56_stripe_offset;
 };
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32
  2023-02-05  8:53 ` [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32 Qu Wenruo
@ 2023-02-05 12:09   ` kernel test robot
  2023-02-05 12:20   ` kernel test robot
  2023-02-06  6:44   ` Christoph Hellwig
  2 siblings, 0 replies; 14+ messages in thread
From: kernel test robot @ 2023-02-05 12:09 UTC (permalink / raw)
  To: Qu Wenruo, linux-btrfs; +Cc: oe-kbuild-all

Hi Qu,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on v6.2-rc6]
[also build test ERROR on linus/master]
[cannot apply to kdave/for-next next-20230203]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Qu-Wenruo/btrfs-remove-map_lookup-stripe_len/20230205-165612
patch link:    https://lore.kernel.org/r/275da997c70615256bed3cff8e74ab2b3fecbafc.1675586554.git.wqu%40suse.com
patch subject: [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32
config: i386-randconfig-a003 (https://download.01.org/0day-ci/archive/20230205/202302051950.KouT9cVY-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-8) 11.3.0
reproduce (this is a W=1 build):
        # https://github.com/intel-lab-lkp/linux/commit/dc356ab4c1f118e55634c17c1e086bfc0536198d
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Qu-Wenruo/btrfs-remove-map_lookup-stripe_len/20230205-165612
        git checkout dc356ab4c1f118e55634c17c1e086bfc0536198d
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        make W=1 O=build_dir ARCH=i386 olddefconfig
        make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "__udivdi3" [fs/btrfs/btrfs.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32
  2023-02-05  8:53 ` [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32 Qu Wenruo
  2023-02-05 12:09   ` kernel test robot
@ 2023-02-05 12:20   ` kernel test robot
  2023-02-06  6:44   ` Christoph Hellwig
  2 siblings, 0 replies; 14+ messages in thread
From: kernel test robot @ 2023-02-05 12:20 UTC (permalink / raw)
  To: Qu Wenruo, linux-btrfs; +Cc: oe-kbuild-all

Hi Qu,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on v6.2-rc6]
[also build test ERROR on linus/master]
[cannot apply to kdave/for-next next-20230203]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Qu-Wenruo/btrfs-remove-map_lookup-stripe_len/20230205-165612
patch link:    https://lore.kernel.org/r/275da997c70615256bed3cff8e74ab2b3fecbafc.1675586554.git.wqu%40suse.com
patch subject: [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20230205/202302052002.9uoFbMlg-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/dc356ab4c1f118e55634c17c1e086bfc0536198d
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Qu-Wenruo/btrfs-remove-map_lookup-stripe_len/20230205-165612
        git checkout dc356ab4c1f118e55634c17c1e086bfc0536198d
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   m68k-linux-ld: fs/btrfs/block-group.o: in function `btrfs_rmap_block':
>> block-group.c:(.text+0x396c): undefined reference to `__udivdi3'

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants
  2023-02-05  8:53 [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants Qu Wenruo
  2023-02-05  8:53 ` [PATCH 1/2] btrfs: remove map_lookup->stripe_len Qu Wenruo
  2023-02-05  8:53 ` [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32 Qu Wenruo
@ 2023-02-06  6:38 ` Christoph Hellwig
  2023-02-06  6:58   ` Qu Wenruo
  2 siblings, 1 reply; 14+ messages in thread
From: Christoph Hellwig @ 2023-02-06  6:38 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: linux-btrfs

On Sun, Feb 05, 2023 at 04:53:40PM +0800, Qu Wenruo wrote:
> Div64 is much slower than 32 bit division, and only get improved in
> the most recent CPUs, that's why we have dedicated div64* helpers.

I think that's a little too simple.  All 64-bit CPUs can do 64-bit
divisions of course.  32-bit CPUs usually can't do it inside a single
instruction, and the helpers exist to avoid the libgcc calls.

That should not stand against an cleanups and optimizations of course.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/2] btrfs: remove map_lookup->stripe_len
  2023-02-05  8:53 ` [PATCH 1/2] btrfs: remove map_lookup->stripe_len Qu Wenruo
@ 2023-02-06  6:39   ` Christoph Hellwig
  2023-02-06  8:28   ` Johannes Thumshirn
  1 sibling, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2023-02-06  6:39 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: linux-btrfs

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32
  2023-02-05  8:53 ` [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32 Qu Wenruo
  2023-02-05 12:09   ` kernel test robot
  2023-02-05 12:20   ` kernel test robot
@ 2023-02-06  6:44   ` Christoph Hellwig
  2023-02-06 10:16     ` Qu Wenruo
  2 siblings, 1 reply; 14+ messages in thread
From: Christoph Hellwig @ 2023-02-06  6:44 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: linux-btrfs

> +	if (unlikely(((u64)U32_MAX << BTRFS_STRIPE_LEN_SHIFT) <= length)) {

Nit, at least to me this order reads weird and I had to stop and think
a while.   This version:

	if (unlikely(length >= ((u64)U32_MAX << BTRFS_STRIPE_LEN_SHIFT))) {

would be more obvious.

> @@ -6344,7 +6345,7 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em,
>  
>  	io_geom->len = len;
>  	io_geom->offset = offset;
> -	io_geom->stripe_len = stripe_len;
> +	io_geom->stripe_len = BTRFS_STRIPE_LEN;

This conflicts with the bio split series that has been in for-next
for a few weeks (but not in misc-next yet).

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants
  2023-02-06  6:38 ` [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants Christoph Hellwig
@ 2023-02-06  6:58   ` Qu Wenruo
  2023-02-06  7:02     ` Christoph Hellwig
  0 siblings, 1 reply; 14+ messages in thread
From: Qu Wenruo @ 2023-02-06  6:58 UTC (permalink / raw)
  To: Christoph Hellwig, Qu Wenruo; +Cc: linux-btrfs



On 2023/2/6 14:38, Christoph Hellwig wrote:
> On Sun, Feb 05, 2023 at 04:53:40PM +0800, Qu Wenruo wrote:
>> Div64 is much slower than 32 bit division, and only get improved in
>> the most recent CPUs, that's why we have dedicated div64* helpers.
> 
> I think that's a little too simple.  All 64-bit CPUs can do 64-bit
> divisions of course.  32-bit CPUs usually can't do it inside a single
> instruction, and the helpers exist to avoid the libgcc calls.

Right, I focused too much on the perf part, but sometimes the perf part 
may sound more scary:

   For example, DIVQ on Skylake has latency of 42-95 cycles [1] (and
   reciprocal throughput of 24-90), for 64-bits inputs.

I'm not sure what's the best way to benchmark such thing.
Maybe just do such division with random numbers and run it at module 
load time to verify the perf?

Thanks,
Qu

> 
> That should not stand against an cleanups and optimizations of course.
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants
  2023-02-06  6:58   ` Qu Wenruo
@ 2023-02-06  7:02     ` Christoph Hellwig
  0 siblings, 0 replies; 14+ messages in thread
From: Christoph Hellwig @ 2023-02-06  7:02 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: Christoph Hellwig, Qu Wenruo, linux-btrfs

On Mon, Feb 06, 2023 at 02:58:55PM +0800, Qu Wenruo wrote:
> Right, I focused too much on the perf part, but sometimes the perf part may
> sound more scary:
> 
>   For example, DIVQ on Skylake has latency of 42-95 cycles [1] (and
>   reciprocal throughput of 24-90), for 64-bits inputs.
> 
> I'm not sure what's the best way to benchmark such thing.
> Maybe just do such division with random numbers and run it at module load
> time to verify the perf?

Honestly, getting rid of the ugly divisions calls is probably
reason enough as the series looks like a nice cleanup.  I just had
to nipick on the sentence.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/2] btrfs: remove map_lookup->stripe_len
  2023-02-05  8:53 ` [PATCH 1/2] btrfs: remove map_lookup->stripe_len Qu Wenruo
  2023-02-06  6:39   ` Christoph Hellwig
@ 2023-02-06  8:28   ` Johannes Thumshirn
  2023-02-06  8:50     ` Qu Wenruo
  1 sibling, 1 reply; 14+ messages in thread
From: Johannes Thumshirn @ 2023-02-06  8:28 UTC (permalink / raw)
  To: Qu Wenruo, linux-btrfs@vger.kernel.org

On 05.02.23 09:54, Qu Wenruo wrote:
> Currently btrfs doesn't support stripe lengths other than 64KiB.
> This is already in the tree-checker.

Do we actually ever want to do variable length stripes? I'm just asking
for e.g. parity RAID.

[...]

> diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
> index 6b7a05f6cf82..7d0d9f25864c 100644
> --- a/fs/btrfs/volumes.h
> +++ b/fs/btrfs/volumes.h
> @@ -19,6 +19,10 @@ extern struct mutex uuid_mutex;
>  
>  #define BTRFS_STRIPE_LEN	SZ_64K
>  
> +#define BTRFS_STRIPE_LEN_SHIFT	(16)

Maybe:
#define BTRFS_STRIPE_LEN_SHIFT (const_ilog2(BTRFS_STRIPE_LEN))

But even without:
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/2] btrfs: remove map_lookup->stripe_len
  2023-02-06  8:28   ` Johannes Thumshirn
@ 2023-02-06  8:50     ` Qu Wenruo
  2023-02-06  8:56       ` Johannes Thumshirn
  0 siblings, 1 reply; 14+ messages in thread
From: Qu Wenruo @ 2023-02-06  8:50 UTC (permalink / raw)
  To: Johannes Thumshirn, linux-btrfs@vger.kernel.org



On 2023/2/6 16:28, Johannes Thumshirn wrote:
> On 05.02.23 09:54, Qu Wenruo wrote:
>> Currently btrfs doesn't support stripe lengths other than 64KiB.
>> This is already in the tree-checker.
> 
> Do we actually ever want to do variable length stripes? I'm just asking
> for e.g. parity RAID.

And even if we go support different stripe length, would it be a global 
one (every chunk still go the same stripe len, just not 64K), or really 
every chunk can have its own stripe len?

Personally speaking, I prefer the latter one, but that means, we have to 
add a new member into the super block, thus needs a new incompat flag then.

I'm also curious, for the parity RAID (is that the old raid stripe 
tree?) is there anything penalty using the old 64K stripe length?

Thanks,
Qu
> 
> [...]
> 
>> diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
>> index 6b7a05f6cf82..7d0d9f25864c 100644
>> --- a/fs/btrfs/volumes.h
>> +++ b/fs/btrfs/volumes.h
>> @@ -19,6 +19,10 @@ extern struct mutex uuid_mutex;
>>   
>>   #define BTRFS_STRIPE_LEN	SZ_64K
>>   
>> +#define BTRFS_STRIPE_LEN_SHIFT	(16)
> 
> Maybe:
> #define BTRFS_STRIPE_LEN_SHIFT (const_ilog2(BTRFS_STRIPE_LEN))
> 
> But even without:
> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/2] btrfs: remove map_lookup->stripe_len
  2023-02-06  8:50     ` Qu Wenruo
@ 2023-02-06  8:56       ` Johannes Thumshirn
  0 siblings, 0 replies; 14+ messages in thread
From: Johannes Thumshirn @ 2023-02-06  8:56 UTC (permalink / raw)
  To: Qu Wenruo, linux-btrfs@vger.kernel.org

On 06.02.23 09:51, Qu Wenruo wrote:
> 
> 
> On 2023/2/6 16:28, Johannes Thumshirn wrote:
>> On 05.02.23 09:54, Qu Wenruo wrote:
>>> Currently btrfs doesn't support stripe lengths other than 64KiB.
>>> This is already in the tree-checker.
>>
>> Do we actually ever want to do variable length stripes? I'm just asking
>> for e.g. parity RAID.
> 
> And even if we go support different stripe length, would it be a global 
> one (every chunk still go the same stripe len, just not 64K), or really 
> every chunk can have its own stripe len?
> 
> Personally speaking, I prefer the latter one, but that means, we have to 
> add a new member into the super block, thus needs a new incompat flag then.
> 
> I'm also curious, for the parity RAID (is that the old raid stripe 
> tree?) is there anything penalty using the old 64K stripe length?

No I'm just thinking of different ways to handle RAID. For instance ZFS'
RAID-Z has a variable length stripe length so it never needs to do sub-stripe
writes.

I actually have no real clue yet how to handle RAID5/6 with raid stripe tree.
Need to get RAID0/1/10/DUP stable first.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32
  2023-02-06  6:44   ` Christoph Hellwig
@ 2023-02-06 10:16     ` Qu Wenruo
  0 siblings, 0 replies; 14+ messages in thread
From: Qu Wenruo @ 2023-02-06 10:16 UTC (permalink / raw)
  To: Christoph Hellwig, Qu Wenruo; +Cc: linux-btrfs



On 2023/2/6 14:44, Christoph Hellwig wrote:
>> +	if (unlikely(((u64)U32_MAX << BTRFS_STRIPE_LEN_SHIFT) <= length)) {
> 
> Nit, at least to me this order reads weird and I had to stop and think
> a while.   This version:
> 
> 	if (unlikely(length >= ((u64)U32_MAX << BTRFS_STRIPE_LEN_SHIFT))) {
> 
> would be more obvious.
> 
>> @@ -6344,7 +6345,7 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *em,
>>   
>>   	io_geom->len = len;
>>   	io_geom->offset = offset;
>> -	io_geom->stripe_len = stripe_len;
>> +	io_geom->stripe_len = BTRFS_STRIPE_LEN;
> 
> This conflicts with the bio split series that has been in for-next
> for a few weeks (but not in misc-next yet).

I really hope David could solve it manually.

As I'm not sure if we should really base most of our development on 
for-next, as normally that branch is not updated frequently as misc-next.

Thanks,
Qu

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2023-02-06 10:16 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-02-05  8:53 [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants Qu Wenruo
2023-02-05  8:53 ` [PATCH 1/2] btrfs: remove map_lookup->stripe_len Qu Wenruo
2023-02-06  6:39   ` Christoph Hellwig
2023-02-06  8:28   ` Johannes Thumshirn
2023-02-06  8:50     ` Qu Wenruo
2023-02-06  8:56       ` Johannes Thumshirn
2023-02-05  8:53 ` [PATCH 2/2] btrfs: reduce div64 calls by limiting the number of stripes of a chunk to u32 Qu Wenruo
2023-02-05 12:09   ` kernel test robot
2023-02-05 12:20   ` kernel test robot
2023-02-06  6:44   ` Christoph Hellwig
2023-02-06 10:16     ` Qu Wenruo
2023-02-06  6:38 ` [PATCH 0/2] btrfs: reduce div64 calls for __btrfs_map_block() and its variants Christoph Hellwig
2023-02-06  6:58   ` Qu Wenruo
2023-02-06  7:02     ` Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox