Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/amd64/pmap.c
Show First 20 Lines • Show All 608 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Internal flags for pmap_enter()'s helper functions. | * Internal flags for pmap_enter()'s helper functions. | ||||
*/ | */ | ||||
#define PMAP_ENTER_NORECLAIM 0x1000000 /* Don't reclaim PV entries. */ | #define PMAP_ENTER_NORECLAIM 0x1000000 /* Don't reclaim PV entries. */ | ||||
#define PMAP_ENTER_NOREPLACE 0x2000000 /* Don't replace mappings. */ | #define PMAP_ENTER_NOREPLACE 0x2000000 /* Don't replace mappings. */ | ||||
static void free_pv_chunk(struct pv_chunk *pc); | static void free_pv_chunk(struct pv_chunk *pc); | ||||
static void free_pv_entry(pmap_t pmap, pv_entry_t pv); | static void free_pv_entry(pmap_t pmap, pv_entry_t pv); | ||||
static pv_entry_t get_pv_entry(pmap_t pmap, struct rwlock **lockp); | static pv_entry_t get_pv_entry(pmap_t pmap, vm_offset_t va, | ||||
struct rwlock **lockp); | |||||
static int popcnt_pc_map_pq(uint64_t *map); | static int popcnt_pc_map_pq(uint64_t *map); | ||||
static vm_page_t reclaim_pv_chunk(pmap_t locked_pmap, struct rwlock **lockp); | static vm_page_t reclaim_pv_chunk(pmap_t locked_pmap, vm_offset_t skip_va, | ||||
static void reserve_pv_entries(pmap_t pmap, int needed, | |||||
struct rwlock **lockp); | struct rwlock **lockp); | ||||
static void reserve_pv_entries(pmap_t pmap, vm_offset_t skip_va, int needed, | |||||
struct rwlock **lockp); | |||||
static void pmap_pv_demote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, | static void pmap_pv_demote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, | ||||
struct rwlock **lockp); | struct rwlock **lockp); | ||||
static bool pmap_pv_insert_pde(pmap_t pmap, vm_offset_t va, pd_entry_t pde, | static bool pmap_pv_insert_pde(pmap_t pmap, vm_offset_t va, pd_entry_t pde, | ||||
u_int flags, struct rwlock **lockp); | u_int flags, struct rwlock **lockp); | ||||
#if VM_NRESERVLEVEL > 0 | #if VM_NRESERVLEVEL > 0 | ||||
static void pmap_pv_promote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, | static void pmap_pv_promote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, | ||||
struct rwlock **lockp); | struct rwlock **lockp); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 2,539 Lines • ▼ Show 20 Lines | if (pmap != locked_pmap) | ||||
PMAP_UNLOCK(pmap); | PMAP_UNLOCK(pmap); | ||||
if (start_di) | if (start_di) | ||||
pmap_delayed_invl_finished(); | pmap_delayed_invl_finished(); | ||||
} | } | ||||
/* | /* | ||||
* We are in a serious low memory condition. Resort to | * We are in a serious low memory condition. Resort to | ||||
* drastic measures to free some pages so we can allocate | * drastic measures to free some pages so we can allocate | ||||
* another pv entry chunk. | * another pv entry chunk. Do not free a PV entry for skip_va from | ||||
* the specified pmap since the caller may be attempting to update | |||||
* the corresponding page table entry. | |||||
* | * | ||||
* Returns NULL if PV entries were reclaimed from the specified pmap. | * Returns NULL if PV entries were reclaimed from the specified pmap. | ||||
* | * | ||||
* We do not, however, unmap 2mpages because subsequent accesses will | * We do not, however, unmap 2mpages because subsequent accesses will | ||||
* allocate per-page pv entries until repromotion occurs, thereby | * allocate per-page pv entries until repromotion occurs, thereby | ||||
* exacerbating the shortage of free pv entries. | * exacerbating the shortage of free pv entries. | ||||
*/ | */ | ||||
static vm_page_t | static vm_page_t | ||||
reclaim_pv_chunk(pmap_t locked_pmap, struct rwlock **lockp) | reclaim_pv_chunk(pmap_t locked_pmap, vm_offset_t skip_va, struct rwlock **lockp) | ||||
{ | { | ||||
struct pv_chunk *pc, *pc_marker, *pc_marker_end; | struct pv_chunk *pc, *pc_marker, *pc_marker_end; | ||||
struct pv_chunk_header pc_marker_b, pc_marker_end_b; | struct pv_chunk_header pc_marker_b, pc_marker_end_b; | ||||
struct md_page *pvh; | struct md_page *pvh; | ||||
pd_entry_t *pde; | pd_entry_t *pde; | ||||
pmap_t next_pmap, pmap; | pmap_t next_pmap, pmap; | ||||
pt_entry_t *pte, tpte; | pt_entry_t *pte, tpte; | ||||
pt_entry_t PG_G, PG_A, PG_M, PG_RW; | pt_entry_t PG_G, PG_A, PG_M, PG_RW; | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | while ((pc = TAILQ_NEXT(pc_marker, pc_lru)) != pc_marker_end && | ||||
*/ | */ | ||||
freed = 0; | freed = 0; | ||||
for (field = 0; field < _NPCM; field++) { | for (field = 0; field < _NPCM; field++) { | ||||
for (inuse = ~pc->pc_map[field] & pc_freemask[field]; | for (inuse = ~pc->pc_map[field] & pc_freemask[field]; | ||||
inuse != 0; inuse &= ~(1UL << bit)) { | inuse != 0; inuse &= ~(1UL << bit)) { | ||||
bit = bsfq(inuse); | bit = bsfq(inuse); | ||||
pv = &pc->pc_pventry[field * 64 + bit]; | pv = &pc->pc_pventry[field * 64 + bit]; | ||||
va = pv->pv_va; | va = pv->pv_va; | ||||
if (pmap == locked_pmap && va == skip_va) | |||||
continue; | |||||
pde = pmap_pde(pmap, va); | pde = pmap_pde(pmap, va); | ||||
if ((*pde & PG_PS) != 0) | if ((*pde & PG_PS) != 0) | ||||
continue; | continue; | ||||
pte = pmap_pde_to_pte(pde, va); | pte = pmap_pde_to_pte(pde, va); | ||||
if ((*pte & PG_W) != 0) | if ((*pte & PG_W) != 0) | ||||
continue; | continue; | ||||
tpte = pte_load_clear(pte); | tpte = pte_load_clear(pte); | ||||
if ((tpte & PG_G) != 0) | if ((tpte & PG_G) != 0) | ||||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | free_pv_chunk(struct pv_chunk *pc) | ||||
/* entire chunk is free, return it */ | /* entire chunk is free, return it */ | ||||
m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pc)); | m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pc)); | ||||
dump_drop_page(m->phys_addr); | dump_drop_page(m->phys_addr); | ||||
vm_page_unwire(m, PQ_NONE); | vm_page_unwire(m, PQ_NONE); | ||||
vm_page_free(m); | vm_page_free(m); | ||||
} | } | ||||
/* | /* | ||||
* Returns a new PV entry, allocating a new PV chunk from the system when | * Returns a new PV entry for the specified virtual address, allocating a new | ||||
* needed. If this PV chunk allocation fails and a PV list lock pointer was | * PV chunk from the system when needed. If this PV chunk allocation fails | ||||
* given, a PV chunk is reclaimed from an arbitrary pmap. Otherwise, NULL is | * and a PV list lock pointer was given, a PV chunk is reclaimed from an | ||||
* returned. | * arbitrary pmap. Otherwise, NULL is returned. | ||||
* | * | ||||
* The given PV list lock may be released. | * The given PV list lock may be released. | ||||
*/ | */ | ||||
static pv_entry_t | static pv_entry_t | ||||
get_pv_entry(pmap_t pmap, struct rwlock **lockp) | get_pv_entry(pmap_t pmap, vm_offset_t va, struct rwlock **lockp) | ||||
{ | { | ||||
int bit, field; | int bit, field; | ||||
pv_entry_t pv; | pv_entry_t pv; | ||||
struct pv_chunk *pc; | struct pv_chunk *pc; | ||||
vm_page_t m; | vm_page_t m; | ||||
PMAP_LOCK_ASSERT(pmap, MA_OWNED); | PMAP_LOCK_ASSERT(pmap, MA_OWNED); | ||||
PV_STAT(atomic_add_long(&pv_entry_allocs, 1)); | PV_STAT(atomic_add_long(&pv_entry_allocs, 1)); | ||||
retry: | retry: | ||||
pc = TAILQ_FIRST(&pmap->pm_pvchunk); | pc = TAILQ_FIRST(&pmap->pm_pvchunk); | ||||
if (pc != NULL) { | if (pc != NULL) { | ||||
for (field = 0; field < _NPCM; field++) { | for (field = 0; field < _NPCM; field++) { | ||||
if (pc->pc_map[field]) { | if (pc->pc_map[field]) { | ||||
bit = bsfq(pc->pc_map[field]); | bit = bsfq(pc->pc_map[field]); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (field < _NPCM) { | if (field < _NPCM) { | ||||
pv = &pc->pc_pventry[field * 64 + bit]; | pv = &pc->pc_pventry[field * 64 + bit]; | ||||
pv->pv_va = va; | |||||
pc->pc_map[field] &= ~(1ul << bit); | pc->pc_map[field] &= ~(1ul << bit); | ||||
/* If this was the last item, move it to tail */ | /* If this was the last item, move it to tail */ | ||||
if (pc->pc_map[0] == 0 && pc->pc_map[1] == 0 && | if (pc->pc_map[0] == 0 && pc->pc_map[1] == 0 && | ||||
pc->pc_map[2] == 0) { | pc->pc_map[2] == 0) { | ||||
TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list); | TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list); | ||||
TAILQ_INSERT_TAIL(&pmap->pm_pvchunk, pc, | TAILQ_INSERT_TAIL(&pmap->pm_pvchunk, pc, | ||||
pc_list); | pc_list); | ||||
} | } | ||||
PV_STAT(atomic_add_long(&pv_entry_count, 1)); | PV_STAT(atomic_add_long(&pv_entry_count, 1)); | ||||
PV_STAT(atomic_subtract_int(&pv_entry_spare, 1)); | PV_STAT(atomic_subtract_int(&pv_entry_spare, 1)); | ||||
return (pv); | return (pv); | ||||
} | } | ||||
} | } | ||||
/* No free items, allocate another chunk */ | /* No free items, allocate another chunk */ | ||||
m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | | m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | | ||||
VM_ALLOC_WIRED); | VM_ALLOC_WIRED); | ||||
if (m == NULL) { | if (m == NULL) { | ||||
if (lockp == NULL) { | if (lockp == NULL) { | ||||
PV_STAT(pc_chunk_tryfail++); | PV_STAT(pc_chunk_tryfail++); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
m = reclaim_pv_chunk(pmap, lockp); | m = reclaim_pv_chunk(pmap, va, lockp); | ||||
if (m == NULL) | if (m == NULL) | ||||
goto retry; | goto retry; | ||||
} | } | ||||
PV_STAT(atomic_add_int(&pc_chunk_count, 1)); | PV_STAT(atomic_add_int(&pc_chunk_count, 1)); | ||||
PV_STAT(atomic_add_int(&pc_chunk_allocs, 1)); | PV_STAT(atomic_add_int(&pc_chunk_allocs, 1)); | ||||
dump_add_page(m->phys_addr); | dump_add_page(m->phys_addr); | ||||
pc = (void *)PHYS_TO_DMAP(m->phys_addr); | pc = (void *)PHYS_TO_DMAP(m->phys_addr); | ||||
pc->pc_pmap = pmap; | pc->pc_pmap = pmap; | ||||
pc->pc_map[0] = PC_FREE0 & ~1ul; /* preallocated bit 0 */ | pc->pc_map[0] = PC_FREE0 & ~1ul; /* preallocated bit 0 */ | ||||
pc->pc_map[1] = PC_FREE1; | pc->pc_map[1] = PC_FREE1; | ||||
pc->pc_map[2] = PC_FREE2; | pc->pc_map[2] = PC_FREE2; | ||||
mtx_lock(&pv_chunks_mutex); | mtx_lock(&pv_chunks_mutex); | ||||
TAILQ_INSERT_TAIL(&pv_chunks, pc, pc_lru); | TAILQ_INSERT_TAIL(&pv_chunks, pc, pc_lru); | ||||
mtx_unlock(&pv_chunks_mutex); | mtx_unlock(&pv_chunks_mutex); | ||||
pv = &pc->pc_pventry[0]; | pv = &pc->pc_pventry[0]; | ||||
pv->pv_va = va; | |||||
TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc, pc_list); | TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc, pc_list); | ||||
PV_STAT(atomic_add_long(&pv_entry_count, 1)); | PV_STAT(atomic_add_long(&pv_entry_count, 1)); | ||||
PV_STAT(atomic_add_int(&pv_entry_spare, _NPCPV - 1)); | PV_STAT(atomic_add_int(&pv_entry_spare, _NPCPV - 1)); | ||||
return (pv); | return (pv); | ||||
} | } | ||||
/* | /* | ||||
* Returns the number of one bits within the given PV chunk map. | * Returns the number of one bits within the given PV chunk map. | ||||
Show All 21 Lines | __asm __volatile("xorl %k0,%k0;popcntq %2,%0;" | ||||
"xorl %k1,%k1;popcntq %4,%1;addl %k1,%k0" | "xorl %k1,%k1;popcntq %4,%1;addl %k1,%k0" | ||||
: "=&r" (result), "=&r" (tmp) | : "=&r" (result), "=&r" (tmp) | ||||
: "m" (map[0]), "m" (map[1]), "m" (map[2])); | : "m" (map[0]), "m" (map[1]), "m" (map[2])); | ||||
return (result); | return (result); | ||||
} | } | ||||
/* | /* | ||||
* Ensure that the number of spare PV entries in the specified pmap meets or | * Ensure that the number of spare PV entries in the specified pmap meets or | ||||
* exceeds the given count, "needed". | * exceeds the given count, "needed". If it becomes necessary to reclaim a PV | ||||
* chunk in order to satisfy the reservation, do not reclaim a PV entry for | |||||
* skip_va. | |||||
* | * | ||||
* The given PV list lock may be released. | * The given PV list lock may be released. | ||||
*/ | */ | ||||
static void | static void | ||||
reserve_pv_entries(pmap_t pmap, int needed, struct rwlock **lockp) | reserve_pv_entries(pmap_t pmap, vm_offset_t skip_va, int needed, | ||||
struct rwlock **lockp) | |||||
{ | { | ||||
struct pch new_tail; | struct pch new_tail; | ||||
struct pv_chunk *pc; | struct pv_chunk *pc; | ||||
int avail, free; | int avail, free; | ||||
vm_page_t m; | vm_page_t m; | ||||
PMAP_LOCK_ASSERT(pmap, MA_OWNED); | PMAP_LOCK_ASSERT(pmap, MA_OWNED); | ||||
KASSERT(lockp != NULL, ("reserve_pv_entries: lockp is NULL")); | KASSERT(lockp != NULL, ("reserve_pv_entries: lockp is NULL")); | ||||
Show All 20 Lines | #endif | ||||
avail += free; | avail += free; | ||||
if (avail >= needed) | if (avail >= needed) | ||||
break; | break; | ||||
} | } | ||||
for (; avail < needed; avail += _NPCPV) { | for (; avail < needed; avail += _NPCPV) { | ||||
m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | | m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | | ||||
VM_ALLOC_WIRED); | VM_ALLOC_WIRED); | ||||
if (m == NULL) { | if (m == NULL) { | ||||
m = reclaim_pv_chunk(pmap, lockp); | m = reclaim_pv_chunk(pmap, skip_va, lockp); | ||||
if (m == NULL) | if (m == NULL) | ||||
goto retry; | goto retry; | ||||
} | } | ||||
PV_STAT(atomic_add_int(&pc_chunk_count, 1)); | PV_STAT(atomic_add_int(&pc_chunk_count, 1)); | ||||
PV_STAT(atomic_add_int(&pc_chunk_allocs, 1)); | PV_STAT(atomic_add_int(&pc_chunk_allocs, 1)); | ||||
dump_add_page(m->phys_addr); | dump_add_page(m->phys_addr); | ||||
pc = (void *)PHYS_TO_DMAP(m->phys_addr); | pc = (void *)PHYS_TO_DMAP(m->phys_addr); | ||||
pc->pc_pmap = pmap; | pc->pc_pmap = pmap; | ||||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | |||||
static boolean_t | static boolean_t | ||||
pmap_try_insert_pv_entry(pmap_t pmap, vm_offset_t va, vm_page_t m, | pmap_try_insert_pv_entry(pmap_t pmap, vm_offset_t va, vm_page_t m, | ||||
struct rwlock **lockp) | struct rwlock **lockp) | ||||
{ | { | ||||
pv_entry_t pv; | pv_entry_t pv; | ||||
PMAP_LOCK_ASSERT(pmap, MA_OWNED); | PMAP_LOCK_ASSERT(pmap, MA_OWNED); | ||||
/* Pass NULL instead of the lock pointer to disable reclamation. */ | /* Pass NULL instead of the lock pointer to disable reclamation. */ | ||||
if ((pv = get_pv_entry(pmap, NULL)) != NULL) { | if ((pv = get_pv_entry(pmap, va, NULL)) != NULL) { | ||||
pv->pv_va = va; | |||||
CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m); | CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m); | ||||
TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); | TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); | ||||
m->md.pv_gen++; | m->md.pv_gen++; | ||||
return (TRUE); | return (TRUE); | ||||
} else | } else | ||||
return (FALSE); | return (FALSE); | ||||
} | } | ||||
/* | /* | ||||
* Create the PV entry for a 2MB page mapping. Always returns true unless the | * Create the PV entry for a 2MB page mapping. Always returns true unless the | ||||
* flag PMAP_ENTER_NORECLAIM is specified. If that flag is specified, returns | * flag PMAP_ENTER_NORECLAIM is specified. If that flag is specified, returns | ||||
* false if the PV entry cannot be allocated without resorting to reclamation. | * false if the PV entry cannot be allocated without resorting to reclamation. | ||||
*/ | */ | ||||
static bool | static bool | ||||
pmap_pv_insert_pde(pmap_t pmap, vm_offset_t va, pd_entry_t pde, u_int flags, | pmap_pv_insert_pde(pmap_t pmap, vm_offset_t va, pd_entry_t pde, u_int flags, | ||||
struct rwlock **lockp) | struct rwlock **lockp) | ||||
{ | { | ||||
struct md_page *pvh; | struct md_page *pvh; | ||||
pv_entry_t pv; | pv_entry_t pv; | ||||
vm_paddr_t pa; | vm_paddr_t pa; | ||||
PMAP_LOCK_ASSERT(pmap, MA_OWNED); | PMAP_LOCK_ASSERT(pmap, MA_OWNED); | ||||
/* Pass NULL instead of the lock pointer to disable reclamation. */ | /* Pass NULL instead of the lock pointer to disable reclamation. */ | ||||
if ((pv = get_pv_entry(pmap, (flags & PMAP_ENTER_NORECLAIM) != 0 ? | if ((pv = get_pv_entry(pmap, va, (flags & PMAP_ENTER_NORECLAIM) != 0 ? | ||||
NULL : lockp)) == NULL) | NULL : lockp)) == NULL) | ||||
return (false); | return (false); | ||||
pv->pv_va = va; | |||||
pa = pde & PG_PS_FRAME; | pa = pde & PG_PS_FRAME; | ||||
CHANGE_PV_LIST_LOCK_TO_PHYS(lockp, pa); | CHANGE_PV_LIST_LOCK_TO_PHYS(lockp, pa); | ||||
pvh = pa_to_pvh(pa); | pvh = pa_to_pvh(pa); | ||||
TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_next); | TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_next); | ||||
pvh->pv_gen++; | pvh->pv_gen++; | ||||
return (true); | return (true); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, | ||||
* The spare PV entries must be reserved prior to demoting the | * The spare PV entries must be reserved prior to demoting the | ||||
* mapping, that is, prior to changing the PDE. Otherwise, the state | * mapping, that is, prior to changing the PDE. Otherwise, the state | ||||
* of the PDE and the PV lists will be inconsistent, which can result | * of the PDE and the PV lists will be inconsistent, which can result | ||||
* in reclaim_pv_chunk() attempting to remove a PV entry from the | * in reclaim_pv_chunk() attempting to remove a PV entry from the | ||||
* wrong PV list and pmap_pv_demote_pde() failing to find the expected | * wrong PV list and pmap_pv_demote_pde() failing to find the expected | ||||
* PV entry for the 2MB page mapping that is being demoted. | * PV entry for the 2MB page mapping that is being demoted. | ||||
*/ | */ | ||||
if ((oldpde & PG_MANAGED) != 0) | if ((oldpde & PG_MANAGED) != 0) | ||||
reserve_pv_entries(pmap, NPTEPG - 1, lockp); | reserve_pv_entries(pmap, va, NPTEPG - 1, lockp); | ||||
/* | /* | ||||
* Demote the mapping. This pmap is locked. The old PDE has | * Demote the mapping. This pmap is locked. The old PDE has | ||||
* PG_A set. If the old PDE has PG_RW set, it also has PG_M | * PG_A set. If the old PDE has PG_RW set, it also has PG_M | ||||
* set. Thus, there is no danger of a race with another | * set. Thus, there is no danger of a race with another | ||||
* processor changing the setting of PG_A and/or PG_M between | * processor changing the setting of PG_A and/or PG_M between | ||||
* the read above and the store below. | * the read above and the store below. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 938 Lines • ▼ Show 20 Lines | if ((newpte & PG_W) != 0) | ||||
pmap->pm_stats.wired_count++; | pmap->pm_stats.wired_count++; | ||||
pmap_resident_count_inc(pmap, 1); | pmap_resident_count_inc(pmap, 1); | ||||
} | } | ||||
/* | /* | ||||
* Enter on the PV list if part of our managed memory. | * Enter on the PV list if part of our managed memory. | ||||
*/ | */ | ||||
if ((newpte & PG_MANAGED) != 0) { | if ((newpte & PG_MANAGED) != 0) { | ||||
pv = get_pv_entry(pmap, &lock); | pv = get_pv_entry(pmap, va, &lock); | ||||
pv->pv_va = va; | |||||
CHANGE_PV_LIST_LOCK_TO_PHYS(&lock, pa); | CHANGE_PV_LIST_LOCK_TO_PHYS(&lock, pa); | ||||
TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); | TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); | ||||
m->md.pv_gen++; | m->md.pv_gen++; | ||||
if ((newpte & PG_RW) != 0) | if ((newpte & PG_RW) != 0) | ||||
vm_page_aflag_set(m, PGA_WRITEABLE); | vm_page_aflag_set(m, PGA_WRITEABLE); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 3,263 Lines • Show Last 20 Lines |