? sys/arch/i386/conf/TYAN251X
? sys/arch/i386/conf/TYAN251X.MP
? sys/arch/i386/conf/TYAN251X.MPDEBUG
? usr.sbin/user/.gdbinit
? usr.sbin/user/group.cat8
? usr.sbin/user/groupadd.cat8
? usr.sbin/user/groupdel
? usr.sbin/user/groupdel.cat8
? usr.sbin/user/groupinfo.cat8
? usr.sbin/user/groupmod.cat8
? usr.sbin/user/user
? usr.sbin/user/user.c.diff
? usr.sbin/user/user.cat8
? usr.sbin/user/useradd.cat8
? usr.sbin/user/userdel.cat8
? usr.sbin/user/userinfo.cat8
? usr.sbin/user/usermgmt.conf.cat5
? usr.sbin/user/usermod.cat8
Index: sys/arch/amd64/amd64/pmap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/amd64/pmap.c,v
retrieving revision 1.9.2.1.2.1
diff -u -r1.9.2.1.2.1 pmap.c
--- sys/arch/amd64/amd64/pmap.c	8 Jun 2005 11:34:04 -0000	1.9.2.1.2.1
+++ sys/arch/amd64/amd64/pmap.c	16 Jun 2005 17:23:36 -0000
@@ -1608,7 +1608,7 @@
 		/* unmap the page */
 		dead_entries = NULL;
 		uvm_unmap_remove(map, (vaddr_t)pvp, ((vaddr_t)pvp) + PAGE_SIZE,
-		    &dead_entries);
+		    &dead_entries, NULL);
 		vm_map_unlock(map);
 
 		if (dead_entries != NULL)
Index: sys/arch/i386/i386/pmap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/pmap.c,v
retrieving revision 1.171.2.1.2.1
diff -u -r1.171.2.1.2.1 pmap.c
--- sys/arch/i386/i386/pmap.c	8 Jun 2005 11:29:43 -0000	1.171.2.1.2.1
+++ sys/arch/i386/i386/pmap.c	16 Jun 2005 17:23:37 -0000
@@ -1494,7 +1494,7 @@
 		/* unmap the page */
 		dead_entries = NULL;
 		uvm_unmap_remove(map, (vaddr_t)pvp, ((vaddr_t)pvp) + PAGE_SIZE,
-		    &dead_entries);
+		    &dead_entries, NULL);
 		vm_map_unlock(map);
 
 		if (dead_entries != NULL)
Index: sys/arch/pc532/pc532/pmap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/pc532/pc532/pmap.c,v
retrieving revision 1.74.6.1
diff -u -r1.74.6.1 pmap.c
--- sys/arch/pc532/pc532/pmap.c	8 Jun 2005 11:35:09 -0000	1.74.6.1
+++ sys/arch/pc532/pc532/pmap.c	16 Jun 2005 17:23:37 -0000
@@ -1170,7 +1170,7 @@
 		/* unmap the page */
 		dead_entries = NULL;
 		uvm_unmap_remove(map, (vaddr_t)pvp, ((vaddr_t)pvp) + PAGE_SIZE,
-		    &dead_entries);
+		    &dead_entries, NULL);
 		vm_map_unlock(map);
 
 		if (dead_entries != NULL)
Index: sys/arch/xen/i386/pmap.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/i386/pmap.c,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 pmap.c
--- sys/arch/xen/i386/pmap.c	22 May 2004 15:57:52 -0000	1.1.2.1
+++ sys/arch/xen/i386/pmap.c	16 Jun 2005 17:23:38 -0000
@@ -1690,7 +1690,7 @@
 		/* unmap the page */
 		dead_entries = NULL;
 		uvm_unmap_remove(map, (vaddr_t)pvp, ((vaddr_t)pvp) + PAGE_SIZE,
-		    &dead_entries);
+		    &dead_entries, NULL);
 		vm_map_unlock(map);
 
 		if (dead_entries != NULL)
Index: sys/uvm/uvm.h
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm.h,v
retrieving revision 1.37
diff -u -r1.37 uvm.h
--- sys/uvm/uvm.h	10 Feb 2004 01:30:49 -0000	1.37
+++ sys/uvm/uvm.h	16 Jun 2005 17:23:38 -0000
@@ -110,8 +110,6 @@
 	struct vm_anon *afree;		/* anon free list */
 	struct simplelock afreelock; 	/* lock on anon free list */
 
-	/* static kernel map entry pool */
-	struct vm_map_entry *kentry_free;	/* free page pool */
 	struct simplelock kentry_lock;
 
 	/* aio_done is locked by uvm.pagedaemon_lock and splbio! */
Index: sys/uvm/uvm_amap.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_amap.c,v
retrieving revision 1.53.4.1
diff -u -r1.53.4.1 uvm_amap.c
--- sys/uvm/uvm_amap.c	16 Mar 2005 12:11:12 -0000	1.53.4.1
+++ sys/uvm/uvm_amap.c	16 Jun 2005 17:23:38 -0000
@@ -767,10 +767,10 @@
 			UVMHIST_LOG(maphist, "  chunk amap ==> clip 0x%x->0x%x"
 			    "to 0x%x->0x%x", entry->start, entry->end, startva,
 			    endva);
-			UVM_MAP_CLIP_START(map, entry, startva);
+			UVM_MAP_CLIP_START(map, entry, startva, NULL);
 			/* watch out for endva wrap-around! */
 			if (endva >= startva)
