FreeBSD/sys/arm/arm/pmap-v6.c
/*
 *  We are in a serious low memory condition.  Resort to
 *  drastic measures to free some pages so we can allocate
 *  another pv entry chunk.
 */
We are in a serious low memory condition.  Resort to
drastic measures to free some pages so we can allocate
another pv entry chunk.
We are in a serious low memory condition . Resort to drastic measures to free some pages so we can allocate another pv entry chunk .
static vm_page_t
pmap_pv_reclaim(pmap_t locked_pmap)
{
	struct pch newtail;
	struct pv_chunk *pc;
	struct md_page *pvh;
	pt1_entry_t *pte1p;
	pmap_t pmap;
	pt2_entry_t *pte2p, tpte2;
	pv_entry_t pv;
	vm_offset_t va;
	vm_page_t m, m_pc;
	struct spglist free;
	uint32_t inuse;
	int bit, field, freed;
	PMAP_LOCK_ASSERT(locked_pmap, MA_OWNED);
	pmap = NULL;
	m_pc = NULL;
	SLIST_INIT(&free);
	TAILQ_INIT(&newtail);
	while ((pc = TAILQ_FIRST(&pv_chunks)) != NULL && (pv_vafree == 0 ||
	    SLIST_EMPTY(&free))) {
		TAILQ_REMOVE(&pv_chunks, pc, pc_lru);
		if (pmap != pc->pc_pmap) {
			if (pmap != NULL) {
				if (pmap != locked_pmap)
					PMAP_UNLOCK(pmap);
			}
			pmap = pc->pc_pmap;
			if (pmap > locked_pmap)
				PMAP_LOCK(pmap);
			else if (pmap != locked_pmap && !PMAP_TRYLOCK(pmap)) {
				pmap = NULL;
				TAILQ_INSERT_TAIL(&newtail, pc, pc_lru);
				continue;
			}
		}
		freed = 0;
		for (field = 0; field < _NPCM; field++) {
			for (inuse = ~pc->pc_map[field] & pc_freemask[field];
			    inuse != 0; inuse &= ~(1UL << bit)) {
				bit = ffs(inuse) - 1;
				pv = &pc->pc_pventry[field * 32 + bit];
				va = pv->pv_va;
				pte1p = pmap_pte1(pmap, va);
				if (pte1_is_section(pte1_load(pte1p)))
					continue;
				pte2p = pmap_pte2(pmap, va);
				tpte2 = pte2_load(pte2p);
				if ((tpte2 & PTE2_W) == 0)
					tpte2 = pte2_load_clear(pte2p);
				pmap_pte2_release(pte2p);
				if ((tpte2 & PTE2_W) != 0)
					continue;
				KASSERT(tpte2 != 0,
				    ("pmap_pv_reclaim: pmap %p va %#x zero pte",
				    pmap, va));
				pmap_tlb_flush(pmap, va);
				m = PHYS_TO_VM_PAGE(pte2_pa(tpte2));
				if (pte2_is_dirty(tpte2))
					vm_page_dirty(m);
				if ((tpte2 & PTE2_A) != 0)
					vm_page_aflag_set(m, PGA_REFERENCED);
				TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
				if (TAILQ_EMPTY(&m->md.pv_list) &&
				    (m->flags & PG_FICTITIOUS) == 0) {
					pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m));
					if (TAILQ_EMPTY(&pvh->pv_list)) {
						vm_page_aflag_clear(m,
						    PGA_WRITEABLE);
					}
				}
				pc->pc_map[field] |= 1UL << bit;
				pmap_unuse_pt2(pmap, va, &free);
				freed++;
			}
		}
		if (freed == 0) {
			TAILQ_INSERT_TAIL(&newtail, pc, pc_lru);
			continue;
		}
		pmap->pm_stats.resident_count -= freed;
		PV_STAT(pv_entry_frees += freed);
		PV_STAT(pv_entry_spare += freed);
		pv_entry_count -= freed;
		TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
		for (field = 0; field < _NPCM; field++)
			if (pc->pc_map[field] != pc_freemask[field]) {
				TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc,
				    pc_list);
				TAILQ_INSERT_TAIL(&newtail, pc, pc_lru);
				if (pmap == locked_pmap)
					goto out;
				break;
			}
		if (field == _NPCM) {
			PV_STAT(pv_entry_spare -= _NPCPV);
			PV_STAT(pc_chunk_count--);
			PV_STAT(pc_chunk_frees++);
			m_pc = PHYS_TO_VM_PAGE(pmap_kextract((vm_offset_t)pc));
			pmap_qremove((vm_offset_t)pc, 1);
			pmap_pte2list_free(&pv_vafree, (vm_offset_t)pc);
			break;
		}
	}
