svn commit: r191300 - head/sys/mips/mips

Alan Cox alc at FreeBSD.org
Mon Apr 20 03:44:55 UTC 2009


Author: alc
Date: Mon Apr 20 03:44:54 2009
New Revision: 191300
URL: http://svn.freebsd.org/changeset/base/191300

Log:
  MFamd64/i386
    Introduce pmap_try_insert_pv_entry(), a function that conditionally
    creates a pv entry if the number of entries is below the high water mark
    for pv entries.
  
    Introduce pmap_enter_quick_locked() and use it to reimplement
    pmap_enter_object().  The old implementation was broken.  For example,
    it could block while holding a mutex lock.
  
    Change pmap_enter_quick_locked() to fail rather than wait if it is
    unable to allocate a page table page.  This prevents a race between
    pmap_enter_object() and the page daemon.  Specifically, an inactive
    page that is a successor to the page that was given to
    pmap_enter_quick_locked() might become a cache page while
    pmap_enter_quick_locked() waits and later pmap_enter_object() maps
    the cache page violating the invariant that cache pages are never
    mapped.  Similarly, change
    pmap_enter_quick_locked() to call pmap_try_insert_pv_entry() rather
    than pmap_insert_entry().  Generally speaking,
    pmap_enter_quick_locked() is used to create speculative mappings.  So,
    it should not try hard to allocate memory if free memory is scarce.
  
  Tested by:	gonzo

Modified:
  head/sys/mips/mips/pmap.c

Modified: head/sys/mips/mips/pmap.c
==============================================================================
--- head/sys/mips/mips/pmap.c	Mon Apr 20 01:19:59 2009	(r191299)
+++ head/sys/mips/mips/pmap.c	Mon Apr 20 03:44:54 2009	(r191300)
@@ -171,6 +171,8 @@ static PMAP_INLINE void free_pv_entry(pv
 static pv_entry_t get_pv_entry(pmap_t locked_pmap);
 static __inline void pmap_changebit(vm_page_t m, int bit, boolean_t setem);
 
+static vm_page_t pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va,
+    vm_page_t m, vm_prot_t prot, vm_page_t mpte);
 static int pmap_remove_pte(struct pmap *pmap, pt_entry_t *ptq, vm_offset_t va);
 static void pmap_remove_page(struct pmap *pmap, vm_offset_t va);
 static void pmap_remove_entry(struct pmap *pmap, vm_page_t m, vm_offset_t va);
@@ -178,6 +180,8 @@ static boolean_t pmap_testbit(vm_page_t 
 static void 
 pmap_insert_entry(pmap_t pmap, vm_offset_t va, vm_page_t mpte,
     vm_page_t m, boolean_t wired);
+static boolean_t pmap_try_insert_pv_entry(pmap_t pmap, vm_page_t mpte,
+    vm_offset_t va, vm_page_t m);
 
 static vm_page_t pmap_allocpte(pmap_t pmap, vm_offset_t va, int flags);
 
@@ -1461,6 +1465,32 @@ pmap_insert_entry(pmap_t pmap, vm_offset
 }
 
 /*
+ * Conditionally create a pv entry.
+ */
+static boolean_t
+pmap_try_insert_pv_entry(pmap_t pmap, vm_page_t mpte, vm_offset_t va,
+    vm_page_t m)
+{
+	pv_entry_t pv;
+
+	PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+	mtx_assert(&vm_page_queue_mtx, MA_OWNED);
+	if (pv_entry_count < pv_entry_high_water && 
+	    (pv = uma_zalloc(pvzone, M_NOWAIT)) != NULL) {
+		pv_entry_count++;
+		pv->pv_va = va;
+		pv->pv_pmap = pmap;
+		pv->pv_ptem = mpte;
+		pv->pv_wired = FALSE;
+		TAILQ_INSERT_TAIL(&pmap->pm_pvlist, pv, pv_plist);
+		TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list);
+		m->md.pv_list_count++;
+		return (TRUE);
+	} else
+		return (FALSE);
+}
+
+/*
  * pmap_remove_pte: do the things to unmap a page in a process
  */
 static int
@@ -1919,20 +1949,28 @@ validate:
  * but is *MUCH* faster than pmap_enter...
  */
 