-				UVM_MAP_CLIP_END(map, entry, endva);
+				UVM_MAP_CLIP_END(map, entry, endva, NULL);
 		}
 
 		UVMHIST_LOG(maphist, "<- done [creating new amap 0x%x->0x%x]",
Index: sys/uvm/uvm_extern.h
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_extern.h,v
retrieving revision 1.91
diff -u -r1.91 uvm_extern.h
--- sys/uvm/uvm_extern.h	24 Mar 2004 07:55:01 -0000	1.91
+++ sys/uvm/uvm_extern.h	16 Jun 2005 17:23:38 -0000
@@ -143,6 +143,7 @@
 #define UVM_FLAG_AMAPPAD 0x100000 /* for bss: pad amap to reduce malloc() */
 #define UVM_FLAG_TRYLOCK 0x200000 /* fail if we can not lock map */
 #define UVM_FLAG_NOWAIT  0x400000 /* not allowed to sleep */
+#define UVM_FLAG_QUANTUM 0x800000 /* entry never be splitted later */
 
 /* macros to extract info */
 #define UVM_PROTECTION(X)	((X) & UVM_PROT_MASK)
Index: sys/uvm/uvm_io.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_io.c,v
retrieving revision 1.18
diff -u -r1.18 uvm_io.c
--- sys/uvm/uvm_io.c	23 Apr 2003 00:55:21 -0000	1.18
+++ sys/uvm/uvm_io.c	16 Jun 2005 17:23:38 -0000
@@ -142,7 +142,8 @@
 		 */
 
 		vm_map_lock(kernel_map);
-		uvm_unmap_remove(kernel_map, kva, kva + chunksz, &dead_entries);
+		uvm_unmap_remove(kernel_map, kva, kva + chunksz, &dead_entries,
+		    NULL);
 		vm_map_unlock(kernel_map);
 		if (dead_entries != NULL)
 			uvm_unmap_detach(dead_entries, AMAP_REFALL);
Index: sys/uvm/uvm_km.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_km.c,v
retrieving revision 1.69
diff -u -r1.69 uvm_km.c
--- sys/uvm/uvm_km.c	24 Mar 2004 07:47:32 -0000	1.69
+++ sys/uvm/uvm_km.c	16 Jun 2005 17:23:38 -0000
@@ -155,6 +155,7 @@
  */
 
 static struct vm_map		kernel_map_store;
+static struct vm_map_entry	kernel_first_mapent_store;
 
 /*
  * uvm_km_init: init kernel maps and objects to reflect reality (i.e.
@@ -187,12 +188,25 @@
 
 	uvm_map_setup(&kernel_map_store, base, end, VM_MAP_PAGEABLE);
 	kernel_map_store.pmap = pmap_kernel();
-	if (start != base &&
-	    uvm_map(&kernel_map_store, &base, start - base, NULL,
-		    UVM_UNKNOWN_OFFSET, 0,
+	if (start != base) {
+		int error;
+		struct uvm_map_args args;
+
+		error = uvm_map_prepare(&kernel_map_store, base, start - base,
+		    NULL, UVM_UNKNOWN_OFFSET, 0,
 		    UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE,
-		    		UVM_ADV_RANDOM, UVM_FLAG_FIXED)) != 0)
-		panic("uvm_km_init: could not reserve space for kernel");
+		    		UVM_ADV_RANDOM, UVM_FLAG_FIXED), &args);
+		if (!error) {
+			kernel_first_mapent_store.flags =
+			    UVM_MAP_KERNEL | UVM_MAP_FIRST;
+			error = uvm_map_enter(&kernel_map_store, &args,
+			    &kernel_first_mapent_store);
+		}
+
+		if (error)
+			panic(
+			    "uvm_km_init: could not reserve space for kernel");
+	}
 
 	/*
 	 * install!
@@ -398,7 +412,8 @@
 	if (__predict_false(uvm_map(map, &kva, size, obj, prefer, align,
 		UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL, UVM_INH_NONE,
 			    UVM_ADV_RANDOM,
-			    (flags & (UVM_KMF_TRYLOCK | UVM_KMF_NOWAIT))))
+			    (flags & (UVM_KMF_TRYLOCK | UVM_KMF_NOWAIT))
+			    | UVM_FLAG_QUANTUM))
 			!= 0)) {
 		UVMHIST_LOG(maphist, "<- done (no VM)",0,0,0,0);
 		return(0);
@@ -448,7 +463,8 @@
 			if ((flags & UVM_KMF_NOWAIT) ||
 			    ((flags & UVM_KMF_CANFAIL) && uvm_swapisfull())) {
 				/* free everything! */
-				uvm_unmap(map, kva, kva + size);
+				uvm_unmap1(map, kva, kva + size,
+				    UVM_FLAG_QUANTUM);
 				return (0);
 			} else {
 				uvm_wait("km_getwait2");	/* sleep here */
@@ -489,7 +505,8 @@
 	vaddr_t addr;
 	vsize_t size;
 {
-	uvm_unmap(map, trunc_page(addr), round_page(addr+size));
+	uvm_unmap1(map, trunc_page(addr), round_page(addr+size),
+	    UVM_FLAG_QUANTUM);
 }
 
 /*
@@ -509,7 +526,7 @@
 
 	vm_map_lock(map);
 	uvm_unmap_remove(map, trunc_page(addr), round_page(addr + size),
-	    &dead_entries);
+	    &dead_entries, NULL);
 	wakeup(map);
 	vm_map_unlock(map);
 	if (dead_entries != NULL)
@@ -545,7 +562,7 @@
 	if (__predict_false(uvm_map(map, &kva, size, uvm.kernel_object,
 	      UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL,
 					      UVM_INH_NONE, UVM_ADV_RANDOM,
-					      0)) != 0)) {
+					      UVM_FLAG_QUANTUM)) != 0)) {
 		UVMHIST_LOG(maphist,"<- done (no VM)",0,0,0,0);
 		return(0);
 	}
@@ -632,6 +649,7 @@
 	if (size > vm_map_max(map) - vm_map_min(map))
 		return (0);
 
+	flags |= UVM_FLAG_QUANTUM;
 	for (;;) {
 		kva = vm_map_min(map);		/* hint */
 
Index: sys/uvm/uvm_map.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_map.c,v
retrieving revision 1.164.2.3.2.2
diff -u -r1.164.2.3.2.2 uvm_map.c
--- sys/uvm/uvm_map.c	11 May 2005 19:15:43 -0000	1.164.2.3.2.2
+++ sys/uvm/uvm_map.c	16 Jun 2005 17:23:38 -0000
@@ -101,8 +101,6 @@
 #include <uvm/uvm_ddb.h>
 #endif
 
-extern struct vm_map *pager_map;
-
 #ifndef UVMMAP_NOCOUNTERS
 #include <sys/device.h>
 struct evcnt map_ubackmerge = EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL,
@@ -160,7 +158,6 @@
  */
 
 struct pool uvm_map_entry_pool;
-struct pool uvm_map_entry_kmem_pool;
 
 MALLOC_DEFINE(M_VMMAP, "VM map", "VM map structures");
 MALLOC_DEFINE(M_VMPMAP, "VM pmap", "VM pmap");
@@ -181,6 +178,14 @@
  */
 
 /*
+ * VM_MAP_USE_KMAPENT: determine if uvm_kmapent_alloc/free is used
+ * for the vm_map.
+ */
+extern struct vm_map *pager_map; /* XXX */
+#define	VM_MAP_USE_KMAPENT(map) \
+	(((map)->flags & VM_MAP_INTRSAFE) || (map) == kernel_map)
+
+/*
  * uvm_map_entry_link: insert entry into a map
  *
  * => map must be locked
@@ -240,8 +245,15 @@
 
 static struct vm_map_entry *
 		uvm_mapent_alloc(struct vm_map *, int);
+static struct vm_map_entry *
+		uvm_mapent_alloc_split(struct vm_map *,
+		    const struct vm_map_entry *, int,
+		    struct uvm_mapent_reservation *);
 static void	uvm_mapent_copy(struct vm_map_entry *, struct vm_map_entry *);
 static void	uvm_mapent_free(struct vm_map_entry *);
+static struct vm_map_entry *
+		uvm_kmapent_alloc(struct vm_map *, int);
+static void	uvm_kmapent_free(struct vm_map_entry *);
 static void	uvm_map_entry_unwire(struct vm_map *, struct vm_map_entry *);
 static void	uvm_map_reference_amap(struct vm_map_entry *, int);
 static int	uvm_map_space_avail(vaddr_t *, vsize_t, voff_t, vsize_t, int,
@@ -416,6 +428,8 @@
  * local inlines
  */
 
+static __inline struct vm_map *uvm_kmapent_map(struct vm_map_entry *);
+
 /*
  * uvm_mapent_alloc: allocate a map entry
  */
@@ -424,29 +438,11 @@
 uvm_mapent_alloc(struct vm_map *map, int flags)
 {
 	struct vm_map_entry *me;
-	int s;
 	int pflags = (flags & UVM_FLAG_NOWAIT) ? PR_NOWAIT : PR_WAITOK;
 	UVMHIST_FUNC("uvm_mapent_alloc"); UVMHIST_CALLED(maphist);
 
-	if (map->flags & VM_MAP_INTRSAFE || cold) {
-		s = splvm();
-		simple_lock(&uvm.kentry_lock);
-		me = uvm.kentry_free;
-		if (me)
-			uvm.kentry_free = me->next;
-		simple_unlock(&uvm.kentry_lock);
-		splx(s);
-		if (__predict_false(me == NULL)) {
-			panic("uvm_mapent_alloc: out of static map entries, "
-			    "check MAX_KMAPENT (currently %d)",
-			    MAX_KMAPENT);
-		}
-		me->flags = UVM_MAP_STATIC;
-	} else if (map == kernel_map) {
-		me = pool_get(&uvm_map_entry_kmem_pool, pflags);
-		if (__predict_false(me == NULL))
-			return NULL;
-		me->flags = UVM_MAP_KMEM;
+	if (VM_MAP_USE_KMAPENT(map)) {
+		me = uvm_kmapent_alloc(map, flags);
 	} else {
 		me = pool_get(&uvm_map_entry_pool, pflags);
 		if (__predict_false(me == NULL))
@@ -460,28 +456,88 @@
 }
 
 /*
+ * uvm_mapent_alloc_split: allocate a map entry for clipping.
+ */
+
+static __inline struct vm_map_entry *
+uvm_mapent_alloc_split(struct vm_map *map,
+    const struct vm_map_entry *old_entry, int flags,
+    struct uvm_mapent_reservation *umr)
+{
+	struct vm_map_entry *me;
+
+	KASSERT(!VM_MAP_USE_KMAPENT(map) ||
+	    (old_entry->flags & UVM_MAP_QUANTUM) || !UMR_EMPTY(umr));
+
+	if (old_entry->flags & UVM_MAP_QUANTUM) {
+		int s;
+
+		s = splvm();
+		simple_lock(&uvm.kentry_lock);
+		me = map->merged_entries;
+		KASSERT(me);
+		map->merged_entries = me->next;
+		simple_unlock(&uvm.kentry_lock);
+		splx(s);
+		KASSERT(me->flags & UVM_MAP_QUANTUM);
+	} else {
+		me = uvm_mapent_alloc(map, flags);
+	}
+
+	return me;
+}
+
+/*
  * uvm_mapent_free: free map entry
  */
 
 static __inline void
 uvm_mapent_free(struct vm_map_entry *me)
 {
-	int s;
 	UVMHIST_FUNC("uvm_mapent_free"); UVMHIST_CALLED(maphist);
 
 	UVMHIST_LOG(maphist,"<- freeing map entry=0x%x [flags=%d]",
 		me, me->flags, 0, 0);
-	if (me->flags & UVM_MAP_STATIC) {
+	if (me->flags & UVM_MAP_KERNEL) {
+		uvm_kmapent_free(me);
+	} else {
+		pool_put(&uvm_map_entry_pool, me);
+	}
+}
+
+/*
+ * uvm_mapent_free_merge: free merged map entry
+ *
+ * => keep the entry if needed.
+ * => caller shouldn't hold map locked.
+ */
+
+static __inline void
+uvm_mapent_free_merged(struct vm_map *map, struct vm_map_entry *me)
+{
+
+	KASSERT(!(me->flags & UVM_MAP_KERNEL) || uvm_kmapent_map(me) == map);
+
+	if (me->flags & UVM_MAP_QUANTUM) {
+		/*
+		 * keep this entry for later splitting.
+		 */
+		struct vm_map *map;
+		int s;
+
+		KASSERT(VM_MAP_IS_KERNEL(map));
+		KASSERT(!VM_MAP_USE_KMAPENT(map) ||
+		    (me->flags & UVM_MAP_KERNEL));
+
+		map = uvm_kmapent_map(me);
 		s = splvm();
 		simple_lock(&uvm.kentry_lock);
-		me->next = uvm.kentry_free;
-		uvm.kentry_free = me;
+		me->next = map->merged_entries;
+		map->merged_entries = me;
 		simple_unlock(&uvm.kentry_lock);
 		splx(s);
-	} else if (me->flags & UVM_MAP_KMEM) {
-		pool_put(&uvm_map_entry_kmem_pool, me);
 	} else {
-		pool_put(&uvm_map_entry_pool, me);
+		uvm_mapent_free(me);
 	}
 }
 
@@ -544,12 +600,10 @@
 void
 uvm_map_init(void)
 {
-	static struct vm_map_entry kernel_map_entry[MAX_KMAPENT];
 #if defined(UVMHIST)
 	static struct uvm_history_ent maphistbuf[100];
 	static struct uvm_history_ent pdhistbuf[100];
 #endif
-	int lcv;
 
 	/*
 	 * first, init logging system.
@@ -562,15 +616,12 @@
 	UVMHIST_LOG(maphist,"<starting uvm map system>", 0, 0, 0, 0);
 
 	/*
-	 * now set up static pool of kernel map entrys ...
+	 * initialize the global lock for kernel map entry.
+	 *
+	 * XXX is it worth to have per-map lock instead?
 	 */
 
 	simple_lock_init(&uvm.kentry_lock);
-	uvm.kentry_free = NULL;
-	for (lcv = 0 ; lcv < MAX_KMAPENT ; lcv++) {
-		kernel_map_entry[lcv].next = uvm.kentry_free;
-		uvm.kentry_free = &kernel_map_entry[lcv];
-	}
 
 	/*
 	 * initialize the map-related pools.
@@ -579,8 +630,6 @@
 	    0, 0, 0, "vmsppl", &pool_allocator_nointr);
 	pool_init(&uvm_map_entry_pool, sizeof(struct vm_map_entry),
 	    0, 0, 0, "vmmpepl", &pool_allocator_nointr);
-	pool_init(&uvm_map_entry_kmem_pool, sizeof(struct vm_map_entry),
-	    0, 0, 0, "vmmpekpl", NULL);
 }
 
 /*
@@ -598,7 +647,7 @@
 
 void
 uvm_map_clip_start(struct vm_map *map, struct vm_map_entry *entry,
-    vaddr_t start)
+    vaddr_t start, struct uvm_mapent_reservation *umr)
 {
 	struct vm_map_entry *new_entry;
 	vaddr_t new_adj;
@@ -612,8 +661,7 @@
 	 * entry BEFORE this one, so that this entry has the specified
 	 * starting address.
 	 */
-
-	new_entry = uvm_mapent_alloc(map, 0);
+	new_entry = uvm_mapent_alloc_split(map, entry, 0, umr);
 	uvm_mapent_copy(entry, new_entry); /* entry -> new_entry */
 
 	new_entry->end = start;
@@ -654,18 +702,19 @@
  */
 
 void
-uvm_map_clip_end(struct vm_map *map, struct vm_map_entry *entry, vaddr_t end)
+uvm_map_clip_end(struct vm_map *map, struct vm_map_entry *entry, vaddr_t end,
+    struct uvm_mapent_reservation *umr)
 {
 	struct vm_map_entry *	new_entry;
 	vaddr_t new_adj; /* #bytes we move start forward */
 
 	uvm_tree_sanity(map, "clip_end entry");
+
 	/*
 	 *	Create a new entry and insert it
 	 *	AFTER the specified entry
 	 */
-
-	new_entry = uvm_mapent_alloc(map, 0);
+	new_entry = uvm_mapent_alloc_split(map, entry, 0, umr);
 	uvm_mapent_copy(entry, new_entry); /* entry -> new_entry */
 
 	new_entry->start = entry->end = end;
@@ -727,20 +776,59 @@
 uvm_map(struct vm_map *map, vaddr_t *startp /* IN/OUT */, vsize_t size,
     struct uvm_object *uobj, voff_t uoffset, vsize_t align, uvm_flag_t flags)
 {
-	struct vm_map_entry *prev_entry, *new_entry;
-	const int amapwaitflag = (flags & UVM_FLAG_NOWAIT) ?
-	    AMAP_EXTEND_NOWAIT : 0;
-	vm_prot_t prot = UVM_PROTECTION(flags), maxprot =
-	    UVM_MAXPROTECTION(flags);
-	vm_inherit_t inherit = UVM_INHERIT(flags);
-	int advice = UVM_ADVICE(flags);
-	int error, merged = 0, kmap = (vm_map_pmap(map) == pmap_kernel());
-	int newetype;
-	UVMHIST_FUNC("uvm_map");
+	struct uvm_map_args args;
+	struct vm_map_entry *new_entry;
+	int error;
+
+	KASSERT((flags & UVM_FLAG_QUANTUM) == 0 || VM_MAP_IS_KERNEL(map));
+
+	/*
+	 * for pager_map, allocate the new entry first to avoid sleeping
+	 * for memory while we have the map locked.
+	 *
+	 * besides, because we allocates entries for in-kernel maps
+	 * a bit differently (cf. uvm_kmapent_alloc/free), we need to
+	 * allocate them before locking the map.
+	 */
+
+	new_entry = NULL;
+	if (VM_MAP_USE_KMAPENT(map) || (flags & UVM_FLAG_QUANTUM) ||
+	    map == pager_map) {
+		new_entry = uvm_mapent_alloc(map, (flags & UVM_FLAG_NOWAIT));
+		if (__predict_false(new_entry == NULL))
+			return ENOMEM;
+		if (flags & UVM_FLAG_QUANTUM)
+			new_entry->flags |= UVM_MAP_QUANTUM;
+	}
+	if (map == pager_map)
+		flags |= UVM_FLAG_NOMERGE;
+
+	error = uvm_map_prepare(map, *startp, size, uobj, uoffset, align,
+	    flags, &args);
+	if (!error) {
+		error = uvm_map_enter(map, &args, new_entry);
+		*startp = args.uma_start;
+	} else if (new_entry) {
+		uvm_mapent_free(new_entry);
+	}
+
+	return error;
+}
+
+int
+uvm_map_prepare(struct vm_map *map, vaddr_t start, vsize_t size,
+    struct uvm_object *uobj, voff_t uoffset, vsize_t align, uvm_flag_t flags,
+    struct uvm_map_args *args)
+{
+	struct vm_map_entry *prev_entry;
+	vm_prot_t prot = UVM_PROTECTION(flags);
+	vm_prot_t maxprot = UVM_MAXPROTECTION(flags);
+
+	UVMHIST_FUNC("uvm_map_prepare");
 	UVMHIST_CALLED(maphist);
 
-	UVMHIST_LOG(maphist, "(map=0x%x, *startp=0x%x, size=%d, flags=0x%x)",
-	    map, *startp, size, flags);
+	UVMHIST_LOG(maphist, "(map=0x%x, start=0x%x, size=%d, flags=0x%x)",
+	    map, start, size, flags);
 	UVMHIST_LOG(maphist, "  uobj/offset 0x%x/%d", uobj, uoffset,0,0);
 
 	/*
@@ -768,37 +856,19 @@
 	}
 
 	/*
-	 * for pager_map, allocate the new entry first to avoid sleeping
-	 * for memory while we have the map locked.
-	 */
-
-	new_entry = NULL;
-	if (map == pager_map) {
-		new_entry = uvm_mapent_alloc(map, (flags & UVM_FLAG_NOWAIT));
-		if (__predict_false(new_entry == NULL))
-			return ENOMEM;
-	}
-
-	/*
 	 * figure out where to put new VM range
 	 */
 
 	if (vm_map_lock_try(map) == FALSE) {
 		if (flags & UVM_FLAG_TRYLOCK) {
-			if (new_entry) {
-				uvm_mapent_free(new_entry);
-			}
 			return EAGAIN;
 		}
 		vm_map_lock(map); /* could sleep here */
 	}
-	if ((prev_entry = uvm_map_findspace(map, *startp, size, startp,
+	if ((prev_entry = uvm_map_findspace(map, start, size, &start,
 	    uobj, uoffset, align, flags)) == NULL) {
 		UVMHIST_LOG(maphist,"<- uvm_map_findspace failed!",0,0,0,0);
 		vm_map_unlock(map);
-		if (new_entry) {
-			uvm_mapent_free(new_entry);
-		}
 		return ENOMEM;
 	}
 
@@ -807,8 +877,8 @@
 	 * If the kernel pmap can't map the requested space,
 	 * then allocate more resources for it.
 	 */
-	if (map == kernel_map && uvm_maxkaddr < (*startp + size))
-		uvm_maxkaddr = pmap_growkernel(*startp + size);
+	if (map == kernel_map && uvm_maxkaddr < (start + size))
+		uvm_maxkaddr = pmap_growkernel(start + size);
 #endif
 
 	UVMCNT_INCR(uvm_map_call);
@@ -834,10 +904,60 @@
 	} else {
 		if (uoffset == UVM_UNKNOWN_OFFSET) {
 			KASSERT(UVM_OBJ_IS_KERN_OBJECT(uobj));
-			uoffset = *startp - vm_map_min(kernel_map);
+			uoffset = start - vm_map_min(kernel_map);
 		}
 	}
 
+	args->uma_flags = flags;
+	args->uma_prev = prev_entry;
+	args->uma_start = start;
+	args->uma_size = size;
+	args->uma_uobj = uobj;
+	args->uma_uoffset = uoffset;
+
+	return 0;
+}
+
+int
+uvm_map_enter(struct vm_map *map, const struct uvm_map_args *args,
+    struct vm_map_entry *new_entry)
+{
+	struct vm_map_entry *prev_entry = args->uma_prev;
+	struct vm_map_entry *dead = NULL;
+
+	const uvm_flag_t flags = args->uma_flags;
+	const vm_prot_t prot = UVM_PROTECTION(flags);
+	const vm_prot_t maxprot = UVM_MAXPROTECTION(flags);
+	const vm_inherit_t inherit = UVM_INHERIT(flags);
+	const int amapwaitflag = (flags & UVM_FLAG_NOWAIT) ?
+	    AMAP_EXTEND_NOWAIT : 0;
+	const int advice = UVM_ADVICE(flags);
+	const int meflagmask = UVM_MAP_NOMERGE | UVM_MAP_QUANTUM;
+	const int meflagval = (flags & UVM_FLAG_QUANTUM) ?
+	    UVM_MAP_QUANTUM : 0;
+
+	vaddr_t start = args->uma_start;
+	vsize_t size = args->uma_size;
+	struct uvm_object *uobj = args->uma_uobj;
+	voff_t uoffset = args->uma_uoffset;
+
+	const int kmap = (vm_map_pmap(map) == pmap_kernel());
+	int merged = 0;
+	int error;
+	int newetype;
+
+	UVMHIST_FUNC("uvm_map_enter");
+	UVMHIST_CALLED(maphist);
+
+	UVMHIST_LOG(maphist, "(map=0x%x, start=0x%x, size=%d, flags=0x%x)",
+	    map, start, size, flags);
+	UVMHIST_LOG(maphist, "  uobj/offset 0x%x/%d", uobj, uoffset,0,0);
+
+	if (flags & UVM_FLAG_QUANTUM) {
+		KASSERT(new_entry);
+		KASSERT(new_entry->flags & UVM_MAP_QUANTUM);
+	}
+
 	if (uobj)
 		newetype = UVM_ET_OBJ;
 	else
@@ -859,11 +979,11 @@
 		goto nomerge;
 
 	if (prev_entry->etype == newetype &&
-	    prev_entry->end == *startp &&
+	    prev_entry->end == start &&
 	    prev_entry != &map->header &&
 	    prev_entry->object.uvm_obj == uobj) {
 
-		if (prev_entry->flags & UVM_MAP_NOMERGE)
+		if ((prev_entry->flags & meflagmask) != meflagval)
 			goto forwardmerge;
 
 		if (uobj && prev_entry->offset +
@@ -896,13 +1016,8 @@
 		if (prev_entry->aref.ar_amap) {
 			error = amap_extend(prev_entry, size,
 			    amapwaitflag | AMAP_EXTEND_FORWARDS);
-			if (error) {
-				vm_map_unlock(map);
-				if (new_entry) {
-					uvm_mapent_free(new_entry);
-				}
-				return error;
-			}
+			if (error)
+				goto done;
 		}
 
 		if (kmap)
@@ -925,20 +1040,16 @@
 		uvm_tree_sanity(map, "map backmerged");
 
 		UVMHIST_LOG(maphist,"<- done (via backmerge)!", 0, 0, 0, 0);
-		if (new_entry) {
-			uvm_mapent_free(new_entry);
-			new_entry = NULL;
-		}
 		merged++;
 	}
 
 forwardmerge:
 	if (prev_entry->next->etype == newetype &&
-	    prev_entry->next->start == (*startp + size) &&
+	    prev_entry->next->start == (start + size) &&
 	    prev_entry->next != &map->header &&
 	    prev_entry->next->object.uvm_obj == uobj) {
 
-		if (prev_entry->next->flags & UVM_MAP_NOMERGE)
+		if ((prev_entry->next->flags & meflagmask) != meflagval)
 			goto nomerge;
 
 		if (uobj && prev_entry->next->offset != uoffset + size)
@@ -1025,13 +1136,8 @@
 			if (prev_entry->next->aref.ar_amap) {
 				error = amap_extend(prev_entry->next, size,
 				    amapwaitflag | AMAP_EXTEND_BACKWARDS);
-				if (error) {
-					vm_map_unlock(map);
-					if (new_entry) {
-						uvm_mapent_free(new_entry);
-					}
-					return error;
-				}
+				if (error)
+					goto done;
 			}
 		}
 
@@ -1060,14 +1166,13 @@
 			uobj->pgops->pgo_detach(uobj);
 
 		if (merged) {
-			struct vm_map_entry *dead = prev_entry->next;
+			dead = prev_entry->next;
 			prev_entry->end = dead->end;
 			uvm_map_entry_unlink(map, dead);
 			if (dead->aref.ar_amap != NULL) {
 				prev_entry->aref = dead->aref;
 				dead->aref.ar_amap = NULL;
 			}
-			uvm_mapent_free(dead);
 		} else {
 			prev_entry->next->start -= size;
 			if (prev_entry != &map->header)
@@ -1079,10 +1184,6 @@
 		uvm_tree_sanity(map, "map forwardmerged");
 
 		UVMHIST_LOG(maphist,"<- done forwardmerge", 0, 0, 0, 0);
-		if (new_entry) {
-			uvm_mapent_free(new_entry);
-			new_entry = NULL;
-		}
 		merged++;
 	}
 
@@ -1102,11 +1203,11 @@
 			new_entry = uvm_mapent_alloc(map,
 				(flags & UVM_FLAG_NOWAIT));
 			if (__predict_false(new_entry == NULL)) {
-				vm_map_unlock(map);
-				return ENOMEM;
+				error = ENOMEM;
+				goto done;
 			}
 		}
-		new_entry->start = *startp;
+		new_entry->start = start;
 		new_entry->end = new_entry->start + size;
 		new_entry->object.uvm_obj = uobj;
 		new_entry->offset = uoffset;
@@ -1134,9 +1235,8 @@
 			struct vm_amap *amap = amap_alloc(size, to_add,
 			    (flags & UVM_FLAG_NOWAIT) ? M_NOWAIT : M_WAITOK);
 			if (__predict_false(amap == NULL)) {
-				vm_map_unlock(map);
-				uvm_mapent_free(new_entry);
-				return ENOMEM;
+				error = ENOMEM;
+				goto done;
 			}
 			new_entry->aref.ar_pageoff = 0;
 			new_entry->aref.ar_amap = amap;
@@ -1153,13 +1253,30 @@
 		if ((map->first_free == prev_entry) &&
 		    (prev_entry->end >= new_entry->start))
 			map->first_free = new_entry;
+
+		new_entry = NULL;
 	}
 
 	map->size += size;
 
 	UVMHIST_LOG(maphist,"<- done!", 0, 0, 0, 0);
+
+	error = 0;
+done:
 	vm_map_unlock(map);
-	return 0;
+	if (new_entry) {
+		if (error == 0) {
+			KDASSERT(merged);
+			uvm_mapent_free_merged(map, new_entry);
+		} else {
+			uvm_mapent_free(new_entry);
+		}
+	}
+	if (dead) {
+		KDASSERT(merged);
+		uvm_mapent_free_merged(map, dead);
+	}
+	return error;
 }
 
 /*
@@ -1690,7 +1807,8 @@
 
 void
 uvm_unmap_remove(struct vm_map *map, vaddr_t start, vaddr_t end,
-    struct vm_map_entry **entry_list /* OUT */)
+    struct vm_map_entry **entry_list /* OUT */,
+    struct uvm_mapent_reservation *umr)
 {
 	struct vm_map_entry *entry, *first_entry, *next;
 	vaddr_t len;
@@ -1709,7 +1827,7 @@
 	if (uvm_map_lookup_entry(map, start, &first_entry) == TRUE) {
 		/* clip and go... */
 		entry = first_entry;
-		UVM_MAP_CLIP_START(map, entry, start);
+		UVM_MAP_CLIP_START(map, entry, start, umr);
 		/* critical!  prevents stale hint */
 		SAVE_HINT(map, entry, entry->prev);
 	} else {
@@ -1749,7 +1867,9 @@
 	 */
 
 	while ((entry != &map->header) && (entry->start < end)) {
-		UVM_MAP_CLIP_END(map, entry, end);
+		KASSERT((entry->flags & UVM_MAP_FIRST) == 0);
+
+		UVM_MAP_CLIP_END(map, entry, end, umr);
 		next = entry->next;
 		len = entry->end - entry->start;
 
@@ -1770,8 +1890,11 @@
 			 * this is mostly used for kmem_map and mb_map.
 			 */
 
-			uvm_km_pgremove_intrsafe(entry->start, entry->end);
-			pmap_kremove(entry->start, len);
+			if ((entry->flags & UVM_MAP_KMAPENT) == 0) {
+				uvm_km_pgremove_intrsafe(entry->start,
+				    entry->end);
+				pmap_kremove(entry->start, len);
+			}
 		} else if (UVM_ET_ISOBJ(entry) &&
 			   UVM_OBJ_IS_KERN_OBJECT(entry->object.uvm_obj)) {
 			KASSERT(vm_map_pmap(map) == pmap_kernel());
@@ -2167,7 +2290,7 @@
 			 * fudge is zero)
 			 */
 
-			UVM_MAP_CLIP_START(srcmap, entry, start);
+			UVM_MAP_CLIP_START(srcmap, entry, start, NULL);
 			SAVE_HINT(srcmap, srcmap->hint, entry->prev);
 			fudge = 0;
 		}
@@ -2196,7 +2319,7 @@
 
 		/* if we are not doing a quick reference, clip it */
 		if ((flags & UVM_EXTRACT_QREF) == 0)
-			UVM_MAP_CLIP_END(srcmap, entry, end);
+			UVM_MAP_CLIP_END(srcmap, entry, end, NULL);
 
 		/* clear needs_copy (allow chunking) */
 		if (UVM_ET_ISNEEDSCOPY(entry)) {
@@ -2435,14 +2558,17 @@
     struct vm_map *submap)
 {
 	struct vm_map_entry *entry;
+	struct uvm_mapent_reservation umr;
 	int error;
 
+	uvm_mapent_reserve(map, &umr, 2, 0);
+
 	vm_map_lock(map);
 	VM_MAP_RANGE_CHECK(map, start, end);
 
 	if (uvm_map_lookup_entry(map, start, &entry)) {
-		UVM_MAP_CLIP_START(map, entry, start);
-		UVM_MAP_CLIP_END(map, entry, end);		/* to be safe */
+		UVM_MAP_CLIP_START(map, entry, start, &umr);
+		UVM_MAP_CLIP_END(map, entry, end, &umr);	/* to be safe */
 	} else {
 		entry = NULL;
 	}
@@ -2460,6 +2586,9 @@
 		error = EINVAL;
 	}
 	vm_map_unlock(map);
+
+	uvm_mapent_unreserve(map, &umr);
+
 	return error;
 }
 
@@ -2487,7 +2616,7 @@
 	vm_map_lock(map);
 	VM_MAP_RANGE_CHECK(map, start, end);
 	if (uvm_map_lookup_entry(map, start, &entry)) {
-		UVM_MAP_CLIP_START(map, entry, start);
+		UVM_MAP_CLIP_START(map, entry, start, NULL);
 	} else {
 		entry = entry->next;
 	}
@@ -2531,7 +2660,7 @@
 	while ((current != &map->header) && (current->start < end)) {
 		vm_prot_t old_prot;
 
-		UVM_MAP_CLIP_END(map, current, end);
+		UVM_MAP_CLIP_END(map, current, end, NULL);
 		old_prot = current->protection;
 		if (set_max)
 			current->protection =
@@ -2601,6 +2730,7 @@
 
  out:
 	vm_map_unlock(map);
+
 	UVMHIST_LOG(maphist, "<- done, error=%d",error,0,0,0);
 	return error;
 }
@@ -2638,12 +2768,12 @@
 	VM_MAP_RANGE_CHECK(map, start, end);
 	if (uvm_map_lookup_entry(map, start, &temp_entry)) {
 		entry = temp_entry;
-		UVM_MAP_CLIP_START(map, entry, start);
+		UVM_MAP_CLIP_START(map, entry, start, NULL);
 	}  else {
 		entry = temp_entry->next;
 	}
 	while ((entry != &map->header) && (entry->start < end)) {
-		UVM_MAP_CLIP_END(map, entry, end);
+		UVM_MAP_CLIP_END(map, entry, end, NULL);
 		entry->inheritance = new_inheritance;
 		entry = entry->next;
 	}
@@ -2670,7 +2800,7 @@
 	VM_MAP_RANGE_CHECK(map, start, end);
 	if (uvm_map_lookup_entry(map, start, &temp_entry)) {
 		entry = temp_entry;
-		UVM_MAP_CLIP_START(map, entry, start);
+		UVM_MAP_CLIP_START(map, entry, start, NULL);
 	} else {
 		entry = temp_entry->next;
 	}
@@ -2680,7 +2810,7 @@
 	 */
 
 	while ((entry != &map->header) && (entry->start < end)) {
-		UVM_MAP_CLIP_END(map, entry, end);
+		UVM_MAP_CLIP_END(map, entry, end, NULL);
 
 		switch (new_advice) {
 		case MADV_NORMAL:
@@ -2757,7 +2887,7 @@
 	 */
 
 	if (new_pageable) {		/* unwire */
-		UVM_MAP_CLIP_START(map, entry, start);
+		UVM_MAP_CLIP_START(map, entry, start, NULL);
 
 		/*
 		 * unwiring.  first ensure that the range to be unwired is
@@ -2785,7 +2915,7 @@
 
 		entry = start_entry;
 		while ((entry != &map->header) && (entry->start < end)) {
-			UVM_MAP_CLIP_END(map, entry, end);
+			UVM_MAP_CLIP_END(map, entry, end, NULL);
 			if (VM_MAPENT_ISWIRED(entry))
 				uvm_map_entry_unwire(map, entry);
 			entry = entry->next;
@@ -2838,8 +2968,8 @@
 				}
 			}
 		}
-		UVM_MAP_CLIP_START(map, entry, start);
-		UVM_MAP_CLIP_END(map, entry, end);
+		UVM_MAP_CLIP_START(map, entry, start, NULL);
+		UVM_MAP_CLIP_END(map, entry, end, NULL);
 		entry->wired_count++;
 
 		/*
@@ -3605,7 +3735,7 @@
 #endif
 	if (map->nentries) {
 		uvm_unmap_remove(map, map->min_offset, map->max_offset,
-		    &dead_entries);
+		    &dead_entries, NULL);
 		if (dead_entries != NULL)
 			uvm_unmap_detach(dead_entries, 0);
 	}
@@ -3854,6 +3984,311 @@
 }
 
 
+/*
+ * in-kernel map entry allocation.
+ */
+
+int ukh_alloc, ukh_free;
+int uke_alloc, uke_free;
+
+struct uvm_kmapent_hdr {
+	LIST_ENTRY(uvm_kmapent_hdr) ukh_listq;
+	int ukh_nused;
+	struct vm_map_entry *ukh_freelist;
+	struct vm_map *ukh_map;
+	struct vm_map_entry ukh_entries[0];
+};
+
+#define	UVM_KMAPENT_CHUNK				\
+	((PAGE_SIZE - sizeof(struct uvm_kmapent_hdr))	\
+	/ sizeof(struct vm_map_entry))
+
+#define	UVM_KHDR_FIND(entry)	\
+	((struct uvm_kmapent_hdr *)(((vaddr_t)entry) & ~PAGE_MASK))
+
+static __inline struct vm_map_entry *uvm_kmapent_get(struct uvm_kmapent_hdr *);
+static __inline void uvm_kmapent_put(struct uvm_kmapent_hdr *,
+    struct vm_map_entry *);
+
+static __inline struct vm_map *
+uvm_kmapent_map(struct vm_map_entry *entry)
+{
+	const struct uvm_kmapent_hdr *ukh;
+
+	ukh = UVM_KHDR_FIND(entry);
+	return ukh->ukh_map;
+}
+
+static __inline struct vm_map_entry *
+uvm_kmapent_get(struct uvm_kmapent_hdr *ukh)
+{
+	struct vm_map_entry *entry;
+
+	KASSERT(ukh->ukh_nused <= UVM_KMAPENT_CHUNK);
+	KASSERT(ukh->ukh_nused >= 0);
+
+	entry = ukh->ukh_freelist;
+	if (entry) {
+		KASSERT((entry->flags & (UVM_MAP_KERNEL | UVM_MAP_KMAPENT))
+		    == UVM_MAP_KERNEL);
+		ukh->ukh_freelist = entry->next;
+		ukh->ukh_nused++;
+		KASSERT(ukh->ukh_nused <= UVM_KMAPENT_CHUNK);
+	} else {
+		KASSERT(ukh->ukh_nused == UVM_KMAPENT_CHUNK);
+	}
+
+	return entry;
+}
+
+static __inline void
+uvm_kmapent_put(struct uvm_kmapent_hdr *ukh, struct vm_map_entry *entry)
+{
+
+	KASSERT((entry->flags & (UVM_MAP_KERNEL | UVM_MAP_KMAPENT))
+	    == UVM_MAP_KERNEL);
+	KASSERT(ukh->ukh_nused <= UVM_KMAPENT_CHUNK);
+	KASSERT(ukh->ukh_nused > 0);
+	KASSERT(ukh->ukh_freelist != NULL ||
+	    ukh->ukh_nused == UVM_KMAPENT_CHUNK);
+	KASSERT(ukh->ukh_freelist == NULL ||
+	    ukh->ukh_nused < UVM_KMAPENT_CHUNK);
+
+	ukh->ukh_nused--;
+	entry->next = ukh->ukh_freelist;
+	ukh->ukh_freelist = entry;
+}
+
+/*
+ * uvm_kmapent_alloc: allocate a map entry for in-kernel map
+ */
+
+static struct vm_map_entry *
+uvm_kmapent_alloc(struct vm_map *map, int flags)
+{
+	struct vm_page *pg;
+	struct uvm_map_args args;
+	struct uvm_kmapent_hdr *ukh;
+	struct vm_map_entry *entry;
+	uvm_flag_t mapflags = UVM_MAPFLAG(UVM_PROT_ALL, UVM_PROT_ALL,
+	    UVM_INH_NONE, UVM_ADV_RANDOM, flags | UVM_FLAG_NOMERGE);
+	vaddr_t va;
+	int error;
+	int i;
+	int s;
+
+	KDASSERT(UVM_KMAPENT_CHUNK > 2);
+	KDASSERT(kernel_map != NULL);
+	KASSERT(vm_map_pmap(map) == pmap_kernel());
+
+	uke_alloc++;
+	entry = NULL;
+again:
+	/*
+	 * try to grab an entry from freelist.
+	 */
+	s = splvm();
+	simple_lock(&uvm.kentry_lock);
+	ukh = LIST_FIRST(&map->kentry_free);
+	if (ukh) {
+		entry = uvm_kmapent_get(ukh);
+		if (ukh->ukh_nused == UVM_KMAPENT_CHUNK)
+			LIST_REMOVE(ukh, ukh_listq);
+	}
+	simple_unlock(&uvm.kentry_lock);
+	splx(s);
+
+	if (entry)
+		return entry;
+
+	/*
+	 * there's no free entry for this vm_map.
+	 * now we need to allocate some vm_map_entry.
+	 * for simplicity, always allocate one page chunk of them at once.
+	 */
+
+	pg = uvm_pagealloc(NULL, 0, NULL, 0);
+	if (__predict_false(pg == NULL)) {
+		if (flags & UVM_FLAG_NOWAIT)
+			return NULL;
+		uvm_wait("kme_alloc");
+		goto again;
+	}
+
+	error = uvm_map_prepare(map, 0, PAGE_SIZE, NULL, 0, 0, mapflags, &args);
+	if (error) {
+		uvm_pagefree(pg);
+		return NULL;
+	}
+
+	va = args.uma_start;
+
+	pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg), VM_PROT_READ|VM_PROT_WRITE);
+	pmap_update(vm_map_pmap(map));
+
+	ukh = (void *)va;
+
+	/*
+	 * use the first entry for ukh itsself.
+	 */
+
+	entry = &ukh->ukh_entries[0];
+	entry->flags = UVM_MAP_KERNEL | UVM_MAP_KMAPENT;
+	error = uvm_map_enter(map, &args, entry);
+	KASSERT(error == 0);
+
+	ukh->ukh_nused = UVM_KMAPENT_CHUNK;
+	ukh->ukh_map = map;
+	ukh->ukh_freelist = NULL;
+	for (i = UVM_KMAPENT_CHUNK - 1; i >= 2; i--) {
+		struct vm_map_entry *entry = &ukh->ukh_entries[i];
+
+		entry->flags = UVM_MAP_KERNEL;
+		uvm_kmapent_put(ukh, entry);
+	}
+	KASSERT(ukh->ukh_nused == 2);
+
+	s = splvm();
+	simple_lock(&uvm.kentry_lock);
+	LIST_INSERT_HEAD(&map->kentry_free, ukh, ukh_listq);
+	simple_unlock(&uvm.kentry_lock);
+	splx(s);
+
+	/*
+	 * return second entry.
+	 */
+
+	entry = &ukh->ukh_entries[1];
+	entry->flags = UVM_MAP_KERNEL;
+	ukh_alloc++;
+	return entry;
+}
+
+/*
+ * uvm_mapent_free: free map entry for in-kernel map
+ */
+
+static void
+uvm_kmapent_free(struct vm_map_entry *entry)
+{
+	struct uvm_kmapent_hdr *ukh;
+	struct vm_page *pg;
+	struct vm_map *map;
+	struct pmap *pmap;
+	vaddr_t va;
+	paddr_t pa;
+	struct vm_map_entry *deadentry;
+	int s;
+
+	uke_free++;
+	ukh = UVM_KHDR_FIND(entry);
+	map = ukh->ukh_map;
+
+	s = splvm();
+	simple_lock(&uvm.kentry_lock);
+	uvm_kmapent_put(ukh, entry);
+	if (ukh->ukh_nused > 1) {
+		if (ukh->ukh_nused == UVM_KMAPENT_CHUNK - 1)
+			LIST_INSERT_HEAD(&map->kentry_free, ukh, ukh_listq);
+		simple_unlock(&uvm.kentry_lock);
+		splx(s);
+		return;
+	}
+
+	/*
+	 * now we can free this ukh.
+	 *
+	 * however, keep an empty ukh to avoid ping-pong.
+	 */
+
+	if (LIST_FIRST(&map->kentry_free) == ukh &&
+	    LIST_NEXT(ukh, ukh_listq) == NULL) {
+		simple_unlock(&uvm.kentry_lock);
+		splx(s);
+		return;
+	}
+	LIST_REMOVE(ukh, ukh_listq);
+	simple_unlock(&uvm.kentry_lock);
+	splx(s);
+
+	KASSERT(ukh->ukh_nused == 1);
+
+	/*
+	 * remove map entry for ukh itsself.
+	 */
+
+	va = (vaddr_t)ukh;
+	KASSERT((va & PAGE_MASK) == 0);
+	uvm_unmap_remove(map, va, va + PAGE_SIZE, &deadentry, NULL);
+	KASSERT(deadentry->flags & UVM_MAP_KERNEL);
+	KASSERT(deadentry->flags & UVM_MAP_KMAPENT);
+	KASSERT(deadentry->next == NULL);
+	KASSERT(deadentry == &ukh->ukh_entries[0]);
+
+	/*
+	 * unmap the page from pmap and free it.
+	 */
+
+	pmap = vm_map_pmap(map);
+	KASSERT(pmap == pmap_kernel());
+	if (!pmap_extract(pmap, va, &pa))
+		panic("%s: no mapping", __func__);
+	pmap_kremove(va, PAGE_SIZE);
+	pg = PHYS_TO_VM_PAGE(pa);
+	uvm_pagefree(pg);
+	ukh_free++;
+}
+
+/*
+ * map entry reservation
+ */
+
+/*
+ * uvm_mapent_reserve: reserve map entries for clipping before locking map.
+ *
+ * => needed when unmapping entries allocated without UVM_FLAG_QUANTUM.
+ * => caller shouldn't hold map locked.
+ */
+int
+uvm_mapent_reserve(struct vm_map *map, struct uvm_mapent_reservation *umr,
+    int nentries, int flags)
+{
+
+	umr->umr_nentries = 0;
+
+	if ((flags & UVM_FLAG_QUANTUM) != 0)
+		return 0;
+
+	if (!VM_MAP_USE_KMAPENT(map))
+		return 0;
+
+	while (nentries--) {
+		struct vm_map_entry *ent;
+		ent = uvm_kmapent_alloc(map, flags);
+		if (!ent) {
+			uvm_mapent_unreserve(map, umr);
+			return ENOMEM;
+		}
+		UMR_PUTENTRY(umr, ent);
+	}
+
+	return 0;
+}
+
+/*
+ * uvm_mapent_unreserve:
+ *
+ * => caller shouldn't hold map locked.
+ * => never fail or sleep.
+ */
+void
+uvm_mapent_unreserve(struct vm_map *map, struct uvm_mapent_reservation *umr)
+{
+
+	while (!UMR_EMPTY(umr))
+		uvm_kmapent_free(UMR_GETENTRY(umr));
+}
+
 #if defined(DDB)
 
 /*
Index: sys/uvm/uvm_map.h
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_map.h,v
retrieving revision 1.39
diff -u -r1.39 uvm_map.h
--- sys/uvm/uvm_map.h	10 Feb 2004 01:30:49 -0000	1.39
+++ sys/uvm/uvm_map.h	16 Jun 2005 17:23:38 -0000
@@ -86,8 +86,8 @@
  * => map must be locked by caller
  */
 
-#define UVM_MAP_CLIP_START(MAP,ENTRY,VA) { \
-	if ((VA) > (ENTRY)->start) uvm_map_clip_start(MAP,ENTRY,VA); }
+#define UVM_MAP_CLIP_START(MAP,ENTRY,VA,UMR) { \
+	if ((VA) > (ENTRY)->start) uvm_map_clip_start(MAP,ENTRY,VA,UMR); }
 
 /*
  * UVM_MAP_CLIP_END: ensure that the entry ends at or before
@@ -96,8 +96,8 @@
  * => map must be locked by caller
  */
 
-#define UVM_MAP_CLIP_END(MAP,ENTRY,VA) { \
-	if ((VA) < (ENTRY)->end) uvm_map_clip_end(MAP,ENTRY,VA); }
+#define UVM_MAP_CLIP_END(MAP,ENTRY,VA,UMR) { \
+	if ((VA) < (ENTRY)->end) uvm_map_clip_end(MAP,ENTRY,VA,UMR); }
 
 /*
  * extract flags
@@ -142,8 +142,11 @@
 #define uvm_map_entry_stop_copy flags
 	u_int8_t		flags;		/* flags */
 
-#define UVM_MAP_STATIC		0x01		/* static map entry */
-#define UVM_MAP_KMEM		0x02		/* from kmem entry pool */
+#define	UVM_MAP_KERNEL		0x01		/* kernel map entry */
+#define	UVM_MAP_KMAPENT		0x02		/* contains map entries */
+#define	UVM_MAP_FIRST		0x04		/* the first special entry */
+#define	UVM_MAP_QUANTUM		0x08		/* allocated with
+						 * UVM_FLAG_QUANTUM */
 #define	UVM_MAP_NOMERGE		0x10		/* this entry is not mergable */
 
 };
@@ -226,6 +229,11 @@
 	int			flags;		/* flags */
 	struct simplelock	flags_lock;	/* Lock for flags field */
 	unsigned int		timestamp;	/* Version number */
+	LIST_HEAD(, uvm_kmapent_hdr) kentry_free; /* Freelist of map entry */
+
+	struct vm_map_entry	*merged_entries;/* Merged entries, kept for
+						 * later splitting */
+
 #define	min_offset		header.end
 #define	max_offset		header.start
 };
