diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index b5e469b..5197608 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -974,7 +974,6 @@ pmap_extract_and_hold(pmap_t pmap, vm_of vm_page_t m; m = NULL; - vm_page_lock_queues(); PMAP_LOCK(pmap); pdep = pmap_pde(pmap, va); if (pdep != NULL && (pde = *pdep)) { @@ -993,7 +992,6 @@ pmap_extract_and_hold(pmap_t pmap, vm_of } } } - vm_page_unlock_queues(); PMAP_UNLOCK(pmap); return (m); } diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 0836e25..b5ca61c 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -855,9 +855,7 @@ exec_map_first_page(imgp) return (EIO); } } - vm_page_lock_queues(); vm_page_hold(ma[0]); - vm_page_unlock_queues(); vm_page_wakeup(ma[0]); VM_OBJECT_UNLOCK(object); @@ -877,9 +875,7 @@ exec_unmap_first_page(imgp) m = sf_buf_page(imgp->firstpage); sf_buf_free(imgp->firstpage); imgp->firstpage = NULL; - vm_page_lock_queues(); vm_page_unhold(m); - vm_page_unlock_queues(); } } diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 703134a..99ccee8 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -781,10 +781,8 @@ pipe_build_write_buffer(wpipe, uio) */ race: if (vm_fault_quick((caddr_t)addr, VM_PROT_READ) < 0) { - vm_page_lock_queues(); for (j = 0; j < i; j++) vm_page_unhold(wpipe->pipe_map.ms[j]); - vm_page_unlock_queues(); return (EFAULT); } wpipe->pipe_map.ms[i] = pmap_extract_and_hold(pmap, addr, @@ -824,11 +822,9 @@ pipe_destroy_write_buffer(wpipe) int i; PIPE_LOCK_ASSERT(wpipe, MA_OWNED); - vm_page_lock_queues(); for (i = 0; i < wpipe->pipe_map.npages; i++) { vm_page_unhold(wpipe->pipe_map.ms[i]); } - vm_page_unlock_queues(); wpipe->pipe_map.npages = 0; } diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 18e2db0..1c310c0 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -309,9 +309,7 @@ proc_rwmem(struct proc *p, struct uio *u /* * Hold the page in memory. */ - vm_page_lock_queues(); vm_page_hold(m); - vm_page_unlock_queues(); /* * We're done with tmap now. @@ -326,9 +324,7 @@ proc_rwmem(struct proc *p, struct uio *u /* * Release the page. */ - vm_page_lock_queues(); vm_page_unhold(m); - vm_page_unlock_queues(); } while (error == 0 && uio->uio_resid > 0); diff --git a/sys/kern/uipc_cow.c b/sys/kern/uipc_cow.c index e384b84..ef22a0b 100644 --- a/sys/kern/uipc_cow.c +++ b/sys/kern/uipc_cow.c @@ -135,8 +135,8 @@ socow_setup(struct mbuf *m0, struct uio * wire the page for I/O */ vm_page_wire(pp); - vm_page_unhold(pp); vm_page_unlock_queues(); + vm_page_unhold(pp); /* * Allocate an sf buf diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index c741021..c1260a0 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -3740,12 +3740,10 @@ vmapbuf(struct buf *bp) retry: if (vm_fault_quick(addr >= bp->b_data ? addr : bp->b_data, prot) < 0) { - vm_page_lock_queues(); for (i = 0; i < pidx; ++i) { vm_page_unhold(bp->b_pages[i]); bp->b_pages[i] = NULL; } - vm_page_unlock_queues(); return(-1); } m = pmap_extract_and_hold(pmap, (vm_offset_t)addr, prot); @@ -3776,10 +3774,8 @@ vunmapbuf(struct buf *bp) npages = bp->b_npages; pmap_qremove(trunc_page((vm_offset_t)bp->b_data), npages); - vm_page_lock_queues(); for (pidx = 0; pidx < npages; pidx++) vm_page_unhold(bp->b_pages[pidx]); - vm_page_unlock_queues(); bp->b_data = bp->b_saveaddr; } diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index ce7ab95..b690d4d 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -270,9 +270,7 @@ vm_imgact_hold_page(vm_object_t object, goto out; } } - vm_page_lock_queues(); vm_page_hold(m); - vm_page_unlock_queues(); vm_page_wakeup(m); out: VM_OBJECT_UNLOCK(object); @@ -306,9 +304,7 @@ vm_imgact_unmap_page(struct sf_buf *sf) m = sf_buf_page(sf); sf_buf_free(sf); sched_unpin(); - vm_page_lock_queues(); vm_page_unhold(m); - vm_page_unlock_queues(); } #ifndef KSTACK_MAX_PAGES diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index dd2ff95..8efe7ec 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -456,19 +456,29 @@ void vm_page_hold(vm_page_t mem) { - mtx_assert(&vm_page_queue_mtx, MA_OWNED); - mem->hold_count++; + atomic_add_int(&mem->hold_count, 1); } void vm_page_unhold(vm_page_t mem) { + int cnt; - mtx_assert(&vm_page_queue_mtx, MA_OWNED); - --mem->hold_count; - KASSERT(mem->hold_count >= 0, ("vm_page_unhold: hold count < 0!!!")); - if (mem->hold_count == 0 && VM_PAGE_INQUEUE2(mem, PQ_HOLD)) + cnt = atomic_fetchadd_int(&mem->hold_count, -1); + KASSERT(cnt >= 0, ("vm_page_unhold: hold count < 0!!!")); + if (cnt == 1 && VM_PAGE_INQUEUE2(mem, PQ_HOLD)) { + vm_page_lock_queues(); + /* + * Check which queue we're in again, in case we raced with + * vm_page_free_toq(). + */ + if (!VM_PAGE_INQUEUE2(mem, PQ_HOLD)) { + vm_page_unlock_queues(); + return; + } vm_page_free_toq(mem); + vm_page_unlock_queues(); + } } /* @@ -1146,8 +1156,17 @@ vm_page_free_toq(vm_page_t m) panic("vm_page_free: freeing wired page"); } if (m->hold_count != 0) { - m->flags &= ~PG_ZERO; VM_PAGE_SETQUEUE2(m, PQ_HOLD); + + /* + * Check if we raced with vm_page_unhold(), in which case + * we need to move the page back into the free queue. + */ + if (m->hold_count == 0) + VM_PAGE_SETQUEUE1(m, PQ_FREE); + else + m->flags &= ~PG_ZERO; + } else VM_PAGE_SETQUEUE1(m, PQ_FREE); pq = &vm_page_queues[VM_PAGE_GETQUEUE(m)]; diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index d173eab..892435a 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -115,7 +115,7 @@ struct vm_page { pc; /* page color */ u_short wire_count; /* wired down maps refs (P) */ u_int cow; /* page cow mapping count */ - short hold_count; /* page hold count */ + u_int hold_count; /* page hold count */ u_short oflags; /* page flags (O) */ u_char act_count; /* page usage count */ u_char busy; /* page busy count (O) */