diff options
author | alc <alc@FreeBSD.org> | 2004-06-23 04:37:14 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2004-06-23 04:37:14 +0000 |
commit | a7339dd630908d8b36aa1327f9cfe91bbb08e166 (patch) | |
tree | 3742d51cf242ef418dfad9c40e00446a2d7bb21a /sys/amd64 | |
parent | 02f435b86f33f736587cc5061f5997c04ac4e923 (diff) | |
download | FreeBSD-src-a7339dd630908d8b36aa1327f9cfe91bbb08e166.zip FreeBSD-src-a7339dd630908d8b36aa1327f9cfe91bbb08e166.tar.gz |
Implement the protection check required by the pmap_extract_and_hold()
specification. This enables the elimination of Giant from that function.
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/amd64/pmap.c | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 81b2669..4ab9630 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -801,18 +801,34 @@ pmap_extract(pmap, va) vm_page_t pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot) { - vm_paddr_t pa; + pd_entry_t pde, *pdep; + pt_entry_t pte; vm_page_t m; m = NULL; - mtx_lock(&Giant); - if ((pa = pmap_extract(pmap, va)) != 0) { - m = PHYS_TO_VM_PAGE(pa); - vm_page_lock_queues(); - vm_page_hold(m); - vm_page_unlock_queues(); + if (pmap == NULL) + return (m); + vm_page_lock_queues(); + PMAP_LOCK(pmap); + pdep = pmap_pde(pmap, va); + if (pdep != NULL && (pde = *pdep)) { + if (pde & PG_PS) { + if ((pde & PG_RW) || (prot & VM_PROT_WRITE) == 0) { + m = PHYS_TO_VM_PAGE((pde & ~PDRMASK) | + (va & PDRMASK)); + vm_page_hold(m); + } + } else { + pte = *pmap_pte(pmap, va); + if ((pte & PG_V) && + ((pte & PG_RW) || (prot & VM_PROT_WRITE) == 0)) { + m = PHYS_TO_VM_PAGE(pte & PG_FRAME); + vm_page_hold(m); + } + } } - mtx_unlock(&Giant); + vm_page_unlock_queues(); + PMAP_UNLOCK(pmap); return (m); } |