@@ -239,15 +247,28 @@
 #define	VM_MAP_DYING		0x20		/* rw: map is being destroyed */
 #define	VM_MAP_TOPDOWN		0x40		/* ro: arrange map top-down */
 
-/* XXX: number of kernel maps and entries to statically allocate */
+#ifdef _KERNEL
+struct uvm_mapent_reservation {
+	struct vm_map_entry *umr_entries[2];
+	int umr_nentries;
+};
+#define	UMR_EMPTY(umr)		((umr) == NULL || (umr)->umr_nentries == 0)
+#define	UMR_GETENTRY(umr)	((umr)->umr_entries[--(umr)->umr_nentries])
+#define	UMR_PUTENTRY(umr, ent)	\
+	(umr)->umr_entries[(umr)->umr_nentries++] = (ent)
+
+struct uvm_map_args {
+	struct vm_map_entry *uma_prev;
 
-#if !defined(MAX_KMAPENT)
-#if (50 + (2 * NPROC) > 1000)
-#define MAX_KMAPENT (50 + (2 * NPROC))
-#else
-#define	MAX_KMAPENT	1000  /* XXXCDC: no crash */
-#endif
-#endif	/* !defined MAX_KMAPENT */
+	vaddr_t uma_start;
+	vsize_t uma_size;
+
+	struct uvm_object *uma_uobj;
+	voff_t uma_uoffset;
+
+	uvm_flag_t uma_flags;
+};
+#endif /* _KERNEL */
 
 #ifdef _KERNEL
 #define	vm_map_modflags(map, set, clear)				\
