FreeBSD/sys/i386/i386/pmap.c
/*
 *	Apply the given advice to the specified range of addresses within the
 *	given pmap.  Depending on the advice, clear the referenced and/or
 *	modified flags in each mapping and set the mapped page's dirty field.
 */
Apply the given advice to the specified range of addresses within the
given pmap.  Depending on the advice, clear the referenced and/or
modified flags in each mapping and set the mapped page's dirty field.
Apply the given advice to the specified range of addresses within the given pmap . Depending on the advice clear the referenced and / or modified flags in each mapping and set the mapped page ' s dirty field .
void
pmap_advise(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, int advice)
{
	pd_entry_t oldpde, *pde;
	pt_entry_t *pte;
	vm_offset_t pdnxt;
	vm_page_t m;
	boolean_t anychanged, pv_lists_locked;
	if (advice != MADV_DONTNEED && advice != MADV_FREE)
		return;
	if (pmap_is_current(pmap))
		pv_lists_locked = FALSE;
	else {
		pv_lists_locked = TRUE;
resume:
		rw_wlock(&pvh_global_lock);
		sched_pin();
	}
	anychanged = FALSE;
	PMAP_LOCK(pmap);
	for (; sva < eva; sva = pdnxt) {
		pdnxt = (sva + NBPDR) & ~PDRMASK;
		if (pdnxt < sva)
			pdnxt = eva;
		pde = pmap_pde(pmap, sva);
		oldpde = *pde;
		if ((oldpde & PG_V) == 0)
			continue;
		else if ((oldpde & PG_PS) != 0) {
			if ((oldpde & PG_MANAGED) == 0)
				continue;
			if (!pv_lists_locked) {
				pv_lists_locked = TRUE;
				if (!rw_try_wlock(&pvh_global_lock)) {
					if (anychanged)
						pmap_invalidate_all(pmap);
					PMAP_UNLOCK(pmap);
					goto resume;
				}
				sched_pin();
			}
			if (!pmap_demote_pde(pmap, pde, sva)) {
				continue;
			}
			if ((oldpde & PG_W) == 0) {
				pte = pmap_pte_quick(pmap, sva);
				KASSERT((*pte & PG_V) != 0,
				    ("pmap_advise: invalid PTE"));
				pmap_remove_pte(pmap, pte, sva, NULL);
				anychanged = TRUE;
			}
		}
		if (pdnxt > eva)
			pdnxt = eva;
		for (pte = pmap_pte_quick(pmap, sva); sva != pdnxt; pte++,
		    sva += PAGE_SIZE) {
			if ((*pte & (PG_MANAGED | PG_V)) != (PG_MANAGED |
			    PG_V))
				continue;
			else if ((*pte & (PG_M | PG_RW)) == (PG_M | PG_RW)) {
				if (advice == MADV_DONTNEED) {
					m = PHYS_TO_VM_PAGE(*pte & PG_FRAME);
					vm_page_dirty(m);
				}
				atomic_clear_int((u_int *)pte, PG_M | PG_A);
			} else if ((*pte & PG_A) != 0)
				atomic_clear_int((u_int *)pte, PG_A);
			else
				continue;
			if ((*pte & PG_G) != 0)
				pmap_invalidate_page(pmap, sva);
			else
				anychanged = TRUE;
		}
	}
	if (anychanged)
		pmap_invalidate_all(pmap);
	if (pv_lists_locked) {
		sched_unpin();
		rw_wunlock(&pvh_global_lock);
	}
	PMAP_UNLOCK(pmap);
}
void pmap_advise ( pmap_t pmap , vm_offset_t sva , vm_offset_t eva , int advice ) { pd_entry_t oldpde , * pde ; pt_entry_t * pte ; vm_offset_t pdnxt ; vm_page_t m ; boolean_t anychanged , pv_lists_locked ; if ( advice != MADV_DONTNEED && advice != MADV_FREE ) return ; if ( pmap_is_current ( pmap ) ) pv_lists_locked = FALSE ; else { pv_lists_locked = TRUE ; resume : rw_wlock ( & pvh_global_lock ) ; sched_pin ( ) ; } anychanged = FALSE ; PMAP_LOCK ( pmap ) ; for ( ; sva < eva ; sva = pdnxt ) { pdnxt = ( sva + NBPDR ) & ~ PDRMASK ; if ( pdnxt < sva ) pdnxt = eva ; pde = pmap_pde ( pmap , sva ) ; oldpde = * pde ; if ( ( oldpde & PG_V ) == 0 ) continue ; else if ( ( oldpde & PG_PS ) != 0 ) { if ( ( oldpde & PG_MANAGED ) == 0 ) continue ; if ( ! pv_lists_locked ) { pv_lists_locked = TRUE ; if ( ! rw_try_wlock ( & pvh_global_lock ) ) { if ( anychanged ) pmap_invalidate_all ( pmap ) ; PMAP_UNLOCK ( pmap ) ; goto resume ; } sched_pin ( ) ; } if ( ! pmap_demote_pde ( pmap , pde , sva ) ) { continue ; } if ( ( oldpde & PG_W ) == 0 ) { pte = pmap_pte_quick ( pmap , sva ) ; KASSERT ( ( * pte & PG_V ) != 0 , ( " " ) ) ; pmap_remove_pte ( pmap , pte , sva , NULL ) ; anychanged = TRUE ; } } if ( pdnxt > eva ) pdnxt = eva ; for ( pte = pmap_pte_quick ( pmap , sva ) ; sva != pdnxt ; pte ++ , sva += PAGE_SIZE ) { if ( ( * pte & ( PG_MANAGED | PG_V ) ) != ( PG_MANAGED | PG_V ) ) continue ; else if ( ( * pte & ( PG_M | PG_RW ) ) == ( PG_M | PG_RW ) ) { if ( advice == MADV_DONTNEED ) { m = PHYS_TO_VM_PAGE ( * pte & PG_FRAME ) ; vm_page_dirty ( m ) ; } atomic_clear_int ( ( u_int * ) pte , PG_M | PG_A ) ; } else if ( ( * pte & PG_A ) != 0 ) atomic_clear_int ( ( u_int * ) pte , PG_A ) ; else continue ; if ( ( * pte & PG_G ) != 0 ) pmap_invalidate_page ( pmap , sva ) ; else anychanged = TRUE ; } } if ( anychanged ) pmap_invalidate_all ( pmap ) ; if ( pv_lists_locked ) { sched_unpin ( ) ; rw_wunlock ( & pvh_global_lock ) ; } PMAP_UNLOCK ( pmap ) ; }
Apply the given advice to the specified range of addresses within the
      given pmap.
Apply the given advice to the specified range of addresses within the given pmap .
/*
				 * The large page mapping was destroyed.
				 */ /*
			 * Unless the page mappings are wired, remove the
			 * mapping to a single page so that a subsequent
			 * access may repromote.  Since the underlying page
			 * table page is fully populated, this removal never
			 * frees a page table page.
			 */ /*
					 * Future calls to pmap_is_modified()
					 * can be avoided by making the page
					 * dirty now.
					 */