Author: alc
Date: Mon Oct  8 16:57:05 2012
New Revision: 241353
URL: http://svn.freebsd.org/changeset/base/241353

Log:
  In a few places, like the implementation of ptrace(), a thread may call
  upon pmap_enter() to create a mapping within a different address space,
  i.e., not the thread's own address space.  On i386, this entails the
  creation of a temporary mapping to the affected page table page (PTP).  In
  general, pmap_enter() will read from this PTP, allocate a PV entry, and
  write to this PTP.  The trouble comes when the system is short of memory.
  In order to allocate a new PV entry, an older PV entry has to be
  reclaimed.  Reclaiming a PV entry involves destroying a mapping, which
  requires access to the affected PTP.  Thus, the PTP mapped at the
  beginning of pmap_enter() is no longer mapped at the end of pmap_enter(),
  which leads to pmap_enter() modifying the wrong PTP.  To address this
  problem, pmap_pv_reclaim() is changed to use an alternate method of
  mapping PTPs.
  
  Update a related comment.
  
  Reported by:  pho
  Diagnosed by: kib
  MFC after:    5 days

Modified:
  head/sys/i386/i386/pmap.c
  head/sys/i386/xen/pmap.c

Modified: head/sys/i386/i386/pmap.c
==============================================================================
--- head/sys/i386/i386/pmap.c   Mon Oct  8 16:00:33 2012        (r241352)
+++ head/sys/i386/i386/pmap.c   Mon Oct  8 16:57:05 2012        (r241353)
@@ -475,7 +475,8 @@ pmap_bootstrap(vm_paddr_t firstaddr)
        KPTmap -= i386_btop(KPTDI << PDRSHIFT);
 
        /*
-        * ptemap is used for pmap_pte_quick
+        * PADDR1 and PADDR2 are used by pmap_pte_quick() and pmap_pte(),
+        * respectively.
         */
        SYSMAP(pt_entry_t *, PMAP1, PADDR1, 1)
        SYSMAP(pt_entry_t *, PMAP2, PADDR2, 1)
@@ -2228,7 +2229,6 @@ pmap_pv_reclaim(pmap_t locked_pmap)
        pmap = NULL;
        free = m_pc = NULL;
        TAILQ_INIT(&newtail);
-       sched_pin();
        while ((pc = TAILQ_FIRST(&pv_chunks)) != NULL && (pv_vafree == 0 ||
            free == NULL)) {
                TAILQ_REMOVE(&pv_chunks, pc, pc_lru);
@@ -2262,10 +2262,13 @@ pmap_pv_reclaim(pmap_t locked_pmap)
                                pde = pmap_pde(pmap, va);
                                if ((*pde & PG_PS) != 0)
                                        continue;
-                               pte = pmap_pte_quick(pmap, va);
-                               if ((*pte & PG_W) != 0)
+                               pte = pmap_pte(pmap, va);
+                               tpte = *pte;
+                               if ((tpte & PG_W) == 0)
+                                       tpte = pte_load_clear(pte);
+                               pmap_pte_release(pte);
+                               if ((tpte & PG_W) != 0)
                                        continue;
-                               tpte = pte_load_clear(pte);
                                if ((tpte & PG_G) != 0)
                                        pmap_invalidate_page(pmap, va);
                                m = PHYS_TO_VM_PAGE(tpte & PG_FRAME);
@@ -2323,7 +2326,6 @@ pmap_pv_reclaim(pmap_t locked_pmap)
                }
        }
 out:
-       sched_unpin();
        TAILQ_CONCAT(&pv_chunks, &newtail, pc_lru);
        if (pmap != NULL) {
                pmap_invalidate_all(pmap);

Modified: head/sys/i386/xen/pmap.c
==============================================================================
--- head/sys/i386/xen/pmap.c    Mon Oct  8 16:00:33 2012        (r241352)
+++ head/sys/i386/xen/pmap.c    Mon Oct  8 16:57:05 2012        (r241353)
@@ -429,7 +429,8 @@ pmap_bootstrap(vm_paddr_t firstaddr)
        SYSMAP(struct msgbuf *, unused, msgbufp, atop(round_page(msgbufsize)))
 
        /*
-        * ptemap is used for pmap_pte_quick
+        * PADDR1 and PADDR2 are used by pmap_pte_quick() and pmap_pte(),
+        * respectively.
         */
        SYSMAP(pt_entry_t *, PMAP1, PADDR1, 1)
        SYSMAP(pt_entry_t *, PMAP2, PADDR2, 1)
@@ -1976,7 +1977,6 @@ pmap_pv_reclaim(pmap_t locked_pmap)
        pmap = NULL;
        free = m_pc = NULL;
        TAILQ_INIT(&newtail);
-       sched_pin();
        while ((pc = TAILQ_FIRST(&pv_chunks)) != NULL && (pv_vafree == 0 ||
            free == NULL)) {
                TAILQ_REMOVE(&pv_chunks, pc, pc_lru);
@@ -2007,10 +2007,13 @@ pmap_pv_reclaim(pmap_t locked_pmap)
                                bit = bsfl(inuse);
                                pv = &pc->pc_pventry[field * 32 + bit];
                                va = pv->pv_va;
-                               pte = pmap_pte_quick(pmap, va);
-                               if ((*pte & PG_W) != 0)
+                               pte = pmap_pte(pmap, va);
+                               tpte = *pte;
+                               if ((tpte & PG_W) == 0)
+                                       tpte = pte_load_clear(pte);
+                               pmap_pte_release(pte);
+                               if ((tpte & PG_W) != 0)
                                        continue;
-                               tpte = pte_load_clear(pte);
                                if ((tpte & PG_G) != 0)
                                        pmap_invalidate_page(pmap, va);
                                m = PHYS_TO_VM_PAGE(tpte & PG_FRAME);
@@ -2062,7 +2065,6 @@ pmap_pv_reclaim(pmap_t locked_pmap)
                }
        }
 out:
-       sched_unpin();
        TAILQ_CONCAT(&pv_chunks, &newtail, pc_lru);
        if (pmap != NULL) {
                pmap_invalidate_all(pmap);
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to