* Returns a new PV entry, allocating a new PV chunk from the system when * needed. If this PV chunk allocation fails and a PV list lock pointer was * given, a PV chunk is reclaimed from an arbitrary pmap. Otherwise, NULL is * returned. * * The given PV list lock may be released. */
| 5209 | * The given PV list lock may be released. |
| 5210 | */ |
| 5211 | static pv_entry_t |
| 5212 | get_pv_entry(pmap_t pmap, struct rwlock **lockp) |
| 5213 | { |
| 5214 | struct pv_chunks_list *pvc; |
| 5215 | int bit, field; |
| 5216 | pv_entry_t pv; |
| 5217 | struct pv_chunk *pc; |
| 5218 | vm_page_t m; |
| 5219 | |
| 5220 | PMAP_LOCK_ASSERT(pmap, MA_OWNED); |
| 5221 | PV_STAT(atomic_add_long(&pv_entry_allocs, 1)); |
| 5222 | retry: |
| 5223 | pc = TAILQ_FIRST(&pmap->pm_pvchunk); |
| 5224 | if (pc != NULL) { |
| 5225 | for (field = 0; field < _NPCM; field++) { |
| 5226 | if (pc->pc_map[field]) { |
| 5227 | bit = bsfq(pc->pc_map[field]); |
| 5228 | break; |
| 5229 | } |
| 5230 | } |
| 5231 | if (field < _NPCM) { |
| 5232 | pv = &pc->pc_pventry[field * 64 + bit]; |
| 5233 | pc->pc_map[field] &= ~(1ul << bit); |
| 5234 | /* If this was the last item, move it to tail */ |
| 5235 | if (pc->pc_map[0] == 0 && pc->pc_map[1] == 0 && |
| 5236 | pc->pc_map[2] == 0) { |
| 5237 | TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list); |
| 5238 | TAILQ_INSERT_TAIL(&pmap->pm_pvchunk, pc, |
| 5239 | pc_list); |
| 5240 | } |
| 5241 | PV_STAT(atomic_add_long(&pv_entry_count, 1)); |
| 5242 | PV_STAT(atomic_subtract_int(&pv_entry_spare, 1)); |
| 5243 | return (pv); |
| 5244 | } |
| 5245 | } |
| 5246 | /* No free items, allocate another chunk */ |
| 5247 | m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | |
| 5248 | VM_ALLOC_WIRED); |
| 5249 | if (m == NULL) { |
| 5250 | if (lockp == NULL) { |
| 5251 | PV_STAT(pc_chunk_tryfail++); |
| 5252 | return (NULL); |
| 5253 | } |
| 5254 | m = reclaim_pv_chunk(pmap, lockp); |
| 5255 | if (m == NULL) |
| 5256 | goto retry; |
| 5257 | } |
| 5258 | PV_STAT(atomic_add_int(&pc_chunk_count, 1)); |
| 5259 | PV_STAT(atomic_add_int(&pc_chunk_allocs, 1)); |
| 5260 | dump_add_page(m->phys_addr); |
| 5261 | pc = (void *)PHYS_TO_DMAP(m->phys_addr); |
| 5262 | pc->pc_pmap = pmap; |
| 5263 | pc->pc_map[0] = PC_FREE0 & ~1ul; /* preallocated bit 0 */ |
| 5264 | pc->pc_map[1] = PC_FREE1; |
| 5265 | pc->pc_map[2] = PC_FREE2; |
| 5266 | pvc = &pv_chunks[vm_page_domain(m)]; |
| 5267 | mtx_lock(&pvc->pvc_lock); |
| 5268 | TAILQ_INSERT_TAIL(&pvc->pvc_list, pc, pc_lru); |
no test coverage detected