diff options
author | Thordur I. Bjornsson <thib@cvs.openbsd.org> | 2010-06-27 03:03:50 +0000 |
---|---|---|
committer | Thordur I. Bjornsson <thib@cvs.openbsd.org> | 2010-06-27 03:03:50 +0000 |
commit | 8a46d785199bcae03d0469a55b99e08fe33263fa (patch) | |
tree | 9b784b445528b5c78da12077fd065ae9030cf6d7 /sys/uvm | |
parent | b109c783d06f4af76ff573fa020fbe9d1d855f7b (diff) |
uvm constraints. Add two mandatory MD symbols, uvm_md_constraints
which contains the constraints for DMA/memory allocation for each
architecture, and dma_constraints which contains the range of addresses
that are dma accessable by the system.
This is based on ariane@'s physcontig diff, with lots of bugfixes and
additions the following additions by my self:
Introduce a new function pool_set_constraints() which sets the address
range for which we allocate pages for the pool from, this is now used
for the mbuf/mbuf cluster pools to keep them dma accessible.
The !direct archs no longer stuff pages into the kernel object in
uvm_km_getpage_pla but rather do a pmap_extract() in uvm_km_putpages.
Tested heavily by my self on i386, amd64 and sparc64. Some tests on
alpha and SGI.
"commit it" beck, art, oga, deraadt
"i like the diff" deraadt
Diffstat (limited to 'sys/uvm')
-rw-r--r-- | sys/uvm/uvm.h | 43 | ||||
-rw-r--r-- | sys/uvm/uvm_extern.h | 18 | ||||
-rw-r--r-- | sys/uvm/uvm_km.c | 305 | ||||
-rw-r--r-- | sys/uvm/uvm_page.c | 43 | ||||
-rw-r--r-- | sys/uvm/uvm_page.h | 4 | ||||
-rw-r--r-- | sys/uvm/uvm_pglist.c | 3 | ||||
-rw-r--r-- | sys/uvm/uvm_pmemrange.c | 61 |
7 files changed, 281 insertions, 196 deletions
diff --git a/sys/uvm/uvm.h b/sys/uvm/uvm.h index 9814120fd39..258a16c8f3c 100644 --- a/sys/uvm/uvm.h +++ b/sys/uvm/uvm.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm.h,v 1.39 2010/06/09 08:26:21 thib Exp $ */ +/* $OpenBSD: uvm.h,v 1.40 2010/06/27 03:03:49 thib Exp $ */ /* $NetBSD: uvm.h,v 1.24 2000/11/27 08:40:02 chs Exp $ */ /* @@ -68,33 +68,28 @@ #include <machine/vmparam.h> /* - * UVM_IO_RANGES: paddr_t pairs, describing the lowest and highest address - * that should be reserved. These ranges (which may overlap) will have their - * use counter increased, causing them to be avoided if an allocation can be - * satisfied from another range of memory. + * uvm_constraint_range's: + * MD code is allowed to setup constraint ranges for memory allocators, the + * primary use for this is to keep allocation for certain memory consumers + * such as mbuf pools withing address ranges that are reachable by devices + * that perform DMA. * - * UVM_IO_RANGES actually results into a call to uvm_pmr_use_inc() per range - * at uvm initialization. uvm_pmr_use_inc() can also be called after uvm_init() - * has completed. + * It is also to discourge memory allocations from being satisfied from ranges + * such as the ISA memory range, if they can be satisfied with allocation + * from other ranges. * - * Note: the upper bound is specified in the same way as to uvm_pglistalloc. - * Ex: a memory range of 16 bit is specified as: { 0, 0xffff }. - * Default: no special ranges in use. + * the MD ranges are defined in arch/ARCH/ARCH/machdep.c */ -#ifndef UVM_IO_RANGES -#define UVM_IO_RANGES \ - { \ - { 0, 0x00ffffffUL }, /* ISA memory */ \ - { 0, 0xffffffffUL }, /* 32-bit PCI memory */ \ - } -#endif - -/* UVM IO ranges are described in an array of struct uvm_io_ranges. */ -struct uvm_io_ranges { - paddr_t low; - paddr_t high; +struct uvm_constraint_range { + paddr_t ucr_low; + paddr_t ucr_high; }; +/* Constraint ranges, set by MD code. */ +extern struct uvm_constraint_range isa_constraint; +extern struct uvm_constraint_range dma_constraint; +extern struct uvm_constraint_range *uvm_md_constraints[]; + /* * uvm structure (vm global state: collected in one structure for ease * of reference...) @@ -103,7 +98,7 @@ struct uvm_io_ranges { struct uvm { /* vm_page related parameters */ - /* vm_page queues */ + /* vm_page queues */ struct pglist page_active; /* allocated pages, in use */ struct pglist page_inactive_swp;/* pages inactive (reclaim or free) */ struct pglist page_inactive_obj;/* pages inactive (reclaim or free) */ diff --git a/sys/uvm/uvm_extern.h b/sys/uvm/uvm_extern.h index 7941d55963f..e9ea11298e5 100644 --- a/sys/uvm/uvm_extern.h +++ b/sys/uvm/uvm_extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_extern.h,v 1.86 2010/06/09 08:26:21 thib Exp $ */ +/* $OpenBSD: uvm_extern.h,v 1.87 2010/06/27 03:03:49 thib Exp $ */ /* $NetBSD: uvm_extern.h,v 1.57 2001/03/09 01:02:12 chs Exp $ */ /* @@ -205,6 +205,7 @@ typedef int vm_prot_t; #define UVM_KMF_NOWAIT 0x1 /* matches M_NOWAIT */ #define UVM_KMF_VALLOC 0x2 /* allocate VA only */ #define UVM_KMF_CANFAIL 0x4 /* caller handles failure */ +#define UVM_KMF_ZERO 0x08 /* zero pages */ #define UVM_KMF_TRYLOCK UVM_FLAG_TRYLOCK /* try locking only */ /* @@ -517,8 +518,11 @@ vaddr_t uvm_km_alloc1(vm_map_t, vsize_t, vsize_t, boolean_t); void uvm_km_free(vm_map_t, vaddr_t, vsize_t); void uvm_km_free_wakeup(vm_map_t, vaddr_t, vsize_t); -vaddr_t uvm_km_kmemalloc(vm_map_t, struct uvm_object *, - vsize_t, int); +vaddr_t uvm_km_kmemalloc_pla(struct vm_map *, + struct uvm_object *, vsize_t, int, paddr_t, + paddr_t, paddr_t, paddr_t, int); +#define uvm_km_kmemalloc(map, obj, sz, flags) \ + uvm_km_kmemalloc_pla(map, obj, sz, flags, 0, (paddr_t)-1, 0, 0, 0) struct vm_map *uvm_km_suballoc(vm_map_t, vaddr_t *, vaddr_t *, vsize_t, int, boolean_t, vm_map_t); @@ -528,7 +532,13 @@ vaddr_t uvm_km_valloc_wait(vm_map_t, vsize_t); vaddr_t uvm_km_valloc_align(struct vm_map *, vsize_t, vsize_t, int); vaddr_t uvm_km_valloc_prefer_wait(vm_map_t, vsize_t, voff_t); -void *uvm_km_getpage(boolean_t, int *); +void *uvm_km_getpage_pla(boolean_t, int *, paddr_t, paddr_t, + paddr_t, paddr_t); +/* Wrapper around old function prototype. */ +#define uvm_km_getpage(waitok, slowdown) \ + uvm_km_getpage_pla(((waitok) ? 0 : UVM_KMF_NOWAIT), (slowdown), \ + (paddr_t)0, (paddr_t)-1, 0, 0) + void uvm_km_putpage(void *); /* uvm_map.c */ diff --git a/sys/uvm/uvm_km.c b/sys/uvm/uvm_km.c index e00ee709591..19d22bb269e 100644 --- a/sys/uvm/uvm_km.c +++ b/sys/uvm/uvm_km.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_km.c,v 1.76 2010/02/12 01:35:14 tedu Exp $ */ +/* $OpenBSD: uvm_km.c,v 1.77 2010/06/27 03:03:49 thib Exp $ */ /* $NetBSD: uvm_km.c,v 1.42 2001/01/14 02:10:01 thorpej Exp $ */ /* @@ -326,7 +326,6 @@ uvm_km_pgremove_intrsafe(vaddr_t start, vaddr_t end) } } - /* * uvm_km_kmemalloc: lower level kernel memory allocator for malloc() * @@ -337,20 +336,29 @@ uvm_km_pgremove_intrsafe(vaddr_t start, vaddr_t end) * => we return KVA of memory allocated * => flags: NOWAIT, VALLOC - just allocate VA, TRYLOCK - fail if we can't * lock the map + * => low, high, alignment, boundary, nsegs are the corresponding parameters + * to uvm_pglistalloc + * => flags: ZERO - correspond to uvm_pglistalloc flags */ vaddr_t -uvm_km_kmemalloc(struct vm_map *map, struct uvm_object *obj, vsize_t size, - int flags) +uvm_km_kmemalloc_pla(struct vm_map *map, struct uvm_object *obj, vsize_t size, + int flags, paddr_t low, paddr_t high, paddr_t alignment, paddr_t boundary, + int nsegs) { vaddr_t kva, loopva; voff_t offset; struct vm_page *pg; + struct pglist pgl; + int pla_flags; UVMHIST_FUNC("uvm_km_kmemalloc"); UVMHIST_CALLED(maphist); UVMHIST_LOG(maphist," (map=%p, obj=%p, size=0x%lx, flags=%d)", map, obj, size, flags); KASSERT(vm_map_pmap(map) == pmap_kernel()); + /* UVM_KMF_VALLOC => !UVM_KMF_ZERO */ + KASSERT(!(flags & UVM_KMF_VALLOC) || + !(flags & UVM_KMF_ZERO)); /* * setup for call @@ -358,6 +366,8 @@ uvm_km_kmemalloc(struct vm_map *map, struct uvm_object *obj, vsize_t size, size = round_page(size); kva = vm_map_min(map); /* hint */ + if (nsegs == 0) + nsegs = atop(size); /* * allocate some virtual space @@ -394,28 +404,31 @@ uvm_km_kmemalloc(struct vm_map *map, struct uvm_object *obj, vsize_t size, * now allocate and map in the memory... note that we are the only ones * whom should ever get a handle on this area of VM. */ + TAILQ_INIT(&pgl); + pla_flags = 0; + if ((flags & UVM_KMF_NOWAIT) || + ((flags & UVM_KMF_CANFAIL) && + uvmexp.swpgonly - uvmexp.swpages <= atop(size))) + pla_flags |= UVM_PLA_NOWAIT; + else + pla_flags |= UVM_PLA_WAITOK; + if (flags & UVM_KMF_ZERO) + pla_flags |= UVM_PLA_ZERO; + if (uvm_pglistalloc(size, low, high, alignment, boundary, &pgl, nsegs, + pla_flags) != 0) { + /* Failed. */ + uvm_unmap(map, kva, kva + size); + return (0); + } loopva = kva; while (loopva != kva + size) { - pg = uvm_pagealloc(obj, offset, NULL, 0); - if (pg) { - atomic_clearbits_int(&pg->pg_flags, PG_BUSY); - UVM_PAGE_OWN(pg, NULL); - } - - if (__predict_false(pg == NULL)) { - if ((flags & UVM_KMF_NOWAIT) || - ((flags & UVM_KMF_CANFAIL) && - uvmexp.swpgonly == uvmexp.swpages)) { - /* free everything! */ - uvm_unmap(map, kva, kva + size); - return (0); - } else { - uvm_wait("km_getwait2"); /* sleep here */ - continue; - } - } - + pg = TAILQ_FIRST(&pgl); + TAILQ_REMOVE(&pgl, pg, pageq); + uvm_pagealloc_pg(pg, obj, offset, NULL); + atomic_clearbits_int(&pg->pg_flags, PG_BUSY); + UVM_PAGE_OWN(pg, NULL); + /* * map it in: note that we call pmap_enter with the map and * object unlocked in case we are kmem_map. @@ -432,6 +445,7 @@ uvm_km_kmemalloc(struct vm_map *map, struct uvm_object *obj, vsize_t size, loopva += PAGE_SIZE; offset += PAGE_SIZE; } + KASSERT(TAILQ_EMPTY(&pgl)); pmap_update(pmap_kernel()); UVMHIST_LOG(maphist,"<- done (kva=0x%lx)", kva,0,0,0); @@ -666,7 +680,7 @@ int uvm_km_pages_free; /* number of pages currently on free list */ * uvm_km_page allocator, __HAVE_PMAP_DIRECT arch * On architectures with machine memory direct mapped into a portion * of KVM, we have very little work to do. Just get a physical page, - * and find and return its VA. We use the poolpage functions for this. + * and find and return its VA. */ void uvm_km_page_init(void) @@ -674,34 +688,6 @@ uvm_km_page_init(void) /* nothing */ } -void * -uvm_km_getpage(boolean_t waitok, int *slowdown) -{ - struct vm_page *pg; - vaddr_t va; - - *slowdown = 0; - again: - pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE); - if (__predict_false(pg == NULL)) { - if (waitok) { - uvm_wait("plpg"); - goto again; - } else - return (NULL); - } - va = pmap_map_direct(pg); - if (__predict_false(va == 0)) - uvm_pagefree(pg); - return ((void *)va); -} - -void -uvm_km_putpage(void *v) -{ - uvm_pagefree(pmap_unmap_direct((vaddr_t)v)); -} - #else /* * uvm_km_page allocator, non __HAVE_PMAP_DIRECT archs @@ -714,13 +700,24 @@ uvm_km_putpage(void *v) * not zero filled. */ -struct mutex uvm_km_mtx; -int uvm_km_pages_lowat; /* allocate more when reserve drops below this */ -struct km_page { - struct km_page *next; -} *uvm_km_pages_head; +#define UVM_KM_PAGES_LOWAT_MAX (2048) +#define UVM_KM_PAGES_HIWAT_MAX (4 * UVM_KM_PAGES_LOWAT_MAX) + +struct uvm_km_pages { + struct mutex mtx; + + /* Low and high water mark for addresses. */ + int lowat; + int hiwat; -struct proc *uvm_km_proc; + /* Kernel address pool. */ + int free; + vaddr_t page[UVM_KM_PAGES_HIWAT_MAX]; + + struct proc *km_proc; +}; + +struct uvm_km_pages uvm_km_pages; void uvm_km_createthread(void *); void uvm_km_thread(void *); @@ -734,31 +731,36 @@ void uvm_km_thread(void *); void uvm_km_page_init(void) { - struct km_page *page; int lowat_min; int i; - mtx_init(&uvm_km_mtx, IPL_VM); - if (!uvm_km_pages_lowat) { + mtx_init(&uvm_km_pages.mtx, IPL_VM); + if (!uvm_km_pages.lowat) { /* based on physmem, calculate a good value here */ - uvm_km_pages_lowat = physmem / 256; - if (uvm_km_pages_lowat > 2048) - uvm_km_pages_lowat = 2048; + uvm_km_pages.lowat = physmem / 256; lowat_min = physmem < atop(16 * 1024 * 1024) ? 32 : 128; - if (uvm_km_pages_lowat < lowat_min) - uvm_km_pages_lowat = lowat_min; + if (uvm_km_pages.lowat < lowat_min) + uvm_km_pages.lowat = lowat_min; } - - for (i = 0; i < uvm_km_pages_lowat * 4; i++) { - page = (void *)uvm_km_alloc(kernel_map, PAGE_SIZE); - page->next = uvm_km_pages_head; - uvm_km_pages_head = page; + if (uvm_km_pages.lowat > UVM_KM_PAGES_LOWAT_MAX) + uvm_km_pages.lowat = UVM_KM_PAGES_LOWAT_MAX; + uvm_km_pages.hiwat = 4 * uvm_km_pages.lowat; + if (uvm_km_pages.hiwat > UVM_KM_PAGES_HIWAT_MAX) + uvm_km_pages.hiwat = UVM_KM_PAGES_HIWAT_MAX; + + for (i = 0; i < uvm_km_pages.hiwat; i++) { + uvm_km_pages.page[i] = (vaddr_t)uvm_km_kmemalloc(kernel_map, + NULL, PAGE_SIZE, UVM_KMF_NOWAIT|UVM_KMF_VALLOC); + if (uvm_km_pages.page[i] == NULL) + break; } - uvm_km_pages_free = i; + uvm_km_pages.free = i; + for ( ; i < UVM_KM_PAGES_HIWAT_MAX; i++) + uvm_km_pages.page[i] = NULL; /* tone down if really high */ - if (uvm_km_pages_lowat > 512) - uvm_km_pages_lowat = 512; + if (uvm_km_pages.lowat > 512) + uvm_km_pages.lowat = 512; kthread_create_deferred(uvm_km_createthread, NULL); } @@ -766,7 +768,7 @@ uvm_km_page_init(void) void uvm_km_createthread(void *arg) { - kthread_create(uvm_km_thread, NULL, &uvm_km_proc, "kmthread"); + kthread_create(uvm_km_thread, NULL, &uvm_km_pages.km_proc, "kmthread"); } /* @@ -778,74 +780,123 @@ uvm_km_createthread(void *arg) void uvm_km_thread(void *arg) { - struct km_page *head, *tail, *page; - int i, want; - - for (i = want = 16; ; ) { - if (i < want || uvm_km_pages_free >= uvm_km_pages_lowat) - tsleep(&uvm_km_pages_head, PVM, "kmalloc", 0); - for (i = 0; i < want; i++) { - page = (void *)uvm_km_alloc(kernel_map, PAGE_SIZE); - if (i == 0) - head = tail = page; - if (page == NULL) - break; - page->next = head; - head = page; + vaddr_t pg[16]; + int i; + + for (;;) { + mtx_enter(&uvm_km_pages.mtx); + if (uvm_km_pages.free >= uvm_km_pages.lowat) { + msleep(&uvm_km_pages.km_proc, &uvm_km_pages.mtx, + PVM, "kmalloc", 0); + } + + for (i = 0; i < nitems(pg); i++) { + pg[i] = (vaddr_t)uvm_km_kmemalloc(kernel_map, NULL, + PAGE_SIZE, UVM_KMF_VALLOC); } - if (head != NULL) { - mtx_enter(&uvm_km_mtx); - tail->next = uvm_km_pages_head; - uvm_km_pages_head = head; - uvm_km_pages_free += i; - mtx_leave(&uvm_km_mtx); + + mtx_enter(&uvm_km_pages.mtx); + for (i = 0; i < nitems(pg); i++) { + if (uvm_km_pages.free == nitems(uvm_km_pages.page)) + break; + else + uvm_km_pages.page[uvm_km_pages.free++] = pg[i]; } - if (uvm_km_pages_free) - wakeup(&uvm_km_pages_free); + + wakeup(&uvm_km_pages.free); + mtx_leave(&uvm_km_pages.mtx); + + /* Cleanup left-over pages (if any). */ + for (; i < nitems(pg); i++) + uvm_km_free_wakeup(kernel_map, pg[i], PAGE_SIZE); } } +#endif - -/* - * Allocate one page. We can sleep for more if the caller - * permits it. Wake up the thread if we've dropped below lowat. - */ void * -uvm_km_getpage(boolean_t waitok, int *slowdown) +uvm_km_getpage_pla(int flags, int *slowdown, paddr_t low, paddr_t high, + paddr_t alignment, paddr_t boundary) { - struct km_page *page = NULL; + struct pglist pgl; + int pla_flags; + struct vm_page *pg; + vaddr_t va; *slowdown = 0; - mtx_enter(&uvm_km_mtx); - for (;;) { - page = uvm_km_pages_head; - if (page) { - uvm_km_pages_head = page->next; - uvm_km_pages_free--; - break; + pla_flags = (flags & UVM_KMF_NOWAIT) ? UVM_PLA_NOWAIT : UVM_PLA_WAITOK; + if (flags & UVM_KMF_ZERO) + pla_flags |= UVM_PLA_ZERO; + TAILQ_INIT(&pgl); + if (uvm_pglistalloc(PAGE_SIZE, low, high, alignment, boundary, &pgl, + 1, pla_flags) != 0) + return NULL; + pg = TAILQ_FIRST(&pgl); + KASSERT(pg != NULL && TAILQ_NEXT(pg, pageq) == NULL); + TAILQ_REMOVE(&pgl, pg, pageq); + +#ifdef __HAVE_PMAP_DIRECT + va = pmap_map_direct(pg); + if (__predict_false(va == 0)) + uvm_pagefree(pg); + +#else /* !__HAVE_PMAP_DIRECT */ + mtx_enter(&uvm_km_pages.mtx); + while (uvm_km_pages.free == 0) { + if (flags & UVM_KMF_NOWAIT) { + mtx_leave(&uvm_km_pages.mtx); + uvm_pagefree(pg); + return NULL; } - if (!waitok) - break; - msleep(&uvm_km_pages_free, &uvm_km_mtx, PVM, "getpage", 0); + msleep(&uvm_km_pages.free, &uvm_km_pages.mtx, PVM, "getpage", + 0); } - mtx_leave(&uvm_km_mtx); - if (uvm_km_pages_free < uvm_km_pages_lowat) { - if (curproc != uvm_km_proc) - *slowdown = 1; - wakeup(&uvm_km_pages_head); + + va = uvm_km_pages.page[--uvm_km_pages.free]; + if (uvm_km_pages.free < uvm_km_pages.lowat && + curproc != uvm_km_pages.km_proc) { + *slowdown = 1; + wakeup(&uvm_km_pages.km_proc); } - return (page); + mtx_leave(&uvm_km_pages.mtx); + + + atomic_setbits_int(&pg->pg_flags, PG_FAKE); + UVM_PAGE_OWN(pg, NULL); + + pmap_enter(kernel_map->pmap, va, VM_PAGE_TO_PHYS(pg), UVM_PROT_RW, + PMAP_WIRED | VM_PROT_READ | VM_PROT_WRITE); + pmap_update(kernel_map->pmap); + +#endif /* !__HAVE_PMAP_DIRECT */ + return ((void *)va); } void uvm_km_putpage(void *v) { - struct km_page *page = v; + vaddr_t va = (vaddr_t)v; + struct vm_page *pg; + +#ifdef __HAVE_PMAP_DIRECT + pg = pmap_unmap_direct(va); +#else /* !__HAVE_PMAP_DIRECT */ + paddr_t pa; + if (!pmap_extract(pmap_kernel(), va, &pa)) + panic("lost pa"); + pg = PHYS_TO_VM_PAGE(pa); + + KASSERT(pg != NULL); - mtx_enter(&uvm_km_mtx); - page->next = uvm_km_pages_head; - uvm_km_pages_head = page; - uvm_km_pages_free++; - mtx_leave(&uvm_km_mtx); + pmap_remove(kernel_map->pmap, va, va + PAGE_SIZE); + pmap_update(kernel_map->pmap); + + mtx_enter(&uvm_km_pages.mtx); + if (uvm_km_pages.free < uvm_km_pages.hiwat) + uvm_km_pages.page[uvm_km_pages.free++] = va; + else + uvm_km_free_wakeup(kernel_map, va, PAGE_SIZE); + mtx_leave(&uvm_km_pages.mtx); +#endif /* !__HAVE_PMAP_DIRECT */ + + uvm_pagefree(pg); } -#endif diff --git a/sys/uvm/uvm_page.c b/sys/uvm/uvm_page.c index d40e6a41abb..6a038d8d015 100644 --- a/sys/uvm/uvm_page.c +++ b/sys/uvm/uvm_page.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_page.c,v 1.100 2010/04/22 19:02:55 oga Exp $ */ +/* $OpenBSD: uvm_page.c,v 1.101 2010/06/27 03:03:49 thib Exp $ */ /* $NetBSD: uvm_page.c,v 1.44 2000/11/27 08:40:04 chs Exp $ */ /* @@ -777,6 +777,33 @@ uvm_shutdown(void) } /* + * Perform insert of a given page in the specified anon of obj. + * This is basically, uvm_pagealloc, but with the page already given. + */ +void +uvm_pagealloc_pg(struct vm_page *pg, struct uvm_object *obj, voff_t off, + struct vm_anon *anon) +{ + int flags; + + flags = PG_BUSY | PG_FAKE; + pg->offset = off; + pg->uobject = obj; + pg->uanon = anon; + + if (anon) { + anon->an_page = pg; + flags |= PQ_ANON; + } else if (obj) + uvm_pageinsert(pg); + atomic_setbits_int(&pg->pg_flags, flags); +#if defined(UVM_PAGE_TRKOWN) + pg->owner_tag = NULL; +#endif + UVM_PAGE_OWN(pg, "new alloc"); +} + +/* * uvm_pagealloc_strat: allocate vm_page from a particular free list. * * => return null if no pages free @@ -836,23 +863,11 @@ uvm_pagealloc(struct uvm_object *obj, voff_t off, struct vm_anon *anon, pg = TAILQ_FIRST(&pgl); KASSERT(pg != NULL && TAILQ_NEXT(pg, pageq) == NULL); - pg->offset = off; - pg->uobject = obj; - pg->uanon = anon; + uvm_pagealloc_pg(pg, obj, off, anon); KASSERT((pg->pg_flags & PG_DEV) == 0); atomic_setbits_int(&pg->pg_flags, PG_BUSY|PG_CLEAN|PG_FAKE); if (flags & UVM_PGA_ZERO) atomic_clearbits_int(&pg->pg_flags, PG_CLEAN); - if (anon) { - anon->an_page = pg; - atomic_setbits_int(&pg->pg_flags, PQ_ANON); - } else if (obj) - uvm_pageinsert(pg); - -#if defined(UVM_PAGE_TRKOWN) - pg->owner_tag = NULL; -#endif - UVM_PAGE_OWN(pg, "new alloc"); UVMHIST_LOG(pghist, "allocated pg %p/%lx", pg, (u_long)VM_PAGE_TO_PHYS(pg), 0, 0); diff --git a/sys/uvm/uvm_page.h b/sys/uvm/uvm_page.h index eda9030fe63..c8e2b04fd36 100644 --- a/sys/uvm/uvm_page.h +++ b/sys/uvm/uvm_page.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_page.h,v 1.42 2010/04/22 19:02:55 oga Exp $ */ +/* $OpenBSD: uvm_page.h,v 1.43 2010/06/27 03:03:49 thib Exp $ */ /* $NetBSD: uvm_page.h,v 1.19 2000/12/28 08:24:55 chs Exp $ */ /* @@ -249,6 +249,8 @@ void uvm_pagewait(struct vm_page *, int); void uvm_pagewake(struct vm_page *); void uvm_pagewire(struct vm_page *); void uvm_pagezero(struct vm_page *); +void uvm_pagealloc_pg(struct vm_page *, struct uvm_object *, + voff_t, struct vm_anon *); int uvm_page_lookup_freelist(struct vm_page *); diff --git a/sys/uvm/uvm_pglist.c b/sys/uvm/uvm_pglist.c index 94b68efba13..17fd8751bec 100644 --- a/sys/uvm/uvm_pglist.c +++ b/sys/uvm/uvm_pglist.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_pglist.c,v 1.37 2010/06/10 08:48:36 thib Exp $ */ +/* $OpenBSD: uvm_pglist.c,v 1.38 2010/06/27 03:03:49 thib Exp $ */ /* $NetBSD: uvm_pglist.c,v 1.13 2001/02/18 21:19:08 chs Exp $ */ /*- @@ -77,7 +77,6 @@ u_long uvm_pglistalloc_npages; * UVM_PLA_NOWAIT fail if allocation fails * UVM_PLA_WAITOK wait for memory to become avail * UVM_PLA_ZERO return zeroed memory - * UVM_PLA_TRYCONTIG caller (device) prefers p-linear memory */ int diff --git a/sys/uvm/uvm_pmemrange.c b/sys/uvm/uvm_pmemrange.c index 54d3f6960d6..d4c6bd87789 100644 --- a/sys/uvm/uvm_pmemrange.c +++ b/sys/uvm/uvm_pmemrange.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_pmemrange.c,v 1.14 2010/06/23 09:36:03 thib Exp $ */ +/* $OpenBSD: uvm_pmemrange.c,v 1.15 2010/06/27 03:03:49 thib Exp $ */ /* * Copyright (c) 2009, 2010 Ariane van der Steldt <ariane@stack.nl> @@ -109,7 +109,6 @@ void uvm_pmr_assertvalid(struct uvm_pmemrange *pmr); #define uvm_pmr_assertvalid(pmr) do {} while (0) #endif - int uvm_pmr_get1page(psize_t, int, struct pglist *, paddr_t, paddr_t); @@ -1305,7 +1304,26 @@ uvm_pmr_split(paddr_t pageno) KASSERT(pmr->low < pageno); KASSERT(pmr->high > pageno); + /* + * uvm_pmr_allocpmr() calls into malloc() which in turn calls into + * uvm_kmemalloc which calls into pmemrange, making the locking + * a bit hard, so we just race! + */ + uvm_unlock_fpageq(); drain = uvm_pmr_allocpmr(); + uvm_lock_fpageq(); + pmr = uvm_pmemrange_find(pageno); + if (pmr == NULL || !(pmr->low < pageno)) { + /* + * We lost the race since someone else ran this or a related + * function, however this should be triggered very rarely so + * we just leak the pmr. + */ + printf("uvm_pmr_split: lost one pmr\n"); + uvm_unlock_fpageq(); + return; + } + drain->low = pageno; drain->high = pmr->high; drain->use = pmr->use; @@ -1379,37 +1397,29 @@ void uvm_pmr_use_inc(paddr_t low, paddr_t high) { struct uvm_pmemrange *pmr; + paddr_t sz; - /* - * If high+1 == 0 and low == 0, then you are increasing use - * of the whole address space, which won't make any difference. - * Skip in that case. - */ + /* pmr uses page numbers, translate low and high. */ high++; - if (high == 0 && low == 0) - return; - - /* - * pmr uses page numbers, translate low and high. - */ - low = atop(round_page(low)); high = atop(trunc_page(high)); + low = atop(round_page(low)); uvm_pmr_split(low); uvm_pmr_split(high); uvm_lock_fpageq(); - /* Increase use count on segments in range. */ RB_FOREACH(pmr, uvm_pmemrange_addr, &uvm.pmr_control.addr) { if (PMR_IS_SUBRANGE_OF(pmr->low, pmr->high, low, high)) { TAILQ_REMOVE(&uvm.pmr_control.use, pmr, pmr_use); pmr->use++; + sz += pmr->high - pmr->low; uvm_pmemrange_use_insert(&uvm.pmr_control.use, pmr); } uvm_pmr_assertvalid(pmr); } - uvm_unlock_fpageq(); + + KASSERT(sz >= high - low); } /* @@ -1420,19 +1430,21 @@ uvm_pmr_use_inc(paddr_t low, paddr_t high) * (And if called in between, you're dead.) */ struct uvm_pmemrange * -uvm_pmr_allocpmr() +uvm_pmr_allocpmr(void) { struct uvm_pmemrange *nw; int i; + /* We're only ever hitting the !uvm.page_init_done case for now. */ if (!uvm.page_init_done) { nw = (struct uvm_pmemrange *) uvm_pageboot_alloc(sizeof(struct uvm_pmemrange)); - bzero(nw, sizeof(struct uvm_pmemrange)); } else { nw = malloc(sizeof(struct uvm_pmemrange), - M_VMMAP, M_NOWAIT | M_ZERO); + M_VMMAP, M_NOWAIT); } + KASSERT(nw != NULL); + bzero(nw, sizeof(struct uvm_pmemrange)); RB_INIT(&nw->addr); for (i = 0; i < UVM_PMR_MEMTYPE_MAX; i++) { RB_INIT(&nw->size[i]); @@ -1441,8 +1453,6 @@ uvm_pmr_allocpmr() return nw; } -static const struct uvm_io_ranges uvm_io_ranges[] = UVM_IO_RANGES; - /* * Initialization of pmr. * Called by uvm_page_init. @@ -1458,15 +1468,18 @@ uvm_pmr_init(void) TAILQ_INIT(&uvm.pmr_control.use); RB_INIT(&uvm.pmr_control.addr); + /* By default, one range for the entire address space. */ new_pmr = uvm_pmr_allocpmr(); new_pmr->low = 0; - new_pmr->high = atop((paddr_t)-1) + 1; + new_pmr->high = atop((paddr_t)-1) + 1; RB_INSERT(uvm_pmemrange_addr, &uvm.pmr_control.addr, new_pmr); uvm_pmemrange_use_insert(&uvm.pmr_control.use, new_pmr); - for (i = 0; i < nitems(uvm_io_ranges); i++) - uvm_pmr_use_inc(uvm_io_ranges[i].low, uvm_io_ranges[i].high); + for (i = 0; uvm_md_constraints[i] != NULL; i++) { + uvm_pmr_use_inc(uvm_md_constraints[i]->ucr_low, + uvm_md_constraints[i]->ucr_high); + } } /* |