aboutsummaryrefslogtreecommitdiff
path: root/sys/amd64
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>2004-06-07 23:51:20 +0000
committerPeter Wemm <peter@FreeBSD.org>2004-06-07 23:51:20 +0000
commitc2490f2dfbe30a95ace7aa381a8f4d8dd29e78f5 (patch)
tree8140801e52c2e9c6ca292c619e8c6c184ce06fce /sys/amd64
parentb8168edefc1bdebd0cd2138191bf74be5d46c456 (diff)
downloadsrc-c2490f2dfbe30a95ace7aa381a8f4d8dd29e78f5.tar.gz
src-c2490f2dfbe30a95ace7aa381a8f4d8dd29e78f5.zip
Fix a serious problem that manifested during swap, and a few other times.
pmap_remove() would be called with a huge range and we'd stride across it in only 2MB chunks. This would manifest as massive cpu time and a largely unresponsive system during hard swap. Instead, check the higher page directories which means we can run pmap_remove() in just a few hundred loop iterations instead of millions since we can process address space in chunks of 512GB and 1GB as well as 2MB. Eternal thanks to: tmm
Notes
Notes: svn path=/head/; revision=130219
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/amd64/pmap.c78
1 files changed, 60 insertions, 18 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index fe64ae49f54c..24db5746a727 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -1561,7 +1561,9 @@ pmap_remove_page(pmap_t pmap, vm_offset_t va)
void
pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
{
- vm_offset_t pdnxt;
+ vm_offset_t va_next;
+ pml4_entry_t *pml4e;
+ pdp_entry_t *pdpe;
pd_entry_t ptpaddr, *pde;
pt_entry_t *pte;
int anyvalid;
@@ -1587,15 +1589,27 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
anyvalid = 0;
- for (; sva < eva; sva = pdnxt) {
+ for (; sva < eva; sva = va_next) {
if (pmap->pm_stats.resident_count == 0)
break;
+ pml4e = pmap_pml4e(pmap, sva);
+ if (pml4e == 0) {
+ va_next = (sva + NBPML4) & ~PML4MASK;
+ continue;
+ }
+
+ pdpe = pmap_pdpe(pmap, sva);
+ if (pdpe == 0) {
+ va_next = (sva + NBPDP) & ~PDPMASK;
+ continue;
+ }
+
/*
* Calculate index for next page table.
*/
- pdnxt = (sva + NBPDR) & ~PDRMASK;
+ va_next = (sva + NBPDR) & ~PDRMASK;
pde = pmap_pde(pmap, sva);
if (pde == 0)
@@ -1624,10 +1638,10 @@ pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
* by the current page table page, or to the end of the
* range being removed.
*/
- if (pdnxt > eva)
- pdnxt = eva;
+ if (va_next > eva)
+ va_next = eva;
- for (; sva != pdnxt; sva += PAGE_SIZE) {
+ for (; sva != va_next; sva += PAGE_SIZE) {
pte = pmap_pte(pmap, sva);
if (pte == NULL || *pte == 0)
continue;
@@ -1713,7 +1727,9 @@ pmap_remove_all(vm_page_t m)
void
pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
{
- vm_offset_t pdnxt;
+ vm_offset_t va_next;
+ pml4_entry_t *pml4e;
+ pdp_entry_t *pdpe;
pd_entry_t ptpaddr, *pde;
int anychanged;
@@ -1730,9 +1746,21 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
anychanged = 0;
- for (; sva < eva; sva = pdnxt) {
+ for (; sva < eva; sva = va_next) {
+
+ pml4e = pmap_pml4e(pmap, sva);
+ if (pml4e == 0) {
+ va_next = (sva + NBPML4) & ~PML4MASK;
+ continue;
+ }
+
+ pdpe = pmap_pdpe(pmap, sva);
+ if (pdpe == 0) {
+ va_next = (sva + NBPDP) & ~PDPMASK;
+ continue;
+ }
- pdnxt = (sva + NBPDR) & ~PDRMASK;
+ va_next = (sva + NBPDR) & ~PDRMASK;
pde = pmap_pde(pmap, sva);
if (pde == NULL)
@@ -1756,10 +1784,10 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
continue;
}
- if (pdnxt > eva)
- pdnxt = eva;
+ if (va_next > eva)
+ va_next = eva;
- for (; sva != pdnxt; sva += PAGE_SIZE) {
+ for (; sva != va_next; sva += PAGE_SIZE) {
pt_entry_t pbits;
pt_entry_t *pte;
vm_page_t m;
@@ -2195,7 +2223,7 @@ 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_offset_t va_next;
vm_page_t m;
if (dst_addr != src_addr)
@@ -2204,9 +2232,11 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
if (!pmap_is_current(src_pmap))
return;
- for (addr = src_addr; addr < end_addr; addr = pdnxt) {
+ for (addr = src_addr; addr < end_addr; addr = va_next) {
pt_entry_t *src_pte, *dst_pte;
vm_page_t dstmpte, srcmpte;
+ pml4_entry_t *pml4e;
+ pdp_entry_t *pdpe;
pd_entry_t srcptepaddr, *pde;
vm_pindex_t ptepindex;
@@ -2222,7 +2252,19 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
pv_entry_count > pv_entry_high_water)
break;
- pdnxt = (addr + NBPDR) & ~PDRMASK;
+ pml4e = pmap_pml4e(src_pmap, addr);
+ if (pml4e == 0) {
+ va_next = (addr + NBPML4) & ~PML4MASK;
+ continue;
+ }
+
+ pdpe = pmap_pdpe(src_pmap, addr);
+ if (pdpe == 0) {
+ va_next = (addr + NBPDP) & ~PDPMASK;
+ continue;
+ }
+
+ va_next = (addr + NBPDR) & ~PDRMASK;
ptepindex = pmap_pde_pindex(addr);
pde = pmap_pde(src_pmap, addr);
@@ -2254,11 +2296,11 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
if (srcmpte->hold_count == 0 || (srcmpte->flags & PG_BUSY))
continue;
- if (pdnxt > end_addr)
- pdnxt = end_addr;
+ if (va_next > end_addr)
+ va_next = end_addr;
src_pte = vtopte(addr);
- while (addr < pdnxt) {
+ while (addr < va_next) {
pt_entry_t ptetemp;
ptetemp = *src_pte;
/*