* Re: Removing ->dirty_folio
2026-08-24 19:08 Removing ->dirty_folio Matthew Wilcox
@ 2026-08-24 19:25 ` John Hubbard
2026-08-24 19:43 ` Matthew Wilcox
2026-08-24 19:33 ` Rik van Riel
` (6 subsequent siblings)
7 siblings, 1 reply; 27+ messages in thread
From: John Hubbard @ 2026-08-24 19:25 UTC (permalink / raw)
To: Matthew Wilcox, Pedro Falcato, Christoph Hellwig, Jann Horn,
David Howells, Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong,
linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
On 8/24/26 12:08 PM, Matthew Wilcox wrote:
> I think it's time to remove folio_mark_dirty(), ->dirty_folio() and so on.
>
> This is not how filesystems want to be informed of folio dirtying.
> It was fine for ext2, but anything that's journalled or COW has work
> to do before the folio is made dirty, and it's hard to do that work
> under the page table spinlock (not all callers hold that lock, but the
> filesystem has to be able to handle the cases where it is.
>
> Filesystems want the page_mkwrite() entry point to be how they find out
> about a folio being dirtied -- and that works great! Except that we
> can writeback the folio for a number of reasons. If it's been dirtied
> due to a shared writable mmap, that's fine; we map the folio read-only
> and any subsequent writes will re-enter the page_mkwrite path.
>
> The problem is GUP. We have no way to force the GUP caller to go
> through page_mkwrite again. So instead we make the GUP caller call
> folio_mark_dirty_lock() which many just don't, and generally we get away
> with it. But it's a bug, and a bad interface.
>
> There's also the problem that GUP users bypass the folio_wait_stable()
> mechanism. If a page is written to while somebody is creating a
> checksum over that page, the checksum will be corrupted. If we want
> to fix this, we have to bounce-buffer the page. There's no way to
> prevent or delay a GUP user from writing to the page. Enjoy your RAID.
>
> My proposal is this:
>
> - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> If it's true, do the writeback, but retain/recreate whatever data
> structures you need in order to write the folio again; behave as if
> ->page_mkdirty() had been called again for each page in the folio is
> marked as dirty.
Yes, that would work nicely.
> - The MM behaves similarly; we do not clear the writeback flag for
> folio_maybe_dma_pinned().
>
> This will have the effect of writing pinned folios back every time the
> inode is scheduled for writeback. But since we have no idea whether
> the folio is actually dirty (because the GUP user won't tell us),
> this is the correct behaviour.
>
> I'm probably missing some stuff here. Let me know.
OK, so working through the end of the pinning, I think it still is
correct: device finishes writing to pinned memory, device driver
unpins the memory but the page has been left marked dirty the whole
time and still is, so the next writeback still does the writeback,
but this time sees no pins and so it marks the page clean.
thanks,
--
John Hubbard
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: Removing ->dirty_folio
2026-08-24 19:25 ` John Hubbard
@ 2026-08-24 19:43 ` Matthew Wilcox
2026-08-24 19:51 ` John Hubbard
2026-08-25 7:59 ` Pedro Falcato
0 siblings, 2 replies; 27+ messages in thread
From: Matthew Wilcox @ 2026-08-24 19:43 UTC (permalink / raw)
To: John Hubbard
Cc: Pedro Falcato, Christoph Hellwig, Jann Horn, David Howells,
Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On Mon, Aug 24, 2026 at 12:25:42PM -0700, John Hubbard wrote:
> > My proposal is this:
> >
> > - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> > If it's true, do the writeback, but retain/recreate whatever data
> > structures you need in order to write the folio again; behave as if
> > ->page_mkdirty() had been called again for each page in the folio is
> > marked as dirty.
>
> Yes, that would work nicely.
>
> > - The MM behaves similarly; we do not clear the writeback flag for
> > folio_maybe_dma_pinned().
> >
> > This will have the effect of writing pinned folios back every time the
> > inode is scheduled for writeback. But since we have no idea whether
> > the folio is actually dirty (because the GUP user won't tell us),
> > this is the correct behaviour.
> >
> > I'm probably missing some stuff here. Let me know.
>
> OK, so working through the end of the pinning, I think it still is
> correct: device finishes writing to pinned memory, device driver
> unpins the memory but the page has been left marked dirty the whole
> time and still is, so the next writeback still does the writeback,
> but this time sees no pins and so it marks the page clean.
Excellent! By the way, what would you think to this?
@@ -2717,7 +2719,8 @@ static inline bool folio_maybe_dma_pinned(struct folio *folio)
* Here, for that overflow case, use the sign bit to count a little
* bit higher via unsigned math, and thus still get an accurate result.
*/
- return ((unsigned int)folio_ref_count(folio)) >=
+ mapcount = folio_mapcount(folio);
+ return (folio_ref_count(folio) - mapcount) >=
GUP_PIN_COUNTING_BIAS;
}
It should improve the accuracy of folio_maybe_dma_pinned() for folios
which are mapped many, many times (eg a page of libc). I'm a little
concerned about races turning that number negative since we don't
necessarily have the folio locked at that point.
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: Removing ->dirty_folio
2026-08-24 19:43 ` Matthew Wilcox
@ 2026-08-24 19:51 ` John Hubbard
2026-08-24 21:05 ` Matthew Wilcox
2026-08-25 7:59 ` Pedro Falcato
1 sibling, 1 reply; 27+ messages in thread
From: John Hubbard @ 2026-08-24 19:51 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Pedro Falcato, Christoph Hellwig, Jann Horn, David Howells,
Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On 8/24/26 12:43 PM, Matthew Wilcox wrote:
> On Mon, Aug 24, 2026 at 12:25:42PM -0700, John Hubbard wrote:
>>> My proposal is this:
>>>
>>> - Fileystems take note of folio_maybe_dma_pinned() during writeback.
>>> If it's true, do the writeback, but retain/recreate whatever data
>>> structures you need in order to write the folio again; behave as if
>>> ->page_mkdirty() had been called again for each page in the folio is
>>> marked as dirty.
>>
>> Yes, that would work nicely.
>>
>>> - The MM behaves similarly; we do not clear the writeback flag for
>>> folio_maybe_dma_pinned().
>>>
>>> This will have the effect of writing pinned folios back every time the
>>> inode is scheduled for writeback. But since we have no idea whether
>>> the folio is actually dirty (because the GUP user won't tell us),
>>> this is the correct behaviour.
>>>
>>> I'm probably missing some stuff here. Let me know.
>>
>> OK, so working through the end of the pinning, I think it still is
>> correct: device finishes writing to pinned memory, device driver
>> unpins the memory but the page has been left marked dirty the whole
oh, I just thought of a minor hole that we need to fill: how to mark the
page dirty in the first place, in the absence of mark_[page|folio]_dirty()?
Under this new scheme, we will need to pin first, then mark dirty, to
set up. The filesystem can't do everything, because even if it were to
call page_mkdirty(), a writeback could clear that before the page gets
pinned.
Then teardown is simply to unpin, as discussed already.
>> time and still is, so the next writeback still does the writeback,
>> but this time sees no pins and so it marks the page clean.
>
> Excellent! By the way, what would you think to this?
>
> @@ -2717,7 +2719,8 @@ static inline bool folio_maybe_dma_pinned(struct folio *folio)
> * Here, for that overflow case, use the sign bit to count a little
> * bit higher via unsigned math, and thus still get an accurate result.
> */
> - return ((unsigned int)folio_ref_count(folio)) >=
> + mapcount = folio_mapcount(folio);
> + return (folio_ref_count(folio) - mapcount) >=
As long as the math works: need to not underflow. I guess mapcount is
always less than refcount, so OK.
So it *seems* correct to me, fwiw. :)
> GUP_PIN_COUNTING_BIAS;
> }
>
>
> It should improve the accuracy of folio_maybe_dma_pinned() for folios
> which are mapped many, many times (eg a page of libc). I'm a little
> concerned about races turning that number negative since we don't
> necessarily have the folio locked at that point.
thanks,
--
John Hubbard
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-24 19:51 ` John Hubbard
@ 2026-08-24 21:05 ` Matthew Wilcox
0 siblings, 0 replies; 27+ messages in thread
From: Matthew Wilcox @ 2026-08-24 21:05 UTC (permalink / raw)
To: John Hubbard
Cc: Pedro Falcato, Christoph Hellwig, Jann Horn, David Howells,
Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On Mon, Aug 24, 2026 at 12:51:43PM -0700, John Hubbard wrote:
> On 8/24/26 12:43 PM, Matthew Wilcox wrote:
> > On Mon, Aug 24, 2026 at 12:25:42PM -0700, John Hubbard wrote:
> >>> My proposal is this:
> >>>
> >>> - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> >>> If it's true, do the writeback, but retain/recreate whatever data
> >>> structures you need in order to write the folio again; behave as if
> >>> ->page_mkdirty() had been called again for each page in the folio is
> >>> marked as dirty.
> >>
> >> Yes, that would work nicely.
> >>
> >>> - The MM behaves similarly; we do not clear the writeback flag for
> >>> folio_maybe_dma_pinned().
> >>>
> >>> This will have the effect of writing pinned folios back every time the
> >>> inode is scheduled for writeback. But since we have no idea whether
> >>> the folio is actually dirty (because the GUP user won't tell us),
> >>> this is the correct behaviour.
> >>>
> >>> I'm probably missing some stuff here. Let me know.
> >>
> >> OK, so working through the end of the pinning, I think it still is
> >> correct: device finishes writing to pinned memory, device driver
> >> unpins the memory but the page has been left marked dirty the whole
>
> oh, I just thought of a minor hole that we need to fill: how to mark the
> page dirty in the first place, in the absence of mark_[page|folio]_dirty()?
>
> Under this new scheme, we will need to pin first, then mark dirty, to
> set up. The filesystem can't do everything, because even if it were to
> call page_mkdirty(), a writeback could clear that before the page gets
> pinned.
The page fault path:
handle_mm_fault()
__handle_mm_fault()
handle_pte_fault()
do_wp_page() [just assuming the pte is present, but !writable]
wp_page_shared()
do_page_mkwrite()
vmf->vma->vm_ops->page_mkwrite(vmf)
and that's where the filesystem gets notified that this page is about
to become writable.
So your concern is obviously "how do we prevent the writeout from
happening before we set the pincount", and I think it's that the
writeout path will make the PTE read-only before it does writeback,
and we hold the mmap_lock which prevents the page table entry from being
made read-only.
But I'm only about 80% sure that's what happens.
> > @@ -2717,7 +2719,8 @@ static inline bool folio_maybe_dma_pinned(struct folio *folio)
> > * Here, for that overflow case, use the sign bit to count a little
> > * bit higher via unsigned math, and thus still get an accurate result.
> > */
> > - return ((unsigned int)folio_ref_count(folio)) >=
> > + mapcount = folio_mapcount(folio);
> > + return (folio_ref_count(folio) - mapcount) >=
>
> As long as the math works: need to not underflow. I guess mapcount is
> always less than refcount, so OK.
>
> So it *seems* correct to me, fwiw. :)
Yeah, and if we hold the folio locked, it's true. But we could sample
mapcount, then have a few unmaps come in before we read refcount, and
we've got an underflow. I mean, it's only "maybe" mapped ... ;-)
Perhaps we could have two functions, one for if you have the folio
locked (like in the writeback path) where you can rely on mapcount
not changing, and thus refcount always being > mapcount.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-24 19:43 ` Matthew Wilcox
2026-08-24 19:51 ` John Hubbard
@ 2026-08-25 7:59 ` Pedro Falcato
1 sibling, 0 replies; 27+ messages in thread
From: Pedro Falcato @ 2026-08-25 7:59 UTC (permalink / raw)
To: Matthew Wilcox
Cc: John Hubbard, Christoph Hellwig, Jann Horn, David Howells,
Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On Mon, Aug 24, 2026 at 08:43:39PM +0100, Matthew Wilcox wrote:
> On Mon, Aug 24, 2026 at 12:25:42PM -0700, John Hubbard wrote:
> > > My proposal is this:
> > >
> > > - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> > > If it's true, do the writeback, but retain/recreate whatever data
> > > structures you need in order to write the folio again; behave as if
> > > ->page_mkdirty() had been called again for each page in the folio is
> > > marked as dirty.
> >
> > Yes, that would work nicely.
> >
> > > - The MM behaves similarly; we do not clear the writeback flag for
> > > folio_maybe_dma_pinned().
> > >
> > > This will have the effect of writing pinned folios back every time the
> > > inode is scheduled for writeback. But since we have no idea whether
> > > the folio is actually dirty (because the GUP user won't tell us),
> > > this is the correct behaviour.
> > >
> > > I'm probably missing some stuff here. Let me know.
> >
> > OK, so working through the end of the pinning, I think it still is
> > correct: device finishes writing to pinned memory, device driver
> > unpins the memory but the page has been left marked dirty the whole
> > time and still is, so the next writeback still does the writeback,
> > but this time sees no pins and so it marks the page clean.
>
> Excellent! By the way, what would you think to this?
>
> @@ -2717,7 +2719,8 @@ static inline bool folio_maybe_dma_pinned(struct folio *folio)
> * Here, for that overflow case, use the sign bit to count a little
> * bit higher via unsigned math, and thus still get an accurate result.
> */
> - return ((unsigned int)folio_ref_count(folio)) >=
> + mapcount = folio_mapcount(folio);
> + return (folio_ref_count(folio) - mapcount) >=
> GUP_PIN_COUNTING_BIAS;
> }
>
>
> It should improve the accuracy of folio_maybe_dma_pinned() for folios
> which are mapped many, many times (eg a page of libc). I'm a little
> concerned about races turning that number negative since we don't
> necessarily have the folio locked at that point.
It's perhaps a radical idea, but how about just not incrementing
refcount for mappings? Essentially, for the main state transitions
(mapped to unmapped, and vice-versa):
0 mapcount -> 1 mapcount: refcount++
1 mapcount -> 0 mapcount: refcount--
and anything else doesn't touch refcount.
I think it's worth considering standalone (one less atomic inc :) and
reduces any ambiguity in folio_maybe_dma_pinned() to essentially 0 (unless
you have 2048 short-term pins for the folio, rather unlikely I would say).
--
Pedro
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-24 19:08 Removing ->dirty_folio Matthew Wilcox
2026-08-24 19:25 ` John Hubbard
@ 2026-08-24 19:33 ` Rik van Riel
2026-08-25 8:21 ` David Hildenbrand (Arm)
2026-08-24 21:27 ` Boris Burkov
` (5 subsequent siblings)
7 siblings, 1 reply; 27+ messages in thread
From: Rik van Riel @ 2026-08-24 19:33 UTC (permalink / raw)
To: Matthew Wilcox, Pedro Falcato, Christoph Hellwig, Jann Horn,
David Howells, John Hubbard, Jan Kara, Qu Wenruo, Darrick J. Wong,
linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
Cc: David Hildenbrand
On Mon, 2026-08-24 at 20:08 +0100, Matthew Wilcox wrote:
> I think it's time to remove folio_mark_dirty(), ->dirty_folio() and
> so on.
>
> This is not how filesystems want to be informed of folio dirtying.
>
This sounds like I should leave the folio_mark_dirty()
stuff in the get_user_pages() code alone for now, and
leave the shaving of that yak to another day?
In that case, I'll prepare my next version of the
get_user_pages() series.
--
All Rights Reversed.
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: Removing ->dirty_folio
2026-08-24 19:33 ` Rik van Riel
@ 2026-08-25 8:21 ` David Hildenbrand (Arm)
0 siblings, 0 replies; 27+ messages in thread
From: David Hildenbrand (Arm) @ 2026-08-25 8:21 UTC (permalink / raw)
To: Rik van Riel, Matthew Wilcox, Pedro Falcato, Christoph Hellwig,
Jann Horn, David Howells, John Hubbard, Jan Kara, Qu Wenruo,
Darrick J. Wong, linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
On 8/24/26 21:33, Rik van Riel wrote:
> On Mon, 2026-08-24 at 20:08 +0100, Matthew Wilcox wrote:
>> I think it's time to remove folio_mark_dirty(), ->dirty_folio() and
>> so on.
>>
>> This is not how filesystems want to be informed of folio dirtying.
>>
> This sounds like I should leave the folio_mark_dirty()
> stuff in the get_user_pages() code alone for now, and
> leave the shaving of that yak to another day?
Absolutely. Making it consistent in GUP is a reasonable cleanup, but don't mix
in too many unrelated things into the same patch set.
> In that case, I'll prepare my next version of the
> get_user_pages() series.
I still want to go over it and provide more feedback.
But that won't happen right now (it's surprising how many people miss that we
are in the merge window) and also not next week (traveling).
But there is also no need to rush this, I'm sure we'll get something done for
the next merge window :)
--
Cheers,
David
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-24 19:08 Removing ->dirty_folio Matthew Wilcox
2026-08-24 19:25 ` John Hubbard
2026-08-24 19:33 ` Rik van Riel
@ 2026-08-24 21:27 ` Boris Burkov
2026-08-25 19:47 ` Matthew Wilcox
2026-08-24 22:38 ` Qu Wenruo
` (4 subsequent siblings)
7 siblings, 1 reply; 27+ messages in thread
From: Boris Burkov @ 2026-08-24 21:27 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Pedro Falcato, Christoph Hellwig, Jann Horn, David Howells,
John Hubbard, Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong,
linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
On Mon, Aug 24, 2026 at 08:08:06PM +0100, Matthew Wilcox wrote:
> I think it's time to remove folio_mark_dirty(), ->dirty_folio() and so on.
>
> This is not how filesystems want to be informed of folio dirtying.
> It was fine for ext2, but anything that's journalled or COW has work
> to do before the folio is made dirty, and it's hard to do that work
> under the page table spinlock (not all callers hold that lock, but the
> filesystem has to be able to handle the cases where it is.
>
> Filesystems want the page_mkwrite() entry point to be how they find out
> about a folio being dirtied -- and that works great! Except that we
> can writeback the folio for a number of reasons. If it's been dirtied
> due to a shared writable mmap, that's fine; we map the folio read-only
> and any subsequent writes will re-enter the page_mkwrite path.
Can you elaborate on this part a bit more? I can't tell if you are
proposing a change or saying the existing behavior is fine if we drop
->dirty_folio(). I am also confused about exactly what sort of folio
dirtying you are referring to. Sorry if I am being obtuse.
When I was recently adding ->dirty_folio() to btrfs, one of the main
cases was the call to folio_mark_dirty() that came via
__iomap_dio_bio_end_io() calling bio_check_pages_dirty() which schedules
bio_dirty_fn(). (i.e., completion of a dio read into a shared mmap)
Is that the case you are referring to here, or are you referring to
someone just modifying a byte they faulted in from a shared mmap? The
latter I would expect to have called page_mkwrite in the fault and done
fs-specific work, so I assume it's the former that you are referring to?
Either way, I do believe that for the dio read endio case pinning is not
involved and btrfs relies on the ->dirty_folio() call, so I think
something would need to be done about that case too.
I believe you saw this patch since it was your idea for us to use
->dirty_folio(), but just for reference for anyone else who didn't see
it, the btrfs patch adding ->dirty_folio():
https://lore.kernel.org/linux-btrfs/69d0043e0f6a3d17048dfde857127ab0bf331154.1785190866.git.boris@bur.io/
Thanks,
Boris
>
> The problem is GUP. We have no way to force the GUP caller to go
> through page_mkwrite again. So instead we make the GUP caller call
> folio_mark_dirty_lock() which many just don't, and generally we get away
> with it. But it's a bug, and a bad interface.
>
> There's also the problem that GUP users bypass the folio_wait_stable()
> mechanism. If a page is written to while somebody is creating a
> checksum over that page, the checksum will be corrupted. If we want
> to fix this, we have to bounce-buffer the page. There's no way to
> prevent or delay a GUP user from writing to the page. Enjoy your RAID.
>
> My proposal is this:
>
> - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> If it's true, do the writeback, but retain/recreate whatever data
> structures you need in order to write the folio again; behave as if
> ->page_mkdirty() had been called again for each page in the folio is
> marked as dirty.
> - The MM behaves similarly; we do not clear the writeback flag for
> folio_maybe_dma_pinned().
>
> This will have the effect of writing pinned folios back every time the
> inode is scheduled for writeback. But since we have no idea whether
> the folio is actually dirty (because the GUP user won't tell us),
> this is the correct behaviour.
>
> I'm probably missing some stuff here. Let me know.
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: Removing ->dirty_folio
2026-08-24 21:27 ` Boris Burkov
@ 2026-08-25 19:47 ` Matthew Wilcox
0 siblings, 0 replies; 27+ messages in thread
From: Matthew Wilcox @ 2026-08-25 19:47 UTC (permalink / raw)
To: Boris Burkov
Cc: Pedro Falcato, Christoph Hellwig, Jann Horn, David Howells,
John Hubbard, Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong,
linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
On Mon, Aug 24, 2026 at 02:27:27PM -0700, Boris Burkov wrote:
> On Mon, Aug 24, 2026 at 08:08:06PM +0100, Matthew Wilcox wrote:
> > I think it's time to remove folio_mark_dirty(), ->dirty_folio() and so on.
> >
> > This is not how filesystems want to be informed of folio dirtying.
> > It was fine for ext2, but anything that's journalled or COW has work
> > to do before the folio is made dirty, and it's hard to do that work
> > under the page table spinlock (not all callers hold that lock, but the
> > filesystem has to be able to handle the cases where it is.
> >
> > Filesystems want the page_mkwrite() entry point to be how they find out
> > about a folio being dirtied -- and that works great! Except that we
> > can writeback the folio for a number of reasons. If it's been dirtied
> > due to a shared writable mmap, that's fine; we map the folio read-only
> > and any subsequent writes will re-enter the page_mkwrite path.
>
> Can you elaborate on this part a bit more? I can't tell if you are
> proposing a change or saying the existing behavior is fine if we drop
> ->dirty_folio(). I am also confused about exactly what sort of folio
> dirtying you are referring to. Sorry if I am being obtuse.
Sorry for not being clearer. This is what happens today. We first
tell the FS that we're going to write to the page through
page_mkwrite(), then we transfer the dirty bit from the PTE to
the folio through ->dirty_folio() ... but it's already there, thanks
to the call to page_mkwrite()!
> When I was recently adding ->dirty_folio() to btrfs, one of the main
> cases was the call to folio_mark_dirty() that came via
> __iomap_dio_bio_end_io() calling bio_check_pages_dirty() which schedules
> bio_dirty_fn(). (i.e., completion of a dio read into a shared mmap)
>
> Is that the case you are referring to here, or are you referring to
> someone just modifying a byte they faulted in from a shared mmap? The
> latter I would expect to have called page_mkwrite in the fault and done
> fs-specific work, so I assume it's the former that you are referring to?
Right. The former, I _believe_ already calls page_mkwrite() today, and so
the call to dirty_folio() is redundant. Except if writeback came in
while the I/O was in progress. So if we preserve the dirty bit for
pinned pages in the writeback code, the caall to dirty_folio() will
always be redundant and can be removed.
> Either way, I do believe that for the dio read endio case pinning is not
> involved and btrfs relies on the ->dirty_folio() call, so I think
> something would need to be done about that case too.
I traced that code path down into iov_iter_extract_user_pages() which
calls pin_user_pages_fast(), so I do think the pages you're talking
about are pinned and would be handled through page_mkwrite() already.
iomap_dio_rw
__iomap_dio_rw
iomap_dio_iter
iomap_dio_bio_iter
iomap_dio_bio_iter_one
bio_iov_iter_get_pages
iov_iter_extract_bvecs
iov_iter_extract_pages
iov_iter_extract_user_pages
> I believe you saw this patch since it was your idea for us to use
> ->dirty_folio(), but just for reference for anyone else who didn't see
> it, the btrfs patch adding ->dirty_folio():
> https://lore.kernel.org/linux-btrfs/69d0043e0f6a3d17048dfde857127ab0bf331154.1785190866.git.boris@bur.io/
Yes, I want you to be able to revert that patch ;-)
>
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-24 19:08 Removing ->dirty_folio Matthew Wilcox
` (2 preceding siblings ...)
2026-08-24 21:27 ` Boris Burkov
@ 2026-08-24 22:38 ` Qu Wenruo
2026-08-25 19:26 ` Matthew Wilcox
2026-08-25 6:48 ` David Howells
` (3 subsequent siblings)
7 siblings, 1 reply; 27+ messages in thread
From: Qu Wenruo @ 2026-08-24 22:38 UTC (permalink / raw)
To: Matthew Wilcox, Pedro Falcato, Christoph Hellwig, Jann Horn,
David Howells, John Hubbard, Jan Kara, Rik van Riel, Qu Wenruo,
Darrick J. Wong, linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
在 2026/8/25 04:38, Matthew Wilcox 写道:
> I think it's time to remove folio_mark_dirty(), ->dirty_folio() and so on.
>
> This is not how filesystems want to be informed of folio dirtying.
> It was fine for ext2, but anything that's journalled or COW has work
> to do before the folio is made dirty, and it's hard to do that work
> under the page table spinlock (not all callers hold that lock, but the
> filesystem has to be able to handle the cases where it is.
>
> Filesystems want the page_mkwrite() entry point to be how they find out
> about a folio being dirtied -- and that works great! Except that we
> can writeback the folio for a number of reasons. If it's been dirtied
> due to a shared writable mmap, that's fine; we map the folio read-only
> and any subsequent writes will re-enter the page_mkwrite path.
That's exactly my previous expectation, really hope this can become true.
>
> The problem is GUP. We have no way to force the GUP caller to go
> through page_mkwrite again. So instead we make the GUP caller call
> folio_mark_dirty_lock() which many just don't, and generally we get away
> with it. But it's a bug, and a bad interface.
>
> There's also the problem that GUP users bypass the folio_wait_stable()
> mechanism. If a page is written to while somebody is creating a
> checksum over that page, the checksum will be corrupted. If we want
> to fix this, we have to bounce-buffer the page. There's no way to
> prevent or delay a GUP user from writing to the page. Enjoy your RAID.
>
> My proposal is this:
>
> - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> If it's true, do the writeback, but retain/recreate whatever data
> structures you need in order to write the folio again; behave as if
> ->page_mkdirty() had been called again for each page in the folio is
> marked as dirty.
This may make COW more complex.
For folio_maybe_dma_pinned() case, we will need to do extra space
reservation similar to page_mkdirty() again, so that the folio can be
written back again.
I'm not sure if we will have a good timing for re-reserving space inside
btrfs.
Would it be possible for MM/VFS layer to trigger page_mkdirty() instead?
> - The MM behaves similarly; we do not clear the writeback flag for
> folio_maybe_dma_pinned().
>
> This will have the effect of writing pinned folios back every time the
> inode is scheduled for writeback. But since we have no idea whether
> the folio is actually dirty (because the GUP user won't tell us),
> this is the correct behaviour.
>
> I'm probably missing some stuff here. Let me know.
>
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: Removing ->dirty_folio
2026-08-24 22:38 ` Qu Wenruo
@ 2026-08-25 19:26 ` Matthew Wilcox
2026-08-25 22:33 ` Qu Wenruo
2026-08-26 8:01 ` Christoph Hellwig
0 siblings, 2 replies; 27+ messages in thread
From: Matthew Wilcox @ 2026-08-25 19:26 UTC (permalink / raw)
To: Qu Wenruo
Cc: Pedro Falcato, Christoph Hellwig, Jann Horn, David Howells,
John Hubbard, Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong,
linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
On Tue, Aug 25, 2026 at 08:08:48AM +0930, Qu Wenruo wrote:
> > The problem is GUP. We have no way to force the GUP caller to go
> > through page_mkwrite again. So instead we make the GUP caller call
> > folio_mark_dirty_lock() which many just don't, and generally we get away
> > with it. But it's a bug, and a bad interface.
> >
> > There's also the problem that GUP users bypass the folio_wait_stable()
> > mechanism. If a page is written to while somebody is creating a
> > checksum over that page, the checksum will be corrupted. If we want
> > to fix this, we have to bounce-buffer the page. There's no way to
> > prevent or delay a GUP user from writing to the page. Enjoy your RAID.
> >
> > My proposal is this:
> >
> > - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> > If it's true, do the writeback, but retain/recreate whatever data
> > structures you need in order to write the folio again; behave as if
> > ->page_mkdirty() had been called again for each page in the folio is
> > marked as dirty.
>
> This may make COW more complex.
It's probably wise to be explicit when talking about COW. Anyone from
the MM side of the house is probably thinking "but this is only relevant
for shared writable mmap and we don't do a COW". You're talking about
filesystems doing a COW of the on-disc data, not about the MM COWing the
pagecache page into an anonymous page.
> For folio_maybe_dma_pinned() case, we will need to do extra space
> reservation similar to page_mkdirty() again, so that the folio can be
> written back again.
Yes, you will.
> I'm not sure if we will have a good timing for re-reserving space inside
> btrfs.
Why is it hard to do it immediately at writeback time? I think you're
in an even less restrictive locking environment than page_mkwrite is
called in because you're not under any MM locks. According to
Documentation/filesystems/locking.rst, ->writepages is called with
absolutely no locks held.
> Would it be possible for MM/VFS layer to trigger page_mkdirty() instead?
Actually ... no, because the VFS no longer knows which pages in the
folio are dirty. That's information the MM had, and communicated to
the FS which (if it cares) has stored in its folio->private. But the
VFS no longer has access to that information.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-25 19:26 ` Matthew Wilcox
@ 2026-08-25 22:33 ` Qu Wenruo
2026-08-26 4:53 ` Christoph Hellwig
2026-08-26 8:01 ` Christoph Hellwig
1 sibling, 1 reply; 27+ messages in thread
From: Qu Wenruo @ 2026-08-25 22:33 UTC (permalink / raw)
To: Matthew Wilcox, Qu Wenruo
Cc: Pedro Falcato, Christoph Hellwig, Jann Horn, David Howells,
John Hubbard, Jan Kara, Rik van Riel, Darrick J. Wong,
linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
在 2026/8/26 04:56, Matthew Wilcox 写道:
> On Tue, Aug 25, 2026 at 08:08:48AM +0930, Qu Wenruo wrote:
>>> The problem is GUP. We have no way to force the GUP caller to go
>>> through page_mkwrite again. So instead we make the GUP caller call
>>> folio_mark_dirty_lock() which many just don't, and generally we get away
>>> with it. But it's a bug, and a bad interface.
>>>
>>> There's also the problem that GUP users bypass the folio_wait_stable()
>>> mechanism. If a page is written to while somebody is creating a
>>> checksum over that page, the checksum will be corrupted. If we want
>>> to fix this, we have to bounce-buffer the page. There's no way to
>>> prevent or delay a GUP user from writing to the page. Enjoy your RAID.
>>>
>>> My proposal is this:
>>>
>>> - Fileystems take note of folio_maybe_dma_pinned() during writeback.
>>> If it's true, do the writeback, but retain/recreate whatever data
>>> structures you need in order to write the folio again; behave as if
>>> ->page_mkdirty() had been called again for each page in the folio is
>>> marked as dirty.
>>
>> This may make COW more complex.
>
> It's probably wise to be explicit when talking about COW. Anyone from
> the MM side of the house is probably thinking "but this is only relevant
> for shared writable mmap and we don't do a COW". You're talking about
> filesystems doing a COW of the on-disc data, not about the MM COWing the
> pagecache page into an anonymous page.
>
>> For folio_maybe_dma_pinned() case, we will need to do extra space
>> reservation similar to page_mkdirty() again, so that the folio can be
>> written back again.
>
> Yes, you will.
>
>> I'm not sure if we will have a good timing for re-reserving space inside
>> btrfs.
>
> Why is it hard to do it immediately at writeback time? I think you're
> in an even less restrictive locking environment than page_mkwrite is
> called in because you're not under any MM locks. According to
> Documentation/filesystems/locking.rst, ->writepages is called with
> absolutely no locks held.
This space reservation problem is a btrfs specific problem.
The root problem here is, btrfs space reservation can trigger
writeback/transaction commit.
This is due to the data/metadata COW nature, and that's why we rely
completely on buffered write to do space reservation, and avoid any
extra space reservation at writeback time.
This is also why we have the complex fixup mechanism, to avoid writing
the folio that needs fixup, but queue it for space reservation.
Other than other fses to do the space reservation at writeback time.
I believe since we have some space reservation for no-wait writes, it
can be slightly simplified using no-wait reservation (aka, reserve
during writeback), but it has a much higher chance to hit ENOSPC.
Although I think on the long run, as long as we want to migrate to
iomap, we should find out a proper way to address this problem.
>
>> Would it be possible for MM/VFS layer to trigger page_mkdirty() instead?
>
> Actually ... no, because the VFS no longer knows which pages in the
> folio are dirty. That's information the MM had, and communicated to
> the FS which (if it cares) has stored in its folio->private. But the
> VFS no longer has access to that information.
>
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-25 22:33 ` Qu Wenruo
@ 2026-08-26 4:53 ` Christoph Hellwig
0 siblings, 0 replies; 27+ messages in thread
From: Christoph Hellwig @ 2026-08-26 4:53 UTC (permalink / raw)
To: Qu Wenruo
Cc: Matthew Wilcox, Qu Wenruo, Pedro Falcato, Christoph Hellwig,
Jann Horn, David Howells, John Hubbard, Jan Kara, Rik van Riel,
Darrick J. Wong, linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
On Wed, Aug 26, 2026 at 08:03:38AM +0930, Qu Wenruo wrote:
>> Why is it hard to do it immediately at writeback time? I think you're
>> in an even less restrictive locking environment than page_mkwrite is
>> called in because you're not under any MM locks. According to
>> Documentation/filesystems/locking.rst, ->writepages is called with
>> absolutely no locks held.
>
> This space reservation problem is a btrfs specific problem.
Not entirely. It really is an issue for everyone doing (forced) out of
place writes.
> The root problem here is, btrfs space reservation can trigger
> writeback/transaction commit.
While zoned xfs doesn't actively trigger it, it still has to wait
for the GC daemon, so we're in exactly the same boat here. The
space reservation has to be done without VFS locks, and in the
rare cases where we can't do that (->setattr for an unaligned
truncate) we have to play with fire and dip into a reserved pool.
It has been on my TODO list to fix up the VFS interfaces for
that to be called without locks held.
> This is due to the data/metadata COW nature, and that's why we rely
> completely on buffered write to do space reservation, and avoid any extra
> space reservation at writeback time.
That's the only sane thing to do, as at writeback time it is too late
to reserve space.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-25 19:26 ` Matthew Wilcox
2026-08-25 22:33 ` Qu Wenruo
@ 2026-08-26 8:01 ` Christoph Hellwig
1 sibling, 0 replies; 27+ messages in thread
From: Christoph Hellwig @ 2026-08-26 8:01 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Qu Wenruo, Pedro Falcato, Christoph Hellwig, Jann Horn,
David Howells, John Hubbard, Jan Kara, Rik van Riel, Qu Wenruo,
Darrick J. Wong, linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
On Tue, Aug 25, 2026 at 08:26:56PM +0100, Matthew Wilcox wrote:
> > > ->page_mkdirty() had been called again for each page in the folio is
> > > marked as dirty.
> >
> > This may make COW more complex.
>
> It's probably wise to be explicit when talking about COW. Anyone from
> the MM side of the house is probably thinking "but this is only relevant
> for shared writable mmap and we don't do a COW". You're talking about
> filesystems doing a COW of the on-disc data, not about the MM COWing the
> pagecache page into an anonymous page.
Heh. There's way too many COWs around (says that one on vacation
all around lower case cows).
> > I'm not sure if we will have a good timing for re-reserving space inside
> > btrfs.
>
> Why is it hard to do it immediately at writeback time? I think you're
> in an even less restrictive locking environment than page_mkwrite is
> called in because you're not under any MM locks. According to
> Documentation/filesystems/locking.rst, ->writepages is called with
> absolutely no locks held.
Re-reserving can fail. So if we want to be fail-safe we need to do
it ahead of time. Then again as per my other mail we might only
have to do it for long-term pins where the place of dirtying is
explicitly controlled.
>
> > Would it be possible for MM/VFS layer to trigger page_mkdirty() instead?
>
> Actually ... no, because the VFS no longer knows which pages in the
> folio are dirty. That's information the MM had, and communicated to
> the FS which (if it cares) has stored in its folio->private. But the
> VFS no longer has access to that information.
All of this is quite a mess. We'd need to allocate it a head of time
to be safe, but for that the file system would have to manage
multiple overlapping reservations for the same region of the file.
Which I don't think anyone does right now.
For RDMA/HMM we might be able to tell the file system ahead of
time with some rework, but none of these good ideas are going to
work for vmsplice. So the only option is to grab space from
a reserved pool covering the max writeback size, which can be
refilled when freeing them. Assuming we can actually free them
an no one took a snapshot permanently pinning the old blocks in
the meantime.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-24 19:08 Removing ->dirty_folio Matthew Wilcox
` (3 preceding siblings ...)
2026-08-24 22:38 ` Qu Wenruo
@ 2026-08-25 6:48 ` David Howells
2026-08-25 19:16 ` Matthew Wilcox
2026-08-25 7:39 ` Christoph Hellwig
` (2 subsequent siblings)
7 siblings, 1 reply; 27+ messages in thread
From: David Howells @ 2026-08-25 6:48 UTC (permalink / raw)
To: Matthew Wilcox
Cc: dhowells, Pedro Falcato, Christoph Hellwig, Jann Horn,
John Hubbard, Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong,
linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
Matthew Wilcox <willy@infradead.org> wrote:
> I'm probably missing some stuff here. Let me know.
mmap()? That usually tosses a spanner in somewhere.
David
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: Removing ->dirty_folio
2026-08-25 6:48 ` David Howells
@ 2026-08-25 19:16 ` Matthew Wilcox
0 siblings, 0 replies; 27+ messages in thread
From: Matthew Wilcox @ 2026-08-25 19:16 UTC (permalink / raw)
To: David Howells
Cc: Pedro Falcato, Christoph Hellwig, Jann Horn, John Hubbard,
Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On Tue, Aug 25, 2026 at 07:48:06AM +0100, David Howells wrote:
> Matthew Wilcox <willy@infradead.org> wrote:
>
> > I'm probably missing some stuff here. Let me know.
>
> mmap()? That usually tosses a spanner in somewhere.
Well, you have to have mmap()ed a file for GUP to be able to happen.
And it has to be shared writable for us to care about writeback.
The nice thing about GUP is that it goes through the normal fault
handler path. The nasty thing about GUP is that we don't have a way to
revoke a GUP access to that page like we do through page tables.
>
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-24 19:08 Removing ->dirty_folio Matthew Wilcox
` (4 preceding siblings ...)
2026-08-25 6:48 ` David Howells
@ 2026-08-25 7:39 ` Christoph Hellwig
2026-08-25 19:14 ` Matthew Wilcox
2026-08-25 8:25 ` Pedro Falcato
2026-08-25 19:35 ` Jann Horn
7 siblings, 1 reply; 27+ messages in thread
From: Christoph Hellwig @ 2026-08-25 7:39 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Pedro Falcato, Christoph Hellwig, Jann Horn, David Howells,
John Hubbard, Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong,
linux-btrfs, linux-fsdevel, linux-mm, linux-xfs
On Mon, Aug 24, 2026 at 08:08:06PM +0100, Matthew Wilcox wrote:
> My proposal is this:
>
> - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> If it's true, do the writeback, but retain/recreate whatever data
> structures you need in order to write the folio again; behave as if
> ->page_mkdirty() had been called again for each page in the folio is
> marked as dirty.
> - The MM behaves similarly; we do not clear the writeback flag for
> folio_maybe_dma_pinned().
>
> This will have the effect of writing pinned folios back every time the
> inode is scheduled for writeback. But since we have no idea whether
> the folio is actually dirty (because the GUP user won't tell us),
> this is the correct behaviour.
>
> I'm probably missing some stuff here. Let me know.
We've been through this a few times, I remember me and Jan discussing
it maybe a year or so on the list last. This is what I remember:
- the best thing would be to just not write folio_maybe_dma_pinned
folios at all. Jan brought up cases where that might not be
possible, so we might have to write anyway. IIRC the major
one is that we actually do allow FOLL_LONGTERM even on file
backed mappings, and those could be pinned forever.
- when we write them anyway we really have to bounce buffer the
data. Basically copy and do something like in-kernel direct I/O
- Even that can be tricky, because we'd still need a space reservation
for that write at it would otherwise consume the space reservation
at dirty time, but we still might have to write it again. One
option might be to only do the force bounce buffer write for
FOLL_LONGTERM as the others should go away, and FOLL_LONGTERM
gets a call into the fs to reserve extra space. This would not
be enough for a lot of writes, but enough to allow for
"bank switching" over GC cycles.
So, not perfect, but probably better than the status quo. But a lot
of work that someone needs to do for being a bit better than the
status quo.
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: Removing ->dirty_folio
2026-08-25 7:39 ` Christoph Hellwig
@ 2026-08-25 19:14 ` Matthew Wilcox
0 siblings, 0 replies; 27+ messages in thread
From: Matthew Wilcox @ 2026-08-25 19:14 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Pedro Falcato, Jann Horn, David Howells, John Hubbard, Jan Kara,
Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On Tue, Aug 25, 2026 at 09:39:18AM +0200, Christoph Hellwig wrote:
> On Mon, Aug 24, 2026 at 08:08:06PM +0100, Matthew Wilcox wrote:
> > My proposal is this:
> >
> > - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> > If it's true, do the writeback, but retain/recreate whatever data
> > structures you need in order to write the folio again; behave as if
> > ->page_mkdirty() had been called again for each page in the folio is
> > marked as dirty.
> > - The MM behaves similarly; we do not clear the writeback flag for
> > folio_maybe_dma_pinned().
> >
> > This will have the effect of writing pinned folios back every time the
> > inode is scheduled for writeback. But since we have no idea whether
> > the folio is actually dirty (because the GUP user won't tell us),
> > this is the correct behaviour.
> >
> > I'm probably missing some stuff here. Let me know.
>
> We've been through this a few times, I remember me and Jan discussing
> it maybe a year or so on the list last. This is what I remember:
>
> - the best thing would be to just not write folio_maybe_dma_pinned
> folios at all. Jan brought up cases where that might not be
> possible, so we might have to write anyway. IIRC the major
> one is that we actually do allow FOLL_LONGTERM even on file
> backed mappings, and those could be pinned forever.
> - when we write them anyway we really have to bounce buffer the
> data. Basically copy and do something like in-kernel direct I/O
> - Even that can be tricky, because we'd still need a space reservation
> for that write at it would otherwise consume the space reservation
> at dirty time, but we still might have to write it again. One
> option might be to only do the force bounce buffer write for
> FOLL_LONGTERM as the others should go away, and FOLL_LONGTERM
> gets a call into the fs to reserve extra space. This would not
> be enough for a lot of writes, but enough to allow for
> "bank switching" over GC cycles.
>
> So, not perfect, but probably better than the status quo. But a lot
> of work that someone needs to do for being a bit better than the
> status quo.
Thanks for summarising the previous discussion. I understand what
you're saying about the space reservation; that's why we have to
bring filesystems into the conversation rather than doing it entireely
within the VFS. They have to know that they must create a new space
reservation immediately after writing back this folio. That should
be feasible in the writeback path because we're not under any mad
locking scheme like holding the PTL.
I think the only disagreement I have is about the upsides:
- Filesystems no longer need to implement ->dirty_folio()
- The page pinning API becomes a bit easier to use (no need to call
folio_mark_dirty() / folio_mark_dirty_locked())
I'm just trying to figure out if we can do this in small chunks, or
if we have to do the whole thing at once.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-24 19:08 Removing ->dirty_folio Matthew Wilcox
` (5 preceding siblings ...)
2026-08-25 7:39 ` Christoph Hellwig
@ 2026-08-25 8:25 ` Pedro Falcato
2026-08-25 18:35 ` Matthew Wilcox
2026-08-25 19:35 ` Jann Horn
7 siblings, 1 reply; 27+ messages in thread
From: Pedro Falcato @ 2026-08-25 8:25 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Christoph Hellwig, Jann Horn, David Howells, John Hubbard,
Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On Mon, Aug 24, 2026 at 08:08:06PM +0100, Matthew Wilcox wrote:
> I think it's time to remove folio_mark_dirty(), ->dirty_folio() and so on.
>
> This is not how filesystems want to be informed of folio dirtying.
> It was fine for ext2, but anything that's journalled or COW has work
> to do before the folio is made dirty, and it's hard to do that work
> under the page table spinlock (not all callers hold that lock, but the
> filesystem has to be able to handle the cases where it is.
>
> Filesystems want the page_mkwrite() entry point to be how they find out
> about a folio being dirtied -- and that works great! Except that we
> can writeback the folio for a number of reasons. If it's been dirtied
> due to a shared writable mmap, that's fine; we map the folio read-only
> and any subsequent writes will re-enter the page_mkwrite path.
>
> The problem is GUP. We have no way to force the GUP caller to go
> through page_mkwrite again. So instead we make the GUP caller call
> folio_mark_dirty_lock() which many just don't, and generally we get away
> with it. But it's a bug, and a bad interface.
>
> There's also the problem that GUP users bypass the folio_wait_stable()
> mechanism. If a page is written to while somebody is creating a
> checksum over that page, the checksum will be corrupted. If we want
> to fix this, we have to bounce-buffer the page. There's no way to
> prevent or delay a GUP user from writing to the page. Enjoy your RAID.
>
> My proposal is this:
>
> - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> If it's true, do the writeback, but retain/recreate whatever data
> structures you need in order to write the folio again; behave as if
> ->page_mkdirty() had been called again for each page in the folio is
I don't think you can do this for stable writes. It's probably ok for
!stable writes filesystem stacks, as long as the filesystem & writeback
can handle making no progress at all. But since stable writes' writeback
can't race with "writes", I don't think you can Just Do It as long as the
folio is DMA pinned.
Perhaps we should give up trying to writeback these folios, and start
writeback right after they're unpinned? at least on the stable case.
> marked as dirty.
> - The MM behaves similarly; we do not clear the writeback flag for
> folio_maybe_dma_pinned().
This sounds like a problem. You don't want users expecting writeback to make
progress to suddenly stall on e.g folio_wait_writeback() indefinitely.
>
> This will have the effect of writing pinned folios back every time the
> inode is scheduled for writeback. But since we have no idea whether
> the folio is actually dirty (because the GUP user won't tell us),
> this is the correct behaviour.
>
> I'm probably missing some stuff here. Let me know.
I don't quite understand what your plan for getting rid of dirty_folio,
et al is. page_mkwrite has the fatal flaw of being directly tied to VM
page faults; I don't think it's the ideal interface for notifying filesystems.
It's also the case that page_mkwrite can trivially sleep, and GUP calls it under
the PTE lock. So how can we replace that? Would callers need to manually dirty
folios after GUP, in process context?
--
Pedro
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: Removing ->dirty_folio
2026-08-25 8:25 ` Pedro Falcato
@ 2026-08-25 18:35 ` Matthew Wilcox
0 siblings, 0 replies; 27+ messages in thread
From: Matthew Wilcox @ 2026-08-25 18:35 UTC (permalink / raw)
To: Pedro Falcato
Cc: Christoph Hellwig, Jann Horn, David Howells, John Hubbard,
Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On Tue, Aug 25, 2026 at 09:25:53AM +0100, Pedro Falcato wrote:
> On Mon, Aug 24, 2026 at 08:08:06PM +0100, Matthew Wilcox wrote:
> > I think it's time to remove folio_mark_dirty(), ->dirty_folio() and so on.
> >
> > This is not how filesystems want to be informed of folio dirtying.
> > It was fine for ext2, but anything that's journalled or COW has work
> > to do before the folio is made dirty, and it's hard to do that work
> > under the page table spinlock (not all callers hold that lock, but the
> > filesystem has to be able to handle the cases where it is.
> >
> > Filesystems want the page_mkwrite() entry point to be how they find out
> > about a folio being dirtied -- and that works great! Except that we
> > can writeback the folio for a number of reasons. If it's been dirtied
> > due to a shared writable mmap, that's fine; we map the folio read-only
> > and any subsequent writes will re-enter the page_mkwrite path.
> >
> > The problem is GUP. We have no way to force the GUP caller to go
> > through page_mkwrite again. So instead we make the GUP caller call
> > folio_mark_dirty_lock() which many just don't, and generally we get away
> > with it. But it's a bug, and a bad interface.
> >
> > There's also the problem that GUP users bypass the folio_wait_stable()
> > mechanism. If a page is written to while somebody is creating a
> > checksum over that page, the checksum will be corrupted. If we want
> > to fix this, we have to bounce-buffer the page. There's no way to
> > prevent or delay a GUP user from writing to the page. Enjoy your RAID.
> >
> > My proposal is this:
> >
> > - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> > If it's true, do the writeback, but retain/recreate whatever data
> > structures you need in order to write the folio again; behave as if
> > ->page_mkdirty() had been called again for each page in the folio is
>
> I don't think you can do this for stable writes. It's probably ok for
> !stable writes filesystem stacks, as long as the filesystem & writeback
> can handle making no progress at all. But since stable writes' writeback
> can't race with "writes", I don't think you can Just Do It as long as the
> folio is DMA pinned.
Ah, yes, I forgot to specify that. For mappings which need stable pages,
we have to bounce buffer them. I wonder if that's something we should
do inside the VFS or if each filesystem should try to do it itself?
> Perhaps we should give up trying to writeback these folios, and start
> writeback right after they're unpinned? at least on the stable case.
The thing is, what do we do for somebody calling fsync()? I don't
think that "Oh, sorry, someone gave its address to an RDMA device
so we just didn't bother" is acceptable as an answer.
> > marked as dirty.
> > - The MM behaves similarly; we do not clear the writeback flag for
> > folio_maybe_dma_pinned().
>
> This sounds like a problem. You don't want users expecting writeback to make
> progress to suddenly stall on e.g folio_wait_writeback() indefinitely.
I should have written "the dirty flag" there. I do not propose to keep
the writeback flag set indefinitely; it should be cleared after I/O has
completed, as it is now.
> I don't quite understand what your plan for getting rid of dirty_folio,
> et al is. page_mkwrite has the fatal flaw of being directly tied to VM
> page faults; I don't think it's the ideal interface for notifying filesystems.
> It's also the case that page_mkwrite can trivially sleep, and GUP calls it under
> the PTE lock. So how can we replace that? Would callers need to manually dirty
> folios after GUP, in process context?
GUP doesn't call page_mkwrite() under the PTL. See my reply to John,
or just look at do_page_mkwrite():
* We do this without the lock held, so that it can sleep if it needs to.
*/
static vm_fault_t do_page_mkwrite(struct vm_fault *vmf, struct folio *folio)
folio_mark_dirty() is called under the PTE lock. My point is that (with
the proposed changes) we won't need to call it in zap_present_folio_ptes()
because the filesystem will already know that this page is dirty.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-24 19:08 Removing ->dirty_folio Matthew Wilcox
` (6 preceding siblings ...)
2026-08-25 8:25 ` Pedro Falcato
@ 2026-08-25 19:35 ` Jann Horn
2026-08-25 19:54 ` Matthew Wilcox
7 siblings, 1 reply; 27+ messages in thread
From: Jann Horn @ 2026-08-25 19:35 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Pedro Falcato, Christoph Hellwig, David Howells, John Hubbard,
Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On Mon, Aug 24, 2026 at 9:08 PM Matthew Wilcox <willy@infradead.org> wrote:
> I think it's time to remove folio_mark_dirty(), ->dirty_folio() and so on.
>
> This is not how filesystems want to be informed of folio dirtying.
> It was fine for ext2, but anything that's journalled or COW has work
> to do before the folio is made dirty, and it's hard to do that work
> under the page table spinlock (not all callers hold that lock, but the
> filesystem has to be able to handle the cases where it is.
>
> Filesystems want the page_mkwrite() entry point to be how they find out
> about a folio being dirtied -- and that works great! Except that we
> can writeback the folio for a number of reasons. If it's been dirtied
> due to a shared writable mmap, that's fine; we map the folio read-only
> and any subsequent writes will re-enter the page_mkwrite path.
>
> The problem is GUP. We have no way to force the GUP caller to go
> through page_mkwrite again. So instead we make the GUP caller call
> folio_mark_dirty_lock() which many just don't, and generally we get away
> with it. But it's a bug, and a bad interface.
We currently have get_user_pages*() and pin_user_pages*(), where only
the pin_*() version is properly usable for write access, right? And
dropping such pins should always go through unpin_*() helpers?
Could we strictly ban using get_user_pages*() for write access, and
use the unpin_*() helpers to somehow enforce that folios are always
dirtied on unpin? I guess the problem with that is that we have no
state that tracks whether the pin was read-only, and finding free bits
in struct page to keep track of this is hard?
> There's also the problem that GUP users bypass the folio_wait_stable()
> mechanism. If a page is written to while somebody is creating a
> checksum over that page, the checksum will be corrupted. If we want
> to fix this, we have to bounce-buffer the page. There's no way to
> prevent or delay a GUP user from writing to the page. Enjoy your RAID.
>
> My proposal is this:
>
> - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> If it's true, do the writeback, but retain/recreate whatever data
> structures you need in order to write the folio again; behave as if
> ->page_mkdirty() had been called again for each page in the folio is
> marked as dirty.
I don't understand this part of the MM/VFS machinery well - would this
mean that a long-term pin of a dirty pagecache folio could cause an
unbounded number of disk writes in regular intervals, even if nothing
actually writes into the folio? I'm guessing that could be bad for
cheap flash storage, but maybe this is in the category of "yes that
would be bad but it would be userspace's fault".
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: Removing ->dirty_folio
2026-08-25 19:35 ` Jann Horn
@ 2026-08-25 19:54 ` Matthew Wilcox
2026-08-25 20:06 ` Jann Horn
2026-08-26 5:07 ` Christoph Hellwig
0 siblings, 2 replies; 27+ messages in thread
From: Matthew Wilcox @ 2026-08-25 19:54 UTC (permalink / raw)
To: Jann Horn
Cc: Pedro Falcato, Christoph Hellwig, David Howells, John Hubbard,
Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On Tue, Aug 25, 2026 at 09:35:57PM +0200, Jann Horn wrote:
> > The problem is GUP. We have no way to force the GUP caller to go
> > through page_mkwrite again. So instead we make the GUP caller call
> > folio_mark_dirty_lock() which many just don't, and generally we get away
> > with it. But it's a bug, and a bad interface.
>
> We currently have get_user_pages*() and pin_user_pages*(), where only
> the pin_*() version is properly usable for write access, right? And
> dropping such pins should always go through unpin_*() helpers?
Right. I'm stuffing cheese into my ears and pretending that people
aren't calling get_user_pages() to do write accesses. We should be
able to use this work to flush out the last remaining ones -- we
can put in various assertions that folios should still be dirty where
we currently have folio_mark_dirty() calls.
> Could we strictly ban using get_user_pages*() for write access, and
> use the unpin_*() helpers to somehow enforce that folios are always
> dirtied on unpin? I guess the problem with that is that we have no
> state that tracks whether the pin was read-only, and finding free bits
> in struct page to keep track of this is hard?
We'd need a count, not just a bit or two. A pincount for all folios
is on its way (eventually) but I wans't planning on tracking writable vs
read-only pins.
> > My proposal is this:
> >
> > - Fileystems take note of folio_maybe_dma_pinned() during writeback.
> > If it's true, do the writeback, but retain/recreate whatever data
> > structures you need in order to write the folio again; behave as if
> > ->page_mkdirty() had been called again for each page in the folio is
> > marked as dirty.
>
> I don't understand this part of the MM/VFS machinery well - would this
> mean that a long-term pin of a dirty pagecache folio could cause an
> unbounded number of disk writes in regular intervals, even if nothing
> actually writes into the folio? I'm guessing that could be bad for
> cheap flash storage, but maybe this is in the category of "yes that
> would be bad but it would be userspace's fault".
Yes. I think the only alternative would be storing a checksum of the
contents of the folio and seeing if it changed since the last write.
As you say, this is userspace doing something incredibly odd (I really
don't think people make a habit of mmap()ing files shared writable and
then giving RDMA longterm write accesses to them. Not on machines with
poor quality flash storage anyway).
Or we could say "these pages only get written back on requested fsync()
rather than periodically".
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-25 19:54 ` Matthew Wilcox
@ 2026-08-25 20:06 ` Jann Horn
2026-08-26 0:02 ` Matthew Wilcox
2026-08-26 5:07 ` Christoph Hellwig
1 sibling, 1 reply; 27+ messages in thread
From: Jann Horn @ 2026-08-25 20:06 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Pedro Falcato, Christoph Hellwig, David Howells, John Hubbard,
Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On Tue, Aug 25, 2026 at 9:54 PM Matthew Wilcox <willy@infradead.org> wrote:
> On Tue, Aug 25, 2026 at 09:35:57PM +0200, Jann Horn wrote:
> > Could we strictly ban using get_user_pages*() for write access, and
> > use the unpin_*() helpers to somehow enforce that folios are always
> > dirtied on unpin? I guess the problem with that is that we have no
> > state that tracks whether the pin was read-only, and finding free bits
> > in struct page to keep track of this is hard?
>
> We'd need a count, not just a bit or two. A pincount for all folios
> is on its way (eventually) but I wans't planning on tracking writable vs
> read-only pins.
My thinking was that once a folio has been pinned writably one time,
it should be fine to mark it as dirty every time it is unpinned, even
if some of those pins were read-only?
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-25 20:06 ` Jann Horn
@ 2026-08-26 0:02 ` Matthew Wilcox
0 siblings, 0 replies; 27+ messages in thread
From: Matthew Wilcox @ 2026-08-26 0:02 UTC (permalink / raw)
To: Jann Horn
Cc: Pedro Falcato, Christoph Hellwig, David Howells, John Hubbard,
Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong, linux-btrfs,
linux-fsdevel, linux-mm, linux-xfs
On Tue, Aug 25, 2026 at 10:06:30PM +0200, Jann Horn wrote:
> On Tue, Aug 25, 2026 at 9:54 PM Matthew Wilcox <willy@infradead.org> wrote:
> > On Tue, Aug 25, 2026 at 09:35:57PM +0200, Jann Horn wrote:
> > > Could we strictly ban using get_user_pages*() for write access, and
> > > use the unpin_*() helpers to somehow enforce that folios are always
> > > dirtied on unpin? I guess the problem with that is that we have no
> > > state that tracks whether the pin was read-only, and finding free bits
> > > in struct page to keep track of this is hard?
> >
> > We'd need a count, not just a bit or two. A pincount for all folios
> > is on its way (eventually) but I wans't planning on tracking writable vs
> > read-only pins.
>
> My thinking was that once a folio has been pinned writably one time,
> it should be fine to mark it as dirty every time it is unpinned, even
> if some of those pins were read-only?
Ah, so the point of this proposal is to mark the folio dirty when it's
pinned. Nobody clears the dirty flag at any point until it's written
back after being unpinned.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-25 19:54 ` Matthew Wilcox
2026-08-25 20:06 ` Jann Horn
@ 2026-08-26 5:07 ` Christoph Hellwig
2026-08-26 7:42 ` Christoph Hellwig
1 sibling, 1 reply; 27+ messages in thread
From: Christoph Hellwig @ 2026-08-26 5:07 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Jann Horn, Pedro Falcato, Christoph Hellwig, David Howells,
John Hubbard, Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong,
linux-btrfs, linux-fsdevel, linux-mm, linux-xfs, linux-rdma,
Leon Romanovsky, Jason Gunthorpe
[adding rdma/hmm folks]
On Tue, Aug 25, 2026 at 08:54:25PM +0100, Matthew Wilcox wrote:
> On Tue, Aug 25, 2026 at 09:35:57PM +0200, Jann Horn wrote:
> > > The problem is GUP. We have no way to force the GUP caller to go
> > > through page_mkwrite again. So instead we make the GUP caller call
> > > folio_mark_dirty_lock() which many just don't, and generally we get away
> > > with it. But it's a bug, and a bad interface.
> >
> > We currently have get_user_pages*() and pin_user_pages*(), where only
> > the pin_*() version is properly usable for write access, right? And
> > dropping such pins should always go through unpin_*() helpers?
>
> Right. I'm stuffing cheese into my ears and pretending that people
> aren't calling get_user_pages() to do write accesses. We should be
> able to use this work to flush out the last remaining ones -- we
> can put in various assertions that folios should still be dirty where
> we currently have folio_mark_dirty() calls.
Last time I checked quite a few places still did. Including various
network file system O_DIRECT implementations (some got fixed, and
for NFS a series is outstanding) and some really odd looking networking
code.
I wish we could somehow force them to stop doing that, but I can't
think of any.
> Yes. I think the only alternative would be storing a checksum of the
> contents of the folio and seeing if it changed since the last write.
> As you say, this is userspace doing something incredibly odd (I really
> don't think people make a habit of mmap()ing files shared writable and
> then giving RDMA longterm write accesses to them. Not on machines with
> poor quality flash storage anyway).
>
> Or we could say "these pages only get written back on requested fsync()
> rather than periodically".
Take one step back. For regular pins we should be able to just wait for
them given that they are by definition short lived, where short lived
is defined by typical I/O latency for a wide range of "typical".
We'll need the right helpers from the MM for that, and make sure
we have a good way to debug file system hangs caused by incorrect
use of the pinning, but all that is a solvable problem.
Splitting read vs write pincounts would be really helpful to reduce
the overhead of that.
The interesting case is FOLL_LONGTERM, as it can pin I/O for a much
longer time. And that also means IFF the user of FOLL_LONGTERM actually
wants to be able to persist data on a shared mmap, it has to manually
dirty folios one or more times during the FOLL_LONGTERM pin, because
otherwise the file system would never know there is dirty data.
The set_page_dirty call in ib_umem_odp_unmap_dma_pages is an example
for that.
So what we'll need is:
- a way for the file system to know if a dma pin on a folio is for a
short-term writable pin vs everything else.
- for the short term writable pin wait for it for data integrity syncs,
or otherwise just skip it.
- for FOLL_LONGTERM users we need an interface to (re-dirty) folios
while the long term pin persists. This also needs a way for the
file system to reserve space. Either as a rolling / bank switched
reservation for the whole life time of the mapping (although for
large mappings this might use up a lot of space), or to do that
ahead of whatever triggers the dirtying.
And maybe a way for file systems (or vm ops) to reject long
term writable pins if they don't want to deal with all this.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: Removing ->dirty_folio
2026-08-26 5:07 ` Christoph Hellwig
@ 2026-08-26 7:42 ` Christoph Hellwig
0 siblings, 0 replies; 27+ messages in thread
From: Christoph Hellwig @ 2026-08-26 7:42 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Jann Horn, Pedro Falcato, Christoph Hellwig, David Howells,
John Hubbard, Jan Kara, Rik van Riel, Qu Wenruo, Darrick J. Wong,
linux-btrfs, linux-fsdevel, linux-mm, linux-xfs, linux-rdma,
Leon Romanovsky, Jason Gunthorpe
On Wed, Aug 26, 2026 at 07:07:33AM +0200, Christoph Hellwig wrote:
> The interesting case is FOLL_LONGTERM, as it can pin I/O for a much
> longer time. And that also means IFF the user of FOLL_LONGTERM actually
> wants to be able to persist data on a shared mmap, it has to manually
> dirty folios one or more times during the FOLL_LONGTERM pin, because
> otherwise the file system would never know there is dirty data.
> The set_page_dirty call in ib_umem_odp_unmap_dma_pages is an example
> for that.
... not to forget the epic boss of this genre: vmsplice, which is also
still using get_user_pages_fast/FOLL_GET through iov_iter_get_pages2.
^ permalink raw reply [flat|nested] 27+ messages in thread