* pmap_ts_referenced: * * Return a count of reference bits for a page, clearing those bits. * It is not necessary for every reference bit to be cleared, but it * is necessary that 0 only be returned when there are truly no * reference bits set. * * As an optimization, update the page's dirty field if a modified bit is * found while counting reference bits. This opportunistic update can be
| 5498 | * to pmap_is_modified(). |
| 5499 | */ |
| 5500 | int |
| 5501 | pmap_ts_referenced(vm_page_t m) |
| 5502 | { |
| 5503 | struct md_page *pvh; |
| 5504 | pv_entry_t pv, pvf; |
| 5505 | pmap_t pmap; |
| 5506 | struct rwlock *lock; |
| 5507 | pd_entry_t *pde, tpde; |
| 5508 | pt_entry_t *pte, tpte; |
| 5509 | vm_offset_t va; |
| 5510 | vm_paddr_t pa; |
| 5511 | int cleared, lvl, md_gen, not_cleared, pvh_gen; |
| 5512 | struct spglist free; |
| 5513 | |
| 5514 | KASSERT((m->oflags & VPO_UNMANAGED) == 0, |
| 5515 | ("pmap_ts_referenced: page %p is not managed", m)); |
| 5516 | SLIST_INIT(&free); |
| 5517 | cleared = 0; |
| 5518 | pa = VM_PAGE_TO_PHYS(m); |
| 5519 | lock = PHYS_TO_PV_LIST_LOCK(pa); |
| 5520 | pvh = (m->flags & PG_FICTITIOUS) != 0 ? &pv_dummy : page_to_pvh(m); |
| 5521 | rw_wlock(lock); |
| 5522 | retry: |
| 5523 | not_cleared = 0; |
| 5524 | if ((pvf = TAILQ_FIRST(&pvh->pv_list)) == NULL) |
| 5525 | goto small_mappings; |
| 5526 | pv = pvf; |
| 5527 | do { |
| 5528 | if (pvf == NULL) |
| 5529 | pvf = pv; |
| 5530 | pmap = PV_PMAP(pv); |
| 5531 | if (!PMAP_TRYLOCK(pmap)) { |
| 5532 | pvh_gen = pvh->pv_gen; |
| 5533 | rw_wunlock(lock); |
| 5534 | PMAP_LOCK(pmap); |
| 5535 | rw_wlock(lock); |
| 5536 | if (pvh_gen != pvh->pv_gen) { |
| 5537 | PMAP_UNLOCK(pmap); |
| 5538 | goto retry; |
| 5539 | } |
| 5540 | } |
| 5541 | va = pv->pv_va; |
| 5542 | pde = pmap_pde(pmap, pv->pv_va, &lvl); |
| 5543 | KASSERT(pde != NULL, ("pmap_ts_referenced: no l1 table found")); |
| 5544 | KASSERT(lvl == 1, |
| 5545 | ("pmap_ts_referenced: invalid pde level %d", lvl)); |
| 5546 | tpde = pmap_load(pde); |
| 5547 | KASSERT((tpde & ATTR_DESCR_MASK) == L1_TABLE, |
| 5548 | ("pmap_ts_referenced: found an invalid l1 table")); |
| 5549 | pte = pmap_l1_to_l2(pde, pv->pv_va); |
| 5550 | tpte = pmap_load(pte); |
| 5551 | if (pmap_pte_dirty(pmap, tpte)) { |
| 5552 | /* |
| 5553 | * Although "tpte" is mapping a 2MB page, because |
| 5554 | * this function is called at a 4KB page granularity, |
| 5555 | * we only update the 4KB page under test. |
| 5556 | */ |
| 5557 | vm_page_dirty(m); |
nothing calls this directly
no test coverage detected