2023-03-21 08:09:41

by Kemeng Shi

[permalink] [raw]
Subject: [PATCH 0/8] Some fixes and cleanup to mballoc

We use cluster unit and block unit for different structure members. For
example, in struct ext4_prealloc_space, pa_lstart and pa_pstart are in
block unit while pa_len and pa_free are in cluster unit; in struct
ext4_free_extent, fe_logical is in block unit while fe_start and fe_len
are in cluster unit. The first five patches fix wrong unit use in
mballoc.
The rest is random bugfix and cleanup to mballoc, More details can be
found in respective patches.
Besides, "kvm-xfstest smoke" passes all test.
Thanks!

Kemeng Shi (8):
ext4: fix wrong unit use in ext4_mb_normalize_request
ext4: fix unit mismatch in ext4_mb_new_blocks_simple
ext4: fix wrong unit use in ext4_mb_new_inode_pa
ext4: fix wrong unit use in ext4_mb_find_by_goal
ext4: treat stripe in block unit
ext4: add EXT4_MB_HINT_GOAL_ONLY test in ext4_mb_use_preallocated
ext4: remove ext4_block_group and ext4_block_group_offset declaration
ext4: try all groups in ext4_mb_new_blocks_simple

fs/ext4/ext4.h | 4 ---
fs/ext4/mballoc.c | 75 +++++++++++++++++++++++++++++++++++------------
fs/ext4/super.c | 13 ++++++++
3 files changed, 70 insertions(+), 22 deletions(-)

--
2.30.0



2023-03-21 08:09:44

by Kemeng Shi

[permalink] [raw]
Subject: [PATCH 1/8] ext4: fix wrong unit use in ext4_mb_normalize_request

NRL_CHECK_SIZE will compare input req and size, so req and size should
be in same unit. Input req "fe_len" is in cluster unit while input
size "(8<<20)>>bsbits" is in block unit. Convert "fe_len" to block
unit to fix the mismatch.

