diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2004-12-30 08:28:40 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 2004-12-30 08:28:40 +0000 |
commit | 6defc19dbc11c94abba67f8797c6558c22156e95 (patch) | |
tree | 8f64ed25d4ff8f5f3f0bf8ac45a745dbb2a0fe01 | |
parent | a1f64fdad2755ab10d2b7d520089750586c177e7 (diff) |
Import M_CANFAIL support from NetBSD, removes a nasty panic during low-mem scenarios, instead generating an ENOMEM backfeed, ok tedu@, prodded by many
-rw-r--r-- | sys/kern/kern_malloc.c | 11 | ||||
-rw-r--r-- | sys/sys/malloc.h | 3 | ||||
-rw-r--r-- | sys/uvm/uvm_amap.c | 45 | ||||
-rw-r--r-- | sys/uvm/uvm_amap.h | 4 | ||||
-rw-r--r-- | sys/uvm/uvm_extern.h | 3 | ||||
-rw-r--r-- | sys/uvm/uvm_km.c | 8 | ||||
-rw-r--r-- | sys/uvm/uvm_map.c | 19 |
7 files changed, 61 insertions, 32 deletions
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c index 65a4d81848b..c4825e43e88 100644 --- a/sys/kern/kern_malloc.c +++ b/sys/kern/kern_malloc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_malloc.c,v 1.58 2004/05/23 19:41:23 tedu Exp $ */ +/* $OpenBSD: kern_malloc.c,v 1.59 2004/12/30 08:28:39 niklas Exp $ */ /* $NetBSD: kern_malloc.c,v 1.15.4.2 1996/06/13 17:10:56 cgd Exp $ */ /* @@ -179,8 +179,9 @@ malloc(size, type, flags) allocsize = 1 << indx; npg = btoc(allocsize); va = (caddr_t) uvm_km_kmemalloc(kmem_map, uvmexp.kmem_object, - (vsize_t)ctob(npg), - (flags & M_NOWAIT) ? UVM_KMF_NOWAIT : 0); + (vsize_t)ctob(npg), + ((flags & M_NOWAIT) ? UVM_KMF_NOWAIT : 0) | + ((flags & M_CANFAIL) ? UVM_KMF_CANFAIL : 0)); if (va == NULL) { /* * Kmem_malloc() can return NULL, even if it can @@ -190,10 +191,10 @@ malloc(size, type, flags) * are completely free and which are in buckets * with too many free elements.) */ - if ((flags & M_NOWAIT) == 0) + if ((flags & (M_NOWAIT|M_CANFAIL)) == 0) panic("malloc: out of space in kmem_map"); splx(s); - return ((void *) NULL); + return (NULL); } #ifdef KMEMSTATS kbp->kb_total += kbp->kb_elmpercl; diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h index 89faaec8189..81f7e64c65f 100644 --- a/sys/sys/malloc.h +++ b/sys/sys/malloc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: malloc.h,v 1.73 2004/07/21 17:30:56 marius Exp $ */ +/* $OpenBSD: malloc.h,v 1.74 2004/12/30 08:28:39 niklas Exp $ */ /* $NetBSD: malloc.h,v 1.39 1998/07/12 19:52:01 augustss Exp $ */ /* @@ -54,6 +54,7 @@ */ #define M_WAITOK 0x0000 #define M_NOWAIT 0x0001 +#define M_CANFAIL 0x0002 /* * Types of memory to be allocated diff --git a/sys/uvm/uvm_amap.c b/sys/uvm/uvm_amap.c index 967d984823e..5fb4a2bade1 100644 --- a/sys/uvm/uvm_amap.c +++ b/sys/uvm/uvm_amap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_amap.c,v 1.27 2002/05/09 14:14:18 provos Exp $ */ +/* $OpenBSD: uvm_amap.c,v 1.28 2004/12/30 08:28:39 niklas Exp $ */ /* $NetBSD: uvm_amap.c,v 1.27 2000/11/25 06:27:59 chs Exp $ */ /* @@ -279,10 +279,9 @@ amap_free(amap) * => amap should be unlocked (we will lock it) * => to safely extend an amap it should have a reference count of * one (thus it can't be shared) - * => XXXCDC: needs a waitflag or failure return value? * => XXXCDC: support padding at this level? */ -void +int amap_extend(entry, addsize) vm_map_entry_t entry; vsize_t addsize; @@ -307,7 +306,6 @@ amap_extend(entry, addsize) */ amap_lock(amap); /* lock! */ - AMAP_B2SLOT(slotmapped, entry->end - entry->start); /* slots mapped */ AMAP_B2SLOT(slotadd, addsize); /* slots to add */ slotneed = slotoff + slotmapped + slotadd; @@ -327,13 +325,14 @@ amap_extend(entry, addsize) amap_unlock(amap); UVMHIST_LOG(maphist,"<- done (case 1), amap = 0x%x, sltneed=%d", amap, slotneed, 0, 0); - return; /* done! */ + return (0); } /* * case 2: we pre-allocated slots for use and we just need to * bump nslot up to take account for these slots. */ + if (amap->am_maxslot >= slotneed) { #ifdef UVM_AMAP_PPREF if (amap->am_ppref && amap->am_ppref != PPREF_NONE) { @@ -347,13 +346,14 @@ amap_extend(entry, addsize) #endif amap->am_nslot = slotneed; amap_unlock(amap); + /* * no need to zero am_anon since that was done at * alloc time and we never shrink an allocation. */ - UVMHIST_LOG(maphist,"<- done (case 2), amap = 0x%x, slotneed=%d", - amap, slotneed, 0, 0); - return; + UVMHIST_LOG(maphist,"<- done (case 2), amap = 0x%x, " + "slotneed=%d", amap, slotneed, 0, 0); + return (0); } /* @@ -368,7 +368,8 @@ amap_extend(entry, addsize) #ifdef UVM_AMAP_PPREF newppref = NULL; if (amap->am_ppref && amap->am_ppref != PPREF_NONE) { - newppref = malloc(slotalloc *sizeof(int), M_UVMAMAP, M_NOWAIT); + newppref = malloc(slotalloc *sizeof(int), M_UVMAMAP, + M_WAITOK | M_CANFAIL); if (newppref == NULL) { /* give up if malloc fails */ free(amap->am_ppref, M_UVMAMAP); @@ -376,10 +377,24 @@ amap_extend(entry, addsize) } } #endif - newsl = malloc(slotalloc * sizeof(int), M_UVMAMAP, M_WAITOK); - newbck = malloc(slotalloc * sizeof(int), M_UVMAMAP, M_WAITOK); - newover = malloc(slotalloc * sizeof(struct vm_anon *), - M_UVMAMAP, M_WAITOK); + newsl = malloc(slotalloc * sizeof(int), M_UVMAMAP, + M_WAITOK | M_CANFAIL); + newbck = malloc(slotalloc * sizeof(int), M_UVMAMAP, + M_WAITOK | M_CANFAIL); + newover = malloc(slotalloc * sizeof(struct vm_anon *), M_UVMAMAP, + M_WAITOK | M_CANFAIL); + if (newsl == NULL || newbck == NULL || newover == NULL) { + if (newsl != NULL) { + free(newsl, M_UVMAMAP); + } + if (newbck != NULL) { + free(newbck, M_UVMAMAP); + } + if (newover != NULL) { + free(newover, M_UVMAMAP); + } + return (ENOMEM); + } amap_lock(amap); /* re-lock! */ KASSERT(amap->am_maxslot < slotneed); @@ -397,7 +412,8 @@ amap_extend(entry, addsize) /* do am_anon */ oldover = amap->am_anon; memcpy(newover, oldover, sizeof(struct vm_anon *) * amap->am_nslot); - memset(newover + amap->am_nslot, 0, sizeof(struct vm_anon *) * slotadded); + memset(newover + amap->am_nslot, 0, sizeof(struct vm_anon *) * + slotadded); amap->am_anon = newover; /* do am_bckptr */ @@ -438,6 +454,7 @@ amap_extend(entry, addsize) #endif UVMHIST_LOG(maphist,"<- done (case 3), amap = 0x%x, slotneed=%d", amap, slotneed, 0, 0); + return (0); } /* diff --git a/sys/uvm/uvm_amap.h b/sys/uvm/uvm_amap.h index 1c7c2193b4a..79acf9c4ccb 100644 --- a/sys/uvm/uvm_amap.h +++ b/sys/uvm/uvm_amap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_amap.h,v 1.12 2002/03/15 01:20:04 millert Exp $ */ +/* $OpenBSD: uvm_amap.h,v 1.13 2004/12/30 08:28:39 niklas Exp $ */ /* $NetBSD: uvm_amap.h,v 1.14 2001/02/18 21:19:08 chs Exp $ */ /* @@ -91,7 +91,7 @@ void amap_copy(vm_map_t, vm_map_entry_t, int, boolean_t, vaddr_t, /* resolve all COW faults now */ void amap_cow_now(vm_map_t, vm_map_entry_t); /* make amap larger */ -void amap_extend(vm_map_entry_t, vsize_t); +int amap_extend(vm_map_entry_t, vsize_t); /* get amap's flags */ int amap_flags(struct vm_amap *); /* free amap */ diff --git a/sys/uvm/uvm_extern.h b/sys/uvm/uvm_extern.h index 3efb087c537..91431f49141 100644 --- a/sys/uvm/uvm_extern.h +++ b/sys/uvm/uvm_extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_extern.h,v 1.53 2004/05/27 04:55:28 tedu Exp $ */ +/* $OpenBSD: uvm_extern.h,v 1.54 2004/12/30 08:28:39 niklas Exp $ */ /* $NetBSD: uvm_extern.h,v 1.57 2001/03/09 01:02:12 chs Exp $ */ /* @@ -203,6 +203,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_TRYLOCK UVM_FLAG_TRYLOCK /* try locking only */ /* diff --git a/sys/uvm/uvm_km.c b/sys/uvm/uvm_km.c index 69d36e16eae..e34f1b4161c 100644 --- a/sys/uvm/uvm_km.c +++ b/sys/uvm/uvm_km.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_km.c,v 1.44 2004/08/24 07:16:12 tedu Exp $ */ +/* $OpenBSD: uvm_km.c,v 1.45 2004/12/30 08:28:39 niklas Exp $ */ /* $NetBSD: uvm_km.c,v 1.42 2001/01/14 02:10:01 thorpej Exp $ */ /* @@ -537,10 +537,12 @@ uvm_km_kmemalloc(map, obj, size, flags) */ if (__predict_false(pg == NULL)) { - if (flags & UVM_KMF_NOWAIT) { + if ((flags & UVM_KMF_NOWAIT) || + ((flags & UVM_KMF_CANFAIL) && + uvmexp.swpgonly == uvmexp.swpages)) { /* free everything! */ uvm_unmap(map, kva, kva + size); - return(0); + return (0); } else { uvm_wait("km_getwait2"); /* sleep here */ continue; diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c index 4fbaa4dee79..94e8b0918a2 100644 --- a/sys/uvm/uvm_map.c +++ b/sys/uvm/uvm_map.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_map.c,v 1.69 2004/08/06 22:39:14 deraadt Exp $ */ +/* $OpenBSD: uvm_map.c,v 1.70 2004/12/30 08:28:39 niklas Exp $ */ /* $NetBSD: uvm_map.c,v 1.86 2000/11/27 08:40:03 chs Exp $ */ /* @@ -709,6 +709,7 @@ uvm_map(map, startp, size, uobj, uoffset, align, flags) UVM_MAXPROTECTION(flags); vm_inherit_t inherit = UVM_INHERIT(flags); int advice = UVM_ADVICE(flags); + int error; UVMHIST_FUNC("uvm_map"); UVMHIST_CALLED(maphist); @@ -823,7 +824,16 @@ uvm_map(map, startp, size, uobj, uoffset, align, flags) goto step3; } - /* got it! */ + if (prev_entry->aref.ar_amap) { + error = amap_extend(prev_entry, size); + if (error) { + vm_map_unlock(map); + if (new_entry) { + uvm_mapent_free(new_entry); + } + return (error); + } + } UVMCNT_INCR(map_backmerge); UVMHIST_LOG(maphist," starting back merge", 0, 0, 0, 0); @@ -832,13 +842,10 @@ uvm_map(map, startp, size, uobj, uoffset, align, flags) * drop our reference to uobj since we are extending a reference * that we already have (the ref count can not drop to zero). */ + if (uobj && uobj->pgops->pgo_detach) uobj->pgops->pgo_detach(uobj); - if (prev_entry->aref.ar_amap) { - amap_extend(prev_entry, size); - } - prev_entry->end += size; uvm_rb_fixup(map, prev_entry); map->size += size; |