* 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
| 8457 | * released. |
| 8458 | */ |
| 8459 | int |
| 8460 | pmap_ts_referenced(vm_page_t m) |
| 8461 | { |
| 8462 | struct md_page *pvh; |
| 8463 | pv_entry_t pv, pvf; |
| 8464 | pmap_t pmap; |
| 8465 | struct rwlock *lock; |
| 8466 | pd_entry_t oldpde, *pde; |
| 8467 | pt_entry_t *pte, PG_A, PG_M, PG_RW; |
| 8468 | vm_offset_t va; |
| 8469 | vm_paddr_t pa; |
| 8470 | int cleared, md_gen, not_cleared, pvh_gen; |
| 8471 | struct spglist free; |
| 8472 | boolean_t demoted; |
| 8473 | |
| 8474 | KASSERT((m->oflags & VPO_UNMANAGED) == 0, |
| 8475 | ("pmap_ts_referenced: page %p is not managed", m)); |
| 8476 | SLIST_INIT(&free); |
| 8477 | cleared = 0; |
| 8478 | pa = VM_PAGE_TO_PHYS(m); |
| 8479 | lock = PHYS_TO_PV_LIST_LOCK(pa); |
| 8480 | pvh = (m->flags & PG_FICTITIOUS) != 0 ? &pv_dummy : pa_to_pvh(pa); |
| 8481 | rw_wlock(lock); |
| 8482 | retry: |
| 8483 | not_cleared = 0; |
| 8484 | if ((pvf = TAILQ_FIRST(&pvh->pv_list)) == NULL) |
| 8485 | goto small_mappings; |
| 8486 | pv = pvf; |
| 8487 | do { |
| 8488 | if (pvf == NULL) |
| 8489 | pvf = pv; |
| 8490 | pmap = PV_PMAP(pv); |
| 8491 | if (!PMAP_TRYLOCK(pmap)) { |
| 8492 | pvh_gen = pvh->pv_gen; |
| 8493 | rw_wunlock(lock); |
| 8494 | PMAP_LOCK(pmap); |
| 8495 | rw_wlock(lock); |
| 8496 | if (pvh_gen != pvh->pv_gen) { |
| 8497 | PMAP_UNLOCK(pmap); |
| 8498 | goto retry; |
| 8499 | } |
| 8500 | } |
| 8501 | PG_A = pmap_accessed_bit(pmap); |
| 8502 | PG_M = pmap_modified_bit(pmap); |
| 8503 | PG_RW = pmap_rw_bit(pmap); |
| 8504 | va = pv->pv_va; |
| 8505 | pde = pmap_pde(pmap, pv->pv_va); |
| 8506 | oldpde = *pde; |
| 8507 | if ((oldpde & (PG_M | PG_RW)) == (PG_M | PG_RW)) { |
| 8508 | /* |
| 8509 | * Although "oldpde" is mapping a 2MB page, because |
| 8510 | * this function is called at a 4KB page granularity, |
| 8511 | * we only update the 4KB page under test. |
| 8512 | */ |
| 8513 | vm_page_dirty(m); |
| 8514 | } |
| 8515 | if ((oldpde & PG_A) != 0) { |
| 8516 | /* |
nothing calls this directly
no test coverage detected