git: e77d5a7d20eb - stable/15 - powerpc/radix: acquire the pmap lock in mmu_radix_extract()

From: Piotr Kubaj <pkubaj_at_FreeBSD.org>
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) {