diff options
Diffstat (limited to 'sys/i386')
-rw-r--r-- | sys/i386/i386/pmap.c | 41 |
1 files changed, 28 insertions, 13 deletions
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index b4c9027..7bf6a04 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -263,6 +263,8 @@ 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); static void pmap_insert_entry(pmap_t pmap, vm_offset_t va, vm_page_t m); +static boolean_t pmap_try_insert_pv_entry(pmap_t pmap, vm_offset_t va, + vm_page_t m); static vm_page_t pmap_allocpte(pmap_t pmap, vm_offset_t va, int flags); @@ -1587,6 +1589,29 @@ pmap_insert_entry(pmap_t pmap, vm_offset_t va, vm_page_t m) } /* + * Conditionally create a pv entry. + */ +static boolean_t +pmap_try_insert_pv_entry(pmap_t pmap, 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; + 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 @@ -2341,7 +2366,6 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len, vm_offset_t addr; vm_offset_t end_addr = src_addr + len; vm_offset_t pdnxt; - vm_page_t m; if (dst_addr != src_addr) return; @@ -2367,15 +2391,6 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len, if (addr >= UPT_MIN_ADDRESS) panic("pmap_copy: invalid to pmap_copy page tables"); - /* - * Don't let optional prefaulting of pages make us go - * way below the low water mark of free pages or way - * above high water mark of used pv entries. - */ - if (cnt.v_free_count < cnt.v_free_reserved || - pv_entry_count > pv_entry_high_water) - break; - pdnxt = (addr + NBPDR) & ~PDRMASK; ptepindex = addr >> PDRSHIFT; @@ -2417,16 +2432,16 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len, if (dstmpte == NULL) break; dst_pte = pmap_pte_quick(dst_pmap, addr); - if (*dst_pte == 0) { + if (*dst_pte == 0 && + pmap_try_insert_pv_entry(dst_pmap, addr, + PHYS_TO_VM_PAGE(ptetemp & PG_FRAME))) { /* * Clear the modified and * accessed (referenced) bits * during the copy. */ - m = PHYS_TO_VM_PAGE(ptetemp); *dst_pte = ptetemp & ~(PG_M | PG_A); dst_pmap->pm_stats.resident_count++; - pmap_insert_entry(dst_pmap, addr, m); } else pmap_unwire_pte_hold(dst_pmap, dstmpte); if (dstmpte->wire_count >= srcmpte->wire_count) |