diff options
author | kmacy <kmacy@FreeBSD.org> | 2008-09-29 22:13:29 +0000 |
---|---|---|
committer | kmacy <kmacy@FreeBSD.org> | 2008-09-29 22:13:29 +0000 |
commit | cc2238d3339259960bfe8a6173749d9b0f95c9d9 (patch) | |
tree | dff10c28a75372762a0d64fd69327dc92ebb8084 /sys/dev | |
parent | de9e8917480edc80682a8b4355dfd83e315ea796 (diff) | |
download | FreeBSD-src-cc2238d3339259960bfe8a6173749d9b0f95c9d9.zip FreeBSD-src-cc2238d3339259960bfe8a6173749d9b0f95c9d9.tar.gz |
vm_fault_hold_user_pages will not return if an address in the range passed in is mapped RO
but an RW mapping exists for the underlying page. This change fixes the bug by using the
page / NULL returned from pmap_extract_and_hold to determine whether or not vm_fault needs
to be called.
The bug was pointed out by alc.
MFC after: 3 days
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/cxgb/ulp/tom/cxgb_vm.c | 22 |
1 files changed, 8 insertions, 14 deletions
diff --git a/sys/dev/cxgb/ulp/tom/cxgb_vm.c b/sys/dev/cxgb/ulp/tom/cxgb_vm.c index 9c6898a..0b83d4e 100644 --- a/sys/dev/cxgb/ulp/tom/cxgb_vm.c +++ b/sys/dev/cxgb/ulp/tom/cxgb_vm.c @@ -65,9 +65,7 @@ __FBSDID("$FreeBSD$"); int vm_fault_hold_user_pages(vm_offset_t addr, vm_page_t *mp, int count, int flags) { - vm_offset_t end, va; - vm_paddr_t pa; int faults, rv; struct thread *td; @@ -96,7 +94,6 @@ vm_fault_hold_user_pages(vm_offset_t addr, vm_page_t *mp, int count, int flags) prot = VM_PROT_READ; prot |= (flags & VM_HOLD_WRITEABLE) ? VM_PROT_WRITE : 0; - bzero(pages, sizeof(vm_page_t *) * count); retry: /* @@ -115,13 +112,12 @@ retry: * we were only acquiring the pmap lock 1 time as opposed to potentially * many dozens of times */ - m = pmap_extract_and_hold(pmap, va, prot); + *pages = m = pmap_extract_and_hold(pmap, va, prot); if (m == NULL) { faults++; continue; } - *pages = m; if (flags & VM_HOLD_WRITEABLE) vm_page_dirty(m); } @@ -137,16 +133,14 @@ retry: * trigger a fault where neccessary * */ - for (va = addr; va < end; va += PAGE_SIZE) { - m = NULL; - pa = pmap_extract(pmap, va); + for (pages = mp, va = addr; va < end; va += PAGE_SIZE, pages++) { + m = *pages; rv = 0; - if (pa) - m = PHYS_TO_VM_PAGE(pa); - if (flags & VM_HOLD_WRITEABLE) { - if (m == NULL || (m->flags & PG_WRITEABLE) == 0) - rv = vm_fault(map, va, VM_PROT_WRITE, VM_FAULT_DIRTY); - } else if (m == NULL) + if (m) + continue; + if (flags & VM_HOLD_WRITEABLE) + rv = vm_fault(map, va, VM_PROT_WRITE, VM_FAULT_DIRTY); + else rv = vm_fault(map, va, VM_PROT_READ, VM_FAULT_NORMAL); if (rv) { printf("vm_fault bad return rv=%d va=0x%zx\n", rv, va); |