From: Lorenzo Stoakes <ljs@kernel.org>
To: Rik van Riel <riel@surriel.com>
Cc: linux-kernel@vger.kernel.org, x86@kernel.org, linux-mm@kvack.org,
Thomas Gleixner <tglx@kernel.org>,
Ingo Molnar <mingo@redhat.com>, Dmitry Ilvokhin <d@ilvokhin.com>,
Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
Andrew Morton <akpm@linux-foundation.org>,
David Hildenbrand <david@kernel.org>,
"Liam R. Howlett" <liam@infradead.org>,
Vlastimil Babka <vbabka@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
kernel-team@meta.com
Subject: Re: [PATCH 2/3] mm/pagewalk: let folio_walk_start() run under the per-VMA lock
Date: Tue, 7 Jul 2026 13:24:46 +0100 [thread overview]
Message-ID: <akzv9FWH1peGukyp@lucifer> (raw)
In-Reply-To: <610d1c95a2f9131d5c018304f9a90afb33e8a032.camel@surriel.com>
On Thu, Jun 25, 2026 at 07:20:22AM -0400, Rik van Riel wrote:
> On Thu, 2026-06-25 at 08:34 +0100, Lorenzo Stoakes wrote:
> > Rik, it really would have helped if you'd replied to review :)
> >
> > On Wed, Jun 24, 2026 at 09:50:52PM -0400, Rik van Riel wrote:
> > > folio_walk_start() asserts the mmap lock is held. For callers that
> > > only
> > > need to read a single, already-present page, the mmap lock is a
> > > heavy and
> > > often badly contended hammer. Such a caller can instead hold the
> > > per-VMA
> > > lock, which keeps the VMA itself stable.
> >
> > <newline>
> >
> > > The per-VMA lock does not, however, keep the page tables walked
> > > below that
> > > VMA from being freed. A concurrent munmap() or THP collapse of an
> > > adjacent region in the same mm can free a shared upper-level table,
> > > and
> >
> > Yeah I need to update the documentation on this at
> > https://docs.kernel.org/mm/process_addrs.html it's more subtle than
> > written
> > there.
Actually not so sure I do now :) I mean maybe I need to be explicit about
the need for PTL's too. I guess 'other than the PTLs your page table walker
will take' is kinda implicit there.
> >
> > Firstly you're wrong about munmap() - it acquires the VMA lock of the
> > VMAs freed
> > in the range and will only remove an upper level table if the entire
> > range is
> > spanned.
> >
> > And that's the only way higher level tables can be removed.
> >
> > PTE page tables can be removed via MADV_DONTNEED, but that a.
> > acquires the VMA
> > lock and b. frees the PTE page table under RCU.
> >
> > A THP collapse can happen concurrently, but PTEs are freed under RCU
> > so you
> > don't need to do this GUP fast imitating stuff.
> >
> > > THP collapse (collapse_huge_page() -> retract_page_tables()) frees
> > > page
> > > tables of VMAs whose lock it does not hold. Page table freeing
> >
> > retract_page_tables() -> pte_free_defer() -> RCU
> > try_collapse_pte_mapped_thp() -> pte_free_defer() -> RCU
>
> One issue here is that while we can safely read
> the old page table under the RCU read lock, in
> the middle of a THP collapse there is no guarantee
> that the old page table points at the process's
> current memory.
See below.
>
> Khugepaged could fix this in one of two ways:
> - zap all readers with an IPI, and use that as
> synchronization
> - make sure the old page table's PTEs point at
> the individual pages inside the new PMD
>
> Right now khugepaged does the first.
This is confusing too. Khugepaged _could_ fix this one of two ways, right now it
_does_ the first?
You mean pmdp_get_lockless_sync() calls tlb_remove_table_sync_one()?
But that's for GUP fast right, not folio_walk_start/end()?
>
> Relying only on the RCU read lock to read the
> page table could result in us seeing old page
> table contents, that no longer point at the
> current process memory.
>
> Unless I'm missing something...
I think so! Otherwise we'd already have very broken page table walkers
right?
So:
pte_t *pte_offset_map_lock(struct mm_struct *mm, pmd_t *pmd,
unsigned long addr, spinlock_t **ptlp)
{
spinlock_t *ptl;
pmd_t pmdval;
pte_t *pte;
again:
pte = __pte_offset_map(pmd, addr, &pmdval);
if (unlikely(!pte))
return pte;
ptl = pte_lockptr(mm, &pmdval);
spin_lock(ptl);
if (likely(pmd_same(pmdval, pmdp_get_lockless(pmd)))) {
*ptlp = ptl;
return pte;
}
pte_unmap_unlock(pte, ptl);
goto again;
}
__pte_offset_map() takes the RCU lock, then locklessly retrieves a pointer
to the PTE page table.
As mentioned above, khugepaged retraction causing PTE page table freeing is
also under RCU, so this is safe:
retract_page_tables() -> pte_free_defer() -> RCU
try_collapse_pte_mapped_thp() -> pte_free_defer() -> RCU
And on page table retraction, importantly, the PMD entry is cleared _with
the PTE PTL held_, e.g. in retract_page_tables():
ptl = pte_lockptr(mm, pmd);
if (ptl != pml)
spin_lock_nested(ptl, SINGLE_DEPTH_NESTING);
...
if (likely(file_backed_vma_is_retractable(vma))) {
pgt_pmd = pmdp_collapse_flush(vma, addr, pmd);
...
}
if (ptl != pml)
spin_unlock(ptl);
For anon, we take the mmap write lock/VMA write lock anyway.
And going back to pte_offset_map_lock() - we _recheck the PMD under the
PTL_.
So if the PMD was since cleared, we don't get anything stale. If it wasn't,
then we hold the PTE PTL and exclude khugepaged from changing things under
us.
Thus folio_walk_start(), which holds the PTE PTL, is perfectly fine, and
folio_walk_end() marks the point at which things are no longer safe (but
then we're done with the folio).
So again I don't think there's any problem here, actually.
Thanks, Lorenzo
next prev parent reply other threads:[~2026-07-07 12:25 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-25 1:50 [PATCH v2 0/3] mm: __access_remote_vm with per-VMA lock Rik van Riel
2026-06-25 1:50 ` [PATCH 1/3] x86/mm: use READ_ONCE/WRITE_ONCE for mm->context.untag_mask Rik van Riel
2026-06-25 1:50 ` [PATCH 2/3] mm/pagewalk: let folio_walk_start() run under the per-VMA lock Rik van Riel
2026-06-25 7:34 ` Lorenzo Stoakes
2026-06-25 11:20 ` Rik van Riel
2026-07-07 12:24 ` Lorenzo Stoakes [this message]
2026-07-07 13:52 ` Rik van Riel
2026-06-25 1:50 ` [PATCH 3/3] mm: read remote memory without the mmap lock where possible Rik van Riel
2026-06-25 7:39 ` Lorenzo Stoakes
2026-06-25 6:32 ` [PATCH v2 0/3] mm: __access_remote_vm with per-VMA lock David Hildenbrand (Arm)
2026-06-25 7:47 ` Lorenzo Stoakes
2026-06-25 11:22 ` Rik van Riel
2026-06-26 20:33 ` David Hildenbrand (Arm)
2026-06-26 22:55 ` Rik van Riel
2026-06-27 7:09 ` Lorenzo Stoakes
2026-06-27 8:59 ` Lorenzo Stoakes
-- strict thread matches above, loose matches on Subject: below --
2026-06-16 19:02 [PATCH " Rik van Riel
2026-06-16 19:02 ` [PATCH 2/3] mm/pagewalk: let folio_walk_start() run under the " Rik van Riel
2026-06-19 12:34 ` Lorenzo Stoakes
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=akzv9FWH1peGukyp@lucifer \
--to=ljs@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=bp@alien8.de \
--cc=d@ilvokhin.com \
--cc=dave.hansen@linux.intel.com \
--cc=david@kernel.org \
--cc=kernel-team@meta.com \
--cc=liam@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mingo@redhat.com \
--cc=riel@surriel.com \
--cc=surenb@google.com \
--cc=tglx@kernel.org \
--cc=vbabka@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox