* [PATCH v2 0/9] btrfs: prepare for variable stripe_len
@ 2026-10-21 3:39 Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 1/9] btrfs: reduce the width of num_stripes and sub_stripes Qu Wenruo
` (8 more replies)
0 siblings, 9 replies; 15+ messages in thread
From: Qu Wenruo @ 2026-10-21 3:39 UTC (permalink / raw)
To: linux-btrfs
[CHANGELOG]
v2:
- Use IS_ALINGED() when possible
Mostly affecting zoned.c
- Refactor is_same_chunk_map()
Not only reduce the length of the parameter list, but also make it
easier to expand, with extra unlikely() calls.
- Refactor alloc_scrub_bbio()
Since the @private is always a scrub_stripe pointer, use scrub_stripe
as the type instead, so we can grab stripe_len without introducing a
new parameter.
All are suggested by Johannes.
This is a preparation patchset, to support a stripe_len that is not
64KiB.
This is for the future variable stripe length RAID56 feature, where
RAID56_VSL profile is allowed for data chunks, and the stripe_len can be
as small as sectorsize, meanwhile data IO are kept to be aligned to
data_size, which is power of 2, and larger than sector size.
Finally, RAID56_VSL will always have a number of devices that nr_data ==
data_size / sector_size.
So that's why we want a variable stripe_len.
This series does all the preparation, including supporting stripe_len <
PAGE_SIZE.
For now, tree-checker will still reject stripe_len != 64K, but that
limit will be removed when RAID56_VSL feature is introduced and can be
properly tested.
Qu Wenruo (9):
btrfs: reduce the width of num_stripes and sub_stripes
btrfs: load the on-disk btrfs_chunk::stripe_len
btrfs: add btrfs_io_context::stripe_len and load it
btrfs: change scrub to use stripe_len
btrfs: add a new 'stripe_len' parameter to btrfs_stripe_nr_to_offset()
btrfs: convert volumes.c and block-group.c to use map->stripe_len
btrfs: convert raid56.c to use rbio->bioc->stripe_len
btrfs: convert zoned.c to use map->stripe_len
btrfs: introduce extra limits on btrfs_chunk::stripe_len
fs/btrfs/block-group.c | 9 +--
fs/btrfs/raid56.c | 57 ++++++++++++------
fs/btrfs/raid56.h | 7 +--
fs/btrfs/scrub.c | 129 ++++++++++++++++++++++++++--------------
fs/btrfs/tree-checker.c | 13 +++-
fs/btrfs/volumes.c | 95 +++++++++++++++++++----------
fs/btrfs/volumes.h | 16 +++--
fs/btrfs/zoned.c | 56 +++++++++--------
8 files changed, 246 insertions(+), 136 deletions(-)
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 1/9] btrfs: reduce the width of num_stripes and sub_stripes
2026-10-21 3:39 [PATCH v2 0/9] btrfs: prepare for variable stripe_len Qu Wenruo
@ 2026-10-21 3:39 ` Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 2/9] btrfs: load the on-disk btrfs_chunk::stripe_len Qu Wenruo
` (7 subsequent siblings)
8 siblings, 0 replies; 15+ messages in thread
From: Qu Wenruo @ 2026-10-21 3:39 UTC (permalink / raw)
To: linux-btrfs; +Cc: Johannes Thumshirn
The on-disk btrfs_chunk structure uses u16 for both num_stripes and
sub_stripes, so there is no need to use "int" to represent them in
btrfs_chunk_map.
Follow the on-disk format to use u16 for those members, including
verified_stripes too.
And since verified_stripes is u16, it no longer completely fill the
hole between @refs and @start.
Instead use @num_stripes and @sub_stripes to fill the hole, and leave a 6
bytes hole between @verified_stripes and @stripes.
This doesn't save any space for btrfs_chunk_map, but leaves enough space
for future expansion.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/volumes.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 67464025e449..d97ca875c596 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -623,9 +623,9 @@ extern const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES];
struct btrfs_chunk_map {
struct rb_node rb_node;
- /* For mount time dev extent verification. */
- int verified_stripes;
refcount_t refs;
+ u16 num_stripes;
+ u16 sub_stripes;
u64 start;
u64 chunk_len;
u64 dev_extent_size;
@@ -638,8 +638,8 @@ struct btrfs_chunk_map {
*/
u64 type;
u64 on_disk_type;
- int num_stripes;
- int sub_stripes;
+ /* For mount time dev extent verification. */
+ u16 verified_stripes;
struct btrfs_io_stripe stripes[];
};
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 2/9] btrfs: load the on-disk btrfs_chunk::stripe_len
2026-10-21 3:39 [PATCH v2 0/9] btrfs: prepare for variable stripe_len Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 1/9] btrfs: reduce the width of num_stripes and sub_stripes Qu Wenruo
@ 2026-10-21 3:39 ` Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 3/9] btrfs: add btrfs_io_context::stripe_len and load it Qu Wenruo
` (6 subsequent siblings)
8 siblings, 0 replies; 15+ messages in thread
From: Qu Wenruo @ 2026-10-21 3:39 UTC (permalink / raw)
To: linux-btrfs; +Cc: Johannes Thumshirn
Currently btrfs doesn't load btrfs_chunk::stripe_len into
btrfs_chunk_map, as tree-checker will reject any chunk whose stripe_len
is not 64K.
But for the future we will want stripe length other than 64K.
As a preparation for the variable stripe length in the future, load
btrfs_chunk::stripe_len into btrfs_chunk_map::stripe_len and
stripe_shift.
For now stripe_len is still 64K, no matter if it's loaded from the
on-disk metadata or newly allocated chunk.
As tree-checker still rejects any chunk whose stripe_len is not 64K.
The two new members fit into the existing hole of btrfs_chunk_map, so
the size of btrfs_chunk_map stay the same.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/volumes.c | 12 +++++++++++-
fs/btrfs/volumes.h | 2 ++
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 6574939e1295..a30b212ef0f1 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6166,6 +6166,12 @@ struct btrfs_chunk_map *btrfs_alloc_chunk_map(int num_stripes, gfp_t gfp)
refcount_set(&map->refs, 1);
RB_CLEAR_NODE(&map->rb_node);
+ /*
+ * Initialize the default stripe len, selftests will utilize them
+ * without an on-disk chunk item.
+ */
+ map->stripe_len = BTRFS_STRIPE_LEN;
+ map->stripe_shift = ilog2(map->stripe_len);
return map;
}
@@ -6203,6 +6209,8 @@ static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans,
map->on_disk_type = type;
map->sub_stripes = ctl->sub_stripes;
map->num_stripes = ctl->num_stripes;
+ map->stripe_len = BTRFS_STRIPE_LEN;
+ map->stripe_shift = ilog2(BTRFS_STRIPE_LEN);
set_real_chunk_type(map);
for (int i = 0; i < ctl->ndevs; i++) {
@@ -6381,7 +6389,7 @@ 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, BTRFS_STRIPE_LEN);
+ btrfs_set_stack_chunk_stripe_len(chunk, map->stripe_len);
btrfs_set_stack_chunk_type(chunk, map->on_disk_type);
btrfs_set_stack_chunk_num_stripes(chunk, map->num_stripes);
btrfs_set_stack_chunk_io_align(chunk, BTRFS_STRIPE_LEN);
@@ -7781,6 +7789,8 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
map->chunk_len = length;
map->num_stripes = num_stripes;
map->on_disk_type = type;
+ map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
+ map->stripe_shift = ilog2(map->stripe_len);
/*
* We can't use the sub_stripes value, as for profiles other than
* RAID10, they may have 0 as sub_stripes for filesystems created by
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index d97ca875c596..9dcc14cd61e2 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -640,6 +640,8 @@ struct btrfs_chunk_map {
u64 on_disk_type;
/* For mount time dev extent verification. */
u16 verified_stripes;
+ u8 stripe_shift;
+ u32 stripe_len;
struct btrfs_io_stripe stripes[];
};
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 3/9] btrfs: add btrfs_io_context::stripe_len and load it
2026-10-21 3:39 [PATCH v2 0/9] btrfs: prepare for variable stripe_len Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 1/9] btrfs: reduce the width of num_stripes and sub_stripes Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 2/9] btrfs: load the on-disk btrfs_chunk::stripe_len Qu Wenruo
@ 2026-10-21 3:39 ` Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 4/9] btrfs: change scrub to use stripe_len Qu Wenruo
` (5 subsequent siblings)
8 siblings, 0 replies; 15+ messages in thread
From: Qu Wenruo @ 2026-10-21 3:39 UTC (permalink / raw)
To: linux-btrfs; +Cc: Johannes Thumshirn
The new member will be utilized by various path that no direct
btrfs_chunk_map is available, but a stripe length is still required.
The new member is located inside a hole between @refs and @fs_info, so
no size increase for btrfs_io_context.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/volumes.c | 1 +
fs/btrfs/volumes.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index a30b212ef0f1..ff7189ac1c49 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -7411,6 +7411,7 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
ret = -ENOMEM;
goto out;
}
+ bioc->stripe_len = map->stripe_len;
bioc->map_type = map->type;
bioc->use_rst = io_geom.use_rst;
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 9dcc14cd61e2..9356cec00a90 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -515,6 +515,7 @@ struct btrfs_discard_stripe {
*/
struct btrfs_io_context {
refcount_t refs;
+ u32 stripe_len;
struct btrfs_fs_info *fs_info;
/* Taken from struct btrfs_chunk_map::type. */
u64 map_type;
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 4/9] btrfs: change scrub to use stripe_len
2026-10-21 3:39 [PATCH v2 0/9] btrfs: prepare for variable stripe_len Qu Wenruo
` (2 preceding siblings ...)
2026-10-21 3:39 ` [PATCH v2 3/9] btrfs: add btrfs_io_context::stripe_len and load it Qu Wenruo
@ 2026-10-21 3:39 ` Qu Wenruo
2026-10-21 5:58 ` Johannes Thumshirn
2026-10-21 3:39 ` [PATCH v2 5/9] btrfs: add a new 'stripe_len' parameter to btrfs_stripe_nr_to_offset() Qu Wenruo
` (4 subsequent siblings)
8 siblings, 1 reply; 15+ messages in thread
From: Qu Wenruo @ 2026-10-21 3:39 UTC (permalink / raw)
To: linux-btrfs
Several points to note:
- scrub_ctx::stripes[] stripe_len updates
We always pre-initialize scrub_ctx::stripes[] at the very beginning of
scrub, without holding any btrfs_chunk_map.
So init_scrub_stripe() still uses BTRFS_STRIPE_LEN, and all allocated
memory are based on that stripe length.
But before scrubbing each chunk, update_scrub_stripe_len() will be
called to update the scrub_stripe::stripe_len.
- Stripe_len should not exceed BTRFS_STRIPE_LEN
Since scrub_stripe's heap memory are all based on BTRFS_STRIPE_LEN,
any stripe_len larger than BTRFS_STRIPE_LEN will cause
access-beyond-boundary.
Thankfully there is no plan to support such stripe_len >
BTRFS_STRIPE_LEN any time soon.
- alloc_scrub_bbio() changes
Previously we ensure BTRFS_STRIPE_LEN >= PAGE_SIZE, so
BTRFS_STRIPE_LEN >> PAGE_SHIFT can never be zero.
But now stripe_len can be smaller than PAGE_SIZE. E.g. stripe_len 4K,
page size 64K.
So we have to use "round_up(stripe_len, PAGE_SIZE) >> PAGE_SHIFT"
instead.
Finally alloc_scrub_bbio() is always called with a scrub_stripe
pointer as the @private parameter, change the type from (void *) to
(struct scrub_stripe *), so that we can grab the stripe_len without
a new parameter.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/scrub.c | 99 ++++++++++++++++++++++++++++++++----------------
1 file changed, 66 insertions(+), 33 deletions(-)
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index bf91a6130e46..c3387e109779 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -124,7 +124,7 @@ enum {
};
/*
- * Represent one contiguous range with a length of BTRFS_STRIPE_LEN.
+ * Represent one contiguous range with a length of stripe_len.
*/
struct scrub_stripe {
struct scrub_ctx *sctx;
@@ -139,7 +139,7 @@ struct scrub_stripe {
u16 mirror_num;
- /* Should be BTRFS_STRIPE_LEN / sectorsize. */
+ /* Should be stripe_len / sectorsize. */
u16 nr_sectors;
/*
@@ -150,6 +150,8 @@ struct scrub_stripe {
u16 nr_meta_extents;
atomic_t pending_io;
+ /* From btrfs_chunk_map::stripe_len. Should not exceed BTRFS_STRIPE_LEN. */
+ u32 stripe_len;
wait_queue_head_t io_wait;
wait_queue_head_t repair_wait;
@@ -347,7 +349,13 @@ static int init_scrub_stripe(struct btrfs_fs_info *fs_info,
{
memset(stripe, 0, sizeof(*stripe));
+ /*
+ * Use the max stripe_len for now.
+ *
+ * This will be updated for every chunk using its stripe_len.
+ */
stripe->nr_sectors = BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits;
+ stripe->stripe_len = BTRFS_STRIPE_LEN;
stripe->state = 0;
init_waitqueue_head(&stripe->io_wait);
@@ -901,7 +909,7 @@ static void scrub_bio_add_sector(struct btrfs_bio *bbio, struct scrub_stripe *st
const u32 offset = sector_nr << fs_info->sectorsize_bits;
int ret;
- ASSERT(offset + fs_info->sectorsize <= BTRFS_STRIPE_LEN);
+ ASSERT(offset + fs_info->sectorsize <= stripe->stripe_len);
if (is_vmalloc_addr(stripe->buffer)) {
ret = bio_add_vmalloc(&bbio->bio, stripe->buffer + offset, fs_info->sectorsize);
@@ -914,9 +922,9 @@ static void scrub_bio_add_sector(struct btrfs_bio *bbio, struct scrub_stripe *st
}
static struct btrfs_bio *alloc_scrub_bbio(struct btrfs_fs_info *fs_info,
- blk_opf_t opf,
- u64 logical,
- btrfs_bio_end_io_t end_io, void *private)
+ blk_opf_t opf, u64 logical,
+ btrfs_bio_end_io_t end_io,
+ struct scrub_stripe *stripe)
{
struct btrfs_bio *bbio;
@@ -925,9 +933,10 @@ static struct btrfs_bio *alloc_scrub_bbio(struct btrfs_fs_info *fs_info,
* different physical addresses, we have to ensure the bbio is large
* enough to contain the full stripe.
*/
- bbio = btrfs_bio_alloc(BTRFS_STRIPE_LEN >> PAGE_SHIFT, opf,
+ bbio = btrfs_bio_alloc(round_up(stripe->stripe_len, PAGE_SIZE) >>
+ PAGE_SHIFT, opf,
BTRFS_I(fs_info->btree_inode),
- logical, end_io, private);
+ logical, end_io, stripe);
bbio->is_scrub = true;
bbio->bio.bi_iter.bi_sector = logical >> SECTOR_SHIFT;
return bbio;
@@ -959,7 +968,8 @@ static void scrub_stripe_submit_repair_read(struct scrub_stripe *stripe,
if (!bbio)
bbio = alloc_scrub_bbio(fs_info, REQ_OP_READ,
- stripe->logical + (i << fs_info->sectorsize_bits),
+ stripe->logical +
+ (i << fs_info->sectorsize_bits),
scrub_repair_read_endio, stripe);
scrub_bio_add_sector(bbio, stripe, i);
@@ -1176,7 +1186,7 @@ static void scrub_stripe_read_repair_worker(struct work_struct *work)
const unsigned long old_error_bitmap = scrub_bitmap_read_error(stripe);
scrub_stripe_submit_repair_read(stripe, mirror,
- BTRFS_STRIPE_LEN, false);
+ stripe->stripe_len, false);
wait_scrub_stripe_io(stripe);
scrub_verify_one_stripe(stripe, old_error_bitmap);
if (scrub_bitmap_empty_error(stripe))
@@ -1325,7 +1335,8 @@ static void scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *str
}
if (!bbio)
bbio = alloc_scrub_bbio(fs_info, REQ_OP_WRITE,
- stripe->logical + (sector_nr << fs_info->sectorsize_bits),
+ stripe->logical +
+ (sector_nr << fs_info->sectorsize_bits),
scrub_write_endio, stripe);
scrub_bio_add_sector(bbio, stripe, sector_nr);
}
@@ -1416,7 +1427,7 @@ static int get_raid56_logic_offset(u64 physical, int num,
*offset = last_offset + btrfs_stripe_nr_to_offset(i);
- stripe_nr = (u32)(*offset >> BTRFS_STRIPE_LEN_SHIFT) / data_stripes;
+ stripe_nr = (u32)(*offset >> map->stripe_shift) / data_stripes;
/* Work out the disk rotation on this stripe-set */
rot = stripe_nr % map->num_stripes;
@@ -1591,7 +1602,7 @@ static void fill_one_extent_info(struct btrfs_fs_info *fs_info,
u64 extent_flags, u64 extent_gen)
{
for (u64 cur_logical = max(stripe->logical, extent_start);
- cur_logical < min(stripe->logical + BTRFS_STRIPE_LEN,
+ cur_logical < min(stripe->logical + stripe->stripe_len,
extent_start + extent_len);
cur_logical += fs_info->sectorsize) {
const int nr_sector = (cur_logical - stripe->logical) >>
@@ -1670,15 +1681,15 @@ static int scrub_find_fill_first_stripe(struct btrfs_block_group *bg,
* Round down to stripe boundary.
*
* The extra calculation against bg->start is to handle block groups
- * whose logical bytenr is not BTRFS_STRIPE_LEN aligned.
+ * whose logical bytenr is not stripe_len aligned.
*/
- stripe->logical = round_down(cur_logical - bg->start, BTRFS_STRIPE_LEN) +
+ stripe->logical = round_down(cur_logical - bg->start, stripe->stripe_len) +
bg->start;
stripe->physical = physical + stripe->logical - logical_start;
stripe->dev = dev;
stripe->bg = bg;
stripe->mirror_num = mirror_num;
- stripe_end = stripe->logical + BTRFS_STRIPE_LEN - 1;
+ stripe_end = stripe->logical + stripe->stripe_len - 1;
/* Fill the first extent info into stripe->sectors[] array. */
fill_one_extent_info(fs_info, stripe, extent_start, extent_len,
@@ -1715,10 +1726,15 @@ static int scrub_find_fill_first_stripe(struct btrfs_block_group *bg,
ASSERT(stripe->csums);
/*
- * Our csum bitmap should be large enough, as BTRFS_STRIPE_LEN
- * should contain at most 16 sectors.
+ * Our csum bitmap should be large enough, as stripe_len is no
+ * larger than BTRFS_STRIPE_LEN, and BTRFS_STRIPE_LEN contains
+ * at most 16 sectors (4K sector size).
+ *
+ * So (stripe_len >> sectorsize_bits) should be at most 16,
+ * not reaching BITS_PER_LONG.
*/
- ASSERT(BITS_PER_LONG >= BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits);
+ ASSERT(BITS_PER_LONG >= (stripe->stripe_len >>
+ fs_info->sectorsize_bits));
ret = btrfs_lookup_csums_bitmap(csum_root, csum_path,
stripe->logical, stripe_end,
@@ -1756,7 +1772,7 @@ static u32 stripe_length(const struct scrub_stripe *stripe)
{
ASSERT(stripe->bg);
- return min(BTRFS_STRIPE_LEN,
+ return min(stripe->stripe_len,
stripe->bg->start + stripe->bg->length - stripe->logical);
}
@@ -1766,7 +1782,7 @@ static void scrub_submit_extent_sector_read(struct scrub_stripe *stripe)
struct btrfs_bio *bbio = NULL;
unsigned int nr_sectors = stripe_length(stripe) >> fs_info->sectorsize_bits;
const unsigned long has_extent = scrub_bitmap_read_has_extent(stripe);
- u64 stripe_len = BTRFS_STRIPE_LEN;
+ u64 stripe_len = stripe->stripe_len;
int mirror = stripe->mirror_num;
int i;
@@ -2102,7 +2118,7 @@ static int scrub_raid56_cached_parity(struct scrub_ctx *sctx,
/* For RAID56 write there must be an @bioc allocated. */
ASSERT(bioc);
rbio = raid56_parity_alloc_scrub_rbio(&bio, bioc, scrub_dev, extent_bitmap,
- BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits);
+ map->stripe_len >> fs_info->sectorsize_bits);
btrfs_put_bioc(bioc);
if (!rbio) {
ret = -ENOMEM;
@@ -2113,7 +2129,7 @@ static int scrub_raid56_cached_parity(struct scrub_ctx *sctx,
struct scrub_stripe *stripe = &sctx->raid56_data_stripes[i];
raid56_parity_cache_data_folios(rbio, stripe->buffer,
- full_stripe_start + (i << BTRFS_STRIPE_LEN_SHIFT));
+ full_stripe_start + (i << map->stripe_shift));
}
raid56_parity_submit_scrub_rbio(rbio);
wait_for_completion_io(&io_done);
@@ -2172,7 +2188,7 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
stripe = &sctx->raid56_data_stripes[i];
rot = div_u64(full_stripe_start - bg->start,
- data_stripes) >> BTRFS_STRIPE_LEN_SHIFT;
+ data_stripes) >> map->stripe_shift;
stripe_index = (i + rot) % map->num_stripes;
physical = map->stripes[stripe_index].physical +
btrfs_stripe_nr_to_offset(rot);
@@ -2182,7 +2198,7 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
ret = scrub_find_fill_first_stripe(bg, &extent_path, &csum_path,
map->stripes[stripe_index].dev, physical, 1,
full_stripe_start + btrfs_stripe_nr_to_offset(i),
- BTRFS_STRIPE_LEN, stripe);
+ map->stripe_len, stripe);
if (ret < 0)
return ret;
/*
@@ -2270,6 +2286,7 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
static int scrub_simple_mirror(struct scrub_ctx *sctx,
struct btrfs_block_group *bg,
u64 logical_start, u64 logical_length,
+ u32 stripe_len,
struct btrfs_device *device,
u64 physical, int mirror_num)
{
@@ -2317,7 +2334,7 @@ static int scrub_simple_mirror(struct scrub_ctx *sctx,
/* queue_scrub_stripe() returned 0, @found_logical must be updated. */
ASSERT(found_logical != U64_MAX);
- cur_logical = found_logical + BTRFS_STRIPE_LEN;
+ cur_logical = found_logical + stripe_len;
/* Don't hold CPU for too long time */
cond_resched();
@@ -2372,6 +2389,7 @@ static int scrub_simple_stripe(struct scrub_ctx *sctx,
const u64 orig_logical = simple_stripe_get_logical(map, bg, stripe_index);
const u64 orig_physical = map->stripes[stripe_index].physical;
const u64 end = btrfs_block_group_end(bg);
+ const u32 stripe_len = map->stripe_len;
const int mirror_num = simple_stripe_mirror_num(map, stripe_index);
u64 cur_logical = orig_logical;
u64 cur_physical = orig_physical;
@@ -2384,18 +2402,27 @@ static int scrub_simple_stripe(struct scrub_ctx *sctx,
* this stripe.
*/
ret = scrub_simple_mirror(sctx, bg, cur_logical,
- BTRFS_STRIPE_LEN, device, cur_physical,
+ stripe_len, 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 += BTRFS_STRIPE_LEN;
+ cur_physical += stripe_len;
}
return ret;
}
+static void update_scrub_stripe_len(const struct btrfs_fs_info *fs_info,
+ const struct btrfs_chunk_map *map,
+ struct scrub_stripe *stripe)
+{
+ stripe->stripe_len = map->stripe_len;
+ stripe->nr_sectors = map->stripe_len >> fs_info->sectorsize_bits;
+}
+
static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
struct btrfs_block_group *bg,
struct btrfs_chunk_map *map,
@@ -2405,6 +2432,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
struct btrfs_fs_info *fs_info = sctx->fs_info;
const u64 profile = map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK;
const u64 chunk_logical = bg->start;
+ const u32 stripe_len = map->stripe_len;
int ret;
int ret2;
u64 physical = map->stripes[stripe_index].physical;
@@ -2447,6 +2475,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
goto out;
sctx->raid56_data_stripes[i].bg = bg;
sctx->raid56_data_stripes[i].sctx = sctx;
+ update_scrub_stripe_len(fs_info, map, &sctx->raid56_data_stripes[i]);
}
}
/*
@@ -2467,7 +2496,8 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
* @stripe_index.
*/
ret = scrub_simple_mirror(sctx, bg, bg->start, bg->length,
- scrub_dev, map->stripes[stripe_index].physical,
+ stripe_len, scrub_dev,
+ map->stripes[stripe_index].physical,
stripe_index + 1);
offset = 0;
goto out;
@@ -2505,7 +2535,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
ret = scrub_raid56_parity_stripe(sctx, scrub_dev, bg,
map, stripe_logical);
spin_lock(&sctx->stat_lock);
- sctx->stat.last_physical = min(physical + BTRFS_STRIPE_LEN,
+ sctx->stat.last_physical = min(physical + stripe_len,
physical_end);
spin_unlock(&sctx->stat_lock);
if (ret)
@@ -2521,13 +2551,13 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
* We can reuse scrub_simple_mirror() here, as the repair part
* is still based on @mirror_num.
*/
- ret = scrub_simple_mirror(sctx, bg, logical, BTRFS_STRIPE_LEN,
- scrub_dev, physical, 1);
+ ret = scrub_simple_mirror(sctx, bg, logical, stripe_len,
+ stripe_len, scrub_dev, physical, 1);
if (ret < 0)
goto out;
next:
logical += increment;
- physical += BTRFS_STRIPE_LEN;
+ physical += stripe_len;
spin_lock(&sctx->stat_lock);
sctx->stat.last_physical = physical;
spin_unlock(&sctx->stat_lock);
@@ -2587,6 +2617,9 @@ static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx,
if (map->chunk_len < dev_extent_len)
goto out;
+ for (i = 0; i < SCRUB_TOTAL_STRIPES; i++)
+ update_scrub_stripe_len(fs_info, map, &sctx->stripes[i]);
+
for (i = 0; i < map->num_stripes; ++i) {
if (map->stripes[i].dev->bdev == scrub_dev->bdev &&
map->stripes[i].physical == dev_offset) {
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 5/9] btrfs: add a new 'stripe_len' parameter to btrfs_stripe_nr_to_offset()
2026-10-21 3:39 [PATCH v2 0/9] btrfs: prepare for variable stripe_len Qu Wenruo
` (3 preceding siblings ...)
2026-10-21 3:39 ` [PATCH v2 4/9] btrfs: change scrub to use stripe_len Qu Wenruo
@ 2026-10-21 3:39 ` Qu Wenruo
2026-10-21 6:00 ` Johannes Thumshirn
2026-10-21 3:39 ` [PATCH v2 6/9] btrfs: convert volumes.c and block-group.c to use map->stripe_len Qu Wenruo
` (3 subsequent siblings)
8 siblings, 1 reply; 15+ messages in thread
From: Qu Wenruo @ 2026-10-21 3:39 UTC (permalink / raw)
To: linux-btrfs
That helper is currently using a fixed BTRFS_STRIPE_LEN, change it to
accept a 'u32 stripe_len'.
Also add an ASSERT() to make sure the @stripe_len passed in is power of
2, and no larger than BTRFS_STRIPE_LEN.
There is a special case where we still pass BTRFS_STRIPE_LEN into
btrfs_stripe_nr_to_offset(), that's for chunk allocation to determine
the minimal device extent size.
In that case, since our future planned map->stripe_len is always power
of 2 and no larger than BTRFS_STRIPE_LEN, we are totally fine to use the
old BTRFS_STRIPE_LEN.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/block-group.c | 3 ++-
fs/btrfs/scrub.c | 32 +++++++++++++++++++-------------
fs/btrfs/volumes.c | 40 +++++++++++++++++++++++++++-------------
fs/btrfs/volumes.h | 5 +++--
fs/btrfs/zoned.c | 7 +++++--
5 files changed, 56 insertions(+), 31 deletions(-)
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index f2b55ffbdaef..c0d735cee4a8 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -2302,7 +2302,8 @@ int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start,
/* For RAID5/6 adjust to a full IO stripe length */
if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
- io_stripe_size = btrfs_stripe_nr_to_offset(nr_data_stripes(map));
+ io_stripe_size = btrfs_stripe_nr_to_offset(nr_data_stripes(map),
+ map->stripe_len);
buf = kzalloc_objs(u64, map->num_stripes, GFP_NOFS);
if (!buf) {
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index c3387e109779..98362c91bce4 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -1425,7 +1425,8 @@ static int get_raid56_logic_offset(u64 physical, int num,
u32 stripe_index;
u32 rot;
- *offset = last_offset + btrfs_stripe_nr_to_offset(i);
+ *offset = last_offset + btrfs_stripe_nr_to_offset(i,
+ map->stripe_len);
stripe_nr = (u32)(*offset >> map->stripe_shift) / data_stripes;
@@ -1439,7 +1440,7 @@ static int get_raid56_logic_offset(u64 physical, int num,
if (stripe_index < num)
j++;
}
- *offset = last_offset + btrfs_stripe_nr_to_offset(j);
+ *offset = last_offset + btrfs_stripe_nr_to_offset(j, map->stripe_len);
return 1;
}
@@ -1924,7 +1925,8 @@ static void submit_initial_group_read(struct scrub_ctx *sctx,
ASSERT(first_slot + nr_stripes <= SCRUB_TOTAL_STRIPES);
scrub_throttle_dev_io(sctx, sctx->stripes[0].dev,
- btrfs_stripe_nr_to_offset(nr_stripes));
+ btrfs_stripe_nr_to_offset(nr_stripes,
+ sctx->stripes[0].stripe_len));
blk_start_plug(&plug);
for (int i = 0; i < nr_stripes; i++) {
struct scrub_stripe *stripe = &sctx->stripes[first_slot + i];
@@ -2102,7 +2104,7 @@ static int scrub_raid56_cached_parity(struct scrub_ctx *sctx,
struct btrfs_raid_bio *rbio;
struct bio bio;
const int data_stripes = nr_data_stripes(map);
- u64 length = btrfs_stripe_nr_to_offset(data_stripes);
+ u64 length = btrfs_stripe_nr_to_offset(data_stripes, map->stripe_len);
int ret;
bio_init(&bio, NULL, NULL, 0, REQ_OP_READ);
@@ -2151,6 +2153,7 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
BTRFS_PATH_AUTO_RELEASE(csum_path);
struct scrub_stripe *stripe;
bool all_empty = true;
+ const u32 stripe_len = map->stripe_len;
const int data_stripes = nr_data_stripes(map);
unsigned long extent_bitmap = 0;
int ret;
@@ -2191,14 +2194,15 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
data_stripes) >> map->stripe_shift;
stripe_index = (i + rot) % map->num_stripes;
physical = map->stripes[stripe_index].physical +
- btrfs_stripe_nr_to_offset(rot);
+ btrfs_stripe_nr_to_offset(rot, stripe_len);
scrub_reset_stripe(stripe);
set_bit(SCRUB_STRIPE_FLAG_NO_REPORT, &stripe->state);
ret = scrub_find_fill_first_stripe(bg, &extent_path, &csum_path,
map->stripes[stripe_index].dev, physical, 1,
- full_stripe_start + btrfs_stripe_nr_to_offset(i),
- map->stripe_len, stripe);
+ full_stripe_start +
+ btrfs_stripe_nr_to_offset(i, stripe_len),
+ stripe_len, stripe);
if (ret < 0)
return ret;
/*
@@ -2207,7 +2211,7 @@ static int scrub_raid56_parity_stripe(struct scrub_ctx *sctx,
*/
if (ret > 0) {
stripe->logical = full_stripe_start +
- btrfs_stripe_nr_to_offset(i);
+ btrfs_stripe_nr_to_offset(i, stripe_len);
stripe->dev = map->stripes[stripe_index].dev;
stripe->mirror_num = 1;
set_bit(SCRUB_STRIPE_FLAG_INITIALIZED, &stripe->state);
@@ -2348,7 +2352,8 @@ static u64 simple_stripe_full_stripe_len(const struct btrfs_chunk_map *map)
ASSERT(map->type & (BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID10));
- return btrfs_stripe_nr_to_offset(map->num_stripes / map->sub_stripes);
+ return btrfs_stripe_nr_to_offset(map->num_stripes / map->sub_stripes,
+ map->stripe_len);
}
/* Get the logical bytenr for the stripe */
@@ -2364,8 +2369,8 @@ static u64 simple_stripe_get_logical(struct btrfs_chunk_map *map,
* (stripe_index / sub_stripes) gives how many data stripes we need to
* skip.
*/
- return btrfs_stripe_nr_to_offset(stripe_index / map->sub_stripes) +
- bg->start;
+ return btrfs_stripe_nr_to_offset(stripe_index / map->sub_stripes,
+ map->stripe_len) + bg->start;
}
/* Get the mirror number for the stripe */
@@ -2504,7 +2509,8 @@ 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, bg, map, scrub_dev, stripe_index);
- offset = btrfs_stripe_nr_to_offset(stripe_index / map->sub_stripes);
+ offset = btrfs_stripe_nr_to_offset(stripe_index / map->sub_stripes,
+ stripe_len);
goto out;
}
@@ -2519,7 +2525,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 = btrfs_stripe_nr_to_offset(nr_data_stripes(map));
+ increment = btrfs_stripe_nr_to_offset(nr_data_stripes(map), stripe_len);
/*
* Due to the rotation, for RAID56 it's better to iterate each stripe
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index ff7189ac1c49..6a3ae8a081fe 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -5823,7 +5823,8 @@ 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_nr_to_offset(ctl->dev_stripes);
+ ctl->dev_extent_min = btrfs_stripe_nr_to_offset(ctl->dev_stripes,
+ BTRFS_STRIPE_LEN);
}
static void init_alloc_chunk_ctl_policy_zoned(
@@ -6587,7 +6588,8 @@ unsigned long btrfs_full_stripe_len(struct btrfs_fs_info *fs_info,
if (!WARN_ON(IS_ERR(map))) {
if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK)
- len = btrfs_stripe_nr_to_offset(nr_data_stripes(map));
+ len = btrfs_stripe_nr_to_offset(nr_data_stripes(map),
+ map->stripe_len);
btrfs_free_chunk_map(map);
}
return len;
@@ -6784,6 +6786,7 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
u64 stripe_end_offset;
u64 stripe_offset;
u32 stripe_index;
+ u32 stripe_len;
u32 factor = 0;
u32 sub_stripes = 0;
u32 stripes_per_dev = 0;
@@ -6820,6 +6823,7 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
goto out_free_map;
}
+ stripe_len = map->stripe_len;
offset = logical - map->start;
length = min_t(u64, map->start + map->chunk_len - logical, length);
*length_ret = length;
@@ -6831,12 +6835,13 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
stripe_nr = offset >> BTRFS_STRIPE_LEN_SHIFT;
/* stripe_offset is the offset of this block in its stripe */
- stripe_offset = offset - btrfs_stripe_nr_to_offset(stripe_nr);
+ stripe_offset = offset - btrfs_stripe_nr_to_offset(stripe_nr,
+ 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 = btrfs_stripe_nr_to_offset(stripe_nr_end) -
+ stripe_end_offset = btrfs_stripe_nr_to_offset(stripe_nr_end, stripe_len) -
(offset + length);
/*
* after this, stripe_nr is the number of stripes on this
@@ -6879,12 +6884,14 @@ 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 + btrfs_stripe_nr_to_offset(stripe_nr);
+ stripe_offset + btrfs_stripe_nr_to_offset(stripe_nr,
+ stripe_len);
stripes[i].dev = map->stripes[stripe_index].dev;
if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID10)) {
- stripes[i].length = btrfs_stripe_nr_to_offset(stripes_per_dev);
+ stripes[i].length = btrfs_stripe_nr_to_offset(stripes_per_dev,
+ stripe_len);
if (i / sub_stripes < remaining_stripes)
stripes[i].length += BTRFS_STRIPE_LEN;
@@ -7022,6 +7029,8 @@ static void handle_ops_on_dev_replace(struct btrfs_io_context *bioc,
static u64 btrfs_max_io_len(struct btrfs_chunk_map *map, u64 offset,
struct btrfs_io_geometry *io_geom)
{
+ const u32 stripe_len = map->stripe_len;
+
/*
* Stripe_nr is the stripe where this block falls. stripe_offset is
* the offset of this block in its stripe.
@@ -7033,7 +7042,8 @@ static u64 btrfs_max_io_len(struct btrfs_chunk_map *map, u64 offset,
if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
unsigned long full_stripe_len =
- btrfs_stripe_nr_to_offset(nr_data_stripes(map));
+ btrfs_stripe_nr_to_offset(nr_data_stripes(map),
+ stripe_len);
/*
* For full stripe start, we use previously calculated
@@ -7045,7 +7055,8 @@ static u64 btrfs_max_io_len(struct btrfs_chunk_map *map, u64 offset,
* not ensured to be power of 2.
*/
io_geom->raid56_full_stripe_start = btrfs_stripe_nr_to_offset(
- rounddown(io_geom->stripe_nr, nr_data_stripes(map)));
+ rounddown(io_geom->stripe_nr, nr_data_stripes(map)),
+ stripe_len);
ASSERT(io_geom->raid56_full_stripe_start + full_stripe_len > offset,
"raid56_full_stripe_start=%llu full_stripe_len=%lu offset=%llu",
@@ -7084,7 +7095,8 @@ static int set_io_stripe(struct btrfs_fs_info *fs_info, u64 logical,
dst->physical = map->stripes[io_geom->stripe_index].physical +
io_geom->stripe_offset +
- btrfs_stripe_nr_to_offset(io_geom->stripe_nr);
+ btrfs_stripe_nr_to_offset(io_geom->stripe_nr,
+ map->stripe_len);
return 0;
}
@@ -7207,7 +7219,7 @@ static void map_blocks_raid56_write(struct btrfs_chunk_map *map,
/* Return the length to the full stripe end. */
*length = min(logical + *length,
io_geom->raid56_full_stripe_start + map->start +
- btrfs_stripe_nr_to_offset(data_stripes)) -
+ btrfs_stripe_nr_to_offset(data_stripes, map->stripe_len)) -
logical;
io_geom->stripe_index = 0;
io_geom->stripe_offset = 0;
@@ -7434,7 +7446,8 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
*/
bioc->full_stripe_logical = map->start +
btrfs_stripe_nr_to_offset(io_geom.stripe_nr *
- nr_data_stripes(map));
+ nr_data_stripes(map),
+ map->stripe_len);
for (int i = 0; i < io_geom.num_stripes; i++) {
struct btrfs_io_stripe *dst = &bioc->stripes[i];
u32 stripe_index;
@@ -7444,7 +7457,8 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
dst->physical =
map->stripes[stripe_index].physical +
io_geom.stripe_offset +
- btrfs_stripe_nr_to_offset(io_geom.stripe_nr);
+ btrfs_stripe_nr_to_offset(io_geom.stripe_nr,
+ map->stripe_len);
}
} else {
/*
@@ -9070,7 +9084,7 @@ static void map_raid56_repair_block(struct btrfs_io_context *bioc,
for (i = 0; i < data_stripes; i++) {
u64 stripe_start = bioc->full_stripe_logical +
- btrfs_stripe_nr_to_offset(i);
+ btrfs_stripe_nr_to_offset(i, bioc->stripe_len);
if (logical >= stripe_start &&
logical < stripe_start + BTRFS_STRIPE_LEN)
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 9356cec00a90..75b1179776c8 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -722,9 +722,10 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
* @stripe_nr is u32, with left shift it can overflow u32 for chunks larger
* than 4G. This does the proper type cast to avoid overflow.
*/
-static inline u64 btrfs_stripe_nr_to_offset(u32 stripe_nr)
+static inline u64 btrfs_stripe_nr_to_offset(u32 stripe_nr, u32 stripe_len)
{
- return (u64)stripe_nr << BTRFS_STRIPE_LEN_SHIFT;
+ ASSERT(is_power_of_2(stripe_len) && stripe_len <= BTRFS_STRIPE_LEN);
+ return (u64)stripe_nr << ilog2(stripe_len);
}
void btrfs_get_bioc(struct btrfs_io_context *bioc);
diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
index 1cda88332284..37084c8d8d75 100644
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -1630,7 +1630,9 @@ static int btrfs_load_block_group_raid0(struct btrfs_block_group *bg,
if (zone_info[i].alloc_offset == WP_CONVENTIONAL) {
has_conventional = true;
- zone_info[i].alloc_offset = btrfs_stripe_nr_to_offset(stripe_nr);
+ zone_info[i].alloc_offset =
+ btrfs_stripe_nr_to_offset(stripe_nr,
+ map->stripe_len);
if (stripe_index > i)
zone_info[i].alloc_offset += BTRFS_STRIPE_LEN;
@@ -1772,7 +1774,8 @@ static int btrfs_load_block_group_raid10(struct btrfs_block_group *bg,
if (raid0_allocs[idx] == WP_CONVENTIONAL) {
has_conventional = true;
- raid0_allocs[idx] = btrfs_stripe_nr_to_offset(stripe_nr);
+ raid0_allocs[idx] = btrfs_stripe_nr_to_offset(stripe_nr,
+ map->stripe_len);
if (stripe_index > idx)
raid0_allocs[idx] += BTRFS_STRIPE_LEN;
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 6/9] btrfs: convert volumes.c and block-group.c to use map->stripe_len
2026-10-21 3:39 [PATCH v2 0/9] btrfs: prepare for variable stripe_len Qu Wenruo
` (4 preceding siblings ...)
2026-10-21 3:39 ` [PATCH v2 5/9] btrfs: add a new 'stripe_len' parameter to btrfs_stripe_nr_to_offset() Qu Wenruo
@ 2026-10-21 3:39 ` Qu Wenruo
2026-10-21 6:01 ` Johannes Thumshirn
2026-10-21 3:39 ` [PATCH v2 7/9] btrfs: convert raid56.c to use rbio->bioc->stripe_len Qu Wenruo
` (2 subsequent siblings)
8 siblings, 1 reply; 15+ messages in thread
From: Qu Wenruo @ 2026-10-21 3:39 UTC (permalink / raw)
To: linux-btrfs
There are still some BTRFS_STRIPE_LEN usage remaining, but they are all
for chunk allocation.
There is one more refactor for is_same_chunk_map(), as there are more
members to compare, the parameter list can go longer and longer.
Instead of passing a new @stripe_len member, pass extent_buffer and
btrfs_chunk pointers, and grab the needed member inside that function.
And doing "if (unlikely()) return false" for each member check.
Although this make is_same_chunk_map() more complex, considering it's
only called for system chunks, it should not bring too much overhead.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/block-group.c | 6 ++---
fs/btrfs/volumes.c | 52 ++++++++++++++++++++++++------------------
2 files changed, 33 insertions(+), 25 deletions(-)
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index c0d735cee4a8..092cdbedf39f 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -2297,7 +2297,7 @@ int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start,
return -EIO;
data_stripe_length = map->dev_extent_size;
- io_stripe_size = BTRFS_STRIPE_LEN;
+ io_stripe_size = map->stripe_len;
chunk_start = map->start;
/* For RAID5/6 adjust to a full IO stripe length */
@@ -2322,9 +2322,9 @@ int btrfs_rmap_block(struct btrfs_fs_info *fs_info, u64 chunk_start,
continue;
stripe_nr = (physical - map->stripes[i].physical) >>
- BTRFS_STRIPE_LEN_SHIFT;
+ map->stripe_shift;
offset = (physical - map->stripes[i].physical) &
- BTRFS_STRIPE_LEN_MASK;
+ (map->stripe_len - 1);
if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
BTRFS_BLOCK_GROUP_RAID10))
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 6a3ae8a081fe..ce78a9441c64 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6168,8 +6168,8 @@ struct btrfs_chunk_map *btrfs_alloc_chunk_map(int num_stripes, gfp_t gfp)
RB_CLEAR_NODE(&map->rb_node);
/*
- * Initialize the default stripe len, selftests will utilize them
- * without an on-disk chunk item.
+ * Initialize the default stripe len, selftests and some other call
+ * sites relies on the sane default value.
*/
map->stripe_len = BTRFS_STRIPE_LEN;
map->stripe_shift = ilog2(map->stripe_len);
@@ -6210,8 +6210,6 @@ static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans,
map->on_disk_type = type;
map->sub_stripes = ctl->sub_stripes;
map->num_stripes = ctl->num_stripes;
- map->stripe_len = BTRFS_STRIPE_LEN;
- map->stripe_shift = ilog2(BTRFS_STRIPE_LEN);
set_real_chunk_type(map);
for (int i = 0; i < ctl->ndevs; i++) {
@@ -6393,8 +6391,8 @@ int btrfs_chunk_alloc_add_chunk_item(struct btrfs_trans_handle *trans,
btrfs_set_stack_chunk_stripe_len(chunk, map->stripe_len);
btrfs_set_stack_chunk_type(chunk, map->on_disk_type);
btrfs_set_stack_chunk_num_stripes(chunk, map->num_stripes);
- btrfs_set_stack_chunk_io_align(chunk, BTRFS_STRIPE_LEN);
- btrfs_set_stack_chunk_io_width(chunk, BTRFS_STRIPE_LEN);
+ btrfs_set_stack_chunk_io_align(chunk, map->stripe_len);
+ btrfs_set_stack_chunk_io_width(chunk, map->stripe_len);
btrfs_set_stack_chunk_sector_size(chunk, fs_info->sectorsize);
btrfs_set_stack_chunk_sub_stripes(chunk, map->sub_stripes);
@@ -6832,14 +6830,14 @@ 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 = offset >> BTRFS_STRIPE_LEN_SHIFT;
+ stripe_nr = offset >> map->stripe_shift;
/* stripe_offset is the offset of this block in its stripe */
stripe_offset = offset - btrfs_stripe_nr_to_offset(stripe_nr,
stripe_len);
- stripe_nr_end = round_up(offset + length, BTRFS_STRIPE_LEN) >>
- BTRFS_STRIPE_LEN_SHIFT;
+ stripe_nr_end = round_up(offset + length, stripe_len) >>
+ map->stripe_shift;
stripe_cnt = stripe_nr_end - stripe_nr;
stripe_end_offset = btrfs_stripe_nr_to_offset(stripe_nr_end, stripe_len) -
(offset + length);
@@ -6894,7 +6892,7 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
stripe_len);
if (i / sub_stripes < remaining_stripes)
- stripes[i].length += BTRFS_STRIPE_LEN;
+ stripes[i].length += stripe_len;
/*
* Special for the first stripe and
@@ -7035,8 +7033,8 @@ static u64 btrfs_max_io_len(struct btrfs_chunk_map *map, u64 offset,
* Stripe_nr is the stripe where this block falls. stripe_offset is
* the offset of this block in its stripe.
*/
- io_geom->stripe_offset = offset & BTRFS_STRIPE_LEN_MASK;
- io_geom->stripe_nr = offset >> BTRFS_STRIPE_LEN_SHIFT;
+ io_geom->stripe_offset = offset & (stripe_len - 1);
+ io_geom->stripe_nr = offset >> map->stripe_shift;
ASSERT(io_geom->stripe_offset < U32_MAX,
"stripe_offset=%llu", io_geom->stripe_offset);
@@ -7077,7 +7075,7 @@ static u64 btrfs_max_io_len(struct btrfs_chunk_map *map, u64 offset,
* a single disk).
*/
if (map->type & BTRFS_BLOCK_GROUP_STRIPE_MASK)
- return BTRFS_STRIPE_LEN - io_geom->stripe_offset;
+ return stripe_len - io_geom->stripe_offset;
return U64_MAX;
}
@@ -7741,11 +7739,20 @@ static struct btrfs_device *handle_missing_device(struct btrfs_fs_info *fs_info,
return dev;
}
-static bool is_same_chunk_map(const struct btrfs_chunk_map *map, u64 logical,
- u64 length, u64 type, u16 num_stripes)
+static bool is_same_chunk_map(const struct btrfs_chunk_map *map,
+ const struct extent_buffer *leaf,
+ const struct btrfs_chunk *chunk,
+ u64 logical)
{
- if (map->start != logical || map->chunk_len != length ||
- map->on_disk_type != type || map->num_stripes != num_stripes)
+ if (unlikely(map->start != logical))
+ return false;
+ if (unlikely(map->chunk_len != btrfs_chunk_length(leaf, chunk)))
+ return false;
+ if (unlikely(map->on_disk_type != btrfs_chunk_type(leaf, chunk)))
+ return false;
+ if (unlikely(map->stripe_len != btrfs_chunk_stripe_len(leaf, chunk)))
+ return false;
+ if (unlikely(map->num_stripes != btrfs_chunk_num_stripes(leaf, chunk)))
return false;
return true;
}
@@ -7760,6 +7767,7 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
u64 length;
u64 devid;
u64 type;
+ u32 stripe_len;
u8 uuid[BTRFS_UUID_SIZE];
int index;
int num_stripes;
@@ -7770,6 +7778,7 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
length = btrfs_chunk_length(leaf, chunk);
type = btrfs_chunk_type(leaf, chunk);
index = btrfs_bg_flags_to_raid_index(type);
+ stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
num_stripes = btrfs_chunk_num_stripes(leaf, chunk);
#if BITS_PER_LONG == 32
@@ -7783,8 +7792,7 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
/* Already mapped? Check if the existing one matches. */
if (map) {
- if (unlikely(!is_same_chunk_map(map, logical, length,
- type, num_stripes))) {
+ if (unlikely(!is_same_chunk_map(map, leaf, chunk, logical))) {
btrfs_err(fs_info,
"existing chunk %llu doesn't match the new one at %llu",
map->start, logical);
@@ -7804,7 +7812,7 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf,
map->chunk_len = length;
map->num_stripes = num_stripes;
map->on_disk_type = type;
- map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
+ map->stripe_len = stripe_len;
map->stripe_shift = ilog2(map->stripe_len);
/*
* We can't use the sub_stripes value, as for profiles other than
@@ -9087,14 +9095,14 @@ static void map_raid56_repair_block(struct btrfs_io_context *bioc,
btrfs_stripe_nr_to_offset(i, bioc->stripe_len);
if (logical >= stripe_start &&
- logical < stripe_start + BTRFS_STRIPE_LEN)
+ logical < stripe_start + bioc->stripe_len)
break;
}
ASSERT(i < data_stripes, "i=%d data_stripes=%d", i, data_stripes);
smap->dev = bioc->stripes[i].dev;
smap->physical = bioc->stripes[i].physical +
((logical - bioc->full_stripe_logical) &
- BTRFS_STRIPE_LEN_MASK);
+ (bioc->stripe_len - 1));
}
/*
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 7/9] btrfs: convert raid56.c to use rbio->bioc->stripe_len
2026-10-21 3:39 [PATCH v2 0/9] btrfs: prepare for variable stripe_len Qu Wenruo
` (5 preceding siblings ...)
2026-10-21 3:39 ` [PATCH v2 6/9] btrfs: convert volumes.c and block-group.c to use map->stripe_len Qu Wenruo
@ 2026-10-21 3:39 ` Qu Wenruo
2026-10-21 6:46 ` Johannes Thumshirn
2026-10-21 3:39 ` [PATCH v2 8/9] btrfs: convert zoned.c to use map->stripe_len Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 9/9] btrfs: introduce extra limits on btrfs_chunk::stripe_len Qu Wenruo
8 siblings, 1 reply; 15+ messages in thread
From: Qu Wenruo @ 2026-10-21 3:39 UTC (permalink / raw)
To: linux-btrfs
So that raid56 can support stripe length other than BTRFS_STRIPE_LEN.
There are several extra things to note:
- btrfs_raid_bio::stripe_npages is removed
With stripe_len < BTRFS_STRIPE_LEN, there is no guarantee that a page
won't cross multiple stripes.
E.g. with 4K stripe_len and sectorsize, 2 data stripes, with 64K page
size, one page will cover the full stripe.
So stripe_npages no longer makes sense, just remove it.
- alloc_rbio_data_pages()/alloc_rbio_parity_pages() fallback
For the same above reason, a page can contain both data and parity
blocks.
In that case we can no longer only allocate pages for data/parity.
Add a fallback that if stripe_len is smaller than page size, always
allocate all the pages.
This is not the best solution, but should be good enough for now until
the variable stripe_len is properly tested.
- steal_rbio() fallback
If stripe_len is smaller than PAGE_SIZE, it's hard to only steal the
data pages.
Again skip the stealing if stripe_len is smaller than PAGE_SIZE.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/raid56.c | 57 +++++++++++++++++++++++++++++++----------------
fs/btrfs/raid56.h | 7 +-----
2 files changed, 39 insertions(+), 25 deletions(-)
diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
index 5ec31299f1c3..080be467c6fc 100644
--- a/fs/btrfs/raid56.c
+++ b/fs/btrfs/raid56.c
@@ -395,8 +395,9 @@ static bool is_data_stripe_page(struct btrfs_raid_bio *rbio, int page_nr)
const int sector_nr = page_nr_to_sector_nr(rbio, page_nr);
/*
- * We have ensured PAGE_SIZE is aligned with sectorsize, thus
- * we won't have a page which is half data half parity.
+ * The caller has ensured stripe_len >= PAGE_SIZE, and PAGE_SIZE is
+ * aligned with sectorsize, thus we won't have a page which is half
+ * data half parity.
*
* Thus if the first sector of the page belongs to data stripes, then
* the full page belongs to data stripes.
@@ -417,6 +418,9 @@ static void steal_rbio(struct btrfs_raid_bio *src, struct btrfs_raid_bio *dest)
if (!test_bit(RBIO_CACHE_READY_BIT, &src->flags))
return;
+ /* Data and P/Q can be mixed into a page, skip stealing. */
+ if (src->bioc->stripe_len < PAGE_SIZE)
+ return;
for (i = 0; i < dest->nr_pages; i++) {
struct page *p = src->stripe_pages[i];
@@ -624,12 +628,13 @@ static void cache_rbio(struct btrfs_raid_bio *rbio)
static int rbio_is_full(struct btrfs_raid_bio *rbio)
{
unsigned long size = rbio->bio_list_bytes;
+ const u32 stripe_len = rbio->bioc->stripe_len;
int ret = 1;
spin_lock(&rbio->bio_list_lock);
- if (size != rbio->nr_data * BTRFS_STRIPE_LEN)
+ if (size != rbio->nr_data * stripe_len)
ret = 0;
- BUG_ON(size > rbio->nr_data * BTRFS_STRIPE_LEN);
+ BUG_ON(size > rbio->nr_data * stripe_len);
spin_unlock(&rbio->bio_list_lock);
return ret;
@@ -1041,11 +1046,12 @@ static phys_addr_t sector_paddr_in_rbio(struct btrfs_raid_bio *rbio,
static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
struct btrfs_io_context *bioc)
{
+ const u32 stripe_len = bioc->stripe_len;
const unsigned int real_stripes = bioc->num_stripes - bioc->replace_nr_stripes;
- const unsigned int stripe_npages = BTRFS_STRIPE_LEN >> PAGE_SHIFT;
- const unsigned int num_pages = stripe_npages * real_stripes;
+ const unsigned int num_pages = round_up(stripe_len * real_stripes, PAGE_SIZE) >>
+ PAGE_SHIFT;
const unsigned int stripe_nsectors =
- BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits;
+ stripe_len >> fs_info->sectorsize_bits;
const unsigned int num_sectors = stripe_nsectors * real_stripes;
const unsigned int step = min(fs_info->sectorsize, PAGE_SIZE);
const unsigned int sector_nsteps = fs_info->sectorsize / step;
@@ -1105,7 +1111,6 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
rbio->nr_pages = num_pages;
rbio->nr_sectors = num_sectors;
rbio->real_stripes = real_stripes;
- rbio->stripe_npages = stripe_npages;
rbio->stripe_nsectors = stripe_nsectors;
rbio->sector_nsteps = sector_nsteps;
refcount_set(&rbio->refs, 1);
@@ -1134,9 +1139,17 @@ static int alloc_rbio_pages(struct btrfs_raid_bio *rbio)
/* only allocate pages for p/q stripes */
static int alloc_rbio_parity_pages(struct btrfs_raid_bio *rbio)
{
- const int data_pages = rbio->nr_data * rbio->stripe_npages;
+ int data_pages;
int ret;
+ /*
+ * Page size larger than stripe size, we can not only allocate
+ * pages for P/Q stripes.
+ */
+ if (rbio->bioc->stripe_len < PAGE_SIZE)
+ return alloc_rbio_pages(rbio);
+
+ data_pages = rbio->nr_data * (rbio->bioc->stripe_len >> PAGE_SHIFT);
ret = btrfs_alloc_page_array(rbio->nr_pages - data_pages,
rbio->stripe_pages + data_pages, GFP_NOFS);
if (ret < 0)
@@ -1274,7 +1287,7 @@ static int rbio_add_io_paddrs(struct btrfs_raid_bio *rbio, struct bio_list *bio_
/* put a new bio on the list */
bio = bio_alloc(stripe->dev->bdev,
- max(BTRFS_STRIPE_LEN >> PAGE_SHIFT, 1),
+ max(rbio->bioc->stripe_len >> PAGE_SHIFT, 1),
op, GFP_NOFS);
bio->bi_iter.bi_sector = disk_start >> SECTOR_SHIFT;
bio->bi_private = rbio;
@@ -1715,9 +1728,13 @@ static void submit_read_wait_bio_list(struct btrfs_raid_bio *rbio,
static int alloc_rbio_data_pages(struct btrfs_raid_bio *rbio)
{
- const int data_pages = rbio->nr_data * rbio->stripe_npages;
+ int data_pages;
int ret;
+ if (rbio->bioc->stripe_len < PAGE_SIZE)
+ return alloc_rbio_pages(rbio);
+
+ data_pages = rbio->nr_data * (rbio->bioc->stripe_len >> PAGE_SHIFT);
ret = btrfs_alloc_page_array(data_pages, rbio->stripe_pages, GFP_NOFS);
if (ret < 0)
return ret;
@@ -1804,7 +1821,7 @@ static void rbio_add_bio(struct btrfs_raid_bio *rbio, struct bio *orig_bio)
ASSERT_RBIO_LOGICAL(orig_logical >= full_stripe_start &&
orig_logical + orig_len <= full_stripe_start +
- rbio->nr_data * BTRFS_STRIPE_LEN,
+ rbio->nr_data * rbio->bioc->stripe_len,
rbio, orig_logical);
bio_list_add(&rbio->bio_list, orig_bio);
@@ -3012,6 +3029,7 @@ void raid56_parity_cache_data_folios(struct btrfs_raid_bio *rbio,
struct btrfs_fs_info *fs_info = rbio->bioc->fs_info;
const u64 offset_in_full_stripe = data_logical -
rbio->bioc->full_stripe_logical;
+ const u32 stripe_len = rbio->bioc->stripe_len;
int ret;
/*
@@ -3027,19 +3045,20 @@ void raid56_parity_cache_data_folios(struct btrfs_raid_bio *rbio,
return;
/* data_logical must be at stripe boundary and inside the full stripe. */
- ASSERT(IS_ALIGNED(offset_in_full_stripe, BTRFS_STRIPE_LEN));
- ASSERT(offset_in_full_stripe < (rbio->nr_data << BTRFS_STRIPE_LEN_SHIFT));
+ ASSERT(IS_ALIGNED(offset_in_full_stripe, stripe_len));
+ ASSERT(offset_in_full_stripe < (rbio->nr_data << ilog2(stripe_len)));
for (unsigned int cur_off = offset_in_full_stripe;
- cur_off < offset_in_full_stripe + BTRFS_STRIPE_LEN;
+ cur_off < offset_in_full_stripe + stripe_len;
cur_off += PAGE_SIZE) {
const unsigned int pindex = cur_off >> PAGE_SHIFT;
+ const u32 cur_len = min(stripe_len, PAGE_SIZE);
- ASSERT(cur_off - offset_in_full_stripe + PAGE_SIZE <= BTRFS_STRIPE_LEN);
- memcpy_to_page(rbio->stripe_pages[pindex], 0,
- vaddr + cur_off - offset_in_full_stripe, PAGE_SIZE);
+ ASSERT(cur_off - offset_in_full_stripe + cur_len <= stripe_len);
+ memcpy_to_page(rbio->stripe_pages[pindex], offset_in_page(cur_off),
+ vaddr + cur_off - offset_in_full_stripe, cur_len);
}
bitmap_set(rbio->stripe_uptodate_bitmap,
offset_in_full_stripe >> fs_info->sectorsize_bits,
- BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits);
+ stripe_len >> fs_info->sectorsize_bits);
}
diff --git a/fs/btrfs/raid56.h b/fs/btrfs/raid56.h
index 8542648199f1..8700910b8dc9 100644
--- a/fs/btrfs/raid56.h
+++ b/fs/btrfs/raid56.h
@@ -60,8 +60,6 @@ enum btrfs_rbio_ops {
* stripe_pages[] array stores all the pages covering the full stripe, including
* data and P/Q pages.
* stripe_pages[0] is the first page of the first data stripe.
- * stripe_pages[BTRFS_STRIPE_LEN / PAGE_SIZE] is the first page of the second
- * data stripe.
*
* Some pointers inside stripe_pages[] can be NULL, e.g. for a full stripe write
* (the bio covers all data stripes) there is no need to allocate pages for
@@ -81,7 +79,7 @@ enum btrfs_rbio_ops {
*
* - sector_nr
* Starts from 0 (representing the first sector of the stripe), ends
- * at BTRFS_STRIPE_LEN / sectorsize - 1.
+ * at stripe_len / sectorsize - 1.
*
* - step_nr
* A step is min(sector_size, PAGE_SIZE).
@@ -153,9 +151,6 @@ struct btrfs_raid_bio {
/* Number of all stripes (including P/Q) */
u8 real_stripes;
- /* How many pages there are for each stripe */
- u8 stripe_npages;
-
/* How many sectors there are for each stripe */
u8 stripe_nsectors;
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 8/9] btrfs: convert zoned.c to use map->stripe_len
2026-10-21 3:39 [PATCH v2 0/9] btrfs: prepare for variable stripe_len Qu Wenruo
` (6 preceding siblings ...)
2026-10-21 3:39 ` [PATCH v2 7/9] btrfs: convert raid56.c to use rbio->bioc->stripe_len Qu Wenruo
@ 2026-10-21 3:39 ` Qu Wenruo
2026-10-21 6:47 ` Johannes Thumshirn
2026-10-21 3:39 ` [PATCH v2 9/9] btrfs: introduce extra limits on btrfs_chunk::stripe_len Qu Wenruo
8 siblings, 1 reply; 15+ messages in thread
From: Qu Wenruo @ 2026-10-21 3:39 UTC (permalink / raw)
To: linux-btrfs
There are still several call sites using BTRFS_STRIPE_LEN, but that's
when doing the basic zoned checks.
For other call sites with a btrfs_chunk_map, use map->stripe_len instead
of the hardcoded BTRFS_STRIPE_LEN.
And since we're here, replace the following pattern
if (val & BTRFS_STRIPE_LEN_MASK)
with
if (!IS_ALIGNED(val, stripe_len))
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/zoned.c | 55 ++++++++++++++++++++++++++----------------------
1 file changed, 30 insertions(+), 25 deletions(-)
diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
index 37084c8d8d75..6b6228aaa5fa 100644
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -1576,6 +1576,8 @@ static int btrfs_load_block_group_raid0(struct btrfs_block_group *bg,
u64 last_alloc)
{
struct btrfs_fs_info *fs_info = bg->fs_info;
+ const u32 stripe_len = map->stripe_len;
+ const u8 stripe_shift = map->stripe_shift;
u64 stripe_nr = 0, stripe_offset = 0;
u64 prev_offset = 0;
u32 stripe_index = 0;
@@ -1599,18 +1601,18 @@ static int btrfs_load_block_group_raid0(struct btrfs_block_group *bg,
zone_info[i].alloc_offset == WP_CONVENTIONAL)
continue;
- stripe_nr = zone_info[i].alloc_offset >> BTRFS_STRIPE_LEN_SHIFT;
- stripe_offset = zone_info[i].alloc_offset & BTRFS_STRIPE_LEN_MASK;
+ stripe_nr = zone_info[i].alloc_offset >> stripe_shift;
+ stripe_offset = zone_info[i].alloc_offset & (stripe_len - 1);
if (stripe_offset == 0 && stripe_nr > 0) {
stripe_nr--;
- stripe_offset = BTRFS_STRIPE_LEN;
+ stripe_offset = stripe_len;
}
- alloc = ((stripe_nr * map->num_stripes + i) << BTRFS_STRIPE_LEN_SHIFT) +
+ alloc = ((stripe_nr * map->num_stripes + i) << stripe_shift) +
stripe_offset;
last_alloc = max(last_alloc, alloc);
/* Partially written stripe found. It should be last. */
- if (zone_info[i].alloc_offset & BTRFS_STRIPE_LEN_MASK)
+ if (!IS_ALIGNED(zone_info[i].alloc_offset, stripe_len))
break;
}
stripe_nr = 0;
@@ -1619,8 +1621,8 @@ static int btrfs_load_block_group_raid0(struct btrfs_block_group *bg,
if (last_alloc) {
u32 factor = map->num_stripes;
- stripe_nr = last_alloc >> BTRFS_STRIPE_LEN_SHIFT;
- stripe_offset = last_alloc & BTRFS_STRIPE_LEN_MASK;
+ stripe_nr = last_alloc >> stripe_shift;
+ stripe_offset = last_alloc & (stripe_len - 1);
stripe_nr = div_u64_rem(stripe_nr, factor, &stripe_index);
}
@@ -1631,11 +1633,10 @@ static int btrfs_load_block_group_raid0(struct btrfs_block_group *bg,
if (zone_info[i].alloc_offset == WP_CONVENTIONAL) {
has_conventional = true;
zone_info[i].alloc_offset =
- btrfs_stripe_nr_to_offset(stripe_nr,
- map->stripe_len);
+ btrfs_stripe_nr_to_offset(stripe_nr, stripe_len);
if (stripe_index > i)
- zone_info[i].alloc_offset += BTRFS_STRIPE_LEN;
+ zone_info[i].alloc_offset += stripe_len;
else if (stripe_index == i)
zone_info[i].alloc_offset += stripe_offset;
}
@@ -1650,7 +1651,8 @@ static int btrfs_load_block_group_raid0(struct btrfs_block_group *bg,
}
if (unlikely(has_partial &&
- (zone_info[i].alloc_offset & BTRFS_STRIPE_LEN_MASK))) {
+ !IS_ALIGNED(zone_info[i].alloc_offset,
+ stripe_len))) {
btrfs_err(fs_info,
"zoned: multiple partial written stripe found in block group %llu",
bg->start);
@@ -1659,7 +1661,7 @@ static int btrfs_load_block_group_raid0(struct btrfs_block_group *bg,
}
prev_offset = zone_info[i].alloc_offset;
- if ((zone_info[i].alloc_offset & BTRFS_STRIPE_LEN_MASK) != 0)
+ if (!IS_ALIGNED(zone_info[i].alloc_offset, stripe_len))
has_partial = true;
if (test_bit(0, active) != test_bit(i, active)) {
@@ -1675,7 +1677,7 @@ static int btrfs_load_block_group_raid0(struct btrfs_block_group *bg,
/* Check if all devices stay in the same stripe row. */
if (unlikely(zone_info[0].alloc_offset -
- zone_info[map->num_stripes - 1].alloc_offset > BTRFS_STRIPE_LEN)) {
+ zone_info[map->num_stripes - 1].alloc_offset > stripe_len)) {
btrfs_err(fs_info, "zoned: stripe gap too large in block group %llu", bg->start);
return -EIO;
}
@@ -1699,6 +1701,8 @@ static int btrfs_load_block_group_raid10(struct btrfs_block_group *bg,
u64 AUTO_KFREE(raid0_allocs);
u64 stripe_nr = 0, stripe_offset = 0;
u32 stripe_index = 0;
+ const u32 stripe_len = map->stripe_len;
+ const u8 stripe_shift = map->stripe_shift;
bool has_partial = false, has_conventional = false;
u64 prev_offset = 0;
@@ -1746,16 +1750,16 @@ static int btrfs_load_block_group_raid10(struct btrfs_block_group *bg,
return -EIO;
}
- stripe_nr = alloc >> BTRFS_STRIPE_LEN_SHIFT;
- stripe_offset = alloc & BTRFS_STRIPE_LEN_MASK;
+ stripe_nr = alloc >> stripe_shift;
+ stripe_offset = alloc & (stripe_len - 1);
if (stripe_offset == 0 && stripe_nr > 0) {
stripe_nr--;
- stripe_offset = BTRFS_STRIPE_LEN;
+ stripe_offset = stripe_len;
}
alloc = ((stripe_nr * (map->num_stripes / map->sub_stripes) +
- (i / map->sub_stripes)) <<
- BTRFS_STRIPE_LEN_SHIFT) + stripe_offset;
+ (i / map->sub_stripes)) << stripe_shift) +
+ stripe_offset;
last_alloc = max(last_alloc, alloc);
}
stripe_nr = 0;
@@ -1764,8 +1768,8 @@ static int btrfs_load_block_group_raid10(struct btrfs_block_group *bg,
if (last_alloc) {
u32 factor = map->num_stripes / map->sub_stripes;
- stripe_nr = last_alloc >> BTRFS_STRIPE_LEN_SHIFT;
- stripe_offset = last_alloc & BTRFS_STRIPE_LEN_MASK;
+ stripe_nr = last_alloc >> stripe_shift;
+ stripe_offset = last_alloc & (stripe_len - 1);
stripe_nr = div_u64_rem(stripe_nr, factor, &stripe_index);
}
@@ -1775,10 +1779,10 @@ static int btrfs_load_block_group_raid10(struct btrfs_block_group *bg,
if (raid0_allocs[idx] == WP_CONVENTIONAL) {
has_conventional = true;
raid0_allocs[idx] = btrfs_stripe_nr_to_offset(stripe_nr,
- map->stripe_len);
+ stripe_len);
if (stripe_index > idx)
- raid0_allocs[idx] += BTRFS_STRIPE_LEN;
+ raid0_allocs[idx] += stripe_len;
else if (stripe_index == idx)
raid0_allocs[idx] += stripe_offset;
}
@@ -1794,7 +1798,8 @@ static int btrfs_load_block_group_raid10(struct btrfs_block_group *bg,
}
if (unlikely(has_partial &&
- (raid0_allocs[idx] & BTRFS_STRIPE_LEN_MASK))) {
+ !IS_ALIGNED(raid0_allocs[idx],
+ stripe_len))) {
btrfs_err(fs_info,
"zoned: multiple partial written stripe found in block group %llu",
bg->start);
@@ -1803,7 +1808,7 @@ static int btrfs_load_block_group_raid10(struct btrfs_block_group *bg,
}
prev_offset = raid0_allocs[idx];
- if ((raid0_allocs[idx] & BTRFS_STRIPE_LEN_MASK) != 0)
+ if (!IS_ALIGNED(raid0_allocs[idx], stripe_len))
has_partial = true;
}
@@ -1826,7 +1831,7 @@ static int btrfs_load_block_group_raid10(struct btrfs_block_group *bg,
/* Check if all devices stay in the same stripe row. */
if (unlikely(zone_info[0].alloc_offset -
- zone_info[map->num_stripes - 1].alloc_offset > BTRFS_STRIPE_LEN)) {
+ zone_info[map->num_stripes - 1].alloc_offset > stripe_len)) {
btrfs_err(fs_info, "zoned: stripe gap too large in block group %llu",
bg->start);
return -EIO;
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 9/9] btrfs: introduce extra limits on btrfs_chunk::stripe_len
2026-10-21 3:39 [PATCH v2 0/9] btrfs: prepare for variable stripe_len Qu Wenruo
` (7 preceding siblings ...)
2026-10-21 3:39 ` [PATCH v2 8/9] btrfs: convert zoned.c to use map->stripe_len Qu Wenruo
@ 2026-10-21 3:39 ` Qu Wenruo
8 siblings, 0 replies; 15+ messages in thread
From: Qu Wenruo @ 2026-10-21 3:39 UTC (permalink / raw)
To: linux-btrfs; +Cc: Johannes Thumshirn
The new limits are:
- Stripe_len must be no smaller than sectorsize
As sectorsize is still the minimal unit.
- Stripe_len must be no larger than BTRFS_STRIPE_LEN
We still have a lot of things requiring on BTRFS_STRIPE_LEN alignment,
e.g. dev extent and chunk allocation.
A stripe_len larger than BTRFS_STRIPE_LEN will cause problems for the
existing chunk allocator.
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/tree-checker.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 503b6be90dda..61ea8f42c9f2 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -1044,7 +1044,18 @@ int btrfs_check_chunk_valid(const struct btrfs_fs_info *fs_info,
logical, length);
return -EUCLEAN;
}
- if (unlikely(!is_power_of_2(stripe_len) || stripe_len != BTRFS_STRIPE_LEN)) {
+
+ /*
+ * For now the "stripe_len != BTRFS_STRIPE_LEN" will cover all cases,
+ * but the power_of_2 and stripe_len >= sectorsize and
+ * stripe_len <= BTRFS_STRIPE_LEN are the requirements for future
+ * stripe_len support.
+ *
+ * In the future, "stripe_len != BTRFS_STRIPE_LEN" will be removed.
+ */
+ if (unlikely(stripe_len != BTRFS_STRIPE_LEN ||
+ !is_power_of_2(stripe_len) || stripe_len < sectorsize ||
+ stripe_len > BTRFS_STRIPE_LEN)) {
chunk_err(fs_info, leaf, chunk, logical,
"invalid chunk stripe length: %llu",
stripe_len);
--
2.56.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2 4/9] btrfs: change scrub to use stripe_len
2026-10-21 3:39 ` [PATCH v2 4/9] btrfs: change scrub to use stripe_len Qu Wenruo
@ 2026-10-21 5:58 ` Johannes Thumshirn
0 siblings, 0 replies; 15+ messages in thread
From: Johannes Thumshirn @ 2026-10-21 5:58 UTC (permalink / raw)
To: Qu Wenruo, linux-btrfs
Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 5/9] btrfs: add a new 'stripe_len' parameter to btrfs_stripe_nr_to_offset()
2026-10-21 3:39 ` [PATCH v2 5/9] btrfs: add a new 'stripe_len' parameter to btrfs_stripe_nr_to_offset() Qu Wenruo
@ 2026-10-21 6:00 ` Johannes Thumshirn
0 siblings, 0 replies; 15+ messages in thread
From: Johannes Thumshirn @ 2026-10-21 6:00 UTC (permalink / raw)
To: Qu Wenruo, linux-btrfs
Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 6/9] btrfs: convert volumes.c and block-group.c to use map->stripe_len
2026-10-21 3:39 ` [PATCH v2 6/9] btrfs: convert volumes.c and block-group.c to use map->stripe_len Qu Wenruo
@ 2026-10-21 6:01 ` Johannes Thumshirn
0 siblings, 0 replies; 15+ messages in thread
From: Johannes Thumshirn @ 2026-10-21 6:01 UTC (permalink / raw)
To: Qu Wenruo, linux-btrfs
Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 7/9] btrfs: convert raid56.c to use rbio->bioc->stripe_len
2026-10-21 3:39 ` [PATCH v2 7/9] btrfs: convert raid56.c to use rbio->bioc->stripe_len Qu Wenruo
@ 2026-10-21 6:46 ` Johannes Thumshirn
0 siblings, 0 replies; 15+ messages in thread
From: Johannes Thumshirn @ 2026-10-21 6:46 UTC (permalink / raw)
To: Qu Wenruo, linux-btrfs
Looks good,
Reviewed-by: Johannes Thusmhirn <johannes.thumshirn@wdc.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 8/9] btrfs: convert zoned.c to use map->stripe_len
2026-10-21 3:39 ` [PATCH v2 8/9] btrfs: convert zoned.c to use map->stripe_len Qu Wenruo
@ 2026-10-21 6:47 ` Johannes Thumshirn
0 siblings, 0 replies; 15+ messages in thread
From: Johannes Thumshirn @ 2026-10-21 6:47 UTC (permalink / raw)
To: Qu Wenruo, linux-btrfs
Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-10-21 6:47 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-21 3:39 [PATCH v2 0/9] btrfs: prepare for variable stripe_len Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 1/9] btrfs: reduce the width of num_stripes and sub_stripes Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 2/9] btrfs: load the on-disk btrfs_chunk::stripe_len Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 3/9] btrfs: add btrfs_io_context::stripe_len and load it Qu Wenruo
2026-10-21 3:39 ` [PATCH v2 4/9] btrfs: change scrub to use stripe_len Qu Wenruo
2026-10-21 5:58 ` Johannes Thumshirn
2026-10-21 3:39 ` [PATCH v2 5/9] btrfs: add a new 'stripe_len' parameter to btrfs_stripe_nr_to_offset() Qu Wenruo
2026-10-21 6:00 ` Johannes Thumshirn
2026-10-21 3:39 ` [PATCH v2 6/9] btrfs: convert volumes.c and block-group.c to use map->stripe_len Qu Wenruo
2026-10-21 6:01 ` Johannes Thumshirn
2026-10-21 3:39 ` [PATCH v2 7/9] btrfs: convert raid56.c to use rbio->bioc->stripe_len Qu Wenruo
2026-10-21 6:46 ` Johannes Thumshirn
2026-10-21 3:39 ` [PATCH v2 8/9] btrfs: convert zoned.c to use map->stripe_len Qu Wenruo
2026-10-21 6:47 ` Johannes Thumshirn
2026-10-21 3:39 ` [PATCH v2 9/9] btrfs: introduce extra limits on btrfs_chunk::stripe_len Qu Wenruo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox