* 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. */
| 2524 | * The given PV list lock may be released. |
| 2525 | */ |
| 2526 | static pv_entry_t |
| 2527 | get_pv_entry(pmap_t pmap, struct rwlock **lockp) |
| 2528 | { |
| 2529 | int bit, field; |
| 2530 | pv_entry_t pv; |
| 2531 | struct pv_chunk *pc; |
| 2532 | vm_page_t m; |
| 2533 | |
| 2534 | PMAP_LOCK_ASSERT(pmap, MA_OWNED); |
| 2535 | PV_STAT(atomic_add_long(&pv_entry_allocs, 1)); |
| 2536 | retry: |
| 2537 | pc = TAILQ_FIRST(&pmap->pm_pvchunk); |
| 2538 | if (pc != NULL) { |
| 2539 | for (field = 0; field < _NPCM; field++) { |
| 2540 | if (pc->pc_map[field]) { |
| 2541 | bit = ffsl(pc->pc_map[field]) - 1; |
| 2542 | break; |
| 2543 | } |
| 2544 | } |
| 2545 | if (field < _NPCM) { |
| 2546 | pv = &pc->pc_pventry[field * 64 + bit]; |
| 2547 | pc->pc_map[field] &= ~(1ul << bit); |
| 2548 | /* If this was the last item, move it to tail */ |
| 2549 | if (pc->pc_map[0] == 0 && pc->pc_map[1] == 0 && |
| 2550 | pc->pc_map[2] == 0) { |
| 2551 | TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list); |
| 2552 | TAILQ_INSERT_TAIL(&pmap->pm_pvchunk, pc, |
| 2553 | pc_list); |
| 2554 | } |
| 2555 | PV_STAT(atomic_add_long(&pv_entry_count, 1)); |
| 2556 | PV_STAT(atomic_subtract_int(&pv_entry_spare, 1)); |
| 2557 | return (pv); |
| 2558 | } |
| 2559 | } |
| 2560 | /* No free items, allocate another chunk */ |
| 2561 | m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | |
| 2562 | VM_ALLOC_WIRED); |
| 2563 | if (m == NULL) { |
| 2564 | if (lockp == NULL) { |
| 2565 | PV_STAT(pc_chunk_tryfail++); |
| 2566 | return (NULL); |
| 2567 | } |
| 2568 | m = reclaim_pv_chunk(pmap, lockp); |
| 2569 | if (m == NULL) |
| 2570 | goto retry; |
| 2571 | } |
| 2572 | PV_STAT(atomic_add_int(&pc_chunk_count, 1)); |
| 2573 | PV_STAT(atomic_add_int(&pc_chunk_allocs, 1)); |
| 2574 | dump_add_page(m->phys_addr); |
| 2575 | pc = (void *)PHYS_TO_DMAP(m->phys_addr); |
| 2576 | pc->pc_pmap = pmap; |
| 2577 | pc->pc_map[0] = PC_FREE0 & ~1ul; /* preallocated bit 0 */ |
| 2578 | pc->pc_map[1] = PC_FREE1; |
| 2579 | pc->pc_map[2] = PC_FREE2; |
| 2580 | mtx_lock(&pv_chunks_mutex); |
| 2581 | TAILQ_INSERT_TAIL(&pv_chunks, pc, pc_lru); |
| 2582 | mtx_unlock(&pv_chunks_mutex); |
| 2583 | pv = &pc->pc_pventry[0]; |
no test coverage detected