From: Baokun Li <libaokun1@huawei.com>
To: <linux-ext4@vger.kernel.org>
Cc: <tytso@mit.edu>, <jack@suse.cz>, <adilger.kernel@dilger.ca>,
<ojaswin@linux.ibm.com>, <linux-kernel@vger.kernel.org>,
<yi.zhang@huawei.com>, <yangerkun@huawei.com>,
<libaokun1@huawei.com>
Subject: [PATCH v2 04/16] ext4: utilize multiple global goals to reduce contention
Date: Mon, 23 Jun 2025 15:32:52 +0800 [thread overview]
Message-ID: <20250623073304.3275702-5-libaokun1@huawei.com> (raw)
In-Reply-To: <20250623073304.3275702-1-libaokun1@huawei.com>
When allocating data blocks, if the first try (goal allocation) fails and
stream allocation is on, it tries a global goal starting from the last
group we used (s_mb_last_group). This helps cluster large files together
to reduce free space fragmentation, and the data block contiguity also
accelerates write-back to disk.
However, when multiple processes allocate blocks, having just one global
goal means they all fight over the same group. This drastically lowers
the chances of extents merging and leads to much worse file fragmentation.
To mitigate this multi-process contention, we now employ multiple global
goals, with the number of goals being the CPU count rounded up to the
nearest power of 2. To ensure a consistent goal for each inode, we select
the corresponding goal by taking the inode number modulo the total number
of goals.
Performance test data follows:
Test: Running will-it-scale/fallocate2 on CPU-bound containers.
Observation: Average fallocate operations per container per second.
| Kunpeng 920 / 512GB -P80| AMD 9654 / 1536GB -P96 |
Disk: 960GB SSD |-------------------------|-------------------------|
| base | patched | base | patched |
-------------------|-------|-----------------|-------|-----------------|
mb_optimize_scan=0 | 7612 | 19699 (+158%) | 21647 | 53093 (+145%) |
mb_optimize_scan=1 | 7568 | 9862 (+30.3%) | 9117 | 14401 (+57.9%) |
Signed-off-by: Baokun Li <libaokun1@huawei.com>
---
fs/ext4/ext4.h | 2 +-
fs/ext4/mballoc.c | 31 ++++++++++++++++++++++++-------
fs/ext4/mballoc.h | 9 +++++++++
3 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 93f03d8c3dca..c3f16aba7b79 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1630,7 +1630,7 @@ struct ext4_sb_info {
unsigned int s_mb_group_prealloc;
unsigned int s_max_dir_size_kb;
/* where last allocation was done - for stream allocation */
- ext4_group_t s_mb_last_group;
+ ext4_group_t *s_mb_last_groups;
unsigned int s_mb_prefetch;
unsigned int s_mb_prefetch_limit;
unsigned int s_mb_best_avail_max_trim_order;
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 3f103919868b..216b332a5054 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -2168,9 +2168,12 @@ static void ext4_mb_use_best_found(struct ext4_allocation_context *ac,
ac->ac_buddy_folio = e4b->bd_buddy_folio;
folio_get(ac->ac_buddy_folio);
/* store last allocated for subsequent stream allocation */
- if (ac->ac_flags & EXT4_MB_STREAM_ALLOC)
- /* pairs with smp_load_acquire in ext4_mb_regular_allocator() */
- smp_store_release(&sbi->s_mb_last_group, ac->ac_f_ex.fe_group);
+ if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) {
+ int hash = ac->ac_inode->i_ino % MB_LAST_GROUPS;
+ /* Pairs with smp_load_acquire in ext4_mb_regular_allocator() */
+ smp_store_release(&sbi->s_mb_last_groups[hash],
+ ac->ac_f_ex.fe_group);
+ }
/*
* As we've just preallocated more space than
* user requested originally, we store allocated
@@ -2842,9 +2845,12 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
}
/* if stream allocation is enabled, use global goal */
- if (ac->ac_flags & EXT4_MB_STREAM_ALLOC)
- /* pairs with smp_store_release in ext4_mb_use_best_found() */
- ac->ac_g_ex.fe_group = smp_load_acquire(&sbi->s_mb_last_group);
+ if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) {
+ int hash = ac->ac_inode->i_ino % MB_LAST_GROUPS;
+ /* Pairs with smp_store_release in ext4_mb_use_best_found() */
+ ac->ac_g_ex.fe_group = smp_load_acquire(
+ &sbi->s_mb_last_groups[hash]);
+ }
/*
* Let's just scan groups to find more-less suitable blocks We
@@ -3715,10 +3721,17 @@ int ext4_mb_init(struct super_block *sb)
sbi->s_mb_group_prealloc, EXT4_NUM_B2C(sbi, sbi->s_stripe));
}
+ sbi->s_mb_last_groups = kcalloc(MB_LAST_GROUPS, sizeof(ext4_group_t),
+ GFP_KERNEL);
+ if (sbi->s_mb_last_groups == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group);
if (sbi->s_locality_groups == NULL) {
ret = -ENOMEM;
- goto out;
+ goto out_free_last_groups;
}
for_each_possible_cpu(i) {
struct ext4_locality_group *lg;
@@ -3743,6 +3756,9 @@ int ext4_mb_init(struct super_block *sb)
out_free_locality_groups:
free_percpu(sbi->s_locality_groups);
sbi->s_locality_groups = NULL;
+out_free_last_groups:
+ kvfree(sbi->s_mb_last_groups);
+ sbi->s_mb_last_groups = NULL;
out:
kfree(sbi->s_mb_avg_fragment_size);
kfree(sbi->s_mb_avg_fragment_size_locks);
@@ -3847,6 +3863,7 @@ void ext4_mb_release(struct super_block *sb)
}
free_percpu(sbi->s_locality_groups);
+ kvfree(sbi->s_mb_last_groups);
}
static inline int ext4_issue_discard(struct super_block *sb,
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h
index f8280de3e882..38c37901728d 100644
--- a/fs/ext4/mballoc.h
+++ b/fs/ext4/mballoc.h
@@ -97,6 +97,15 @@
*/
#define MB_NUM_ORDERS(sb) ((sb)->s_blocksize_bits + 2)
+/*
+ * Number of mb last groups
+ */
+#ifdef CONFIG_SMP
+#define MB_LAST_GROUPS roundup_pow_of_two(nr_cpu_ids)
+#else
+#define MB_LAST_GROUPS 1
+#endif
+
struct ext4_free_data {
/* this links the free block information from sb_info */
struct list_head efd_list;
--
2.46.1
next prev parent reply other threads:[~2025-06-23 7:47 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-23 7:32 [PATCH v2 00/16] ext4: better scalability for ext4 block allocation Baokun Li
2025-06-23 7:32 ` [PATCH v2 01/16] ext4: add ext4_try_lock_group() to skip busy groups Baokun Li
2025-06-27 18:06 ` Jan Kara
2025-07-14 6:53 ` Ojaswin Mujoo
2025-06-23 7:32 ` [PATCH v2 02/16] ext4: remove unnecessary s_mb_last_start Baokun Li
2025-06-27 18:15 ` Jan Kara
2025-06-30 3:32 ` Baokun Li
2025-06-30 7:31 ` Jan Kara
2025-06-30 7:52 ` Baokun Li
2025-07-14 7:00 ` Ojaswin Mujoo
2025-06-23 7:32 ` [PATCH v2 03/16] ext4: remove unnecessary s_md_lock on update s_mb_last_group Baokun Li
2025-06-27 18:19 ` Jan Kara
2025-06-30 3:48 ` Baokun Li
2025-06-30 7:47 ` Jan Kara
2025-06-30 9:21 ` Baokun Li
2025-06-30 16:32 ` Jan Kara
2025-07-01 2:39 ` Baokun Li
2025-07-01 12:21 ` Jan Kara
2025-07-01 13:17 ` Baokun Li
2025-07-08 13:08 ` Baokun Li
2025-07-10 14:38 ` Jan Kara
2025-07-14 3:01 ` Theodore Ts'o
2025-07-14 7:00 ` Baokun Li
2025-07-01 2:57 ` kernel test robot
2025-06-23 7:32 ` Baokun Li [this message]
2025-06-27 18:31 ` [PATCH v2 04/16] ext4: utilize multiple global goals to reduce contention Jan Kara
2025-06-30 6:50 ` Baokun Li
2025-06-30 8:38 ` Jan Kara
2025-06-30 10:02 ` Baokun Li
2025-06-30 17:41 ` Jan Kara
2025-07-01 3:32 ` Baokun Li
2025-07-01 11:53 ` Jan Kara
2025-07-01 12:12 ` Baokun Li
2025-06-23 7:32 ` [PATCH v2 05/16] ext4: get rid of some obsolete EXT4_MB_HINT flags Baokun Li
2025-06-23 7:32 ` [PATCH v2 06/16] ext4: fix typo in CR_GOAL_LEN_SLOW comment Baokun Li
2025-06-23 7:32 ` [PATCH v2 07/16] ext4: convert sbi->s_mb_free_pending to atomic_t Baokun Li
2025-06-27 18:33 ` Jan Kara
2025-06-23 7:32 ` [PATCH v2 08/16] ext4: merge freed extent with existing extents before insertion Baokun Li
2025-06-27 19:11 ` Jan Kara
2025-06-23 7:32 ` [PATCH v2 09/16] ext4: fix zombie groups in average fragment size lists Baokun Li
2025-06-27 19:14 ` Jan Kara
2025-06-30 6:53 ` Baokun Li
2025-06-23 7:32 ` [PATCH v2 10/16] ext4: fix largest free orders lists corruption on mb_optimize_scan switch Baokun Li
2025-06-27 19:34 ` Jan Kara
2025-06-30 7:34 ` Baokun Li
2025-06-23 7:32 ` [PATCH v2 11/16] ext4: factor out __ext4_mb_scan_group() Baokun Li
2025-06-23 7:33 ` [PATCH v2 12/16] ext4: factor out ext4_mb_might_prefetch() Baokun Li
2025-06-23 7:33 ` [PATCH v2 13/16] ext4: factor out ext4_mb_scan_group() Baokun Li
2025-06-23 7:33 ` [PATCH v2 14/16] ext4: convert free group lists to ordered xarrays Baokun Li
2025-06-23 7:33 ` [PATCH v2 15/16] ext4: refactor choose group to scan group Baokun Li
2025-06-23 7:33 ` [PATCH v2 16/16] ext4: ensure global ordered traversal across all free groups xarrays Baokun Li
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250623073304.3275702-5-libaokun1@huawei.com \
--to=libaokun1@huawei.com \
--cc=adilger.kernel@dilger.ca \
--cc=jack@suse.cz \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ojaswin@linux.ibm.com \
--cc=tytso@mit.edu \
--cc=yangerkun@huawei.com \
--cc=yi.zhang@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox