summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>2004-12-30 08:28:40 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>2004-12-30 08:28:40 +0000
commit6defc19dbc11c94abba67f8797c6558c22156e95 (patch)
tree8f64ed25d4ff8f5f3f0bf8ac45a745dbb2a0fe01
parenta1f64fdad2755ab10d2b7d520089750586c177e7 (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.c11
-rw-r--r--sys/sys/malloc.h3
-rw-r--r--sys/uvm/uvm_amap.c45
-rw-r--r--sys/uvm/uvm_amap.h4
-rw-r--r--sys/uvm/uvm_extern.h3
-rw-r--r--sys/uvm/uvm_km.c8
-rw-r--r--sys/uvm/uvm_map.c19
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;