Signed-off-by: Kemeng Shi <[email protected]>
---
fs/ext4/mballoc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 63a68cee36c6..6318c763a239 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -4056,7 +4056,7 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
start_off = ((loff_t)ac->ac_o_ex.fe_logical >>
(22 - bsbits)) << 22;
size = 4 * 1024 * 1024;
- } else if (NRL_CHECK_SIZE(ac->ac_o_ex.fe_len,
+ } else if (NRL_CHECK_SIZE(EXT4_C2B(sbi, ac->ac_o_ex.fe_len),
(8<<20)>>bsbits, max, 8 * 1024)) {
start_off = ((loff_t)ac->ac_o_ex.fe_logical >>
(23 - bsbits)) << 23;
--
2.30.0


2023-03-21 08:09:53

by Kemeng Shi

[permalink] [raw]
Subject: [PATCH 4/8] ext4: fix wrong unit use in ext4_mb_find_by_goal

We need start in block unit while fe_start is in cluster unit. Use
ext4_grp_offs_to_block helper to convert fe_start to get start in
block unit.

Signed-off-by: Kemeng Shi <[email protected]>
---
fs/ext4/mballoc.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 86d978e1f7dc..9a40e165e7d2 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -2181,8 +2181,7 @@ int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
if (max >= ac->ac_g_ex.fe_len && ac->ac_g_ex.fe_len == sbi->s_stripe) {
ext4_fsblk_t start;

- start = ext4_group_first_block_no(ac->ac_sb, e4b->bd_group) +
- ex.fe_start;
+ start = ext4_grp_offs_to_block(ac->ac_sb, &ex);
/* use do_div to get remainder (would be 64-bit modulo) */
if (do_div(start, sbi->s_stripe) == 0) {
ac->ac_found++;
--
2.30.0


2023-03-21 08:09:57

by Kemeng Shi

[permalink] [raw]
Subject: [PATCH 6/8] ext4: add EXT4_MB_HINT_GOAL_ONLY test in ext4_mb_use_preallocated

ext4_mb_use_preallocated will ignore the demand to alloc goal blocks,
although the EXT4_MB_HINT_GOAL_ONLY is requested.
For group pa, ext4_mb_group_or_file will not set EXT4_MB_HINT_GROUP_ALLOC
if EXT4_MB_HINT_GOAL_ONLY is set. So we will not alloc goal blocks from
group pa if EXT4_MB_HINT_GOAL_ONLY is set.
For inode pa, ext4_mb_pa_goal_check is added to check if free extent in
found inode pa meets goal blocks when EXT4_MB_HINT_GOAL_ONLY is set.

Signed-off-by: Kemeng Shi <[email protected]>
Suggested-by: Ojaswin Mujoo <[email protected]>
---
fs/ext4/mballoc.c | 34 +++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index b963111eeec6..5b837918c624 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -4351,6 +4351,37 @@ ext4_mb_check_group_pa(ext4_fsblk_t goal_block,
return pa;
}

+/*
+ * check if found pa meets EXT4_MB_HINT_GOAL_ONLY
+ */
+static bool
+ext4_mb_pa_goal_check(struct ext4_allocation_context *ac,
+ struct ext4_prealloc_space *pa)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb);
+ ext4_fsblk_t start;
+
+ if (likely(!(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY)))
+ return true;
+
+ /*
+ * If EXT4_MB_HINT_GOAL_ONLY is set, ac_g_ex will not be adjusted
+ * in ext4_mb_normalize_request and will keep same with ac_o_ex
+ * from ext4_mb_initialize_context. Choose ac_g_ex here to keep
+ * consistent with ext4_mb_find_by_goal.
+ */
+ start = pa->pa_pstart +
+ (ac->ac_g_ex.fe_logical - pa->pa_lstart);
+ if (ext4_grp_offs_to_block(ac->ac_sb, &ac->ac_g_ex) != start)
+ return false;
+
+ if (ac->ac_g_ex.fe_len > pa->pa_len -
+ EXT4_B2C(sbi, ac->ac_g_ex.fe_logical - pa->pa_lstart))
+ return false;
+
+ return true;
+}
+
/*
* search goal blocks in preallocated space
*/
@@ -4387,7 +4418,8 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)

/* found preallocated blocks, use them */
spin_lock(&pa->pa_lock);
- if (pa->pa_deleted == 0 && pa->pa_free) {
+ if (pa->pa_deleted == 0 && pa->pa_free &&
+ likely(ext4_mb_pa_goal_check(ac, pa))) {
atomic_inc(&pa->pa_count);
ext4_mb_use_inode_pa(ac, pa);
spin_unlock(&pa->pa_lock);
--
2.30.0


2023-03-21 08:10:02

by Kemeng Shi

[permalink] [raw]
Subject: [PATCH 5/8] ext4: treat stripe in block unit

Stripe is misused in block unit and in cluster unit in different code
paths. User awared of stripe maybe not awared of bigalloc feature, so
treat stripe only in block unit to fix this.
Besides, it's hard to get stripe aligned blocks (start and length are both
aligned with stripe) if stripe is not aligned with cluster, just disable
stripe and alert user in this case to simpfy the code and avoid
unecessary work to get stripe aligned blocks which likely to be failed.

Signed-off-by: Kemeng Shi <[email protected]>
---
fs/ext4/mballoc.c | 18 +++++++++++-------
fs/ext4/super.c | 13 +++++++++++++
2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 9a40e165e7d2..b963111eeec6 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -2178,7 +2178,8 @@ int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
ac->ac_g_ex.fe_len, &ex);
ex.fe_logical = 0xDEADFA11; /* debug value */

- if (max >= ac->ac_g_ex.fe_len && ac->ac_g_ex.fe_len == sbi->s_stripe) {
+ if (max >= ac->ac_g_ex.fe_len &&
+ ac->ac_g_ex.fe_len == EXT4_B2C(sbi, sbi->s_stripe)) {
ext4_fsblk_t start;

start = ext4_grp_offs_to_block(ac->ac_sb, &ex);
@@ -2343,7 +2344,7 @@ void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
struct ext4_free_extent ex;
ext4_fsblk_t first_group_block;
ext4_fsblk_t a;
- ext4_grpblk_t i;
+ ext4_grpblk_t i, stripe;
int max;

BUG_ON(sbi->s_stripe == 0);
@@ -2355,10 +2356,12 @@ void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
do_div(a, sbi->s_stripe);
i = (a * sbi->s_stripe) - first_group_block;

+ stripe = EXT4_B2C(sbi, sbi->s_stripe);
+ i = EXT4_B2C(sbi, i);
while (i < EXT4_CLUSTERS_PER_GROUP(sb)) {
if (!mb_test_bit(i, bitmap)) {
- max = mb_find_extent(e4b, i, sbi->s_stripe, &ex);
- if (max >= sbi->s_stripe) {
+ max = mb_find_extent(e4b, i, stripe, &ex);
+ if (max >= stripe) {
ac->ac_found++;
ex.fe_logical = 0xDEADF00D; /* debug value */
ac->ac_b_ex = ex;
@@ -2366,7 +2369,7 @@ void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
break;
}
}
- i += sbi->s_stripe;
+ i += stripe;
}
}

@@ -2727,7 +2730,8 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
if (cr == 0)
ext4_mb_simple_scan_group(ac, &e4b);
else if (cr == 1 && sbi->s_stripe &&
- !(ac->ac_g_ex.fe_len % sbi->s_stripe))
+ !(ac->ac_g_ex.fe_len %
+ EXT4_B2C(sbi, sbi->s_stripe)))
ext4_mb_scan_aligned(ac, &e4b);
else
ext4_mb_complex_scan_group(ac, &e4b);
@@ -3441,7 +3445,7 @@ int ext4_mb_init(struct super_block *sb)
*/
if (sbi->s_stripe > 1) {
sbi->s_mb_group_prealloc = roundup(
- sbi->s_mb_group_prealloc, sbi->s_stripe);
+ sbi->s_mb_group_prealloc, EXT4_B2C(sbi, sbi->s_stripe));
}

sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index f226f8ab469b..0a5bf375df5c 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -5231,6 +5231,19 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
goto failed_mount3;

sbi->s_stripe = ext4_get_stripe_size(sbi);
+ /*
+ * It's hard to get stripe aligned blocks if stripe is not aligned with
+ * cluster, just disable stripe and alert user to simpfy code and avoid
+ * stripe aligned allocation which will rarely successes.
+ */
+ if (sbi->s_stripe > 0 && sbi->s_cluster_ratio > 1 &&
+ sbi->s_stripe % sbi->s_cluster_ratio != 0) {
+ ext4_msg(sb, KERN_WARNING,
+ "stripe (%lu) is not aligned with cluster size (%u), "
+ "stripe is disabled",
+ sbi->s_stripe, sbi->s_cluster_ratio);
+ sbi->s_stripe = 0;
+ }
sbi->s_extent_max_zeroout_kb = 32;

/*
--
2.30.0


2023-03-21 08:10:07

by Kemeng Shi

[permalink] [raw]
Subject: [PATCH 8/8] ext4: try all groups in ext4_mb_new_blocks_simple

ext4_mb_new_blocks_simple ignores the group before goal, so it will fail
if free blocks reside in group before goal. Try all groups to avoid
unexpected failure.
Search finishes either if any free block is found or if no available
blocks are found. Simpliy check "i >= max" to distinguish the above
cases.

Signed-off-by: Kemeng Shi <[email protected]>
Suggested-by: Theodore Ts'o <[email protected]>
---
fs/ext4/mballoc.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 5b837918c624..ee564e700278 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -5796,7 +5796,7 @@ static ext4_fsblk_t ext4_mb_new_blocks_simple(handle_t *handle,
struct buffer_head *bitmap_bh;
struct super_block *sb = ar->inode->i_sb;
struct ext4_sb_info *sbi = EXT4_SB(sb);
- ext4_group_t group;
+ ext4_group_t group, nr;
ext4_grpblk_t blkoff;
ext4_grpblk_t max = EXT4_CLUSTERS_PER_GROUP(sb);
ext4_grpblk_t i = 0;
@@ -5810,7 +5810,7 @@ static ext4_fsblk_t ext4_mb_new_blocks_simple(handle_t *handle,

ar->len = 0;
ext4_get_group_no_and_offset(sb, goal, &group, &blkoff);
- for (; group < ext4_get_groups_count(sb); group++) {
+ for (nr = ext4_get_groups_count(sb); nr > 0; nr--) {
bitmap_bh = ext4_read_block_bitmap(sb, group);
if (IS_ERR(bitmap_bh)) {
*errp = PTR_ERR(bitmap_bh);
@@ -5834,10 +5834,13 @@ static ext4_fsblk_t ext4_mb_new_blocks_simple(handle_t *handle,
if (i < max)
break;

+ if (++group >= ext4_get_groups_count(sb))
+ group = 0;
+
blkoff = 0;
}

- if (group >= ext4_get_groups_count(sb) || i >= max) {
+ if (i >= max) {
*errp = -ENOSPC;
return 0;
}
--
2.30.0


2023-03-21 08:10:09

by Kemeng Shi

[permalink] [raw]
Subject: [PATCH 7/8] ext4: remove ext4_block_group and ext4_block_group_offset declaration

For ext4_block_group and ext4_block_group_offset, there are only
declaration without definition. Just remove them.

Signed-off-by: Kemeng Shi <[email protected]>
---
fs/ext4/ext4.h | 4 ----
1 file changed, 4 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 9b2cfc32cf78..f25f13a357de 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2697,10 +2697,6 @@ extern void ext4_get_group_no_and_offset(struct super_block *sb,
extern ext4_group_t ext4_get_group_number(struct super_block *sb,
ext4_fsblk_t block);

-extern unsigned int ext4_block_group(struct super_block *sb,
- ext4_fsblk_t blocknr);
-extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb,
- ext4_fsblk_t blocknr);
extern int ext4_bg_has_super(struct super_block *sb, ext4_group_t group);
extern unsigned long ext4_bg_num_gdb(struct super_block *sb,
ext4_group_t group);
--
2.30.0


2023-04-05 19:21:30

by Ojaswin Mujoo

[permalink] [raw]
Subject: Re: [PATCH 0/8] Some fixes and cleanup to mballoc

On Wed, Mar 22, 2023 at 12:12:12AM +0800, Kemeng Shi wrote:
> We use cluster unit and block unit for different structure members. For
> example, in struct ext4_prealloc_space, pa_lstart and pa_pstart are in
> block unit while pa_len and pa_free are in cluster unit; in struct
> ext4_free_extent, fe_logical is in block unit while fe_start and fe_len
> are in cluster unit. The first five patches fix wrong unit use in
> mballoc.
> The rest is random bugfix and cleanup to mballoc, More details can be
> found in respective patches.
> Besides, "kvm-xfstest smoke" passes all test.
> Thanks!
>
> Kemeng Shi (8):
> ext4: fix wrong unit use in ext4_mb_normalize_request
> ext4: fix unit mismatch in ext4_mb_new_blocks_simple
> ext4: fix wrong unit use in ext4_mb_new_inode_pa
> ext4: fix wrong unit use in ext4_mb_find_by_goal
> ext4: treat stripe in block unit
> ext4: add EXT4_MB_HINT_GOAL_ONLY test in ext4_mb_use_preallocated
> ext4: remove ext4_block_group and ext4_block_group_offset declaration
> ext4: try all groups in ext4_mb_new_blocks_simple
>
> fs/ext4/ext4.h | 4 ---
> fs/ext4/mballoc.c | 75 +++++++++++++++++++++++++++++++++++------------
> fs/ext4/super.c | 13 ++++++++
> 3 files changed, 70 insertions(+), 22 deletions(-)
Hi Kemeng,

Thanks for the patches, they mostly look good to me. I'm running some
tests at my end as well and would provide my RVBs after that. Just
adding a few comments to some of the patches in the meantime.

Regards,
Ojaswin
>
> --
> 2.30.0
>

2023-04-05 19:38:06

by Ojaswin Mujoo

[permalink] [raw]
Subject: Re: [PATCH 6/8] ext4: add EXT4_MB_HINT_GOAL_ONLY test in ext4_mb_use_preallocated

On Wed, Mar 22, 2023 at 12:12:18AM +0800, Kemeng Shi wrote:
> ext4_mb_use_preallocated will ignore the demand to alloc goal blocks,
> although the EXT4_MB_HINT_GOAL_ONLY is requested.
> For group pa, ext4_mb_group_or_file will not set EXT4_MB_HINT_GROUP_ALLOC
> if EXT4_MB_HINT_GOAL_ONLY is set. So we will not alloc goal blocks from
> group pa if EXT4_MB_HINT_GOAL_ONLY is set.
> For inode pa, ext4_mb_pa_goal_check is added to check if free extent in
> found inode pa meets goal blocks when EXT4_MB_HINT_GOAL_ONLY is set.
>
> Signed-off-by: Kemeng Shi <[email protected]>
> Suggested-by: Ojaswin Mujoo <[email protected]>
> ---
> fs/ext4/mballoc.c | 34 +++++++++++++++++++++++++++++++++-
> 1 file changed, 33 insertions(+), 1 deletion(-)
>
> diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
> index b963111eeec6..5b837918c624 100644
> --- a/fs/ext4/mballoc.c
> +++ b/fs/ext4/mballoc.c
> @@ -4351,6 +4351,37 @@ ext4_mb_check_group_pa(ext4_fsblk_t goal_block,
> return pa;
> }
>
> +/*
> + * check if found pa meets EXT4_MB_HINT_GOAL_ONLY
> + */
> +static bool
> +ext4_mb_pa_goal_check(struct ext4_allocation_context *ac,
> + struct ext4_prealloc_space *pa)
> +{
> + struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb);
> + ext4_fsblk_t start;
> +
> + if (likely(!(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY)))
> + return true;
> +
> + /*
> + * If EXT4_MB_HINT_GOAL_ONLY is set, ac_g_ex will not be adjusted
> + * in ext4_mb_normalize_request and will keep same with ac_o_ex
> + * from ext4_mb_initialize_context. Choose ac_g_ex here to keep
> + * consistent with ext4_mb_find_by_goal.
> + */
> + start = pa->pa_pstart +
> + (ac->ac_g_ex.fe_logical - pa->pa_lstart);
> + if (ext4_grp_offs_to_block(ac->ac_sb, &ac->ac_g_ex) != start)
> + return false;
> +
> + if (ac->ac_g_ex.fe_len > pa->pa_len -
> + EXT4_B2C(sbi, ac->ac_g_ex.fe_logical - pa->pa_lstart))
> + return false;
> +
> + return true;
> +}
> +
> /*
> * search goal blocks in preallocated space
> */
> @@ -4387,7 +4418,8 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
>
> /* found preallocated blocks, use them */
> spin_lock(&pa->pa_lock);
> - if (pa->pa_deleted == 0 && pa->pa_free) {
> + if (pa->pa_deleted == 0 && pa->pa_free &&
> + likely(ext4_mb_pa_goal_check(ac, pa))) {
Alright so this looks good to me, I just have one concern.

Consider the following scenario:

1. We find a PA that cover our logical blocks but the physical blocks in
the PA don't match our goal and we return false.

2. We then proceed in ext4_mb_regular_allocator and actually manage to
allocate the goal blocks.

3. Now the logical blocks of the file are associated to the blocks
allocated in Step 2 and the logical blocks of the PA would actually never get
utilized, and hence they are wasted space.

That being said, I think fixing this would be a bit tricky and I'm not sure if
it's even worth the trouble as GOAL_ONLY is not a very common case anyways. Would like
to hear other people's thoughts on this.


Regards,
ojaswin
> atomic_inc(&pa->pa_count);
> ext4_mb_use_inode_pa(ac, pa);
> spin_unlock(&pa->pa_lock);
> --
> 2.30.0
>

2023-04-07 11:09:30

by Ojaswin Mujoo

[permalink] [raw]
Subject: Re: [PATCH 5/8] ext4: treat stripe in block unit

On Wed, Mar 22, 2023 at 12:12:17AM +0800, Kemeng Shi wrote:
> Stripe is misused in block unit and in cluster unit in different code
> paths. User awared of stripe maybe not awared of bigalloc feature, so
> treat stripe only in block unit to fix this.
> Besides, it's hard to get stripe aligned blocks (start and length are both
> aligned with stripe) if stripe is not aligned with cluster, just disable
> stripe and alert user in this case to simpfy the code and avoid
> unecessary work to get stripe aligned blocks which likely to be failed.
>
> Signed-off-by: Kemeng Shi <[email protected]>

Nice fixes, and I agree that we can disable stripes if it is not aligned
with cluster. There are anyways some gaps in our stripe support eg the
normalization logic doesnt even take stripesize into account when
determining the goal length.

Anyways, for this patch feel free to add:

Reviewed-by: Ojaswin Mujoo <[email protected]>

Regards,
ojaswin

> ---
> fs/ext4/mballoc.c | 18 +++++++++++-------
> fs/ext4/super.c | 13 +++++++++++++
> 2 files changed, 24 insertions(+), 7 deletions(-)
>
> diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
> index 9a40e165e7d2..b963111eeec6 100644
> --- a/fs/ext4/mballoc.c
> +++ b/fs/ext4/mballoc.c
> @@ -2178,7 +2178,8 @@ int ext4_mb_find_by_goal(struct ext4_allocation_context *ac,
> ac->ac_g_ex.fe_len, &ex);
> ex.fe_logical = 0xDEADFA11; /* debug value */
>
> - if (max >= ac->ac_g_ex.fe_len && ac->ac_g_ex.fe_len == sbi->s_stripe) {
> + if (max >= ac->ac_g_ex.fe_len &&
> + ac->ac_g_ex.fe_len == EXT4_B2C(sbi, sbi->s_stripe)) {
> ext4_fsblk_t start;
>
> start = ext4_grp_offs_to_block(ac->ac_sb, &ex);
> @@ -2343,7 +2344,7 @@ void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
> struct ext4_free_extent ex;
> ext4_fsblk_t first_group_block;
> ext4_fsblk_t a;
> - ext4_grpblk_t i;
> + ext4_grpblk_t i, stripe;
> int max;
>
> BUG_ON(sbi->s_stripe == 0);
> @@ -2355,10 +2356,12 @@ void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
> do_div(a, sbi->s_stripe);
> i = (a * sbi->s_stripe) - first_group_block;
>
> + stripe = EXT4_B2C(sbi, sbi->s_stripe);
> + i = EXT4_B2C(sbi, i);
> while (i < EXT4_CLUSTERS_PER_GROUP(sb)) {
> if (!mb_test_bit(i, bitmap)) {
> - max = mb_find_extent(e4b, i, sbi->s_stripe, &ex);
> - if (max >= sbi->s_stripe) {
> + max = mb_find_extent(e4b, i, stripe, &ex);
> + if (max >= stripe) {
> ac->ac_found++;
> ex.fe_logical = 0xDEADF00D; /* debug value */
> ac->ac_b_ex = ex;
> @@ -2366,7 +2369,7 @@ void ext4_mb_scan_aligned(struct ext4_allocation_context *ac,
> break;
> }
> }
> - i += sbi->s_stripe;
> + i += stripe;
> }
> }
>
> @@ -2727,7 +2730,8 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
> if (cr == 0)
> ext4_mb_simple_scan_group(ac, &e4b);
> else if (cr == 1 && sbi->s_stripe &&
> - !(ac->ac_g_ex.fe_len % sbi->s_stripe))
> + !(ac->ac_g_ex.fe_len %
> + EXT4_B2C(sbi, sbi->s_stripe)))
> ext4_mb_scan_aligned(ac, &e4b);
> else
> ext4_mb_complex_scan_group(ac, &e4b);
> @@ -3441,7 +3445,7 @@ int ext4_mb_init(struct super_block *sb)
> */
> if (sbi->s_stripe > 1) {
> sbi->s_mb_group_prealloc = roundup(
> - sbi->s_mb_group_prealloc, sbi->s_stripe);
> + sbi->s_mb_group_prealloc, EXT4_B2C(sbi, sbi->s_stripe));
> }
>
> sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group);
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index f226f8ab469b..0a5bf375df5c 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -5231,6 +5231,19 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb)
> goto failed_mount3;
>
> sbi->s_stripe = ext4_get_stripe_size(sbi);
> + /*
> + * It's hard to get stripe aligned blocks if stripe is not aligned with
> + * cluster, just disable stripe and alert user to simpfy code and avoid
> + * stripe aligned allocation which will rarely successes.
> + */
> + if (sbi->s_stripe > 0 && sbi->s_cluster_ratio > 1 &&
> + sbi->s_stripe % sbi->s_cluster_ratio != 0) {
> + ext4_msg(sb, KERN_WARNING,
> + "stripe (%lu) is not aligned with cluster size (%u), "
> + "stripe is disabled",
> + sbi->s_stripe, sbi->s_cluster_ratio);
> + sbi->s_stripe = 0;
> + }
> sbi->s_extent_max_zeroout_kb = 32;
>
> /*
> --
> 2.30.0
>