FreeBSD/sys/i386/i386/pmap.c
/*
 * Clear the write and modified bits in each of the given page's mappings.
 */
Clear the write and modified bits in each of the given page's mappings.
Clear the write and modified bits in each of the given page ' s mappings .
void
pmap_remove_write(vm_page_t m)
{
	struct md_page *pvh;
	pv_entry_t next_pv, pv;
	pmap_t pmap;
	pd_entry_t *pde;
	pt_entry_t oldpte, *pte;
	vm_offset_t va;
	KASSERT((m->oflags & VPO_UNMANAGED) == 0,
	    ("pmap_remove_write: page %p is not managed", m));
	VM_OBJECT_ASSERT_WLOCKED(m->object);
	if (!vm_page_xbusied(m) && (m->aflags & PGA_WRITEABLE) == 0)
		return;
	rw_wlock(&pvh_global_lock);
	sched_pin();
	if ((m->flags & PG_FICTITIOUS) != 0)
		goto small_mappings;
	pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m));
	TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) {
		va = pv->pv_va;
		pmap = PV_PMAP(pv);
		PMAP_LOCK(pmap);
		pde = pmap_pde(pmap, va);
		if ((*pde & PG_RW) != 0)
			(void)pmap_demote_pde(pmap, pde, va);
		PMAP_UNLOCK(pmap);
	}
small_mappings:
	TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
		pmap = PV_PMAP(pv);
		PMAP_LOCK(pmap);
		pde = pmap_pde(pmap, pv->pv_va);
		KASSERT((*pde & PG_PS) == 0, ("pmap_clear_write: found"
		    " a 4mpage in page %p's pv list", m));
		pte = pmap_pte_quick(pmap, pv->pv_va);
retry:
		oldpte = *pte;
		if ((oldpte & PG_RW) != 0) {
			if (!atomic_cmpset_int((u_int *)pte, oldpte,
			    oldpte & ~(PG_RW | PG_M)))
				goto retry;
			if ((oldpte & PG_M) != 0)
				vm_page_dirty(m);
			pmap_invalidate_page(pmap, pv->pv_va);
		}
		PMAP_UNLOCK(pmap);
	}
	vm_page_aflag_clear(m, PGA_WRITEABLE);
	sched_unpin();
	rw_wunlock(&pvh_global_lock);
}
void pmap_remove_write ( vm_page_t m ) { struct md_page * pvh ; pv_entry_t next_pv , pv ; pmap_t pmap ; pd_entry_t * pde ; pt_entry_t oldpte , * pte ; vm_offset_t va ; KASSERT ( ( m -> oflags & VPO_UNMANAGED ) == 0 , ( " " , m ) ) ; VM_OBJECT_ASSERT_WLOCKED ( m -> object ) ; if ( ! vm_page_xbusied ( m ) && ( m -> aflags & PGA_WRITEABLE ) == 0 ) return ; rw_wlock ( & pvh_global_lock ) ; sched_pin ( ) ; if ( ( m -> flags & PG_FICTITIOUS ) != 0 ) goto small_mappings ; pvh = pa_to_pvh ( VM_PAGE_TO_PHYS ( m ) ) ; TAILQ_FOREACH_SAFE ( pv , & pvh -> pv_list , pv_next , next_pv ) { va = pv -> pv_va ; pmap = PV_PMAP ( pv ) ; PMAP_LOCK ( pmap ) ; pde = pmap_pde ( pmap , va ) ; if ( ( * pde & PG_RW ) != 0 ) ( void ) pmap_demote_pde ( pmap , pde , va ) ; PMAP_UNLOCK ( pmap ) ; } small_mappings : TAILQ_FOREACH ( pv , & m -> md . pv_list , pv_next ) { pmap = PV_PMAP ( pv ) ; PMAP_LOCK ( pmap ) ; pde = pmap_pde ( pmap , pv -> pv_va ) ; KASSERT ( ( * pde & PG_PS ) == 0 , ( " " " " , m ) ) ; pte = pmap_pte_quick ( pmap , pv -> pv_va ) ; retry : oldpte = * pte ; if ( ( oldpte & PG_RW ) != 0 ) { if ( ! atomic_cmpset_int ( ( u_int * ) pte , oldpte , oldpte & ~ ( PG_RW | PG_M ) ) ) goto retry ; if ( ( oldpte & PG_M ) != 0 ) vm_page_dirty ( m ) ; pmap_invalidate_page ( pmap , pv -> pv_va ) ; } PMAP_UNLOCK ( pmap ) ; } vm_page_aflag_clear ( m , PGA_WRITEABLE ) ; sched_unpin ( ) ; rw_wunlock ( & pvh_global_lock ) ; }
Clear the write and modified bits in each of the given page's mappings.
Clear the write and modified bits in each of the given page ' s mappings .
/*
	 * If the page is not exclusive busied, then PGA_WRITEABLE cannot be
	 * set by another thread while the object is locked.  Thus,
	 * if PGA_WRITEABLE is clear, no page table entries need updating.
	 */ /*
			 * Regardless of whether a pte is 32 or 64 bits
			 * in size, PG_RW and PG_M are among the least
			 * significant 32 bits.
			 */