Re: [PATCH 07/11] ext4: Convert group-count barrier protocol to acquire/release
From: Zhang Yi
Date: Mon Aug 31 2026 - 08:25:29 EST
On 8/25/2026 5:54 PM, Jinjie Ruan wrote:
> During an online resize, reading s_groups_count and s_blockfile_groups
> requires strict ordering against subsequent initialized block group
> metadata.
>
> Replace the historical smp_wmb()/smp_rmb() pairs with smp_store_release()
> and smp_load_acquire(). This formalizes the publish-subscribe pattern
> and allows weakly-ordered architectures (e.g., arm64) to utilize native
> STLR/LDAR instructions instead of full DMB fences.
>
> Update the documentation in resize.c and ext4.h accordingly.
>
> Assisted-by: Gemini:Gemini-3.1
> Assisted-by: DeepSeek:DeepSeek-V3
> Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
Looks good to me.
Reviewed-by: Zhang Yi <yi.zhang@xxxxxxxxxx>
> ---
> fs/ext4/ext4.h | 10 +++-------
> fs/ext4/mballoc.c | 6 ++----
> fs/ext4/resize.c | 19 +++++++++++--------
> 3 files changed, 16 insertions(+), 19 deletions(-)
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index 724a27e8be61..d70b9cb09155 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -3542,16 +3542,12 @@ static inline void ext4_isize_set(struct ext4_inode *raw_inode, loff_t i_size)
> }
>
> /*
> - * Reading s_groups_count requires using smp_rmb() afterwards. See
> - * the locking protocol documented in the comments of ext4_group_add()
> - * in resize.c
> + * Reading s_groups_count uses acquire semantics.
> */
> static inline ext4_group_t ext4_get_groups_count(struct super_block *sb)
> {
> - ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
> -
> - smp_rmb();
> - return ngroups;
> + /* Pairs with smp_store_release() in ext4_update_super() */
> + return smp_load_acquire(&EXT4_SB(sb)->s_groups_count);
> }
>
> static inline ext4_group_t ext4_flex_group(struct ext4_sb_info *sbi,
> diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
> index 06171a11db12..a15285224cdf 100644
> --- a/fs/ext4/mballoc.c
> +++ b/fs/ext4/mballoc.c
> @@ -899,10 +899,8 @@ static ext4_group_t ext4_get_allocation_groups_count(
>
> /* non-extent files are limited to low blocks/groups */
> if (!(ext4_test_inode_flag(ac->ac_inode, EXT4_INODE_EXTENTS)))
> - ngroups = EXT4_SB(ac->ac_sb)->s_blockfile_groups;
> -
> - /* Pairs with smp_wmb() in ext4_update_super() */
> - smp_rmb();
> + /* Pairs with smp_store_release() in ext4_update_super() */
> + ngroups = smp_load_acquire(&EXT4_SB(ac->ac_sb)->s_blockfile_groups);
>
> return ngroups;
> }
> diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
> index 2c5b851c552a..5e3ad8393cf8 100644
> --- a/fs/ext4/resize.c
> +++ b/fs/ext4/resize.c
> @@ -1462,11 +1462,11 @@ static void ext4_update_super(struct super_block *sb,
> *
> * The precise rules we use are:
> *
> - * * Writers must perform a smp_wmb() after updating all
> - * dependent data and before modifying the groups count
> + * * Writers must use a release store when updating the groups count
> + * after all dependent data has been updated
> *
> - * * Readers must perform an smp_rmb() after reading the groups
> - * count and before reading any dependent data.
> + * * Readers must use an acquire load when reading the groups
> + * count before reading any dependent data.
> *
> * NB. These rules can be relaxed when checking the group count
> * while freeing data, as we can only allocate from a block
> @@ -1474,12 +1474,15 @@ static void ext4_update_super(struct super_block *sb,
> * only then free after serialising in turn against that
> * allocation.
> */
> - smp_wmb();
>
> /* Update the global fs size fields */
> - sbi->s_groups_count += flex_gd->count;
> - sbi->s_blockfile_groups = min(sbi->s_groups_count,
> - (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb)));
> + /* Pairs with smp_load_acquire() in ext4_get_groups_count() */
> + smp_store_release(&sbi->s_groups_count,
> + sbi->s_groups_count + flex_gd->count);
> + /* Pairs with smp_load_acquire() in ext4_get_allocation_groups_count() */
> + smp_store_release(&sbi->s_blockfile_groups,
> + min(sbi->s_groups_count,
> + (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))));
>
> /* Update the reserved block counts only once the new group is
> * active. */