* [PATCH] ext4: cancel dirty accounting for folios without buffers
@ 2026-06-23 9:49 Zhu Jia
2026-06-24 8:20 ` Zhang Yi
2026-06-24 12:32 ` Jan Kara
0 siblings, 2 replies; 9+ messages in thread
From: Zhu Jia @ 2026-06-23 9:49 UTC (permalink / raw)
To: tytso, adilger.kernel
Cc: libaokun, jack, ojaswin, ritesh.list, yi.zhang, linux-ext4,
linux-kernel, Zhu Jia, stable
Since commit cc5095747edf ("ext4: don't BUG if someone dirty pages
without asking ext4 first"), mpage_prepare_extent_to_map() handles dirty
folios without buffer heads by warning, clearing PG_dirty, and skipping
them. ext4 cannot write these folios because there are no buffer heads to
map and submit.
That recovery leaves dirty accounting behind: folio_clear_dirty() clears
PG_dirty but does not undo the accounting charged when the folio was
dirtied. We have seen this in production as Dirty/nr_dirty staying high
while Writeback/nr_writeback and device write IO stayed near zero, with
many writer tasks blocked in balance_dirty_pages() throttling. Thus the
warning-and-skip recovery can still become a dirty-throttle DoS.
Use folio_cancel_dirty() so dropping PG_dirty also cancels the dirty
accounting.
Fixes: cc5095747edf ("ext4: don't BUG if someone dirty pages without asking ext4 first")
Cc: stable@vger.kernel.org
Signed-off-by: Zhu Jia <zhujia.zj@bytedance.com>
---
fs/ext4/inode.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c2c2d6ac7f3d1..7ea280e70c06e 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2715,7 +2715,13 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
*/
if (!folio_buffers(folio)) {
ext4_warning_inode(mpd->inode, "page %lu does not have buffers attached", folio->index);
- folio_clear_dirty(folio);
+ /*
+ * folio_cancel_dirty() pairs the dropped dirty
+ * state with dirty accounting, but leaves stale
+ * PAGECACHE_TAG_DIRTY/TOWRITE tags behind. Later
+ * writeback may rescan this clean folio.
+ */
+ folio_cancel_dirty(folio);
folio_unlock(folio);
continue;
}
--
2.20.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] ext4: cancel dirty accounting for folios without buffers
2026-06-23 9:49 [PATCH] ext4: cancel dirty accounting for folios without buffers Zhu Jia
@ 2026-06-24 8:20 ` Zhang Yi
2026-06-24 9:52 ` Zhu Jia
2026-06-24 12:32 ` Jan Kara
1 sibling, 1 reply; 9+ messages in thread
From: Zhang Yi @ 2026-06-24 8:20 UTC (permalink / raw)
To: Zhu Jia, tytso, adilger.kernel
Cc: libaokun, jack, ojaswin, ritesh.list, linux-ext4, linux-kernel, stable
On 6/23/2026 5:49 PM, Zhu Jia wrote:
> Since commit cc5095747edf ("ext4: don't BUG if someone dirty pages
> without asking ext4 first"), mpage_prepare_extent_to_map() handles dirty
> folios without buffer heads by warning, clearing PG_dirty, and skipping
> them. ext4 cannot write these folios because there are no buffer heads to
> map and submit.
>
> That recovery leaves dirty accounting behind: folio_clear_dirty() clears
> PG_dirty but does not undo the accounting charged when the folio was
> dirtied. We have seen this in production as Dirty/nr_dirty staying high
> while Writeback/nr_writeback and device write IO stayed near zero, with
> many writer tasks blocked in balance_dirty_pages() throttling. Thus the
> warning-and-skip recovery can still become a dirty-throttle DoS.
>
> Use folio_cancel_dirty() so dropping PG_dirty also cancels the dirty
> accounting.
Hi, Zhu jia!
Thanks for the patch. This overall looks good to me. But should we also
clear PAGECACHE_TAG_DIRTY and PAGECACHE_TAG_TOWRITE here? Since the folio
won't be written back again until it gets dirtied, it seems cleaner to
remove these tags as well. Are there any side-effects I'm missing?
Thanks,
Yi.
>
> Fixes: cc5095747edf ("ext4: don't BUG if someone dirty pages without asking ext4 first")
> Cc: stable@vger.kernel.org
> Signed-off-by: Zhu Jia <zhujia.zj@bytedance.com>
> ---
> fs/ext4/inode.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index c2c2d6ac7f3d1..7ea280e70c06e 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -2715,7 +2715,13 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
> */
> if (!folio_buffers(folio)) {
> ext4_warning_inode(mpd->inode, "page %lu does not have buffers attached", folio->index);
> - folio_clear_dirty(folio);
> + /*
> + * folio_cancel_dirty() pairs the dropped dirty
> + * state with dirty accounting, but leaves stale
> + * PAGECACHE_TAG_DIRTY/TOWRITE tags behind. Later
> + * writeback may rescan this clean folio.
> + */
> + folio_cancel_dirty(folio);
> folio_unlock(folio);
> continue;
> }
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] ext4: cancel dirty accounting for folios without buffers
2026-06-24 8:20 ` Zhang Yi
@ 2026-06-24 9:52 ` Zhu Jia
2026-06-24 12:32 ` Jan Kara
0 siblings, 1 reply; 9+ messages in thread
From: Zhu Jia @ 2026-06-24 9:52 UTC (permalink / raw)
To: Zhang Yi
Cc: Zhu Jia, tytso, adilger.kernel, libaokun, jack, ojaswin,
ritesh.list, linux-ext4, linux-kernel, stable
Hi Yi,
Thanks for taking a look.
Yes, clearing PAGECACHE_TAG_DIRTY/TOWRITE would make the page-cache state
cleaner. I had a version that did this by adding a helper around
folio_cancel_dirty() and clearing the xarray tags after confirming the
folio was still the same clean page-cache entry.
It looked like this:
static void ext4_cancel_dirty_folio(struct address_space *mapping,
struct folio *folio)
{
XA_STATE(xas, &mapping->i_pages, folio->index);
unsigned long flags;
folio_cancel_dirty(folio);
xas_lock_irqsave(&xas, flags);
if (xas_load(&xas) == folio && !folio_test_dirty(folio)) {
xas_clear_mark(&xas, PAGECACHE_TAG_DIRTY);
xas_clear_mark(&xas, PAGECACHE_TAG_TOWRITE);
}
xas_unlock_irqrestore(&xas, flags);
}
The reason I left the tags unchanged in this version is that I was not sure
whether it is appropriate for ext4 to open-code xarray tag cleanup directly.
If you think this is the right direction, I can add the helper back and
send a v2.
Thanks,
Jia
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] ext4: cancel dirty accounting for folios without buffers
2026-06-24 9:52 ` Zhu Jia
@ 2026-06-24 12:32 ` Jan Kara
2026-06-24 13:10 ` Zhu Jia
2026-06-24 13:29 ` Zhang Yi
0 siblings, 2 replies; 9+ messages in thread
From: Jan Kara @ 2026-06-24 12:32 UTC (permalink / raw)
To: Zhu Jia
Cc: Zhang Yi, tytso, adilger.kernel, libaokun, jack, ojaswin,
ritesh.list, linux-ext4, linux-kernel, stable
On Wed 24-06-26 17:52:06, Zhu Jia wrote:
> Hi Yi,
>
> Thanks for taking a look.
>
> Yes, clearing PAGECACHE_TAG_DIRTY/TOWRITE would make the page-cache state
> cleaner. I had a version that did this by adding a helper around
> folio_cancel_dirty() and clearing the xarray tags after confirming the
> folio was still the same clean page-cache entry.
>
> It looked like this:
>
> static void ext4_cancel_dirty_folio(struct address_space *mapping,
> struct folio *folio)
> {
> XA_STATE(xas, &mapping->i_pages, folio->index);
> unsigned long flags;
>
> folio_cancel_dirty(folio);
>
> xas_lock_irqsave(&xas, flags);
> if (xas_load(&xas) == folio && !folio_test_dirty(folio)) {
> xas_clear_mark(&xas, PAGECACHE_TAG_DIRTY);
> xas_clear_mark(&xas, PAGECACHE_TAG_TOWRITE);
> }
> xas_unlock_irqrestore(&xas, flags);
> }
>
> The reason I left the tags unchanged in this version is that I was not sure
> whether it is appropriate for ext4 to open-code xarray tag cleanup directly.
>
> If you think this is the right direction, I can add the helper back and
> send a v2.
That was a good judgement! Playing with xarray tags like this in filesystem
code is certainly not a good thing. For now, I'd leave the xarray tags
dangling - they will be eventually synced with reality on next writeback
attempt. If this inconsistency of tags needs to be fixed, the fix belongs
to the generic code (so that it can be used in other places as well).
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] ext4: cancel dirty accounting for folios without buffers
2026-06-23 9:49 [PATCH] ext4: cancel dirty accounting for folios without buffers Zhu Jia
2026-06-24 8:20 ` Zhang Yi
@ 2026-06-24 12:32 ` Jan Kara
1 sibling, 0 replies; 9+ messages in thread
From: Jan Kara @ 2026-06-24 12:32 UTC (permalink / raw)
To: Zhu Jia
Cc: tytso, adilger.kernel, libaokun, jack, ojaswin, ritesh.list,
yi.zhang, linux-ext4, linux-kernel, stable
On Tue 23-06-26 17:49:47, Zhu Jia wrote:
> Since commit cc5095747edf ("ext4: don't BUG if someone dirty pages
> without asking ext4 first"), mpage_prepare_extent_to_map() handles dirty
> folios without buffer heads by warning, clearing PG_dirty, and skipping
> them. ext4 cannot write these folios because there are no buffer heads to
> map and submit.
>
> That recovery leaves dirty accounting behind: folio_clear_dirty() clears
> PG_dirty but does not undo the accounting charged when the folio was
> dirtied. We have seen this in production as Dirty/nr_dirty staying high
> while Writeback/nr_writeback and device write IO stayed near zero, with
> many writer tasks blocked in balance_dirty_pages() throttling. Thus the
> warning-and-skip recovery can still become a dirty-throttle DoS.
>
> Use folio_cancel_dirty() so dropping PG_dirty also cancels the dirty
> accounting.
>
> Fixes: cc5095747edf ("ext4: don't BUG if someone dirty pages without asking ext4 first")
> Cc: stable@vger.kernel.org
> Signed-off-by: Zhu Jia <zhujia.zj@bytedance.com>
Good point. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> fs/ext4/inode.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index c2c2d6ac7f3d1..7ea280e70c06e 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -2715,7 +2715,13 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
> */
> if (!folio_buffers(folio)) {
> ext4_warning_inode(mpd->inode, "page %lu does not have buffers attached", folio->index);
> - folio_clear_dirty(folio);
> + /*
> + * folio_cancel_dirty() pairs the dropped dirty
> + * state with dirty accounting, but leaves stale
> + * PAGECACHE_TAG_DIRTY/TOWRITE tags behind. Later
> + * writeback may rescan this clean folio.
> + */
> + folio_cancel_dirty(folio);
> folio_unlock(folio);
> continue;
> }
> --
> 2.20.1
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] ext4: cancel dirty accounting for folios without buffers
2026-06-24 12:32 ` Jan Kara
@ 2026-06-24 13:10 ` Zhu Jia
2026-06-24 13:29 ` Zhang Yi
1 sibling, 0 replies; 9+ messages in thread
From: Zhu Jia @ 2026-06-24 13:10 UTC (permalink / raw)
To: Jan Kara
Cc: Zhu Jia, Zhang Yi, Theodore Ts'o, Andreas Dilger, Baokun Li,
Ojaswin Mujoo, Ritesh Harjani, linux-ext4, linux-kernel, stable
On Wed, Jun 24, 2026 at 02:32:27PM +0200, Jan Kara wrote:
> On Wed 24-06-26 17:52:06, Zhu Jia wrote:
> > The reason I left the tags unchanged in this version is that I was not sure
> > whether it is appropriate for ext4 to open-code xarray tag cleanup directly.
> >
> > If you think this is the right direction, I can add the helper back and
> > send a v2.
>
> That was a good judgement! Playing with xarray tags like this in filesystem
> code is certainly not a good thing. For now, I'd leave the xarray tags
> dangling - they will be eventually synced with reality on next writeback
> attempt. If this inconsistency of tags needs to be fixed, the fix belongs
> to the generic code (so that it can be used in other places as well).
>
> Honza
Thanks, makes sense. I'll keep the fix as-is and leave the xarray tags
alone.
Thanks,
Jia
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] ext4: cancel dirty accounting for folios without buffers
2026-06-24 12:32 ` Jan Kara
2026-06-24 13:10 ` Zhu Jia
@ 2026-06-24 13:29 ` Zhang Yi
2026-06-25 11:18 ` Jan Kara
1 sibling, 1 reply; 9+ messages in thread
From: Zhang Yi @ 2026-06-24 13:29 UTC (permalink / raw)
To: Jan Kara, Zhu Jia
Cc: Zhang Yi, tytso, adilger.kernel, libaokun, ojaswin, ritesh.list,
linux-ext4, linux-kernel, stable
On 6/24/2026 8:32 PM, Jan Kara wrote:
> On Wed 24-06-26 17:52:06, Zhu Jia wrote:
>> Hi Yi,
>>
>> Thanks for taking a look.
>>
>> Yes, clearing PAGECACHE_TAG_DIRTY/TOWRITE would make the page-cache state
>> cleaner. I had a version that did this by adding a helper around
>> folio_cancel_dirty() and clearing the xarray tags after confirming the
>> folio was still the same clean page-cache entry.
>>
>> It looked like this:
>>
>> static void ext4_cancel_dirty_folio(struct address_space *mapping,
>> struct folio *folio)
>> {
>> XA_STATE(xas, &mapping->i_pages, folio->index);
>> unsigned long flags;
>>
>> folio_cancel_dirty(folio);
>>
>> xas_lock_irqsave(&xas, flags);
>> if (xas_load(&xas) == folio && !folio_test_dirty(folio)) {
>> xas_clear_mark(&xas, PAGECACHE_TAG_DIRTY);
>> xas_clear_mark(&xas, PAGECACHE_TAG_TOWRITE);
>> }
>> xas_unlock_irqrestore(&xas, flags);
>> }
>>
>> The reason I left the tags unchanged in this version is that I was not sure
>> whether it is appropriate for ext4 to open-code xarray tag cleanup directly.
>>
>> If you think this is the right direction, I can add the helper back and
>> send a v2.
>
> That was a good judgement! Playing with xarray tags like this in filesystem
> code is certainly not a good thing. For now, I'd leave the xarray tags
> dangling - they will be eventually synced with reality on next writeback
> attempt. If this inconsistency of tags needs to be fixed, the fix belongs
> to the generic code (so that it can be used in other places as well).
>
> Honza
Yes, I agree. Directly clearing the tag via open code is not a good
approach. However, I took a look at the !nr_to_submit branch in
ext4_bio_write_folio(), and it seems to have a similar simple handling
pattern—it directly calls __folio_start_writeback() and
folio_end_writeback(), which appears to be an elegant way to clear them.
Could we also call these two helpers just after folio_cancel_dirty()
here?
Thanks,
Yi.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] ext4: cancel dirty accounting for folios without buffers
2026-06-24 13:29 ` Zhang Yi
@ 2026-06-25 11:18 ` Jan Kara
2026-06-26 10:05 ` Zhu Jia
0 siblings, 1 reply; 9+ messages in thread
From: Jan Kara @ 2026-06-25 11:18 UTC (permalink / raw)
To: Zhang Yi
Cc: Jan Kara, Zhu Jia, Zhang Yi, tytso, adilger.kernel, libaokun,
ojaswin, ritesh.list, linux-ext4, linux-kernel, stable
On Wed 24-06-26 21:29:58, Zhang Yi wrote:
> On 6/24/2026 8:32 PM, Jan Kara wrote:
> > On Wed 24-06-26 17:52:06, Zhu Jia wrote:
> > > Hi Yi,
> > >
> > > Thanks for taking a look.
> > >
> > > Yes, clearing PAGECACHE_TAG_DIRTY/TOWRITE would make the page-cache state
> > > cleaner. I had a version that did this by adding a helper around
> > > folio_cancel_dirty() and clearing the xarray tags after confirming the
> > > folio was still the same clean page-cache entry.
> > >
> > > It looked like this:
> > >
> > > static void ext4_cancel_dirty_folio(struct address_space *mapping,
> > > struct folio *folio)
> > > {
> > > XA_STATE(xas, &mapping->i_pages, folio->index);
> > > unsigned long flags;
> > >
> > > folio_cancel_dirty(folio);
> > >
> > > xas_lock_irqsave(&xas, flags);
> > > if (xas_load(&xas) == folio && !folio_test_dirty(folio)) {
> > > xas_clear_mark(&xas, PAGECACHE_TAG_DIRTY);
> > > xas_clear_mark(&xas, PAGECACHE_TAG_TOWRITE);
> > > }
> > > xas_unlock_irqrestore(&xas, flags);
> > > }
> > >
> > > The reason I left the tags unchanged in this version is that I was not sure
> > > whether it is appropriate for ext4 to open-code xarray tag cleanup directly.
> > >
> > > If you think this is the right direction, I can add the helper back and
> > > send a v2.
> >
> > That was a good judgement! Playing with xarray tags like this in filesystem
> > code is certainly not a good thing. For now, I'd leave the xarray tags
> > dangling - they will be eventually synced with reality on next writeback
> > attempt. If this inconsistency of tags needs to be fixed, the fix belongs
> > to the generic code (so that it can be used in other places as well).
> >
> > Honza
>
> Yes, I agree. Directly clearing the tag via open code is not a good
> approach. However, I took a look at the !nr_to_submit branch in
> ext4_bio_write_folio(), and it seems to have a similar simple handling
> pattern—it directly calls __folio_start_writeback() and
> folio_end_writeback(), which appears to be an elegant way to clear them.
> Could we also call these two helpers just after folio_cancel_dirty()
> here?
Right, that would be actually doable there and would keep things more
consistent so I think that's a good idea! Thanks!
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] ext4: cancel dirty accounting for folios without buffers
2026-06-25 11:18 ` Jan Kara
@ 2026-06-26 10:05 ` Zhu Jia
0 siblings, 0 replies; 9+ messages in thread
From: Zhu Jia @ 2026-06-26 10:05 UTC (permalink / raw)
To: Jan Kara, Zhang Yi
Cc: Zhu Jia, Zhang Yi, Theodore Ts'o, Andreas Dilger, Baokun Li,
Ojaswin Mujoo, Ritesh Harjani, linux-ext4, linux-kernel, stable
On Thu, Jun 25, 2026 at 01:18:31PM +0200, Jan Kara wrote:
> On Wed 24-06-26 21:29:58, Zhang Yi wrote:
> > On 6/24/2026 8:32 PM, Jan Kara wrote:
> > > On Wed 24-06-26 17:52:06, Zhu Jia wrote:
> > > > The reason I left the tags unchanged in this version is that I was not sure
> > > > whether it is appropriate for ext4 to open-code xarray tag cleanup directly.
> > > >
> > > > If you think this is the right direction, I can add the helper back and
> > > > send a v2.
> > >
> > > That was a good judgement! Playing with xarray tags like this in filesystem
> > > code is certainly not a good thing. For now, I'd leave the xarray tags
> > > dangling - they will be eventually synced with reality on next writeback
> > > attempt. If this inconsistency of tags needs to be fixed, the fix belongs
> > > to the generic code (so that it can be used in other places as well).
> >
> > Yes, I agree. Directly clearing the tag via open code is not a good
> > approach. However, I took a look at the !nr_to_submit branch in
> > ext4_bio_write_folio(), and it seems to have a similar simple handling
> > pattern - it directly calls __folio_start_writeback() and
> > folio_end_writeback(), which appears to be an elegant way to clear them.
> > Could we also call these two helpers just after folio_cancel_dirty()
> > here?
>
> Right, that would be actually doable there and would keep things more
> consistent so I think that's a good idea! Thanks!
Thanks Jan and Yi, your discussion makes sense. I will send v2 shortly.
Thanks,
Jia
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-06-26 10:05 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-23 9:49 [PATCH] ext4: cancel dirty accounting for folios without buffers Zhu Jia
2026-06-24 8:20 ` Zhang Yi
2026-06-24 9:52 ` Zhu Jia
2026-06-24 12:32 ` Jan Kara
2026-06-24 13:10 ` Zhu Jia
2026-06-24 13:29 ` Zhang Yi
2026-06-25 11:18 ` Jan Kara
2026-06-26 10:05 ` Zhu Jia
2026-06-24 12:32 ` Jan Kara
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®