@@ -287,9 +308,9 @@
 
 int		uvm_map_clean(struct vm_map *, vaddr_t, vaddr_t, int);
 void		uvm_map_clip_start(struct vm_map *, struct vm_map_entry *,
-		    vaddr_t);
+		    vaddr_t, struct uvm_mapent_reservation *);
 void		uvm_map_clip_end(struct vm_map *, struct vm_map_entry *,
-		    vaddr_t);
+		    vaddr_t, struct uvm_mapent_reservation *);
 MAP_INLINE
 struct vm_map	*uvm_map_create(pmap_t, vaddr_t, vaddr_t, int);
 int		uvm_map_extract(struct vm_map *, vaddr_t, vsize_t,
@@ -313,10 +334,23 @@
 int		uvm_map_submap(struct vm_map *, vaddr_t, vaddr_t,
 		    struct vm_map *);
 MAP_INLINE
-void		uvm_unmap(struct vm_map *, vaddr_t, vaddr_t);
+void		uvm_unmap1(struct vm_map *, vaddr_t, vaddr_t, int);
+#define	uvm_unmap(map, s, e)	uvm_unmap1((map), (s), (e), 0)
 void		uvm_unmap_detach(struct vm_map_entry *,int);
 void		uvm_unmap_remove(struct vm_map *, vaddr_t, vaddr_t,
-		    struct vm_map_entry **);
+		    struct vm_map_entry **, struct uvm_mapent_reservation *);
+
+int		uvm_map_prepare(struct vm_map *, vaddr_t, vsize_t,
+		    struct uvm_object *, voff_t, vsize_t, uvm_flag_t,
+		    struct uvm_map_args *);
+int		uvm_map_enter(struct vm_map *, const struct uvm_map_args *,
+		    struct vm_map_entry *);
+
+int		uvm_mapent_reserve(struct vm_map *,
+		    struct uvm_mapent_reservation *, int, int);
+void		uvm_mapent_unreserve(struct vm_map *,
+		    struct uvm_mapent_reservation *);
+
 
 #endif /* _KERNEL */
 
@@ -464,6 +498,7 @@
 	if (oflags & VM_MAP_WANTLOCK)					\
 		wakeup(&(map)->flags);					\
 } while (/*CONSTCOND*/ 0)
+
 #endif /* _KERNEL */
 
 /*
Index: sys/uvm/uvm_map_i.h
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_map_i.h,v
retrieving revision 1.28
diff -u -r1.28 uvm_map_i.h
--- sys/uvm/uvm_map_i.h	10 Feb 2004 01:30:49 -0000	1.28
+++ sys/uvm/uvm_map_i.h	16 Jun 2005 17:23:38 -0000
@@ -120,6 +120,8 @@
 	simple_lock_init(&map->ref_lock);
 	simple_lock_init(&map->hint_lock);
 	simple_lock_init(&map->flags_lock);
+	LIST_INIT(&map->kentry_free);
+	map->merged_entries = NULL;
 }
 
 
@@ -128,16 +130,18 @@
  */
 
 /*
- * uvm_unmap: remove mappings from a vm_map (from "start" up to "stop")
+ * uvm_unmap1: remove mappings from a vm_map (from "start" up to "stop")
  *
  * => caller must check alignment and size
  * => map must be unlocked (we will lock it)
+ * => flags is UVM_FLAG_QUANTUM or 0.
  */
 
 MAP_INLINE void
-uvm_unmap(struct vm_map *map, vaddr_t start, vaddr_t end)
+uvm_unmap1(struct vm_map *map, vaddr_t start, vaddr_t end, int flags)
 {
 	struct vm_map_entry *dead_entries;
+	struct uvm_mapent_reservation umr;
 	UVMHIST_FUNC("uvm_unmap"); UVMHIST_CALLED(maphist);
 
 	UVMHIST_LOG(maphist, "  (map=0x%x, start=0x%x, end=0x%x)",
@@ -146,9 +150,11 @@
 	 * work now done by helper functions.   wipe the pmap's and then
 	 * detach from the dead entries...
 	 */
+	uvm_mapent_reserve(map, &umr, 2, flags);
 	vm_map_lock(map);
-	uvm_unmap_remove(map, start, end, &dead_entries);
+	uvm_unmap_remove(map, start, end, &dead_entries, &umr);
 	vm_map_unlock(map);
+	uvm_mapent_unreserve(map, &umr);
 
 	if (dead_entries != NULL)
 		uvm_unmap_detach(dead_entries, 0);
Index: sys/uvm/uvm_mmap.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.82
diff -u -r1.82 uvm_mmap.c
--- sys/uvm/uvm_mmap.c	24 Mar 2004 07:47:33 -0000	1.82
+++ sys/uvm/uvm_mmap.c	16 Jun 2005 17:23:38 -0000
@@ -685,7 +685,7 @@
 		return (EINVAL);
 	}
 #endif
-	uvm_unmap_remove(map, addr, addr + size, &dead_entries);
+	uvm_unmap_remove(map, addr, addr + size, &dead_entries, NULL);
 	vm_map_unlock(map);
 	if (dead_entries != NULL)
 		uvm_unmap_detach(dead_entries, 0);
Index: sys/uvm/uvm_pager.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_pager.c,v
retrieving revision 1.62.2.1
diff -u -r1.62.2.1 uvm_pager.c
--- sys/uvm/uvm_pager.c	10 May 2004 14:26:44 -0000	1.62.2.1
+++ sys/uvm/uvm_pager.c	16 Jun 2005 17:23:38 -0000
@@ -224,7 +224,7 @@
 	}
 
 	vm_map_lock(pager_map);
