* Re: [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite()
2026-11-09 12:04 ` [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite() Kiryl Shutsemau (Meta)
@ 2026-11-09 14:11 ` Pedro Falcato
2026-11-09 14:40 ` Kiryl Shutsemau
2026-11-09 16:11 ` Lorenzo Stoakes (ARM)
` (2 subsequent siblings)
3 siblings, 1 reply; 16+ messages in thread
From: Pedro Falcato @ 2026-11-09 14:11 UTC (permalink / raw)
To: Kiryl Shutsemau (Meta)
Cc: Andrew Morton, David Hildenbrand (Arm), Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Matthew Wilcox (Oracle),
Hugh Dickins, Chris Mason, linux-mm, linux-fsdevel, linux-kernel,
kernel-team, Sashiko
On Mon, Nov 09, 2026 at 12:04:01PM +0000, Kiryl Shutsemau (Meta) wrote:
> do_shared_fault() unlocks the folio around ->page_mkwrite(). Writeback
> can lock it in that window, fail, and clear PG_uptodate with the folio
> left in the page cache. ecryptfs_writepages() does this when encryption
> fails. filemap_page_mkwrite() relocks the folio and checks only
> ->mapping, so the fault maps a folio that is not uptodate:
>
> CPU0 CPU1
> do_shared_fault()
> folio_unlock()
> ecryptfs_writepages()
> folio_clear_uptodate()
> filemap_page_mkwrite()
> folio_lock()
> finish_fault()
>
> The next read(2) or fault on the folio reads it in again from the file,
> over anything stored through the mapping in the meantime. Those stores
> are lost.
>
> Recheck PG_uptodate once ->page_mkwrite() returns with the folio locked,
> and retry the fault if it is clear, the same way filemap_fault() retries
> on a cached folio that lost PG_uptodate. Skip folios outside the page
> cache: driver pages from ->fault() never get PG_uptodate and would
> retry forever.
>
> The check stays out of do_page_mkwrite(): wp_page_shared() calls it on
> a folio that is still mapped, and a retry there would fault on the same
> PTE forever.
>
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/sashiko-outbox-202966@kernel.org/
> Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
> ---
> mm/memory.c | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/mm/memory.c b/mm/memory.c
> index fe72e66c9c2e..cc1d0b7d15c7 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -5613,6 +5613,18 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
> return VM_FAULT_OOM;
> }
>
> +/*
> + * A page cache folio that is not uptodate holds data that was never read in
> + * or cleared, and mapping it leaks stale memory to userspace.
> + */
> +static bool file_folio_not_uptodate(struct folio *folio)
> +{
> + if (likely(folio_test_uptodate(folio)))
> + return false;
> + /* Driver pages from ->fault() never get PG_uptodate */
> + return !folio_test_anon(folio) && folio->mapping;
FYI you can wrap this line in an unlikely() and it has the same effect as
wrapping every call:
return unlikely(!folio_test_anon(folio) && folio->mapping);
> +}
> +
> /*
> * Either the VMA lock or the mmap_lock must have been held on entry
> * (see FAULT_FLAG_VMA_LOCK) and may have been released depending on
> @@ -6163,6 +6175,16 @@ static vm_fault_t do_shared_fault(struct vm_fault *vmf)
> folio_put(folio);
> return tmp;
> }
> +
> + /*
> + * The folio was unlocked for ->page_mkwrite(). If it lost
> + * PG_uptodate meanwhile, retry the fault to read it in again.
> + */
The "read it in again" sounds a bit too prescriptive but, apart from that:
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Thanks!
--
Pedro
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite()
2026-11-09 14:11 ` Pedro Falcato
@ 2026-11-09 14:40 ` Kiryl Shutsemau
0 siblings, 0 replies; 16+ messages in thread
From: Kiryl Shutsemau @ 2026-11-09 14:40 UTC (permalink / raw)
To: Pedro Falcato
Cc: Andrew Morton, David Hildenbrand (Arm), Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Matthew Wilcox (Oracle),
Hugh Dickins, Chris Mason, linux-mm, linux-fsdevel, linux-kernel,
kernel-team, Sashiko
On Mon, Nov 09, 2026 at 02:11:23PM +0000, Pedro Falcato wrote:
> > diff --git a/mm/memory.c b/mm/memory.c
> > index fe72e66c9c2e..cc1d0b7d15c7 100644
> > --- a/mm/memory.c
> > +++ b/mm/memory.c
> > @@ -5613,6 +5613,18 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
> > return VM_FAULT_OOM;
> > }
> >
> > +/*
> > + * A page cache folio that is not uptodate holds data that was never read in
> > + * or cleared, and mapping it leaks stale memory to userspace.
> > + */
> > +static bool file_folio_not_uptodate(struct folio *folio)
> > +{
> > + if (likely(folio_test_uptodate(folio)))
> > + return false;
> > + /* Driver pages from ->fault() never get PG_uptodate */
> > + return !folio_test_anon(folio) && folio->mapping;
>
> FYI you can wrap this line in an unlikely() and it has the same effect as
> wrapping every call:
> return unlikely(!folio_test_anon(folio) && folio->mapping);
I prefer it at the call site. That is where the reader needs to see
that the retry is the rare path.
> > +}
> > +
> > /*
> > * Either the VMA lock or the mmap_lock must have been held on entry
> > * (see FAULT_FLAG_VMA_LOCK) and may have been released depending on
> > @@ -6163,6 +6175,16 @@ static vm_fault_t do_shared_fault(struct vm_fault *vmf)
> > folio_put(folio);
> > return tmp;
> > }
> > +
> > + /*
> > + * The folio was unlocked for ->page_mkwrite(). If it lost
> > + * PG_uptodate meanwhile, retry the fault to read it in again.
> > + */
>
> The "read it in again" sounds a bit too prescriptive but, apart from that:
Okay, will drop it if respin needed.
David, could you adjust it on apply otherwise?
> Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Thanks!
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite()
2026-11-09 12:04 ` [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite() Kiryl Shutsemau (Meta)
2026-11-09 14:11 ` Pedro Falcato
@ 2026-11-09 16:11 ` Lorenzo Stoakes (ARM)
2026-11-09 17:17 ` Kiryl Shutsemau
2026-11-09 20:30 ` Matthew Wilcox
2026-11-10 12:04 ` sashiko-bot
3 siblings, 1 reply; 16+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-11-09 16:11 UTC (permalink / raw)
To: Kiryl Shutsemau (Meta)
Cc: Andrew Morton, David Hildenbrand (Arm), Pedro Falcato,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Matthew Wilcox (Oracle),
Hugh Dickins, Chris Mason, linux-mm, linux-fsdevel, linux-kernel,
kernel-team, Sashiko
On Mon, Nov 09, 2026 at 12:04:01PM +0000, Kiryl Shutsemau (Meta) wrote:
> do_shared_fault() unlocks the folio around ->page_mkwrite(). Writeback
> can lock it in that window, fail, and clear PG_uptodate with the folio
> left in the page cache. ecryptfs_writepages() does this when encryption
> fails. filemap_page_mkwrite() relocks the folio and checks only
> ->mapping, so the fault maps a folio that is not uptodate:
>
> CPU0 CPU1
> do_shared_fault()
> folio_unlock()
> ecryptfs_writepages()
> folio_clear_uptodate()
> filemap_page_mkwrite()
> folio_lock()
> finish_fault()
>
> The next read(2) or fault on the folio reads it in again from the file,
> over anything stored through the mapping in the meantime. Those stores
> are lost.
>
> Recheck PG_uptodate once ->page_mkwrite() returns with the folio locked,
> and retry the fault if it is clear, the same way filemap_fault() retries
> on a cached folio that lost PG_uptodate. Skip folios outside the page
> cache: driver pages from ->fault() never get PG_uptodate and would
> retry forever.
>
> The check stays out of do_page_mkwrite(): wp_page_shared() calls it on
> a folio that is still mapped, and a retry there would fault on the same
> PTE forever.
>
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/sashiko-outbox-202966@kernel.org/
No Fixes? Sorry I may have missed context from v1 here :)
> Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
> ---
> mm/memory.c | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/mm/memory.c b/mm/memory.c
> index fe72e66c9c2e..cc1d0b7d15c7 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -5613,6 +5613,18 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
> return VM_FAULT_OOM;
> }
>
> +/*
> + * A page cache folio that is not uptodate holds data that was never read in
> + * or cleared, and mapping it leaks stale memory to userspace.
> + */
> +static bool file_folio_not_uptodate(struct folio *folio)
> +{
> + if (likely(folio_test_uptodate(folio)))
> + return false;
> + /* Driver pages from ->fault() never get PG_uptodate */
I guess you mean drivers that return non-page cache folios from ->fault()?
Because the driver could return page cache folios there (e.g. shmem), in
which case folio->mapping would be set (set on being added to the page
cache).
But also things are complicated by DAX (of course) which _does_ set
folio->mapping but installs the folio itself so won't reach the test
anyway.
So I think 'rmappable' is the better thing to say given DAX and, given this
is fiddly, maybe worth explicitly pointing out that ->fault might return
non-rmappable folios, e.g.:
/*
* Drivers which specify ->fault() might return non-rmappable folios
* (in which case no PG_uptodate).
*/
> + return !folio_test_anon(folio) && folio->mapping;
Technically folio_test_anon() can never return true based on where this is
called from right? Could this just be a:
VM_WARN_ON_ONCE(folio_test_anon(folio));
/* ... comment */
return folio->mapping;
Instead?
(Note that __folio_add_file_rmap() asserts on folio_test_anon(folio)).
> +}
> +
> /*
> * Either the VMA lock or the mmap_lock must have been held on entry
> * (see FAULT_FLAG_VMA_LOCK) and may have been released depending on
> @@ -6163,6 +6175,16 @@ static vm_fault_t do_shared_fault(struct vm_fault *vmf)
> folio_put(folio);
> return tmp;
> }
> +
> + /*
> + * The folio was unlocked for ->page_mkwrite(). If it lost
> + * PG_uptodate meanwhile, retry the fault to read it in again.
> + */
> + if (unlikely(file_folio_not_uptodate(folio))) {
As Pedro said, I think this unlikely() is probably unnecessary given the true
return case is implicitly unlikely.
> + folio_unlock(folio);
> + folio_put(folio);
> + return VM_FAULT_NOPAGE;
> + }
> }
>
> ret |= finish_fault(vmf);
> --
> 2.54.0
>
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite()
2026-11-09 16:11 ` Lorenzo Stoakes (ARM)
@ 2026-11-09 17:17 ` Kiryl Shutsemau
2026-11-09 17:30 ` Lorenzo Stoakes (ARM)
0 siblings, 1 reply; 16+ messages in thread
From: Kiryl Shutsemau @ 2026-11-09 17:17 UTC (permalink / raw)
To: Lorenzo Stoakes (ARM)
Cc: Andrew Morton, David Hildenbrand (Arm), Pedro Falcato,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Matthew Wilcox (Oracle),
Hugh Dickins, Chris Mason, linux-mm, linux-fsdevel, linux-kernel,
kernel-team, Sashiko
On Mon, Nov 09, 2026 at 04:11:40PM +0000, Lorenzo Stoakes (ARM) wrote:
> On Mon, Nov 09, 2026 at 12:04:01PM +0000, Kiryl Shutsemau (Meta) wrote:
> > do_shared_fault() unlocks the folio around ->page_mkwrite(). Writeback
> > can lock it in that window, fail, and clear PG_uptodate with the folio
> > left in the page cache. ecryptfs_writepages() does this when encryption
> > fails. filemap_page_mkwrite() relocks the folio and checks only
> > ->mapping, so the fault maps a folio that is not uptodate:
> >
> > CPU0 CPU1
> > do_shared_fault()
> > folio_unlock()
> > ecryptfs_writepages()
> > folio_clear_uptodate()
> > filemap_page_mkwrite()
> > folio_lock()
> > finish_fault()
> >
> > The next read(2) or fault on the folio reads it in again from the file,
> > over anything stored through the mapping in the meantime. Those stores
> > are lost.
> >
> > Recheck PG_uptodate once ->page_mkwrite() returns with the folio locked,
> > and retry the fault if it is clear, the same way filemap_fault() retries
> > on a cached folio that lost PG_uptodate. Skip folios outside the page
> > cache: driver pages from ->fault() never get PG_uptodate and would
> > retry forever.
> >
> > The check stays out of do_page_mkwrite(): wp_page_shared() calls it on
> > a folio that is still mapped, and a retry there would fault on the same
> > PTE forever.
> >
> > Reported-by: Sashiko <sashiko-bot@kernel.org>
> > Closes: https://lore.kernel.org/sashiko-outbox-202966@kernel.org/
>
> No Fixes? Sorry I may have missed context from v1 here :)
The window is from 2007, when __do_fault() started to drop the folio
lock around ->page_mkwrite():
Fixes: 6967614761fd ("ocfs2: release page lock before calling ->page_mkwrite")
Not sure how useful such Fixes is. It predates any possible stable tree.
> > ---
> > mm/memory.c | 22 ++++++++++++++++++++++
> > 1 file changed, 22 insertions(+)
> >
> > diff --git a/mm/memory.c b/mm/memory.c
> > index fe72e66c9c2e..cc1d0b7d15c7 100644
> > --- a/mm/memory.c
> > +++ b/mm/memory.c
> > @@ -5613,6 +5613,18 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
> > return VM_FAULT_OOM;
> > }
> >
> > +/*
> > + * A page cache folio that is not uptodate holds data that was never read in
> > + * or cleared, and mapping it leaks stale memory to userspace.
> > + */
> > +static bool file_folio_not_uptodate(struct folio *folio)
> > +{
> > + if (likely(folio_test_uptodate(folio)))
> > + return false;
> > + /* Driver pages from ->fault() never get PG_uptodate */
>
> I guess you mean drivers that return non-page cache folios from ->fault()?
Yes. How about:
/*
* ->fault() can also return driver memory that is not in the page
* cache. It never gets PG_uptodate.
*/
I would rather avoid "rmappable". These folios do get
folio_add_file_rmap_ptes() in set_pte_range(), and the word reads like
PG_large_rmappable. As you said, DAX never reaches the check, so "page
cache" is accurate.
> > + return !folio_test_anon(folio) && folio->mapping;
>
> Technically folio_test_anon() can never return true based on where this is
> called from right? Could this just be a:
>
> VM_WARN_ON_ONCE(folio_test_anon(folio));
> /* ... comment */
> return folio->mapping;
>
> Instead?
Right, all callers pass a file folio.
I will make it an assert, but at the top of the helper, so it checks
every call and not only the rare !uptodate one.
> > @@ -6163,6 +6175,16 @@ static vm_fault_t do_shared_fault(struct vm_fault *vmf)
> > folio_put(folio);
> > return tmp;
> > }
> > +
> > + /*
> > + * The folio was unlocked for ->page_mkwrite(). If it lost
> > + * PG_uptodate meanwhile, retry the fault to read it in again.
> > + */
> > + if (unlikely(file_folio_not_uptodate(folio))) {
>
> As Pedro said, I think this unlikely() is probably unnecessary given the true
> return case is implicitly unlikely.
As I told Pedro, I prefer it at the call site. That is where the reader
needs to see that the retry is the rare path. But if you insist...
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite()
2026-11-09 17:17 ` Kiryl Shutsemau
@ 2026-11-09 17:30 ` Lorenzo Stoakes (ARM)
0 siblings, 0 replies; 16+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-11-09 17:30 UTC (permalink / raw)
To: Kiryl Shutsemau
Cc: Andrew Morton, David Hildenbrand (Arm), Pedro Falcato,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Matthew Wilcox (Oracle),
Hugh Dickins, Chris Mason, linux-mm, linux-fsdevel, linux-kernel,
kernel-team, Sashiko
On Mon, Nov 09, 2026 at 05:17:03PM +0000, Kiryl Shutsemau wrote:
> On Mon, Nov 09, 2026 at 04:11:40PM +0000, Lorenzo Stoakes (ARM) wrote:
> > On Mon, Nov 09, 2026 at 12:04:01PM +0000, Kiryl Shutsemau (Meta) wrote:
> > > do_shared_fault() unlocks the folio around ->page_mkwrite(). Writeback
> > > can lock it in that window, fail, and clear PG_uptodate with the folio
> > > left in the page cache. ecryptfs_writepages() does this when encryption
> > > fails. filemap_page_mkwrite() relocks the folio and checks only
> > > ->mapping, so the fault maps a folio that is not uptodate:
> > >
> > > CPU0 CPU1
> > > do_shared_fault()
> > > folio_unlock()
> > > ecryptfs_writepages()
> > > folio_clear_uptodate()
> > > filemap_page_mkwrite()
> > > folio_lock()
> > > finish_fault()
> > >
> > > The next read(2) or fault on the folio reads it in again from the file,
> > > over anything stored through the mapping in the meantime. Those stores
> > > are lost.
> > >
> > > Recheck PG_uptodate once ->page_mkwrite() returns with the folio locked,
> > > and retry the fault if it is clear, the same way filemap_fault() retries
> > > on a cached folio that lost PG_uptodate. Skip folios outside the page
> > > cache: driver pages from ->fault() never get PG_uptodate and would
> > > retry forever.
> > >
> > > The check stays out of do_page_mkwrite(): wp_page_shared() calls it on
> > > a folio that is still mapped, and a retry there would fault on the same
> > > PTE forever.
> > >
> > > Reported-by: Sashiko <sashiko-bot@kernel.org>
> > > Closes: https://lore.kernel.org/sashiko-outbox-202966@kernel.org/
> >
> > No Fixes? Sorry I may have missed context from v1 here :)
>
> The window is from 2007, when __do_fault() started to drop the folio
> lock around ->page_mkwrite():
>
> Fixes: 6967614761fd ("ocfs2: release page lock before calling ->page_mkwrite")
Yeah not insisting!
>
> Not sure how useful such Fixes is. It predates any possible stable tree.
>
> > > ---
> > > mm/memory.c | 22 ++++++++++++++++++++++
> > > 1 file changed, 22 insertions(+)
> > >
> > > diff --git a/mm/memory.c b/mm/memory.c
> > > index fe72e66c9c2e..cc1d0b7d15c7 100644
> > > --- a/mm/memory.c
> > > +++ b/mm/memory.c
> > > @@ -5613,6 +5613,18 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
> > > return VM_FAULT_OOM;
> > > }
> > >
> > > +/*
> > > + * A page cache folio that is not uptodate holds data that was never read in
> > > + * or cleared, and mapping it leaks stale memory to userspace.
> > > + */
> > > +static bool file_folio_not_uptodate(struct folio *folio)
> > > +{
> > > + if (likely(folio_test_uptodate(folio)))
> > > + return false;
> > > + /* Driver pages from ->fault() never get PG_uptodate */
> >
> > I guess you mean drivers that return non-page cache folios from ->fault()?
>
> Yes. How about:
>
> /*
> * ->fault() can also return driver memory that is not in the page
> * cache. It never gets PG_uptodate.
> */
>
> I would rather avoid "rmappable". These folios do get
> folio_add_file_rmap_ptes() in set_pte_range(), and the word reads like
> PG_large_rmappable. As you said, DAX never reaches the check, so "page
> cache" is accurate.
OK, though my concern is you're making an assumption based on where this is
called from, somebody else could use the function somewhere else and... :)
But this is nitpicking really, that's fine!
>
> > > + return !folio_test_anon(folio) && folio->mapping;
> >
> > Technically folio_test_anon() can never return true based on where this is
> > called from right? Could this just be a:
> >
> > VM_WARN_ON_ONCE(folio_test_anon(folio));
> > /* ... comment */
> > return folio->mapping;
> >
> > Instead?
>
> Right, all callers pass a file folio.
>
> I will make it an assert, but at the top of the helper, so it checks
> every call and not only the rare !uptodate one.
Thanks!
>
> > > @@ -6163,6 +6175,16 @@ static vm_fault_t do_shared_fault(struct vm_fault *vmf)
> > > folio_put(folio);
> > > return tmp;
> > > }
> > > +
> > > + /*
> > > + * The folio was unlocked for ->page_mkwrite(). If it lost
> > > + * PG_uptodate meanwhile, retry the fault to read it in again.
> > > + */
> > > + if (unlikely(file_folio_not_uptodate(folio))) {
> >
> > As Pedro said, I think this unlikely() is probably unnecessary given the true
> > return case is implicitly unlikely.
>
> As I told Pedro, I prefer it at the call site. That is where the reader
> needs to see that the retry is the rare path. But if you insist...
You could also remove the likely() in the function itself ;)
>
> --
> Kiryl Shutsemau / Kirill A. Shutemov
--
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite()
2026-11-09 12:04 ` [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite() Kiryl Shutsemau (Meta)
2026-11-09 14:11 ` Pedro Falcato
2026-11-09 16:11 ` Lorenzo Stoakes (ARM)
@ 2026-11-09 20:30 ` Matthew Wilcox
2026-11-10 10:38 ` Kiryl Shutsemau
2026-11-10 12:04 ` sashiko-bot
3 siblings, 1 reply; 16+ messages in thread
From: Matthew Wilcox @ 2026-11-09 20:30 UTC (permalink / raw)
To: Kiryl Shutsemau (Meta)
Cc: Andrew Morton, David Hildenbrand (Arm), Pedro Falcato,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Chris Mason,
linux-mm, linux-fsdevel, linux-kernel, kernel-team, Sashiko
On Mon, Nov 09, 2026 at 12:04:01PM +0000, Kiryl Shutsemau (Meta) wrote:
> do_shared_fault() unlocks the folio around ->page_mkwrite(). Writeback
> can lock it in that window, fail, and clear PG_uptodate with the folio
> left in the page cache. ecryptfs_writepages() does this when encryption
> fails. filemap_page_mkwrite() relocks the folio and checks only
> ->mapping, so the fault maps a folio that is not uptodate:
Filesystems that do this are buggy. They shuld be fixed, not worked
around like this.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite()
2026-11-09 20:30 ` Matthew Wilcox
@ 2026-11-10 10:38 ` Kiryl Shutsemau
2026-11-10 19:25 ` Matthew Wilcox
0 siblings, 1 reply; 16+ messages in thread
From: Kiryl Shutsemau @ 2026-11-10 10:38 UTC (permalink / raw)
To: Matthew Wilcox
Cc: Andrew Morton, David Hildenbrand (Arm), Pedro Falcato,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Chris Mason,
linux-mm, linux-fsdevel, linux-kernel, kernel-team, Sashiko
On Mon, Nov 09, 2026 at 08:30:47PM +0000, Matthew Wilcox wrote:
> On Mon, Nov 09, 2026 at 12:04:01PM +0000, Kiryl Shutsemau (Meta) wrote:
> > do_shared_fault() unlocks the folio around ->page_mkwrite(). Writeback
> > can lock it in that window, fail, and clear PG_uptodate with the folio
> > left in the page cache. ecryptfs_writepages() does this when encryption
> > fails. filemap_page_mkwrite() relocks the folio and checks only
> > ->mapping, so the fault maps a folio that is not uptodate:
>
> Filesystems that do this are buggy. They shuld be fixed, not worked
> around like this.
Fair. What is your take on the way out?
Is there a timeline for the filesystem fixes?
Until they land, mm should still not map a folio that is not uptodate.
Would WARN_ON_ONCE() and SIGBUS, like the other checks in 2/2, work for
you? It flags the buggy filesystem instead of hiding it.
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite()
2026-11-10 10:38 ` Kiryl Shutsemau
@ 2026-11-10 19:25 ` Matthew Wilcox
0 siblings, 0 replies; 16+ messages in thread
From: Matthew Wilcox @ 2026-11-10 19:25 UTC (permalink / raw)
To: Kiryl Shutsemau
Cc: Andrew Morton, David Hildenbrand (Arm), Pedro Falcato,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Chris Mason,
linux-mm, linux-fsdevel, linux-kernel, kernel-team, Sashiko
On Tue, Nov 10, 2026 at 10:38:34AM +0000, Kiryl Shutsemau wrote:
> On Mon, Nov 09, 2026 at 08:30:47PM +0000, Matthew Wilcox wrote:
> > On Mon, Nov 09, 2026 at 12:04:01PM +0000, Kiryl Shutsemau (Meta) wrote:
> > > do_shared_fault() unlocks the folio around ->page_mkwrite(). Writeback
> > > can lock it in that window, fail, and clear PG_uptodate with the folio
> > > left in the page cache. ecryptfs_writepages() does this when encryption
> > > fails. filemap_page_mkwrite() relocks the folio and checks only
> > > ->mapping, so the fault maps a folio that is not uptodate:
> >
> > Filesystems that do this are buggy. They shuld be fixed, not worked
> > around like this.
>
> Fair. What is your take on the way out?
>
> Is there a timeline for the filesystem fixes?
>
> Until they land, mm should still not map a folio that is not uptodate.
>
> Would WARN_ON_ONCE() and SIGBUS, like the other checks in 2/2, work for
> you? It flags the buggy filesystem instead of hiding it.
It doesn't matter which way round the race ends up; if a filesystem marks
a mapped folio as !uptodate, there are other VM assertions that will
trip eventually. This is one of those cases where we should ignore the
bot because it doesn't quite know enough.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite()
2026-11-09 12:04 ` [PATCH v2 1/2] mm/memory: recheck PG_uptodate after ->page_mkwrite() Kiryl Shutsemau (Meta)
` (2 preceding siblings ...)
2026-11-09 20:30 ` Matthew Wilcox
@ 2026-11-10 12:04 ` sashiko-bot
3 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-11-10 12:04 UTC (permalink / raw)
To: Kiryl Shutsemau (Meta), Andrew Morton, David Hildenbrand (Arm),
Pedro Falcato
Cc: Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Matthew Wilcox (Oracle),
Hugh Dickins, Chris Mason, linux-mm, kernel-team
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [High] mm/memory: PG_uptodate check in do_shared_fault() runs after
->page_mkwrite()
--
commit 700a620ccdd59b966f387e178bdcded1ac07e9a0
Author: Kiryl Shutsemau (Meta) <kas@kernel.org>
mm/memory: recheck PG_uptodate after ->page_mkwrite()
This commit rechecks whether a file folio is still uptodate in
do_shared_fault() after ->page_mkwrite() returns with the folio locked,
retrying the fault if PG_uptodate was cleared while the folio was unlocked.
> diff --git a/mm/memory.c b/mm/memory.c
> index fe72e66c9c2ee..cc1d0b7d15c75 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
[ ... ]
> @@ -6163,6 +6175,16 @@ static vm_fault_t do_shared_fault(struct vm_fault *vmf)
> folio_put(folio);
> return tmp;
> }
> +
> + /*
> + * The folio was unlocked for ->page_mkwrite(). If it lost
> + * PG_uptodate meanwhile, retry the fault to read it in again.
> + */
> + if (unlikely(file_folio_not_uptodate(folio))) {
> + folio_unlock(folio);
> + folio_put(folio);
> + return VM_FAULT_NOPAGE;
> + }
> }
>
> ret |= finish_fault(vmf);
[Severity: High]
Does checking file_folio_not_uptodate(folio) after do_page_mkwrite() run too
late once ->page_mkwrite() has already dirtied the folio or set PG_uptodate
back on it?
In the race with ecryptfs_writepages(), writeback clears PG_dirty via
folio_clear_dirty_for_io() and then clears PG_uptodate when encryption fails.
When filemap_page_mkwrite() runs next, it relocks the folio, checks only
folio->mapping != mapping, and calls folio_mark_dirty():
mm/filemap.c:filemap_page_mkwrite() {
...
folio_lock(folio);
if (folio->mapping != mapping) {
folio_unlock(folio);
ret = VM_FAULT_NOPAGE;
goto out;
}
/*
* We mark the folio dirty already here so that when freeze is in
* progress, we are guaranteed that writeback during freezing will
* see the dirty folio and writeprotect it again.
*/
folio_mark_dirty(folio);
...
}
Before returning to do_shared_fault(), folio_mark_dirty() ->
__folio_mark_dirty() triggers WARN_ON_ONCE(warn && !folio_test_uptodate(folio))
and tags the non-uptodate folio PAGECACHE_TAG_DIRTY. When do_shared_fault()
then aborts with VM_FAULT_NOPAGE, the non-uptodate folio is left unlocked and
dirty in the page cache, where writeback can pick it up again or reclaim
cannot evict it.
On filesystems whose ->page_mkwrite() goes through block_page_mkwrite() or
btrfs_page_mkwrite(), block_commit_write() and btrfs_folio_set_uptodate() set
PG_uptodate back on a full folio without reading from disk, so
file_folio_not_uptodate(folio) returns false and the invalidated folio is
still mapped into userspace.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261109120403.82361-1-kas@kernel.org?part=1
^ permalink raw reply [flat|nested] 16+ messages in thread