The branch main has been updated by alc:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=7502c1f270827434bb9661cbb4b9652fdb836521

commit 7502c1f270827434bb9661cbb4b9652fdb836521
Author:     Alan Cox <a...@freebsd.org>
AuthorDate: 2025-07-19 20:18:04 +0000
Commit:     Alan Cox <a...@freebsd.org>
CommitDate: 2025-07-23 18:00:42 +0000

    pmap_demote_{l2,pde}: never invalidate wired mappings
    
    Rather than demoting a superpage mapping that hasn't been accessed, we
    ordinarily invalidate it.  However, if the mapping is wired,
    invalidation is problematic because the page fault to reinstantiate the
    mapping could sleep.  Instead, demote the wired mapping with the
    accessed flag cleared in the PTEs.
    
    Reviewed by:    kib, markj
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D51431
---
 sys/amd64/amd64/pmap.c | 21 +++++++++++----------
 sys/arm64/arm64/pmap.c | 24 +++++++++++++-----------
 2 files changed, 24 insertions(+), 21 deletions(-)

diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index d1d80afccdc7..8df082f6c5dc 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -5962,17 +5962,18 @@ pmap_demote_pde_mpte(pmap_t pmap, pd_entry_t *pde, 
vm_offset_t va,
        if (mpte == NULL) {
                /*
                 * Invalidate the 2MB page mapping and return "failure" if the
-                * mapping was never accessed.
+                * mapping was never accessed and not wired.
                 */
                if ((oldpde & PG_A) == 0) {
-                       KASSERT((oldpde & PG_W) == 0,
-                   ("pmap_demote_pde: a wired mapping is missing PG_A"));
-                       pmap_demote_pde_abort(pmap, va, pde, oldpde, lockp);
-                       return (false);
-               }
-
-               mpte = pmap_remove_pt_page(pmap, va);
-               if (mpte == NULL) {
+                       if ((oldpde & PG_W) == 0) {
+                               pmap_demote_pde_abort(pmap, va, pde, oldpde,
+                                   lockp);
+                               return (false);
+                       }
+                       mpte = pmap_remove_pt_page(pmap, va);
+                       /* Fill the PTP with PTEs that have PG_A cleared. */
+                       mpte->valid = 0;
+               } else if ((mpte = pmap_remove_pt_page(pmap, va)) == NULL) {
                        KASSERT((oldpde & PG_W) == 0,
     ("pmap_demote_pde: page table page for a wired mapping is missing"));
 
@@ -6024,7 +6025,7 @@ pmap_demote_pde_mpte(pmap_t pmap, pd_entry_t *pde, 
vm_offset_t va,
        /*
         * If the PTP is not leftover from an earlier promotion or it does not
         * have PG_A set in every PTE, then fill it.  The new PTEs will all
-        * have PG_A set.
+        * have PG_A set, unless this is a wired mapping with PG_A clear.
         */
        if (!vm_page_all_valid(mpte))
                pmap_fill_ptp(firstpte, newpte);
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index 459cc8ebe505..2152f7fcc1c6 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -8501,18 +8501,20 @@ pmap_demote_l2_locked(pmap_t pmap, pt_entry_t *l2, 
vm_offset_t va,
 
        /*
         * Invalidate the 2MB page mapping and return "failure" if the
-        * mapping was never accessed.
+        * mapping was never accessed and not wired.
         */
        if ((oldl2 & ATTR_AF) == 0) {
-               KASSERT((oldl2 & ATTR_SW_WIRED) == 0,
-                   ("pmap_demote_l2: a wired mapping is missing ATTR_AF"));
-               pmap_demote_l2_abort(pmap, va, l2, lockp);
-               CTR2(KTR_PMAP, "pmap_demote_l2: failure for va %#lx in pmap %p",
-                   va, pmap);
-               goto fail;
-       }
-
-       if ((ml3 = pmap_remove_pt_page(pmap, va)) == NULL) {
+               if ((oldl2 & ATTR_SW_WIRED) == 0) {
+                       pmap_demote_l2_abort(pmap, va, l2, lockp);
+                       CTR2(KTR_PMAP,
+                           "pmap_demote_l2: failure for va %#lx in pmap %p",
+                           va, pmap);
+                       goto fail;
+               }
+               ml3 = pmap_remove_pt_page(pmap, va);
+               /* Fill the PTP with L3Es that have ATTR_AF cleared. */
+               ml3->valid = 0;
+       } else if ((ml3 = pmap_remove_pt_page(pmap, va)) == NULL) {
                KASSERT((oldl2 & ATTR_SW_WIRED) == 0,
                    ("pmap_demote_l2: page table page for a wired mapping"
                    " is missing"));
@@ -8568,7 +8570,7 @@ pmap_demote_l2_locked(pmap_t pmap, pt_entry_t *l2, 
vm_offset_t va,
        /*
         * If the PTP is not leftover from an earlier promotion or it does not
         * have ATTR_AF set in every L3E, then fill it.  The new L3Es will all
-        * have ATTR_AF set.
+        * have ATTR_AF set, unless this is a wired mapping with ATTR_AF clear.
         *
         * When pmap_update_entry() clears the old L2 mapping, it (indirectly)
         * performs a dsb().  That dsb() ensures that the stores for filling

Reply via email to