-
 void
 pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot)
 {
+
+	PMAP_LOCK(pmap);
+	(void)pmap_enter_quick_locked(pmap, va, m, prot, NULL);
+	PMAP_UNLOCK(pmap);
+}
+
+static vm_page_t
+pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m,
+    vm_prot_t prot, vm_page_t mpte)
+{
 	pt_entry_t *pte;
 	vm_offset_t pa;
-	vm_page_t mpte = NULL;
 
 	KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva ||
 	    (m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0,
-	    ("pmap_enter_quick: managed mapping within the clean submap"));
+	    ("pmap_enter_quick_locked: managed mapping within the clean submap"));
 	mtx_assert(&vm_page_queue_mtx, MA_OWNED);
-	VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED);
-	PMAP_LOCK(pmap);
+	PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+
 	/*
 	 * In the case that a page table page is not resident, we are
 	 * creating it here.
@@ -1948,7 +1986,6 @@ pmap_enter_quick(pmap_t pmap, vm_offset_
 		if (mpte && (mpte->pindex == ptepindex)) {
 			mpte->wire_count++;
 		} else {
-	retry:
 			/*
 			 * Get the page directory entry
 			 */
@@ -1968,19 +2005,10 @@ pmap_enter_quick(pmap_t pmap, vm_offset_
 				}
 				mpte->wire_count++;
 			} else {
-				mpte = _pmap_allocpte(pmap, ptepindex, M_NOWAIT);
-				if (mpte == NULL) {
-					PMAP_UNLOCK(pmap);
-					vm_page_busy(m);
-					vm_page_unlock_queues();
-					VM_OBJECT_UNLOCK(m->object);
-					VM_WAIT;
-					VM_OBJECT_LOCK(m->object);
-					vm_page_lock_queues();
-					vm_page_wakeup(m);
-					PMAP_LOCK(pmap);
-					goto retry;
-				}
+				mpte = _pmap_allocpte(pmap, ptepindex,
+				    M_NOWAIT);
+				if (mpte == NULL)
+					return (mpte);
 			}
 		}
 	} else {
@@ -1989,18 +2017,24 @@ pmap_enter_quick(pmap_t pmap, vm_offset_
 
 	pte = pmap_pte(pmap, va);
 	if (pmap_pte_v(pte)) {
-		if (mpte)
-			pmap_unwire_pte_hold(pmap, mpte);
-		PMAP_UNLOCK(pmap);
-		return;
+		if (mpte != NULL) {
+			mpte->wire_count--;
+			mpte = NULL;
+		}
+		return (mpte);
 	}
+
 	/*
-	 * Enter on the PV list if part of our managed memory. Note that we
-	 * raise IPL while manipulating pv_table since pmap_enter can be
-	 * called at interrupt time.
+	 * Enter on the PV list if part of our managed memory.
 	 */
-	if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0)
-		pmap_insert_entry(pmap, va, mpte, m, FALSE);
+	if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0 &&
+	    !pmap_try_insert_pv_entry(pmap, mpte, va, m)) {
+		if (mpte != NULL) {
+			pmap_unwire_pte_hold(pmap, mpte);
+			mpte = NULL;
+		}
+		return (mpte);
+	}
 
 	/*
 	 * Increment counters
@@ -2033,9 +2067,7 @@ pmap_enter_quick(pmap_t pmap, vm_offset_
 			mips_dcache_wbinv_range(va, NBPG);
 		}
 	}
-
-	PMAP_UNLOCK(pmap);
-	return;
+	return (mpte);
 }
 
 /*
@@ -2114,21 +2146,20 @@ void
 pmap_enter_object(pmap_t pmap, vm_offset_t start, vm_offset_t end,
     vm_page_t m_start, vm_prot_t prot)
 {
-	vm_page_t m;
+	vm_page_t m, mpte;
 	vm_pindex_t diff, psize;
 
+	VM_OBJECT_LOCK_ASSERT(m_start->object, MA_OWNED);
 	psize = atop(end - start);
+	mpte = NULL;
 	m = m_start;
+	PMAP_LOCK(pmap);
 	while (m != NULL && (diff = m->pindex - m_start->pindex) < psize) {
-	        /* FIX ME FIX ME - prot is passed in both the
-		 * the normal spot m, prot but also as the fault_type
-		 * which we don't use. If we ever use it in pmap_enter
-		 * we will have to fix this.
-	         */
-		pmap_enter(pmap, start + ptoa(diff), prot, m, prot &
-		    (VM_PROT_READ | VM_PROT_EXECUTE), FALSE);
+		mpte = pmap_enter_quick_locked(pmap, start + ptoa(diff), m,
+		    prot, mpte);
 		m = TAILQ_NEXT(m, listq);
 	}
+ 	PMAP_UNLOCK(pmap);
 }
 
 /*


More information about the svn-src-head mailing list