out:
	TAILQ_CONCAT(&pv_chunks, &newtail, pc_lru);
	if (pmap != NULL) {
		if (pmap != locked_pmap)
			PMAP_UNLOCK(pmap);
	}
	if (m_pc == NULL && pv_vafree != 0 && SLIST_EMPTY(&free)) {
		m_pc = SLIST_FIRST(&free);
		SLIST_REMOVE_HEAD(&free, plinks.s.ss);
		m_pc->wire_count = 1;
		atomic_add_int(&vm_cnt.v_wire_count, 1);
	}
	pmap_free_zero_pages(&free);
	return (m_pc);
}
static vm_page_t pmap_pv_reclaim ( pmap_t locked_pmap ) { struct pch newtail ; struct pv_chunk * pc ; struct md_page * pvh ; pt1_entry_t * pte1p ; pmap_t pmap ; pt2_entry_t * pte2p , tpte2 ; pv_entry_t pv ; vm_offset_t va ; vm_page_t m , m_pc ; struct spglist free ; uint32_t inuse ; int bit , field , freed ; PMAP_LOCK_ASSERT ( locked_pmap , MA_OWNED ) ; pmap = NULL ; m_pc = NULL ; SLIST_INIT ( & free ) ; TAILQ_INIT ( & newtail ) ; while ( ( pc = TAILQ_FIRST ( & pv_chunks ) ) != NULL && ( pv_vafree == 0 || SLIST_EMPTY ( & free ) ) ) { TAILQ_REMOVE ( & pv_chunks , pc , pc_lru ) ; if ( pmap != pc -> pc_pmap ) { if ( pmap != NULL ) { if ( pmap != locked_pmap ) PMAP_UNLOCK ( pmap ) ; } pmap = pc -> pc_pmap ; if ( pmap > locked_pmap ) PMAP_LOCK ( pmap ) ; else if ( pmap != locked_pmap && ! PMAP_TRYLOCK ( pmap ) ) { pmap = NULL ; TAILQ_INSERT_TAIL ( & newtail , pc , pc_lru ) ; continue ; } } freed = 0 ; for ( field = 0 ; field < _NPCM ; field ++ ) { for ( inuse = ~ pc -> pc_map [ field ] & pc_freemask [ field ] ; inuse != 0 ; inuse &= ~ ( 1UL << bit ) ) { bit = ffs ( inuse ) - 1 ; pv = & pc -> pc_pventry [ field * 32 + bit ] ; va = pv -> pv_va ; pte1p = pmap_pte1 ( pmap , va ) ; if ( pte1_is_section ( pte1_load ( pte1p ) ) ) continue ; pte2p = pmap_pte2 ( pmap , va ) ; tpte2 = pte2_load ( pte2p ) ; if ( ( tpte2 & PTE2_W ) == 0 ) tpte2 = pte2_load_clear ( pte2p ) ; pmap_pte2_release ( pte2p ) ; if ( ( tpte2 & PTE2_W ) != 0 ) continue ; KASSERT ( tpte2 != 0 , ( " " , pmap , va ) ) ; pmap_tlb_flush ( pmap , va ) ; m = PHYS_TO_VM_PAGE ( pte2_pa ( tpte2 ) ) ; if ( pte2_is_dirty ( tpte2 ) ) vm_page_dirty ( m ) ; if ( ( tpte2 & PTE2_A ) != 0 ) vm_page_aflag_set ( m , PGA_REFERENCED ) ; TAILQ_REMOVE ( & m -> md . pv_list , pv , pv_next ) ; if ( TAILQ_EMPTY ( & m -> md . pv_list ) && ( m -> flags & PG_FICTITIOUS ) == 0 ) { pvh = pa_to_pvh ( VM_PAGE_TO_PHYS ( m ) ) ; if ( TAILQ_EMPTY ( & pvh -> pv_list ) ) { vm_page_aflag_clear ( m , PGA_WRITEABLE ) ; } } pc -> pc_map [ field ] |= 1UL << bit ; pmap_unuse_pt2 ( pmap , va , & free ) ; freed ++ ; } } if ( freed == 0 ) { TAILQ_INSERT_TAIL ( & newtail , pc , pc_lru ) ; continue ; } pmap -> pm_stats . resident_count -= freed ; PV_STAT ( pv_entry_frees += freed ) ; PV_STAT ( pv_entry_spare += freed ) ; pv_entry_count -= freed ; TAILQ_REMOVE ( & pmap -> pm_pvchunk , pc , pc_list ) ; for ( field = 0 ; field < _NPCM ; field ++ ) if ( pc -> pc_map [ field ] != pc_freemask [ field ] ) { TAILQ_INSERT_HEAD ( & pmap -> pm_pvchunk , pc , pc_list ) ; TAILQ_INSERT_TAIL ( & newtail , pc , pc_lru ) ; if ( pmap == locked_pmap ) goto out ; break ; } if ( field == _NPCM ) { PV_STAT ( pv_entry_spare -= _NPCPV ) ; PV_STAT ( pc_chunk_count -- ) ; PV_STAT ( pc_chunk_frees ++ ) ; m_pc = PHYS_TO_VM_PAGE ( pmap_kextract ( ( vm_offset_t ) pc ) ) ; pmap_qremove ( ( vm_offset_t ) pc , 1 ) ; pmap_pte2list_free ( & pv_vafree , ( vm_offset_t ) pc ) ; break ; } } out : TAILQ_CONCAT ( & pv_chunks , & newtail , pc_lru ) ; if ( pmap != NULL ) { if ( pmap != locked_pmap ) PMAP_UNLOCK ( pmap ) ; } if ( m_pc == NULL && pv_vafree != 0 && SLIST_EMPTY ( & free ) ) { m_pc = SLIST_FIRST ( & free ) ; SLIST_REMOVE_HEAD ( & free , plinks . s . ss ) ; m_pc -> wire_count = 1 ; atomic_add_int ( & vm_cnt . v_wire_count , 1 ) ; } pmap_free_zero_pages ( & free ) ; return ( m_pc ) ; }
We are in a serious low memory condition.
We are in a serious low memory condition .
/* Avoid deadlock and lock recursion. */ /*
		 * Destroy every non-wired, 4 KB page mapping in the chunk.
		 */ /* Every freed mapping is for a 4 KB page. */ /*
				 * One freed pv entry in locked_pmap is
				 * sufficient.
				 */ /* Entire chunk is free; return it. */ /* Recycle a freed page table page. */