Changeset View
Changeset View
Standalone View
Standalone View
head/sys/riscv/riscv/pmap.c
Show First 20 Lines • Show All 3,944 Lines • ▼ Show 20 Lines | pmap_ts_referenced(vm_page_t m) | ||||
struct md_page *pvh; | struct md_page *pvh; | ||||
struct rwlock *lock; | struct rwlock *lock; | ||||
pv_entry_t pv, pvf; | pv_entry_t pv, pvf; | ||||
pmap_t pmap; | pmap_t pmap; | ||||
pd_entry_t *l2, l2e; | pd_entry_t *l2, l2e; | ||||
pt_entry_t *l3, l3e; | pt_entry_t *l3, l3e; | ||||
vm_paddr_t pa; | vm_paddr_t pa; | ||||
vm_offset_t va; | vm_offset_t va; | ||||
int md_gen, pvh_gen, ret; | int cleared, md_gen, not_cleared, pvh_gen; | ||||
KASSERT((m->oflags & VPO_UNMANAGED) == 0, | KASSERT((m->oflags & VPO_UNMANAGED) == 0, | ||||
("pmap_ts_referenced: page %p is not managed", m)); | ("pmap_ts_referenced: page %p is not managed", m)); | ||||
SLIST_INIT(&free); | SLIST_INIT(&free); | ||||
ret = 0; | cleared = 0; | ||||
pa = VM_PAGE_TO_PHYS(m); | pa = VM_PAGE_TO_PHYS(m); | ||||
pvh = (m->flags & PG_FICTITIOUS) != 0 ? &pv_dummy : pa_to_pvh(pa); | pvh = (m->flags & PG_FICTITIOUS) != 0 ? &pv_dummy : pa_to_pvh(pa); | ||||
lock = PHYS_TO_PV_LIST_LOCK(pa); | lock = PHYS_TO_PV_LIST_LOCK(pa); | ||||
rw_rlock(&pvh_global_lock); | rw_rlock(&pvh_global_lock); | ||||
rw_wlock(lock); | rw_wlock(lock); | ||||
retry: | retry: | ||||
not_cleared = 0; | |||||
if ((pvf = TAILQ_FIRST(&pvh->pv_list)) == NULL) | if ((pvf = TAILQ_FIRST(&pvh->pv_list)) == NULL) | ||||
goto small_mappings; | goto small_mappings; | ||||
pv = pvf; | pv = pvf; | ||||
do { | do { | ||||
pmap = PV_PMAP(pv); | pmap = PV_PMAP(pv); | ||||
if (!PMAP_TRYLOCK(pmap)) { | if (!PMAP_TRYLOCK(pmap)) { | ||||
pvh_gen = pvh->pv_gen; | pvh_gen = pvh->pv_gen; | ||||
rw_wunlock(lock); | rw_wunlock(lock); | ||||
Show All 34 Lines | if ((l2e & PTE_A) != 0) { | ||||
* since the superpage is wired, the current state of | * since the superpage is wired, the current state of | ||||
* its reference bit won't affect page replacement. | * its reference bit won't affect page replacement. | ||||
*/ | */ | ||||
if ((((pa >> PAGE_SHIFT) ^ (pv->pv_va >> L2_SHIFT) ^ | if ((((pa >> PAGE_SHIFT) ^ (pv->pv_va >> L2_SHIFT) ^ | ||||
(uintptr_t)pmap) & (Ln_ENTRIES - 1)) == 0 && | (uintptr_t)pmap) & (Ln_ENTRIES - 1)) == 0 && | ||||
(l2e & PTE_SW_WIRED) == 0) { | (l2e & PTE_SW_WIRED) == 0) { | ||||
pmap_clear_bits(l2, PTE_A); | pmap_clear_bits(l2, PTE_A); | ||||
pmap_invalidate_page(pmap, va); | pmap_invalidate_page(pmap, va); | ||||
cleared++; | |||||
} else | |||||
not_cleared++; | |||||
} | } | ||||
ret++; | |||||
} | |||||
PMAP_UNLOCK(pmap); | PMAP_UNLOCK(pmap); | ||||
/* Rotate the PV list if it has more than one entry. */ | /* Rotate the PV list if it has more than one entry. */ | ||||
if (pv != NULL && TAILQ_NEXT(pv, pv_next) != NULL) { | if (pv != NULL && TAILQ_NEXT(pv, pv_next) != NULL) { | ||||
TAILQ_REMOVE(&pvh->pv_list, pv, pv_next); | TAILQ_REMOVE(&pvh->pv_list, pv, pv_next); | ||||
TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_next); | TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_next); | ||||
pvh->pv_gen++; | pvh->pv_gen++; | ||||
} | } | ||||
if (ret >= PMAP_TS_REFERENCED_MAX) | if (cleared + not_cleared >= PMAP_TS_REFERENCED_MAX) | ||||
goto out; | goto out; | ||||
} while ((pv = TAILQ_FIRST(&pvh->pv_list)) != pvf); | } while ((pv = TAILQ_FIRST(&pvh->pv_list)) != pvf); | ||||
small_mappings: | small_mappings: | ||||
if ((pvf = TAILQ_FIRST(&m->md.pv_list)) == NULL) | if ((pvf = TAILQ_FIRST(&m->md.pv_list)) == NULL) | ||||
goto out; | goto out; | ||||
pv = pvf; | pv = pvf; | ||||
do { | do { | ||||
pmap = PV_PMAP(pv); | pmap = PV_PMAP(pv); | ||||
Show All 22 Lines | if ((l3e & PTE_A) != 0) { | ||||
/* | /* | ||||
* Wired pages cannot be paged out so | * Wired pages cannot be paged out so | ||||
* doing accessed bit emulation for | * doing accessed bit emulation for | ||||
* them is wasted effort. We do the | * them is wasted effort. We do the | ||||
* hard work for unwired pages only. | * hard work for unwired pages only. | ||||
*/ | */ | ||||
pmap_clear_bits(l3, PTE_A); | pmap_clear_bits(l3, PTE_A); | ||||
pmap_invalidate_page(pmap, pv->pv_va); | pmap_invalidate_page(pmap, pv->pv_va); | ||||
cleared++; | |||||
} else | |||||
not_cleared++; | |||||
} | } | ||||
ret++; | |||||
} | |||||
PMAP_UNLOCK(pmap); | PMAP_UNLOCK(pmap); | ||||
/* Rotate the PV list if it has more than one entry. */ | /* Rotate the PV list if it has more than one entry. */ | ||||
if (pv != NULL && TAILQ_NEXT(pv, pv_next) != NULL) { | if (pv != NULL && TAILQ_NEXT(pv, pv_next) != NULL) { | ||||
TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); | TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); | ||||
TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); | TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); | ||||
m->md.pv_gen++; | m->md.pv_gen++; | ||||
} | } | ||||
} while ((pv = TAILQ_FIRST(&m->md.pv_list)) != pvf && ret < | } while ((pv = TAILQ_FIRST(&m->md.pv_list)) != pvf && cleared + | ||||
PMAP_TS_REFERENCED_MAX); | not_cleared < PMAP_TS_REFERENCED_MAX); | ||||
out: | out: | ||||
rw_wunlock(lock); | rw_wunlock(lock); | ||||
rw_runlock(&pvh_global_lock); | rw_runlock(&pvh_global_lock); | ||||
vm_page_free_pages_toq(&free, false); | vm_page_free_pages_toq(&free, false); | ||||
return (ret); | return (cleared + not_cleared); | ||||
} | } | ||||
/* | /* | ||||
* Apply the given advice to the specified range of addresses within the | * Apply the given advice to the specified range of addresses within the | ||||
* given pmap. Depending on the advice, clear the referenced and/or | * given pmap. Depending on the advice, clear the referenced and/or | ||||
* modified flags in each mapping and set the mapped page's dirty field. | * modified flags in each mapping and set the mapped page's dirty field. | ||||
*/ | */ | ||||
void | void | ||||
▲ Show 20 Lines • Show All 390 Lines • Show Last 20 Lines |