git: e77d5a7d20eb - stable/15 - powerpc/radix: acquire the pmap lock in mmu_radix_extract()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 21 Sep 2026 07:31:42 UTC
The branch stable/15 has been updated by pkubaj:
URL: https://cgit.FreeBSD.org/src/commit/?id=e77d5a7d20ebc2f9b62cea03ffab60bc20de6c9c
commit e77d5a7d20ebc2f9b62cea03ffab60bc20de6c9c
Author: Piotr Kubaj <pkubaj@FreeBSD.org>
AuthorDate: 2026-09-14 13:13:51 +0000
Commit: Piotr Kubaj <pkubaj@FreeBSD.org>
CommitDate: 2026-09-21 07:31:36 +0000
powerpc/radix: acquire the pmap lock in mmu_radix_extract()
mmu_radix_extract() walks the page tables without holding the pmap lock,
unlike its hash MMU counterpart moea64_extract(). A concurrent unmap can
free and recycle the page table page being walked, so the read returns
whatever now occupies that memory and the caller gets a physical address
that never existed.
That is how mmu_radix_sync_icache() came to hand a bogus address to
__syncicache() and panic the machine. Commit 1574ca1955f5 worked around
it by taking the pmap lock in mmu_radix_sync_icache(), but the machine
independent callers of pmap_extract() - vm_sync_icache(), proc_rwmem()
and the vslock() paths - remain exposed to the same failure.
Rename the existing body to mmu_radix_extract_locked(), which asserts the
lock, and make mmu_radix_extract() a thin wrapper that acquires it.
mmu_radix_sync_icache() already holds the pmap lock, so it calls the
locked variant directly and neither recurses nor reacquires the lock once
per page.
Suggested by: alc
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D59320
Reviewed by: markj, jhibbits
(cherry picked from commit 42c69445ca336b13e27e3e5960ace344c64ae0eb)
---
sys/powerpc/aim/mmu_radix.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/sys/powerpc/aim/mmu_radix.c b/sys/powerpc/aim/mmu_radix.c
index e54fdbb80933..dce3103e087d 100644
--- a/sys/powerpc/aim/mmu_radix.c
+++ b/sys/powerpc/aim/mmu_radix.c
@@ -3498,19 +3498,19 @@ mmu_radix_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m,
PMAP_UNLOCK(pmap);
}
-vm_paddr_t
-mmu_radix_extract(pmap_t pmap, vm_offset_t va)
+static vm_paddr_t
+mmu_radix_extract_locked(pmap_t pmap, vm_offset_t va)
{
pml3_entry_t *l3e;
pt_entry_t *pte;
vm_paddr_t pa;
+ PMAP_LOCK_ASSERT(pmap, MA_OWNED);
l3e = pmap_pml3e(pmap, va);
if (__predict_false(l3e == NULL))
return (0);
if (be64toh(*l3e) & RPTE_LEAF) {
pa = (be64toh(*l3e) & PG_PS_FRAME) | (va & L3_PAGE_MASK);
- pa |= (va & L3_PAGE_MASK);
} else {
/*
* Beware of a concurrent promotion that changes the
@@ -3525,11 +3525,21 @@ mmu_radix_extract(pmap_t pmap, vm_offset_t va)
return (0);
pa = be64toh(*pte);
pa = (pa & PG_FRAME) | (va & PAGE_MASK);
- pa |= (va & PAGE_MASK);
}
return (pa);
}
+vm_paddr_t
+mmu_radix_extract(pmap_t pmap, vm_offset_t va)
+{
+ vm_paddr_t pa;
+
+ PMAP_LOCK(pmap);
+ pa = mmu_radix_extract_locked(pmap, va);
+ PMAP_UNLOCK(pmap);
+ return (pa);
+}
+
vm_page_t
mmu_radix_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot)
{
@@ -5987,7 +5997,7 @@ mmu_radix_sync_icache(pmap_t pm, vm_offset_t va, vm_size_t sz)
PMAP_LOCK(pm);
while (sz > 0) {
- pa = pmap_extract(pm, va);
+ pa = mmu_radix_extract_locked(pm, va);
sync_sz = PAGE_SIZE - (va & PAGE_MASK);
sync_sz = min(sync_sz, sz);
if (pa != 0) {