diff options
author | alc <alc@FreeBSD.org> | 2010-04-24 17:32:52 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2010-04-24 17:32:52 +0000 |
commit | 0a905b1db997b1f231d5d442e158b5228d69937a (patch) | |
tree | 7bce54bbe68a24f0e3ffcf944e58cf38a95b99e3 /sys/powerpc/booke | |
parent | 49089e216a08f4cd346d73ab4334e75650d4aa16 (diff) | |
download | FreeBSD-src-0a905b1db997b1f231d5d442e158b5228d69937a.zip FreeBSD-src-0a905b1db997b1f231d5d442e158b5228d69937a.tar.gz |
Resurrect pmap_is_referenced() and use it in mincore(). Essentially,
pmap_ts_referenced() is not always appropriate for checking whether or
not pages have been referenced because it clears any reference bits
that it encounters. For example, in mincore(), clearing the reference
bits has two negative consequences. First, it throws off the activity
count calculations performed by the page daemon. Specifically, a page
on which mincore() has called pmap_ts_referenced() looks less active
to the page daemon than it should. Consequently, the page could be
deactivated prematurely by the page daemon. Arguably, this problem
could be fixed by having mincore() duplicate the activity count
calculation on the page. However, there is a second problem for which
that is not a solution. In order to clear a reference on a 4KB page,
it may be necessary to demote a 2/4MB page mapping. Thus, a mincore()
by one process can have the side effect of demoting a superpage
mapping within another process!
Diffstat (limited to 'sys/powerpc/booke')
-rw-r--r-- | sys/powerpc/booke/pmap.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/sys/powerpc/booke/pmap.c b/sys/powerpc/booke/pmap.c index 13e637c..549eaaa 100644 --- a/sys/powerpc/booke/pmap.c +++ b/sys/powerpc/booke/pmap.c @@ -288,6 +288,7 @@ static vm_page_t mmu_booke_extract_and_hold(mmu_t, pmap_t, vm_offset_t, static void mmu_booke_init(mmu_t); static boolean_t mmu_booke_is_modified(mmu_t, vm_page_t); static boolean_t mmu_booke_is_prefaultable(mmu_t, pmap_t, vm_offset_t); +static boolean_t mmu_booke_is_referenced(mmu_t, vm_page_t); static boolean_t mmu_booke_ts_referenced(mmu_t, vm_page_t); static vm_offset_t mmu_booke_map(mmu_t, vm_offset_t *, vm_offset_t, vm_offset_t, int); @@ -342,6 +343,7 @@ static mmu_method_t mmu_booke_methods[] = { MMUMETHOD(mmu_init, mmu_booke_init), MMUMETHOD(mmu_is_modified, mmu_booke_is_modified), MMUMETHOD(mmu_is_prefaultable, mmu_booke_is_prefaultable), + MMUMETHOD(mmu_is_referenced, mmu_booke_is_referenced), MMUMETHOD(mmu_ts_referenced, mmu_booke_ts_referenced), MMUMETHOD(mmu_map, mmu_booke_map), MMUMETHOD(mmu_mincore, mmu_booke_mincore), @@ -2181,6 +2183,33 @@ mmu_booke_is_prefaultable(mmu_t mmu, pmap_t pmap, vm_offset_t addr) } /* + * Return whether or not the specified physical page was referenced + * in any physical maps. + */ +static boolean_t +mmu_booke_is_referenced(mmu_t mmu, vm_page_t m) +{ + pte_t *pte; + pv_entry_t pv; + boolean_t rv; + + mtx_assert(&vm_page_queue_mtx, MA_OWNED); + rv = FALSE; + if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) != 0) + return (rv); + TAILQ_FOREACH(pv, &m->md.pv_list, pv_link) { + PMAP_LOCK(pv->pv_pmap); + if ((pte = pte_find(mmu, pv->pv_pmap, pv->pv_va)) != NULL && + PTE_ISVALID(pte)) + rv = PTE_ISREFERENCED(pte) ? TRUE : FALSE; + PMAP_UNLOCK(pv->pv_pmap); + if (rv) + break; + } + return (rv); +} + +/* * Clear the modify bits on the specified physical page. */ static void |