* [PATCH] ext4: fix JBD2 credit overflow with large folios
@ 2025-06-30 13:13 Sasha Levin
2025-06-30 13:58 ` Zhang Yi
0 siblings, 1 reply; 3+ messages in thread
From: Sasha Levin @ 2025-06-30 13:13 UTC (permalink / raw)
To: tytso; +Cc: yi.zhang, linux-ext4, linux-kernel, Sasha Levin, stable
When large folios are enabled, the blocks-per-folio calculation in
ext4_da_writepages_trans_blocks() can overflow the journal transaction
limits, causing the writeback path to fail with errors like:
JBD2: kworker/u8:0 wants too many credits credits:416 rsv_credits:21 max:334
This occurs with small block sizes (1KB) and large folios (32MB), where
the calculation results in 32768 blocks per folio. The transaction credit
calculation then requests more credits than the journal can handle, leading
to the following warning and writeback failure:
WARNING: CPU: 1 PID: 43 at fs/jbd2/transaction.c:334 start_this_handle+0x4c0/0x4e0
EXT4-fs (loop0): ext4_do_writepages: jbd2_start: 9223372036854775807 pages, ino 14; err -28
Call trace leading to the issue:
ext4_do_writepages()
ext4_da_writepages_trans_blocks()
bpp = ext4_journal_blocks_per_folio() // Returns 32768 for 32MB folio with 1KB blocks
ext4_meta_trans_blocks(inode, MAX_WRITEPAGES_EXTENT_LEN + bpp - 1, bpp)
// With bpp=32768, lblocks=34815, pextents=32768
// Returns credits=415, but with overhead becomes 416 > max 334
ext4_journal_start_with_reserve()
jbd2_journal_start_reserved()
start_this_handle()
// Fails with warning when credits:416 > max:334
The issue was introduced by commit d6bf294773a47 ("ext4/jbd2: convert
jbd2_journal_blocks_per_page() to support large folio"), which added
support for large folios but didn't account for the journal credit limits.
Fix this by capping the blocks-per-folio value at 8192 in the writeback
path. This is the value we'd get with 32MB folios and 4KB blocks, or 8MB
folios with 1KB blocks, which is reasonable and safe for typical journal
configurations.
Fixes: d6bf294773a4 ("ext4/jbd2: convert jbd2_journal_blocks_per_page() to support large folio")
Cc: stable@vger.kernel.org
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/ext4/inode.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index be9a4cba35fd5..860e59a176c97 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2070,6 +2070,14 @@ static int mpage_submit_folio(struct mpage_da_data *mpd, struct folio *folio)
*/
#define MAX_WRITEPAGES_EXTENT_LEN 2048
+/*
+ * Maximum blocks per folio to avoid JBD2 credit overflow.
+ * This is the value we'd get with 32MB folios and 4KB blocks,
+ * or 8MB folios with 1KB blocks, which is reasonable and safe
+ * for typical journal configurations.
+ */
+#define MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK 8192
+
/*
* mpage_add_bh_to_extent - try to add bh to extent of blocks to map
*
@@ -2481,6 +2489,18 @@ static int ext4_da_writepages_trans_blocks(struct inode *inode)
{
int bpp = ext4_journal_blocks_per_folio(inode);
+ /*
+ * With large folios, blocks per folio can get excessively large,
+ * especially with small block sizes. For example, with 32MB folios
+ * (order 11) and 1KB blocks, we get 32768 blocks per folio. This
+ * leads to credit requests that overflow the journal's transaction
+ * limit.
+ *
+ * Limit the value to avoid excessive credit requests.
+ */
+ if (bpp > MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK)
+ bpp = MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK;
+
return ext4_meta_trans_blocks(inode,
MAX_WRITEPAGES_EXTENT_LEN + bpp - 1, bpp);
}
@@ -2559,6 +2579,13 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
handle_t *handle = NULL;
int bpp = ext4_journal_blocks_per_folio(mpd->inode);
+ /*
+ * With large folios, blocks per folio can get excessively large,
+ * especially with small block sizes. Cap it to avoid credit overflow.
+ */
+ if (bpp > MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK)
+ bpp = MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK;
+
if (mpd->wbc->sync_mode == WB_SYNC_ALL || mpd->wbc->tagged_writepages)
tag = PAGECACHE_TAG_TOWRITE;
else
@@ -6179,6 +6206,13 @@ int ext4_writepage_trans_blocks(struct inode *inode)
int bpp = ext4_journal_blocks_per_folio(inode);
int ret;
+ /*
+ * With large folios, blocks per folio can get excessively large,
+ * especially with small block sizes. Cap it to avoid credit overflow.
+ */
+ if (bpp > MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK)
+ bpp = MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK;
+
ret = ext4_meta_trans_blocks(inode, bpp, bpp);
/* Account for data blocks for journalled mode */
--
2.39.5
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] ext4: fix JBD2 credit overflow with large folios
2025-06-30 13:13 [PATCH] ext4: fix JBD2 credit overflow with large folios Sasha Levin
@ 2025-06-30 13:58 ` Zhang Yi
2025-06-30 15:01 ` Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: Zhang Yi @ 2025-06-30 13:58 UTC (permalink / raw)
To: Sasha Levin; +Cc: linux-ext4, linux-kernel, stable, tytso
On 2025/6/30 21:13, Sasha Levin wrote:
> When large folios are enabled, the blocks-per-folio calculation in
> ext4_da_writepages_trans_blocks() can overflow the journal transaction
> limits, causing the writeback path to fail with errors like:
>
> JBD2: kworker/u8:0 wants too many credits credits:416 rsv_credits:21 max:334
>
> This occurs with small block sizes (1KB) and large folios (32MB), where
> the calculation results in 32768 blocks per folio. The transaction credit
> calculation then requests more credits than the journal can handle, leading
> to the following warning and writeback failure:
>
> WARNING: CPU: 1 PID: 43 at fs/jbd2/transaction.c:334 start_this_handle+0x4c0/0x4e0
> EXT4-fs (loop0): ext4_do_writepages: jbd2_start: 9223372036854775807 pages, ino 14; err -28
>
> Call trace leading to the issue:
> ext4_do_writepages()
> ext4_da_writepages_trans_blocks()
> bpp = ext4_journal_blocks_per_folio() // Returns 32768 for 32MB folio with 1KB blocks
> ext4_meta_trans_blocks(inode, MAX_WRITEPAGES_EXTENT_LEN + bpp - 1, bpp)
> // With bpp=32768, lblocks=34815, pextents=32768
> // Returns credits=415, but with overhead becomes 416 > max 334
> ext4_journal_start_with_reserve()
> jbd2_journal_start_reserved()
> start_this_handle()
> // Fails with warning when credits:416 > max:334
>
> The issue was introduced by commit d6bf294773a47 ("ext4/jbd2: convert
> jbd2_journal_blocks_per_page() to support large folio"), which added
> support for large folios but didn't account for the journal credit limits.
>
> Fix this by capping the blocks-per-folio value at 8192 in the writeback
> path. This is the value we'd get with 32MB folios and 4KB blocks, or 8MB
> folios with 1KB blocks, which is reasonable and safe for typical journal
> configurations.
>
> Fixes: d6bf294773a4 ("ext4/jbd2: convert jbd2_journal_blocks_per_page() to support large folio")
> Cc: stable@vger.kernel.org
> Signed-off-by: Sasha Levin <sashal@kernel.org>
Hi, Sasha!
Thank you for the fix. However, simply limiting the credits is not enough,
as this may result in a scenario where there are not enough credits
available to map a large, non-contiguous folio. I've been working on this
issue[1] and I'll release v3 tomorrow if my tests looks fine.
[1] https://lore.kernel.org/linux-ext4/20250611111625.1668035-1-yi.zhang@huaweicloud.com/
Thanks,
Yi.
> ---
> fs/ext4/inode.c | 34 ++++++++++++++++++++++++++++++++++
> 1 file changed, 34 insertions(+)
>
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index be9a4cba35fd5..860e59a176c97 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -2070,6 +2070,14 @@ static int mpage_submit_folio(struct mpage_da_data *mpd, struct folio *folio)
> */
> #define MAX_WRITEPAGES_EXTENT_LEN 2048
>
> +/*
> + * Maximum blocks per folio to avoid JBD2 credit overflow.
> + * This is the value we'd get with 32MB folios and 4KB blocks,
> + * or 8MB folios with 1KB blocks, which is reasonable and safe
> + * for typical journal configurations.
> + */
> +#define MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK 8192
> +
> /*
> * mpage_add_bh_to_extent - try to add bh to extent of blocks to map
> *
> @@ -2481,6 +2489,18 @@ static int ext4_da_writepages_trans_blocks(struct inode *inode)
> {
> int bpp = ext4_journal_blocks_per_folio(inode);
>
> + /*
> + * With large folios, blocks per folio can get excessively large,
> + * especially with small block sizes. For example, with 32MB folios
> + * (order 11) and 1KB blocks, we get 32768 blocks per folio. This
> + * leads to credit requests that overflow the journal's transaction
> + * limit.
> + *
> + * Limit the value to avoid excessive credit requests.
> + */
> + if (bpp > MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK)
> + bpp = MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK;
> +
> return ext4_meta_trans_blocks(inode,
> MAX_WRITEPAGES_EXTENT_LEN + bpp - 1, bpp);
> }
> @@ -2559,6 +2579,13 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
> handle_t *handle = NULL;
> int bpp = ext4_journal_blocks_per_folio(mpd->inode);
>
> + /*
> + * With large folios, blocks per folio can get excessively large,
> + * especially with small block sizes. Cap it to avoid credit overflow.
> + */
> + if (bpp > MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK)
> + bpp = MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK;
> +
> if (mpd->wbc->sync_mode == WB_SYNC_ALL || mpd->wbc->tagged_writepages)
> tag = PAGECACHE_TAG_TOWRITE;
> else
> @@ -6179,6 +6206,13 @@ int ext4_writepage_trans_blocks(struct inode *inode)
> int bpp = ext4_journal_blocks_per_folio(inode);
> int ret;
>
> + /*
> + * With large folios, blocks per folio can get excessively large,
> + * especially with small block sizes. Cap it to avoid credit overflow.
> + */
> + if (bpp > MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK)
> + bpp = MAX_BLOCKS_PER_FOLIO_FOR_WRITEBACK;
> +
> ret = ext4_meta_trans_blocks(inode, bpp, bpp);
>
> /* Account for data blocks for journalled mode */
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] ext4: fix JBD2 credit overflow with large folios
2025-06-30 13:58 ` Zhang Yi
@ 2025-06-30 15:01 ` Sasha Levin
0 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2025-06-30 15:01 UTC (permalink / raw)
To: Zhang Yi; +Cc: linux-ext4, linux-kernel, stable, tytso
On Mon, Jun 30, 2025 at 09:58:52PM +0800, Zhang Yi wrote:
>On 2025/6/30 21:13, Sasha Levin wrote:
>> When large folios are enabled, the blocks-per-folio calculation in
>> ext4_da_writepages_trans_blocks() can overflow the journal transaction
>> limits, causing the writeback path to fail with errors like:
>>
>> JBD2: kworker/u8:0 wants too many credits credits:416 rsv_credits:21 max:334
>>
>> This occurs with small block sizes (1KB) and large folios (32MB), where
>> the calculation results in 32768 blocks per folio. The transaction credit
>> calculation then requests more credits than the journal can handle, leading
>> to the following warning and writeback failure:
>>
>> WARNING: CPU: 1 PID: 43 at fs/jbd2/transaction.c:334 start_this_handle+0x4c0/0x4e0
>> EXT4-fs (loop0): ext4_do_writepages: jbd2_start: 9223372036854775807 pages, ino 14; err -28
>>
>> Call trace leading to the issue:
>> ext4_do_writepages()
>> ext4_da_writepages_trans_blocks()
>> bpp = ext4_journal_blocks_per_folio() // Returns 32768 for 32MB folio with 1KB blocks
>> ext4_meta_trans_blocks(inode, MAX_WRITEPAGES_EXTENT_LEN + bpp - 1, bpp)
>> // With bpp=32768, lblocks=34815, pextents=32768
>> // Returns credits=415, but with overhead becomes 416 > max 334
>> ext4_journal_start_with_reserve()
>> jbd2_journal_start_reserved()
>> start_this_handle()
>> // Fails with warning when credits:416 > max:334
>>
>> The issue was introduced by commit d6bf294773a47 ("ext4/jbd2: convert
>> jbd2_journal_blocks_per_page() to support large folio"), which added
>> support for large folios but didn't account for the journal credit limits.
>>
>> Fix this by capping the blocks-per-folio value at 8192 in the writeback
>> path. This is the value we'd get with 32MB folios and 4KB blocks, or 8MB
>> folios with 1KB blocks, which is reasonable and safe for typical journal
>> configurations.
>>
>> Fixes: d6bf294773a4 ("ext4/jbd2: convert jbd2_journal_blocks_per_page() to support large folio")
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Sasha Levin <sashal@kernel.org>
>
>Hi, Sasha!
>
>Thank you for the fix. However, simply limiting the credits is not enough,
>as this may result in a scenario where there are not enough credits
>available to map a large, non-contiguous folio. I've been working on this
>issue[1] and I'll release v3 tomorrow if my tests looks fine.
>
>[1] https://lore.kernel.org/linux-ext4/20250611111625.1668035-1-yi.zhang@huaweicloud.com/
Ah perfect, I haven't seen your work, thank you for that.
Please ignore my patch.
--
Thanks,
Sasha
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-06-30 15:01 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-30 13:13 [PATCH] ext4: fix JBD2 credit overflow with large folios Sasha Levin
2025-06-30 13:58 ` Zhang Yi
2025-06-30 15:01 ` Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).