diff options
author | Dimitry Andric <dim@cvs.openbsd.org> | 2007-01-16 13:36:39 +0000 |
---|---|---|
committer | Dimitry Andric <dim@cvs.openbsd.org> | 2007-01-16 13:36:39 +0000 |
commit | 941d007d4480e3ea6e71b62f7674add69abb9b49 (patch) | |
tree | 4a4cb6ca79a79029a2de4335a0abe11b5a730e0c | |
parent | 6390d48bb9d9a2461b80547864a17a7a805d0ef1 (diff) |
Implement multiple segment allocation for uvm_pglistalloc, which fixes
most agp_generic_bind_memory failures when memory is limited and very
fragmented.
In effect, this should fix a lot of X startup crashes after
activities that exercise memory a lot (e.g. make builds, building big
ports, etc).
ok mickey, miod
-rw-r--r-- | share/man/man9/uvm.9 | 11 | ||||
-rw-r--r-- | sys/uvm/uvm_pglist.c | 93 |
2 files changed, 99 insertions, 5 deletions
diff --git a/share/man/man9/uvm.9 b/share/man/man9/uvm.9 index ff94415ffbe..eaf4b1e0cfb 100644 --- a/share/man/man9/uvm.9 +++ b/share/man/man9/uvm.9 @@ -1,4 +1,4 @@ -.\" $OpenBSD: uvm.9,v 1.27 2005/09/30 20:34:25 jaredy Exp $ +.\" $OpenBSD: uvm.9,v 1.28 2007/01/16 13:36:38 dim Exp $ .\" $NetBSD: uvm.9,v 1.14 2000/06/29 06:08:44 mrg Exp $ .\" .\" Copyright (c) 1998 Matthew R. Green @@ -700,11 +700,14 @@ If .Fa boundary is non-zero, no segment of the list may cross this power-of-two boundary, relative to zero. -The .Fa nsegs -and +is the maximum number of physically contigous segments. +The .Fa waitok -arguments are currently ignored. +argument is currently ignored. +The allocated memory is returned in the +.Fa rlist +list. .Pp The .Fn uvm_pglistfree diff --git a/sys/uvm/uvm_pglist.c b/sys/uvm/uvm_pglist.c index d9ec0cae496..42d23f2b05a 100644 --- a/sys/uvm/uvm_pglist.c +++ b/sys/uvm/uvm_pglist.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_pglist.c,v 1.16 2006/06/01 05:16:49 krw Exp $ */ +/* $OpenBSD: uvm_pglist.c,v 1.17 2007/01/16 13:36:38 dim Exp $ */ /* $NetBSD: uvm_pglist.c,v 1.13 2001/02/18 21:19:08 chs Exp $ */ /*- @@ -63,6 +63,93 @@ u_long uvm_pglistalloc_npages; #define STAT_DECR(v) #endif +int uvm_pglistalloc_simple(psize_t, paddr_t, paddr_t, struct pglist *); + +int +uvm_pglistalloc_simple(psize_t size, paddr_t low, paddr_t high, + struct pglist *rlist) +{ + psize_t try; + int psi; + struct vm_page *pg; + int s, todo, idx, pgflidx, error, free_list; + UVMHIST_FUNC("uvm_pglistalloc_simple"); UVMHIST_CALLED(pghist); + + /* Default to "lose". */ + error = ENOMEM; + + todo = size / PAGE_SIZE; + + /* + * Block all memory allocation and lock the free list. + */ + s = uvm_lock_fpageq(); + + /* Are there even any free pages? */ + if (uvmexp.free <= (uvmexp.reserve_pagedaemon + uvmexp.reserve_kernel)) + goto out; + + for (try = low; try < high; try += PAGE_SIZE) { + + /* + * Make sure this is a managed physical page. + */ + + if ((psi = vm_physseg_find(atop(try), &idx)) == -1) + continue; /* managed? */ + pg = &vm_physmem[psi].pgs[idx]; + if (VM_PAGE_IS_FREE(pg) == 0) + continue; + + free_list = uvm_page_lookup_freelist(pg); + pgflidx = (pg->flags & PG_ZERO) ? PGFL_ZEROS : PGFL_UNKNOWN; +#ifdef DEBUG + for (tp = TAILQ_FIRST(&uvm.page_free[free_list].pgfl_queues[pgflidx]); + tp != NULL; + tp = TAILQ_NEXT(tp, pageq)) { + if (tp == pg) + break; + } + if (tp == NULL) + panic("uvm_pglistalloc_simple: page not on freelist"); +#endif + TAILQ_REMOVE(&uvm.page_free[free_list].pgfl_queues[pgflidx], pg, pageq); + uvmexp.free--; + if (pg->flags & PG_ZERO) + uvmexp.zeropages--; + pg->flags = PG_CLEAN; + pg->pqflags = 0; + pg->uobject = NULL; + pg->uanon = NULL; + pg->version++; + TAILQ_INSERT_TAIL(rlist, pg, pageq); + STAT_INCR(uvm_pglistalloc_npages); + if (--todo == 0) { + error = 0; + goto out; + } + } + +out: + /* + * check to see if we need to generate some free pages waking + * the pagedaemon. + */ + + if (!error && (uvmexp.free + uvmexp.paging < uvmexp.freemin || + (uvmexp.free + uvmexp.paging < uvmexp.freetarg && + uvmexp.inactive < uvmexp.inactarg))) { + wakeup(&uvm.pagedaemon); + } + + uvm_unlock_fpageq(s); + + if (error) + uvm_pglistfree(rlist); + + return (error); +} + /* * uvm_pglistalloc: allocate a list of pages * @@ -116,6 +203,10 @@ uvm_pglistalloc(size, low, high, alignment, boundary, rlist, nsegs, waitok) size = round_page(size); try = roundup(low, alignment); + if ((nsegs >= size / PAGE_SIZE) && (alignment == PAGE_SIZE) && + (boundary == 0)) + return (uvm_pglistalloc_simple(size, try, high, rlist)); + if (boundary != 0 && boundary < size) return (EINVAL); |