summaryrefslogtreecommitdiffstats
path: root/sys/ia64
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2010-05-24 14:26:57 +0000
committeralc <alc@FreeBSD.org>2010-05-24 14:26:57 +0000
commit32b13ee95703577767e8794ce5e896ad8fdbdee7 (patch)
tree9d773a8e937b9a4faf763308a1843594ec04df60 /sys/ia64
parent95cb40b038035cd0d6e2b2b015f41a7d4dec0fcb (diff)
downloadFreeBSD-src-32b13ee95703577767e8794ce5e896ad8fdbdee7.zip
FreeBSD-src-32b13ee95703577767e8794ce5e896ad8fdbdee7.tar.gz
Roughly half of a typical pmap_mincore() implementation is machine-
independent code. Move this code into mincore(), and eliminate the page queues lock from pmap_mincore(). Push down the page queues lock into pmap_clear_modify(), pmap_clear_reference(), and pmap_is_modified(). Assert that these functions are never passed an unmanaged page. Eliminate an inaccurate comment from powerpc/powerpc/mmu_if.m: Contrary to what the comment says, pmap_mincore() is not simply an optimization. Without a complete pmap_mincore() implementation, mincore() cannot return either MINCORE_MODIFIED or MINCORE_REFERENCED because only the pmap can provide this information. Eliminate the page queues lock from vfs_setdirty_locked_object(), vm_pageout_clean(), vm_object_page_collect_flush(), and vm_object_page_clean(). Generally speaking, these are all accesses to the page's dirty field, which are synchronized by the containing vm object's lock. Reduce the scope of the page queues lock in vm_object_madvise() and vm_page_dontneed(). Reviewed by: kib (an earlier version)
Diffstat (limited to 'sys/ia64')
-rw-r--r--sys/ia64/ia64/pmap.c111
1 files changed, 55 insertions, 56 deletions
diff --git a/sys/ia64/ia64/pmap.c b/sys/ia64/ia64/pmap.c
index d2c5613..86f3ea1 100644
--- a/sys/ia64/ia64/pmap.c
+++ b/sys/ia64/ia64/pmap.c
@@ -1981,10 +1981,20 @@ pmap_is_modified(vm_page_t m)
pv_entry_t pv;
boolean_t rv;
+ KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0,
+ ("pmap_is_modified: page %p is not managed", m));
rv = FALSE;
- if (m->flags & PG_FICTITIOUS)
- return (rv);
+ /*
+ * If the page is not VPO_BUSY, then PG_WRITEABLE cannot be
+ * concurrently set while the object is locked. Thus, if PG_WRITEABLE
+ * is clear, no PTEs can be dirty.
+ */
+ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED);
+ if ((m->oflags & VPO_BUSY) == 0 &&
+ (m->flags & PG_WRITEABLE) == 0)
+ return (rv);
+ vm_page_lock_queues();
TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) {
PMAP_LOCK(pv->pv_pmap);
oldpmap = pmap_switch(pv->pv_pmap);
@@ -1996,7 +2006,7 @@ pmap_is_modified(vm_page_t m)
if (rv)
break;
}
-
+ vm_page_unlock_queues();
return (rv);
}
@@ -2058,9 +2068,20 @@ pmap_clear_modify(vm_page_t m)
pmap_t oldpmap;
pv_entry_t pv;
- if (m->flags & PG_FICTITIOUS)
- return;
+ KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0,
+ ("pmap_clear_modify: page %p is not managed", m));
+ VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED);
+ KASSERT((m->oflags & VPO_BUSY) == 0,
+ ("pmap_clear_modify: page %p is busy", m));
+ /*
+ * If the page is not PG_WRITEABLE, then no PTEs can be modified.
+ * If the object containing the page is locked and the page is not
+ * VPO_BUSY, then PG_WRITEABLE cannot be concurrently set.
+ */
+ if ((m->flags & PG_WRITEABLE) == 0)
+ return;
+ vm_page_lock_queues();
TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) {
PMAP_LOCK(pv->pv_pmap);
oldpmap = pmap_switch(pv->pv_pmap);
@@ -2073,6 +2094,7 @@ pmap_clear_modify(vm_page_t m)
pmap_switch(oldpmap);
PMAP_UNLOCK(pv->pv_pmap);
}
+ vm_page_unlock_queues();
}
/*
@@ -2087,9 +2109,9 @@ pmap_clear_reference(vm_page_t m)
pmap_t oldpmap;
pv_entry_t pv;
- if (m->flags & PG_FICTITIOUS)
- return;
-
+ KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0,
+ ("pmap_clear_reference: page %p is not managed", m));
+ vm_page_lock_queues();
TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) {
PMAP_LOCK(pv->pv_pmap);
oldpmap = pmap_switch(pv->pv_pmap);
@@ -2102,6 +2124,7 @@ pmap_clear_reference(vm_page_t m)
pmap_switch(oldpmap);
PMAP_UNLOCK(pv->pv_pmap);
}
+ vm_page_unlock_queues();
}
/*
@@ -2178,13 +2201,15 @@ pmap_unmapdev(vm_offset_t va, vm_size_t size)
* perform the pmap work for mincore
*/
int
-pmap_mincore(pmap_t pmap, vm_offset_t addr)
+pmap_mincore(pmap_t pmap, vm_offset_t addr, vm_paddr_t *locked_pa)
{
pmap_t oldpmap;
struct ia64_lpte *pte, tpte;
- int val = 0;
+ vm_paddr_t pa;
+ int val;
PMAP_LOCK(pmap);
+retry:
oldpmap = pmap_switch(pmap);
pte = pmap_find_vhpt(addr);
if (pte != NULL) {
@@ -2192,53 +2217,27 @@ pmap_mincore(pmap_t pmap, vm_offset_t addr)
pte = &tpte;
}
pmap_switch(oldpmap);
- PMAP_UNLOCK(pmap);
-
- if (pte == NULL)
- return 0;
-
- if (pmap_present(pte)) {
- vm_page_t m;
- vm_offset_t pa;
-
- val = MINCORE_INCORE;
- if (!pmap_managed(pte))
- return val;
-
+ if (pte == NULL || !pmap_present(pte)) {
+ val = 0;
+ goto out;
+ }
+ val = MINCORE_INCORE;
+ if (pmap_dirty(pte))
+ val |= MINCORE_MODIFIED | MINCORE_MODIFIED_OTHER;
+ if (pmap_accessed(pte))
+ val |= MINCORE_REFERENCED | MINCORE_REFERENCED_OTHER;
+ if ((val & (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER)) !=
+ (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER) &&
+ pmap_managed(pte)) {
pa = pmap_ppn(pte);
-
- m = PHYS_TO_VM_PAGE(pa);
-
- /*
- * Modified by us
- */
- if (pmap_dirty(pte))
- val |= MINCORE_MODIFIED|MINCORE_MODIFIED_OTHER;
- else {
- /*
- * Modified by someone
- */
- vm_page_lock_queues();
- if (pmap_is_modified(m))
- val |= MINCORE_MODIFIED_OTHER;
- vm_page_unlock_queues();
- }
- /*
- * Referenced by us
- */
- if (pmap_accessed(pte))
- val |= MINCORE_REFERENCED|MINCORE_REFERENCED_OTHER;
- else {
- /*
- * Referenced by someone
- */
- vm_page_lock_queues();
- if (pmap_is_referenced(m))
- val |= MINCORE_REFERENCED_OTHER;
- vm_page_unlock_queues();
- }
- }
- return val;
+ /* Ensure that "PHYS_TO_VM_PAGE(pa)->object" doesn't change. */
+ if (vm_page_pa_tryrelock(pmap, pa, locked_pa))
+ goto retry;
+ } else
+out:
+ PA_UNLOCK_COND(*locked_pa);
+ PMAP_UNLOCK(pmap);
+ return (val);
}
void
OpenPOWER on IntegriCloud