PERFORCE change 129199 for review
Kip Macy
kmacy at FreeBSD.org
Sat Nov 17 23:30:48 PST 2007
http://perforce.freebsd.org/chv.cgi?CH=129199
Change 129199 by kmacy at kmacy:storage:toestack on 2007/11/18 07:29:55
- Add efficient routine for holding user pages for reed/write
in order to allow devices to do DMA to user pages
- this needs an additional per process accounting check to prevent
a user application from holding too many pages at once by sending
large amounts of data over slow connections
Affected files ...
.. //depot/projects/toestack/sys/vm/vm_extern.h#4 edit
.. //depot/projects/toestack/sys/vm/vm_fault.c#4 edit
Differences ...
==== //depot/projects/toestack/sys/vm/vm_extern.h#4 (text+ko) ====
@@ -98,5 +98,8 @@
void vm_thread_swapout(struct thread *td);
void *contigmalloc2(vm_page_t m, vm_pindex_t npages, int flags);
+
+#define VM_HOLD_WRITEABLE 0x1
+int vm_fault_hold_user_pages(vm_offset_t addr, int len, vm_page_t *mp, int *count, int flags);
#endif /* _KERNEL */
#endif /* !_VM_EXTERN_H_ */
==== //depot/projects/toestack/sys/vm/vm_fault.c#4 (text+ko) ====
@@ -1308,3 +1308,111 @@
/* return number of pages */
return i;
}
+
+/*
+ * This routine takes a user address range and does the following:
+ * - validate that the user has access to those pages (flags indicates read or write) - if not fail
+ * - validate that count is enough to hold range number of pages - if not fail
+ * - fault in any non-resident pages
+ * - if the user is doing a read force a write fault for any COWed pages
+ * - if the user is doing a read mark all pages as dirty
+ * - hold all pages
+ * - return number of pages in count
+ */
+
+int
+vm_fault_hold_user_pages(vm_offset_t addr, int len, vm_page_t *mp, int *count, int flags)
+{
+
+ vm_offset_t start, va;
+ vm_paddr_t pa;
+ int pageslen, faults, rv;
+
+ struct thread *td;
+ vm_map_t map;
+ pmap_t pmap;
+ vm_page_t m, *pages;
+ vm_prot_t prot;
+
+ start = addr & ~PAGE_MASK;
+ pageslen = roundup2(addr + len, PAGE_SIZE);
+ if (*count < (pageslen >> PAGE_SHIFT))
+ return (EFBIG);
+
+ *count = pageslen >> PAGE_SHIFT;
+ /*
+ * Check that virtual address range is legal
+ * This check is somewhat bogus as on some architectures kernel
+ * and user do not share VA - however, it appears that all FreeBSD
+ * architectures define it
+ */
+ if (addr + len > VM_MAXUSER_ADDRESS)
+ return (EFAULT);
+
+ td = curthread;
+ map = &td->td_proc->p_vmspace->vm_map;
+ pmap = &td->td_proc->p_vmspace->vm_pmap;
+ pages = mp;
+
+ prot = (flags & VM_HOLD_WRITEABLE) ? VM_PROT_WRITE : VM_PROT_READ;
+ bzero(pages, sizeof(vm_page_t *) * (*count));
+retry:
+
+ /*
+ * First optimistically assume that all pages are resident (and R/W if for write)
+ * if so just mark pages as held (and dirty if for write) and return
+ */
+ vm_page_lock_queues();
+ for (pages = mp, faults = 0, va = start; va < pageslen; va += PAGE_SIZE, pages++) {
+ /*
+ * Assure that we only hold the page once
+ */
+ if (*pages == NULL) {
+ /*
+ * page queue mutex is recursable so this is OK
+ * it would be really nice if we had an unlocked version of this so
+ * 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);
+ if (m == NULL) {
+ faults++;
+ continue;
+ }
+ *pages = m;
+ if (flags & VM_HOLD_WRITEABLE)
+ vm_page_dirty(m);
+ }
+ }
+ vm_page_unlock_queues();
+
+ if (faults == 0)
+ return (0);
+ /*
+ * Pages either have insufficient permissions or are not present
+ * trigger a fault where neccessary
+ *
+ */
+ for (va = start; va < pageslen; va += PAGE_SIZE) {
+ m = NULL;
+ pa = pmap_extract(pmap, va);
+ 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)
+ rv = vm_fault(map, va, VM_PROT_READ, VM_FAULT_NORMAL);
+ if (rv)
+ goto error;
+ }
+ goto retry;
+
+ for (pages = mp, va = start; va < pageslen; va += PAGE_SIZE, pages++)
+ if (*pages)
+ vm_page_unhold(*pages);
+
+ return (EFAULT);
+}
+
More information about the p4-projects
mailing list