-	uvm_unmap_remove(pager_map, kva, kva + size, &entries);
+	uvm_unmap_remove(pager_map, kva, kva + size, &entries, NULL);
 	simple_lock(&pager_map_wanted_lock);
 	if (pager_map_wanted) {
 		pager_map_wanted = FALSE;
Index: usr.bin/pmap/pmap.c
===================================================================
RCS file: /cvsroot/src/usr.bin/pmap/pmap.c,v
retrieving revision 1.22
diff -u -r1.22 pmap.c
--- usr.bin/pmap/pmap.c	10 Feb 2004 01:31:41 -0000	1.22
+++ usr.bin/pmap/pmap.c	16 Jun 2005 17:23:39 -0000
@@ -321,10 +321,12 @@
 		printf("%*s    aref = { ar_pageoff = %x, ar_amap = %p },",
 		       indent(2), "", vme->aref.ar_pageoff, vme->aref.ar_amap);
 		printf(" advice = %d,\n", vme->advice);
-		printf("%*s    flags = %x <%s%s%s > }\n", indent(2), "",
+		printf("%*s    flags = %x <%s%s%s%s%s > }\n", indent(2), "",
 		       vme->flags,
-		       vme->flags & UVM_MAP_KMEM ? " KMEM" : "",
-		       vme->flags & UVM_MAP_STATIC ? " STATIC" : "",
+		       vme->flags & UVM_MAP_KERNEL ? " KERNEL" : "",
+		       vme->flags & UVM_MAP_KMAPENT ? " KMAPENT" : "",
+		       vme->flags & UVM_MAP_FIRST ? " FIRST" : "",
+		       vme->flags & UVM_MAP_QUANTUM ? " QUANTUM" : "",
 		       vme->flags & UVM_MAP_NOMERGE ? " NOMERGE" : "");
 	}
 
Index: usr.sbin/user/user.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/user/user.c,v
retrieving revision 1.75
diff -u -r1.75 user.c
--- usr.sbin/user/user.c	14 Jan 2004 09:35:33 -0000	1.75
+++ usr.sbin/user/user.c	16 Jun 2005 17:23:39 -0000
@@ -1977,6 +1977,10 @@
 	if (argc != 1) {
 		usermgmt_usage("groupdel");
 	}
+
+	if (getgrnam(*argv) == NULL) {
+		err(EXIT_FAILURE, "can't find group `%s' to delete", *argv);
+	}	
 	checkeuid();
 	openlog("groupdel", LOG_PID, LOG_USER);
 	if (!modify_gid(*argv, NULL)) {
