? sys/i386/conf/QEMU
Index: bin/sh/miscbltin.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/bin/sh/miscbltin.c,v
retrieving revision 1.30
diff -U5 -r1.30 miscbltin.c
--- bin/sh/miscbltin.c	6 Apr 2004 20:06:51 -0000	1.30
+++ bin/sh/miscbltin.c	15 Jun 2005 10:42:51 -0000
@@ -356,11 +356,11 @@
 	int		set, all = 0;
 	int		optc, what;
 	struct rlimit	limit;
 
 	what = 'f';
-	while ((optc = nextopt("HSatfdsmcnuvlb")) != '\0')
+	while ((optc = nextopt("HSatfdsmcnuvlbw")) != '\0')
 		switch (optc) {
 		case 'H':
 			how = HARD;
 			break;
 		case 'S':
Index: etc/login.conf
===================================================================
RCS file: /usr/local/arch/ncvs/src/etc/login.conf,v
retrieving revision 1.49
diff -U5 -r1.49 login.conf
--- etc/login.conf	6 Jun 2004 11:46:27 -0000	1.49
+++ etc/login.conf	15 Jun 2005 10:43:04 -0000
@@ -33,10 +33,11 @@
 	:coredumpsize=unlimited:\
 	:openfiles=unlimited:\
 	:maxproc=unlimited:\
 	:sbsize=unlimited:\
 	:vmemoryuse=unlimited:\
+	:swapuse=unlimited:\
 	:priority=0:\
 	:ignoretime@:\
 	:umask=022:
 
 
Index: lib/libutil/login_class.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/lib/libutil/login_class.c,v
retrieving revision 1.24
diff -U5 -r1.24 login_class.c
--- lib/libutil/login_class.c	29 Oct 2003 10:55:56 -0000	1.24
+++ lib/libutil/login_class.c	15 Jun 2005 10:43:12 -0000
@@ -57,10 +57,11 @@
     { "maxproc",      login_getcapnum,  RLIMIT_NPROC    },
     { "openfiles",    login_getcapnum,  RLIMIT_NOFILE   },
     { "coredumpsize", login_getcapsize, RLIMIT_CORE     },
     { "sbsize",       login_getcapsize,	RLIMIT_SBSIZE	},
     { "vmemoryuse",   login_getcapsize,	RLIMIT_VMEM	},
+    { "swapuse",      login_getcapsize, RLIMIT_SWAP	},
     { NULL,	      0,		0 	        }
 };
 
 
 void
Index: share/mk/bsd.compat.mk
===================================================================
RCS file: /usr/local/arch/ncvs/src/share/mk/bsd.compat.mk,v
retrieving revision 1.20
diff -U5 -r1.20 bsd.compat.mk
--- share/mk/bsd.compat.mk	2 Mar 2005 11:53:21 -0000	1.20
+++ share/mk/bsd.compat.mk	15 Jun 2005 10:43:22 -0000
@@ -31,11 +31,11 @@
 	NOSHARED:NO_SHARED \
 	NOTAGS:NO_TAGS
 .for old in ${oldnew:C/:.*//}
 .for new in ${oldnew:C/.*://}
 .if defined(${old}) && !defined(${new})
-.warning ${old} is deprecated in favor of ${new}
+#.warning ${old} is deprecated in favor of ${new}
 ${new}=	${${old}}
 .endif
 .endfor
 .endfor
 .endfor
Index: sys/dev/md/md.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/dev/md/md.c,v
retrieving revision 1.153
diff -U5 -r1.153 md.c
--- sys/dev/md/md.c	13 Feb 2005 21:51:50 -0000	1.153
+++ sys/dev/md/md.c	15 Jun 2005 10:43:27 -0000
@@ -73,10 +73,11 @@
 #include <sys/queue.h>
 #include <sys/sched.h>
 #include <sys/sf_buf.h>
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
+#include <sys/resourcevar.h>
 
 #include <geom/geom.h>
 
 #include <vm/vm.h>
 #include <vm/vm_object.h>
@@ -531,11 +532,11 @@
 	u_char *p;
 
 	p = bp->bio_data;
 
 	/*
-	 * offs is the ofset at whih to start operating on the
+	 * offs is the ofset at which to start operating on the
 	 * next (ie, first) page.  lastp is the last page on
 	 * which we're going to operate.  lastend is the ending
 	 * position within that last page (ie, PAGE_SIZE if
 	 * we're operating on complete aligned pages).
 	 */
@@ -986,14 +987,19 @@
 	npage = mdio->md_mediasize / PAGE_SIZE;
 	if (mdio->md_fwsectors != 0)
 		sc->fwsectors = mdio->md_fwsectors;
 	if (mdio->md_fwheads != 0)
 		sc->fwheads = mdio->md_fwheads;
+	if (!swap_reserve_by_uid("md", PAGE_SIZE * npage, td->td_ucred->cr_ruidinfo))
+		return (ENOMEM);
 	sc->object = vm_pager_allocate(OBJT_SWAP, NULL, PAGE_SIZE * npage,
 	    VM_PROT_DEFAULT, 0);
 	if (sc->object == NULL)
 		return (ENOMEM);
+	sc->object->uip = td->td_ucred->cr_ruidinfo;
+	sc->object->charge = ptoa(sc->object->size);
+	uihold(sc->object->uip);
 	sc->flags = mdio->md_options & MD_FORCE;
 	if (mdio->md_options & MD_RESERVE) {
 		if (swap_pager_reserve(sc->object, 0, npage) < 0) {
 			vm_object_deallocate(sc->object);
 			sc->object = NULL;
Index: sys/fs/procfs/procfs_map.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/fs/procfs/procfs_map.c,v
retrieving revision 1.37
diff -U5 -r1.37 procfs_map.c
--- sys/fs/procfs/procfs_map.c	6 Jan 2005 18:10:40 -0000	1.37
+++ sys/fs/procfs/procfs_map.c	15 Jun 2005 10:43:27 -0000
@@ -42,10 +42,11 @@
 #include <sys/malloc.h>
 #include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/uio.h>
 #include <sys/vnode.h>
+#include <sys/resourcevar.h>
 
 #include <fs/pseudofs/pseudofs.h>
 #include <fs/procfs/procfs.h>
 
 #include <vm/vm.h>
@@ -75,10 +76,11 @@
 	vm_map_t map = &p->p_vmspace->vm_map;
 	pmap_t pmap = vmspace_pmap(p->p_vmspace);
 	vm_map_entry_t entry;
 	char mebuffer[MEBUFFERSIZE];
 	char *fullpath, *freepath;
+	struct uidinfo *uip;
 
 	GIANT_REQUIRED;
 
 	PROC_LOCK(p);
 	error = p_candebug(td, p);
@@ -111,10 +113,12 @@
 		if (obj && (obj->shadow_count == 1))
 			privateresident = obj->resident_page_count;
 		else
 			privateresident = 0;
 
+		uip = (entry->uip) ? entry->uip : (obj ? obj->uip : NULL);
+
 		resident = 0;
 		addr = entry->start;
 		while (addr < entry->end) {
 			if (pmap_extract( pmap, addr))
 				resident++;
@@ -157,23 +161,25 @@
 			shadow_count = 0;
 		}
 
 		/*
 		 * format:
-		 *  start, end, resident, private resident, cow, access, type.
+		 *  start, end, resident, private resident, cow, access, type,
+		 *         charged, charged on write.
 		 */
 		snprintf(mebuffer, sizeof mebuffer,
-		    "0x%lx 0x%lx %d %d %p %s%s%s %d %d 0x%x %s %s %s %s\n",
+		    "0x%lx 0x%lx %d %d %p %s%s%s %d %d 0x%x %s %s %s %s %s(%d)\n",
 			(u_long)entry->start, (u_long)entry->end,
 			resident, privateresident, obj,
 			(entry->protection & VM_PROT_READ)?"r":"-",
 			(entry->protection & VM_PROT_WRITE)?"w":"-",
 			(entry->protection & VM_PROT_EXECUTE)?"x":"-",
 			ref_count, shadow_count, flags,
 			(entry->eflags & MAP_ENTRY_COW)?"COW":"NCOW",
 			(entry->eflags & MAP_ENTRY_NEEDS_COPY)?"NC":"NNC",
-			type, fullpath);
+			type, fullpath,
+			uip ? "CH":"NCH", uip ? uip->ui_uid : -1);
 
 		if (freepath != NULL)
 			free(freepath, M_TEMP);
 
 		len = strlen(mebuffer);
Index: sys/kern/init_main.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/init_main.c,v
retrieving revision 1.255
diff -U5 -r1.255 init_main.c
--- sys/kern/init_main.c	17 Feb 2005 10:00:09 -0000	1.255
+++ sys/kern/init_main.c	15 Jun 2005 10:43:27 -0000
@@ -528,12 +528,13 @@
 
 	/*
 	 * Need just enough stack to hold the faked-up "execve()" arguments.
 	 */
 	addr = p->p_sysent->sv_usrstack - PAGE_SIZE;
+/* 	swap_reserve_force(PAGE_SIZE); */
 	if (vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &addr, PAGE_SIZE,
-			FALSE, VM_PROT_ALL, VM_PROT_ALL, 0) != 0)
+			FALSE, VM_PROT_ALL, VM_PROT_ALL, 0 /* MAP_ACC_CHARGED */) != 0)
 		panic("init: couldn't allocate argument space");
 	p->p_vmspace->vm_maxsaddr = (caddr_t)addr;
 	p->p_vmspace->vm_ssize = 1;
 
 	if ((var = getenv("init_path")) != NULL) {
@@ -671,5 +672,31 @@
 	TD_SET_CAN_RUN(td);
 	setrunqueue(td, SRQ_BORING);	/* XXXKSE */
 	mtx_unlock_spin(&sched_lock);
 }
 SYSINIT(kickinit, SI_SUB_KTHREAD_INIT, SI_ORDER_FIRST, kick_init, NULL)
+
+
+/* XXXOVERCOMMIT */
+int
+dump_vmspace(td, uap)
+     struct thread *td;
+     register struct dump_vmspace_args *uap;
+{
+	int pid = uap->pid;
+	char caller[16];
+	struct proc *p;
+
+	if (copyinstr(uap->caller, caller, sizeof(caller), NULL) != 0)
+		return EFAULT;
+	if (pid == -1) {
+		p = curproc;
+	} else {
+		p = pfind(pid);
+		PROC_UNLOCK(p);
+	}
+	if (p == NULL)
+		return ENOENT;
+
+	swap_dump_proc_vmspace(caller, p);
+	return 0;
+}
Index: sys/kern/init_sysent.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/init_sysent.c,v
retrieving revision 1.193
diff -U5 -r1.193 init_sysent.c
--- sys/kern/init_sysent.c	30 May 2005 15:20:20 -0000	1.193
+++ sys/kern/init_sysent.c	15 Jun 2005 10:43:27 -0000
@@ -1,10 +1,10 @@
 /*
  * System call switch table.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/kern/init_sysent.c,v 1.193 2005/05/30 15:20:20 rwatson Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/kern/syscalls.master,v 1.196 2005/05/30 15:09:18 rwatson Exp 
  */
 
 #include "opt_compat.h"
 
@@ -483,6 +483,7 @@
 	{ SYF_MPSAFE | AS(getaudit_addr_args), (sy_call_t *)lkmressys, AUE_NULL },	/* 451 = getaudit_addr */
 	{ SYF_MPSAFE | AS(setaudit_addr_args), (sy_call_t *)lkmressys, AUE_NULL },	/* 452 = setaudit_addr */
 	{ SYF_MPSAFE | AS(auditctl_args), (sy_call_t *)lkmressys, AUE_NULL },	/* 453 = auditctl */
 	{ SYF_MPSAFE | AS(_umtx_op_args), (sy_call_t *)_umtx_op, AUE_NULL },	/* 454 = _umtx_op */
 	{ SYF_MPSAFE | AS(thr_new_args), (sy_call_t *)thr_new, AUE_NULL },	/* 455 = thr_new */
+	{ AS(dump_vmspace_args), (sy_call_t *)dump_vmspace, AUE_NULL },	/* 456 = dump_vmspace */
 };
Index: sys/kern/kern_exec.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.273
diff -U5 -r1.273 kern_exec.c
--- sys/kern/kern_exec.c	9 Jun 2005 19:45:08 -0000	1.273
+++ sys/kern/kern_exec.c	15 Jun 2005 10:43:27 -0000
@@ -908,14 +908,17 @@
 	 * not disrupted
 	 */
 	map = &vmspace->vm_map;
 	if (vmspace->vm_refcnt == 1 && vm_map_min(map) == sv->sv_minuser &&
 	    vm_map_max(map) == sv->sv_maxuser) {
+/*  		swap_dump_vmspace("exec", vmspace); */ /* XXXOVERCOMMIT */
 		shmexit(vmspace);
 		pmap_remove_pages(vmspace_pmap(vmspace), vm_map_min(map),
 		    vm_map_max(map));
+/* 		swap_show_reserved("before exec vmexit"); */ /* XXXOVERCOMMIT */
 		vm_map_remove(map, vm_map_min(map), vm_map_max(map));
+/* 		swap_show_reserved("after exec vmexit"); */ /* XXXOVERCOMMIT */
 	} else {
 		vmspace_exec(p, sv->sv_minuser, sv->sv_maxuser);
 		vmspace = p->p_vmspace;
 		map = &vmspace->vm_map;
 	}
@@ -968,12 +971,11 @@
 	 *	environment strings:
 	 *
 	 * o ARG_MAX for argument and environment;
 	 * o MAXSHELLCMDLEN for the name of interpreters.
 	 */
-	args->buf = (char *) kmem_alloc_wait(exec_map,
-	    PATH_MAX + ARG_MAX + MAXSHELLCMDLEN);
+	args->buf = (char *) kmem_alloc_wait(exec_map, PATH_MAX + ARG_MAX + MAXSHELLCMDLEN);
 	if (args->buf == NULL)
 		return (ENOMEM);
 	args->begin_argv = args->buf;
 	args->endp = args->begin_argv;
 	args->stringspace = ARG_MAX;
Index: sys/kern/kern_exit.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/kern_exit.c,v
retrieving revision 1.263
diff -U5 -r1.263 kern_exit.c
--- sys/kern/kern_exit.c	23 May 2005 23:01:52 -0000	1.263
+++ sys/kern/kern_exit.c	15 Jun 2005 10:43:27 -0000
@@ -277,15 +277,18 @@
 	atomic_add_int(&vm->vm_exitingcnt, 1);
 	do
 		refcnt = vm->vm_refcnt;
 	while (!atomic_cmpset_int(&vm->vm_refcnt, refcnt, refcnt - 1));
 	if (refcnt == 1) {
+/*  		swap_dump_vmspace("exit1", vm); */ /* XXXOVERCOMMIT */
 		shmexit(vm);
 		pmap_remove_pages(vmspace_pmap(vm), vm_map_min(&vm->vm_map),
 		    vm_map_max(&vm->vm_map));
+/* 		swap_show_reserved("before exit"); */ /* XXXOVERCOMMIT */
 		(void) vm_map_remove(&vm->vm_map, vm_map_min(&vm->vm_map),
 		    vm_map_max(&vm->vm_map));
+/* 		swap_show_reserved("after exit"); */ /* XXXOVERCOMMIT */
 	}
 
 	mtx_lock(&Giant);	
 	sx_xlock(&proctree_lock);
 	if (SESS_LEADER(p)) {
Index: sys/kern/kern_fork.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/kern_fork.c,v
retrieving revision 1.251
diff -U5 -r1.251 kern_fork.c
--- sys/kern/kern_fork.c	20 Apr 2005 13:14:52 -0000	1.251
+++ sys/kern/kern_fork.c	15 Jun 2005 10:43:27 -0000
@@ -202,10 +202,12 @@
 	struct filedesc *fd;
 	struct filedesc_to_leader *fdtol;
 	struct thread *td2;
 	struct ksegrp *kg2;
 	struct sigacts *newsigacts;
+	int mem_charged_ok = 0;
+	vm_pindex_t mem_charged;
 	int error;
 
 	/* Can't copy and clear. */
 	if ((flags & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))
 		return (EINVAL);
@@ -215,10 +217,25 @@
 	/*
 	 * Here we don't create a new process, but we divorce
 	 * certain parts of a process from itself.
 	 */
 	if ((flags & RFPROC) == 0) {
+		/*
+		 * Divorce the memory, if it is shared, essentially
+		 * this changes shared memory amongst threads, into
+		 * COW locally.
+		 */
+		if ((flags & RFMEM) == 0) {
+			if (p1->p_vmspace->vm_refcnt > 1) {
+				vm_map_lock(&p1->p_vmspace->vm_map);
+				if (!swap_charge_fork(p1->p_vmspace, NULL)) {
+					vm_map_unlock(&p1->p_vmspace->vm_map);
+					return (ENOMEM);
+				}
+				vmspace_unshare(p1);
+			}
+		}
 		vm_forkproc(td, NULL, NULL, flags);
 
 		/*
 		 * Close all file descriptors.
 		 */
@@ -303,10 +320,21 @@
 	if (!ok) {
 		error = EAGAIN;
 		goto fail;
 	}
 
+	if ((flags & RFMEM) == 0) {
+		vm_map_lock(&p1->p_vmspace->vm_map);
+		mem_charged_ok = swap_charge_fork(p1->p_vmspace, &mem_charged);
+		if (mem_charged_ok == 0) {
+			error = ENOMEM;
+			vm_map_unlock(&p1->p_vmspace->vm_map);
+			goto fail;
+		}
+		p1->p_vmspace->vm_fork_charge = mem_charged;
+	}
+
 	/*
 	 * Increment the nprocs resource before blocking can occur.  There
 	 * are hard-limits as to the number of processes that can run.
 	 */
 	nprocs++;
@@ -720,14 +748,19 @@
 	 * Return child proc pointer to parent.
 	 */
 	*procp = p2;
 	return (0);
 fail:
+	if (mem_charged_ok)
+		swap_release("fork1", mem_charged);
 	sx_sunlock(&proctree_lock);
-	if (ppsratecheck(&lastfail, &curfail, 1))
-		printf("maxproc limit exceeded by uid %i, please see tuning(7) and login.conf(5).\n",
-			uid);
+	if (ppsratecheck(&lastfail, &curfail, 1)) {
+		if (mem_charged_ok) {
+			printf("maxproc limit exceeded by uid %i, please see tuning(7) and login.conf(5).\n",
+			       uid);
+		}
+	}
 	sx_xunlock(&allproc_lock);
 #ifdef MAC
 	mac_destroy_proc(newproc);
 #endif
 	uma_zfree(proc_zone, newproc);
Index: sys/kern/kern_proc.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/kern_proc.c,v
retrieving revision 1.230
diff -U5 -r1.230 kern_proc.c
--- sys/kern/kern_proc.c	18 Apr 2005 02:10:36 -0000	1.230
+++ sys/kern/kern_proc.c	15 Jun 2005 10:43:27 -0000
@@ -98,10 +98,12 @@
 int kstack_pages = KSTACK_PAGES;
 SYSCTL_INT(_kern, OID_AUTO, kstack_pages, CTLFLAG_RD, &kstack_pages, 0, "");
 
 CTASSERT(sizeof(struct kinfo_proc) == KINFO_PROC_SIZE);
 
+/* XXXOVERCOMMIT */
+extern int allow_swap_reserve_check;
 /*
  * Initialize global process hashing structures.
  */
 void
 procinit()
@@ -117,10 +119,11 @@
 	pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
 	proc_zone = uma_zcreate("PROC", sched_sizeof_proc(),
 	    proc_ctor, proc_dtor, proc_init, proc_fini,
 	    UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
 	uihashinit();
+	allow_swap_reserve_check = 1;
 }
 
 /*
  * Prepare a proc for use.
  */
Index: sys/kern/kern_resource.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/kern_resource.c,v
retrieving revision 1.148
diff -U5 -r1.148 kern_resource.c
--- sys/kern/kern_resource.c	1 Jun 2005 17:52:51 -0000	1.148
+++ sys/kern/kern_resource.c	15 Jun 2005 10:43:27 -0000
@@ -1115,10 +1115,13 @@
 			printf("freeing uidinfo: uid = %d, sbsize = %jd\n",
 			    uip->ui_uid, (intmax_t)uip->ui_sbsize);
 		if (uip->ui_proccnt != 0)
 			printf("freeing uidinfo: uid = %d, proccnt = %ld\n",
 			    uip->ui_uid, uip->ui_proccnt);
+		if (uip->ui_vmsize != 0)
+			printf("freeing uidinfo: uid = %d, swapuse = %lld\n",
+			    uip->ui_uid, (unsigned long long)uip->ui_vmsize);
 		UIDINFO_UNLOCK(uip);
 		FREE(uip, M_UIDINFO);
 		return;
 	}
 
@@ -1174,5 +1177,28 @@
 	*hiwat = to;
 	if (new < 0)
 		printf("negative sbsize for uid = %d\n", uip->ui_uid);
 	return (1);
 }
+
+/*
+ * Change the total swap size a user has used.
+ */
+int
+chgswap(uip, charge, fail, max)
+	struct uidinfo	*uip;
+	vm_pindex_t	charge;
+	int		fail;
+	vm_pindex_t	max;
+{
+	UIDINFO_LOCK(uip);
+	/* Don't allow them to exceed max, but allow subtraction. */
+	if ((charge > 0) && (uip->ui_vmsize + charge > max) && (max != 0) && fail) {
+		UIDINFO_UNLOCK(uip);
+		return (0);
+	}
+	uip->ui_vmsize += charge;
+	if (uip->ui_vmsize < 0)
+		printf("negative vmsize for uid = %d\n", uip->ui_uid);
+	UIDINFO_UNLOCK(uip);
+	return (1);
+}
Index: sys/kern/syscalls.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/syscalls.c,v
retrieving revision 1.179
diff -U5 -r1.179 syscalls.c
--- sys/kern/syscalls.c	30 May 2005 15:20:20 -0000	1.179
+++ sys/kern/syscalls.c	15 Jun 2005 10:43:27 -0000
@@ -1,10 +1,10 @@
 /*
  * System call names.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/kern/syscalls.c,v 1.179 2005/05/30 15:20:20 rwatson Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/kern/syscalls.master,v 1.196 2005/05/30 15:09:18 rwatson Exp 
  */
 
 const char *syscallnames[] = {
 	"syscall",			/* 0 = syscall */
@@ -461,6 +461,7 @@
 	"getaudit_addr",			/* 451 = getaudit_addr */
 	"setaudit_addr",			/* 452 = setaudit_addr */
 	"auditctl",			/* 453 = auditctl */
 	"_umtx_op",			/* 454 = _umtx_op */
 	"thr_new",			/* 455 = thr_new */
+	"dump_vmspace",			/* 456 = dump_vmspace */
 };
Index: sys/kern/syscalls.master
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/syscalls.master,v
retrieving revision 1.196
diff -U5 -r1.196 syscalls.master
--- sys/kern/syscalls.master	30 May 2005 15:09:18 -0000	1.196
+++ sys/kern/syscalls.master	15 Jun 2005 10:43:27 -0000
@@ -788,8 +788,10 @@
 453	AUE_NULL	MNOSTD	{ int auditctl(int cmd, char *path); }
 454	AUE_NULL	MSTD	{ int _umtx_op(struct umtx *umtx, int op, \
 				    long id, void *uaddr, void *uaddr2); }
 455	AUE_NULL	MSTD	{ int thr_new(struct thr_param *param, \
 				    int param_size); }
+; XXXOVERCOMMIT
+456	AUE_NULL	STD	{ int dump_vmspace(int pid, char *caller); }
 
 ; Please copy any additions and changes to the following compatability tables:
 ; sys/compat/freebsd32/syscalls.master
Index: sys/kern/sysv_shm.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/sysv_shm.c,v
retrieving revision 1.102
diff -U5 -r1.102 sysv_shm.c
--- sys/kern/sysv_shm.c	12 May 2005 20:04:48 -0000	1.102
+++ sys/kern/sysv_shm.c	15 Jun 2005 10:43:27 -0000
@@ -245,16 +245,25 @@
 static void
 shm_deallocate_segment(shmseg)
 	struct shmid_kernel *shmseg;
 {
 	size_t size;
+	vm_object_t shm_object;
 
 	GIANT_REQUIRED;
 
 	vm_object_deallocate(shmseg->u.shm_internal);
 	shmseg->u.shm_internal = NULL;
 	size = round_page(shmseg->u.shm_segsz);
+	shm_object = shmseg->u.shm_internal;
+	
+	if (shm_object->type == OBJT_SWAP)
+	{
+		swap_release_by_uid("sysvshm", size, shmseg->uip);
+		uifree(shmseg->uip);
+	}
+
 	shm_committed -= btoc(size);
 	shm_nused--;
 	shmseg->u.shm_perm.mode = SHMSEG_FREE;
 #ifdef MAC
 	mac_cleanup_sysv_shm(shmseg);
@@ -771,10 +780,22 @@
 	} else  {
 		segnum = shm_last_free;
 		shm_last_free = -1;
 	}
 	shmseg = &shmsegs[segnum];
+	if (!shm_use_phys) {
+		struct uidinfo *uip;
+
+		if (!swap_reserve("sysvshm", uap->size)) {
+			return (ENOMEM);
+		}
+		uip = cred->cr_ruidinfo;
+		uihold(uip);
+		shmseg->uip = uip;
+	} else {
+		shmseg->uip = NULL;
+	}
 	/*
 	 * In case we sleep in malloc(), mark the segment present but deleted
 	 * so that noone else tries to create the same key.
 	 */
 	shmseg->u.shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
Index: sys/kern/vfs_bio.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/kern/vfs_bio.c,v
retrieving revision 1.490
diff -U5 -r1.490 vfs_bio.c
--- sys/kern/vfs_bio.c	13 Jun 2005 00:45:05 -0000	1.490
+++ sys/kern/vfs_bio.c	15 Jun 2005 10:43:27 -0000
@@ -1918,11 +1918,11 @@
 				goto restart;
 			}
 			if (addr) {
 				vm_map_insert(buffer_map, NULL, 0,
 					addr, addr + maxsize,
-					VM_PROT_ALL, VM_PROT_ALL, MAP_NOFAULT);
+					VM_PROT_ALL, VM_PROT_ALL, MAP_NOFAULT | MAP_ACC_NO_CHARGE);
 
 				bp->b_kvabase = (caddr_t) addr;
 				bp->b_kvasize = maxsize;
 				atomic_add_int(&bufspace, bp->b_kvasize);
 				atomic_add_int(&bufreusecnt, 1);
Index: sys/sys/resource.h
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/sys/resource.h,v
retrieving revision 1.29
diff -U5 -r1.29 resource.h
--- sys/sys/resource.h	7 Jan 2005 02:29:23 -0000	1.29
+++ sys/sys/resource.h	15 Jun 2005 10:43:31 -0000
@@ -93,12 +93,13 @@
 #define	RLIMIT_NPROC	7		/* number of processes */
 #define	RLIMIT_NOFILE	8		/* number of open files */
 #define	RLIMIT_SBSIZE	9		/* maximum size of all socket buffers */
 #define RLIMIT_VMEM	10		/* virtual process size (inclusive of mmap) */
 #define	RLIMIT_AS	RLIMIT_VMEM	/* standard name for RLIMIT_VMEM */
+#define RLIMIT_SWAP	 11
 
-#define	RLIM_NLIMITS	11		/* number of resource limits */
+#define	RLIM_NLIMITS	12		/* number of resource limits */
 
 #define	RLIM_INFINITY	((rlim_t)(((uint64_t)1 << 63) - 1))
 /* XXX Missing: RLIM_SAVED_MAX, RLIM_SAVED_CUR */
 
 
@@ -117,10 +118,11 @@
 	"memlock",
 	"nproc",
 	"nofile",
 	"sbsize",
 	"vmem",
+	"swap",
 };
 #endif
 
 #ifndef _RLIM_T_DECLARED
 typedef	__rlim_t	rlim_t;
Index: sys/sys/resourcevar.h
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/sys/resourcevar.h,v
retrieving revision 1.47
diff -U5 -r1.47 resourcevar.h
--- sys/sys/resourcevar.h	7 Jan 2005 02:29:23 -0000	1.47
+++ sys/sys/resourcevar.h	15 Jun 2005 10:43:31 -0000
@@ -93,10 +93,11 @@
  * (b) Locked by ui_mtxp
  * (c) Locked by global uihashtbl_mtx
  */
 struct uidinfo {
 	LIST_ENTRY(uidinfo) ui_hash;	/* (c) hash chain of uidinfos */
+	vm_pindex_t ui_vmsize;		/* (b) (potential) swap allocation by uid */
 	rlim_t	ui_sbsize;		/* (b) socket buffer space consumed */
 	long	ui_proccnt;		/* (b) number of processes */
 	uid_t	ui_uid;			/* (a) uid */
 	u_int	ui_ref;			/* (b) reference count */
 	struct mtx *ui_mtxp;		/* protect all counts/limits */
@@ -114,10 +115,11 @@
 void	 calccru(struct proc *p, struct timeval *up, struct timeval *sp);
 void	 calcru(struct proc *p, struct timeval *up, struct timeval *sp);
 int	 chgproccnt(struct uidinfo *uip, int diff, int maxval);
 int	 chgsbsize(struct uidinfo *uip, u_int *hiwat, u_int to,
 	    rlim_t maxval);
+int	 chgswap(struct uidinfo *uip, vm_pindex_t charge, int fail, vm_pindex_t max);
 int	 fuswintr(void *base);
 struct plimit
 	*lim_alloc(void);
 void	 lim_copy(struct plimit *dst, struct plimit *src);
 rlim_t	 lim_cur(struct proc *p, int which);
Index: sys/sys/shm.h
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/sys/shm.h,v
retrieving revision 1.23
diff -U5 -r1.23 shm.h
--- sys/sys/shm.h	2 Apr 2005 12:33:36 -0000	1.23
+++ sys/sys/shm.h	15 Jun 2005 10:43:31 -0000
@@ -106,10 +106,11 @@
  * MAC label) can be added to it, without changing the user interface.
  */
 struct shmid_kernel {
 	struct shmid_ds u;
 	struct label *label;	/* MAC label */
+	struct uidinfo *uip;
 };
 
 extern struct shminfo	shminfo;
 
 struct shm_info {
Index: sys/sys/syscall.h
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/sys/syscall.h,v
retrieving revision 1.176
diff -U5 -r1.176 syscall.h
--- sys/sys/syscall.h	30 May 2005 15:20:21 -0000	1.176
+++ sys/sys/syscall.h	15 Jun 2005 10:43:31 -0000
@@ -1,10 +1,10 @@
 /*
  * System call numbers.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/sys/syscall.h,v 1.176 2005/05/30 15:20:21 rwatson Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/kern/syscalls.master,v 1.196 2005/05/30 15:09:18 rwatson Exp 
  */
 
 #define	SYS_syscall	0
 #define	SYS_exit	1
@@ -367,6 +367,7 @@
 #define	SYS_getaudit_addr	451
 #define	SYS_setaudit_addr	452
 #define	SYS_auditctl	453
 #define	SYS__umtx_op	454
 #define	SYS_thr_new	455
-#define	SYS_MAXSYSCALL	456
+#define	SYS_dump_vmspace	456
+#define	SYS_MAXSYSCALL	457
Index: sys/sys/syscall.mk
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/sys/syscall.mk,v
retrieving revision 1.131
diff -U5 -r1.131 syscall.mk
--- sys/sys/syscall.mk	30 May 2005 15:20:21 -0000	1.131
+++ sys/sys/syscall.mk	15 Jun 2005 10:43:31 -0000
@@ -1,8 +1,8 @@
 # FreeBSD system call names.
 # DO NOT EDIT-- this file is automatically generated.
-# $FreeBSD: src/sys/sys/syscall.mk,v 1.131 2005/05/30 15:20:21 rwatson Exp $
+# $FreeBSD$
 # created from FreeBSD: src/sys/kern/syscalls.master,v 1.196 2005/05/30 15:09:18 rwatson Exp 
 MIASM =  \
 	syscall.o \
 	exit.o \
 	fork.o \
@@ -308,6 +308,7 @@
 	setaudit.o \
 	getaudit_addr.o \
 	setaudit_addr.o \
 	auditctl.o \
 	_umtx_op.o \
-	thr_new.o
+	thr_new.o \
+	dump_vmspace.o
Index: sys/sys/sysproto.h
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/sys/sysproto.h,v
retrieving revision 1.175
diff -U5 -r1.175 sysproto.h
--- sys/sys/sysproto.h	30 May 2005 15:20:21 -0000	1.175
+++ sys/sys/sysproto.h	15 Jun 2005 10:43:31 -0000
@@ -1,10 +1,10 @@
 /*
  * System call prototypes.
  *
  * DO NOT EDIT-- this file is automatically generated.
- * $FreeBSD: src/sys/sys/sysproto.h,v 1.175 2005/05/30 15:20:21 rwatson Exp $
+ * $FreeBSD$
  * created from FreeBSD: src/sys/kern/syscalls.master,v 1.196 2005/05/30 15:09:18 rwatson Exp 
  */
 
 #ifndef _SYS_SYSPROTO_H_
 #define	_SYS_SYSPROTO_H_
@@ -1351,10 +1351,14 @@
 };
 struct thr_new_args {
 	char param_l_[PADL_(struct thr_param *)]; struct thr_param * param; char param_r_[PADR_(struct thr_param *)];
 	char param_size_l_[PADL_(int)]; int param_size; char param_size_r_[PADR_(int)];
 };
+struct dump_vmspace_args {
+	char pid_l_[PADL_(int)]; int pid; char pid_r_[PADR_(int)];
+	char caller_l_[PADL_(char *)]; char * caller; char caller_r_[PADR_(char *)];
+};
 int	nosys(struct thread *, struct nosys_args *);
 void	sys_exit(struct thread *, struct sys_exit_args *);
 int	fork(struct thread *, struct fork_args *);
 int	read(struct thread *, struct read_args *);
 int	write(struct thread *, struct write_args *);
@@ -1658,10 +1662,11 @@
 int	getaudit_addr(struct thread *, struct getaudit_addr_args *);
 int	setaudit_addr(struct thread *, struct setaudit_addr_args *);
 int	auditctl(struct thread *, struct auditctl_args *);
 int	_umtx_op(struct thread *, struct _umtx_op_args *);
 int	thr_new(struct thread *, struct thr_new_args *);
+int	dump_vmspace(struct thread *, struct dump_vmspace_args *);
 
 #ifdef COMPAT_43
 
 struct ocreat_args {
 	char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)];
Index: sys/vm/swap_pager.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/vm/swap_pager.c,v
retrieving revision 1.273
diff -U5 -r1.273 swap_pager.c
--- sys/vm/swap_pager.c	20 May 2005 21:26:05 -0000	1.273
+++ sys/vm/swap_pager.c	15 Jun 2005 10:43:31 -0000
@@ -91,10 +91,12 @@
 #include <sys/sysproto.h>
 #include <sys/blist.h>
 #include <sys/lock.h>
 #include <sys/sx.h>
 #include <sys/vmmeter.h>
+#include <sys/resource.h>
+#include <sys/resourcevar.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
 #include <vm/vm_map.h>
 #include <vm/vm_kern.h>
@@ -180,10 +182,178 @@
 static struct swdevt *swdevhd;	/* Allocate from here next */
 static int nswapdev;		/* Number of swap devices */
 int swap_pager_avail;
 static int swdev_syscall_active = 0; /* serialize swap(on|off) */
 
+static vm_pindex_t sw_total;
+SYSCTL_INT(_vm, OID_AUTO, sw_total, CTLFLAG_RD, &sw_total, 0, ""); /* XXXOVERCOMMIT */
+static vm_pindex_t swap_reserved;
+SYSCTL_INT(_vm, OID_AUTO, swap_reserved, CTLFLAG_RD, &swap_reserved, 0, ""); /* XXXOVERCOMMIT */
+static int overcommit = 0;
+SYSCTL_INT(_vm, OID_AUTO, overcommit, CTLFLAG_RW, &overcommit, 0, ""); /* XXXOVERCOMMIT custom handler instead of int */
+/* XXXOVERCOMMIT */
+int overcommit_trace = 0;
+SYSCTL_INT(_vm, OID_AUTO, overcommit_trace, CTLFLAG_RW, &overcommit_trace, 0, "");
+
+int
+swap_reserve(const char *who, vm_pindex_t incr)
+{
+	return swap_reserve_by_uid(who, incr, curthread->td_ucred->cr_ruidinfo);
+}
+
+int
+swap_reserve_by_uid(const char *who, vm_pindex_t incr, struct uidinfo *uip)
+{
+	vm_pindex_t r;
+	int res = 0;
+	int ok;
+
+	if (incr & PAGE_MASK)
+		panic("swap_reserve: & PAGE_MASK");
+
+	mtx_lock(&sw_dev_mtx);
+	r = swap_reserved + incr;
+	if (!(overcommit & 1) || (r <= sw_total)) {
+		swap_reserved = r;
+		res = 1;
+	}
+	mtx_unlock(&sw_dev_mtx);
+
+	if (res == 1) {
+		PROC_LOCK(curproc);
+		ok = chgswap(uip, incr, overcommit & 2,
+			     (uip->ui_uid != 0) ? lim_cur(curproc, RLIMIT_SWAP) : 0); /* XXXOVERCOMMIT */
+		PROC_UNLOCK(curproc);
+		if (!ok && (overcommit & 2)) {
+			mtx_lock(&sw_dev_mtx);
+			swap_reserved -= incr;
+			mtx_unlock(&sw_dev_mtx);
+			res = 0;
+		}
+	}
+
+	if (overcommit_trace)
+		printf("%d(%s) swap_reserve %s: %llx %llx %d\n",
+		       curproc -> p_pid, curproc -> p_comm, who, swap_reserved, incr, res);
+	return res;
+}
+
+void
+swap_reserve_force(vm_pindex_t incr)
+{
+	mtx_lock(&sw_dev_mtx);
+	swap_reserved += incr;
+	mtx_unlock(&sw_dev_mtx);
+
+	PROC_LOCK(curproc);
+	chgswap(curthread->td_ucred->cr_ruidinfo, incr, 0, 0);
+	PROC_UNLOCK(curproc);
+
+	if (overcommit_trace)
+		printf("%d(%s) swap_reserve_force: %llx %llx\n",
+		       curproc -> p_pid, curproc -> p_comm, swap_reserved, incr);
+}
+
+void
+swap_release(const char *who, vm_pindex_t decr)
+{
+	struct uidinfo *uip;
+
+	PROC_LOCK(curproc);
+	uip = curthread->td_ucred->cr_ruidinfo;
+	swap_release_by_uid(who, decr, uip);
+	PROC_UNLOCK(curproc);
+}
+
+void
+swap_release_by_uid(const char *who, vm_pindex_t decr, struct uidinfo *uip)
+{
+	if (overcommit_trace)
+		printf("%d(%s) swap_release %s: %llx %llx\n",
+		       curproc -> p_pid, curproc -> p_comm, who, swap_reserved, decr);
+
+	if (decr & PAGE_MASK)
+		panic("swap_release: & PAGE_MASK");
+
+	mtx_lock(&sw_dev_mtx);
+	if (swap_reserved < decr)
+		panic("swap_reserved < decr");
+	swap_reserved -= decr;
+	mtx_unlock(&sw_dev_mtx);
+
+	UIDINFO_LOCK(uip);
+	if (uip->ui_vmsize < decr)
+		printf("negative vmsize for uid = %d\n", uip->ui_uid);
+	uip->ui_vmsize -= decr;
+	UIDINFO_UNLOCK(uip);
+}
+
+void
+swap_show_reserved(const char *banner)
+{
+	printf("%d(%s) %s: %llx\n",
+	       curproc->p_pid, curproc->p_comm,
+	       banner, swap_reserved);
+}
+
+void
+swap_dump_proc_vmspace(const char *caller, struct proc *p)
+{
+	printf("%d(%s) map at %s:\n",
+	       p->p_pid, p->p_comm, caller);
+	swap_dump_vmspace(p->p_vmspace);
+}
+
+void
+swap_dump_vmspace(struct vmspace *vm)
+{
+	vm_map_entry_t e;
+	int i;
+
+	for (e = vm->vm_map.header.next, i = 0; e != &vm->vm_map.header; e = e->next, i++) {
+		printf("  entry %d: ", i);
+		dump_vm_map_entry(e);
+	}
+}
+
+int allow_swap_reserve_check = 0;
+
+void
+swap_check_reserve(void)
+{
+	struct proc *p;
+	struct vm_object *obj;
+	vm_map_entry_t e;
+	vm_pindex_t e_allocated = 0;
+	vm_pindex_t obj_allocated = 0;
+
+	if (1 || !allow_swap_reserve_check)
+		return;
+
+	sx_slock(&allproc_lock);
+	FOREACH_PROC_IN_SYSTEM(p) {
+		struct vm_map *m = &p->p_vmspace->vm_map;
+		if (m) {
+			for (e = m->header.next; e != &m->header; e = e->next) {
+				if (e->uip)
+					e_allocated += e->end - e->start;
+			}
+		}
+	}
+	sx_sunlock(&allproc_lock);
+
+	mtx_lock(&vm_object_list_mtx);
+	TAILQ_FOREACH(obj, &vm_object_list, object_list) {
+		if (obj->uip)
+			obj_allocated += ptoa(obj->size);
+	}
+	mtx_unlock(&vm_object_list_mtx);
+
+	KASSERT(obj_allocated + e_allocated == swap_reserved,
+		("swap_check_reserve %llx %llx %llx", swap_reserved, obj_allocated, e_allocated));
+}
+
 static void swapdev_strategy(struct buf *, struct swdevt *sw);
 
 #define SWM_FREE	0x02	/* free, period			*/
 #define SWM_POP		0x04	/* pop out			*/
 
@@ -2071,10 +2241,11 @@
 	sp->sw_first = dvbase;
 	sp->sw_end = dvbase + nblks;
 	TAILQ_INSERT_TAIL(&swtailq, sp, sw_list);
 	nswapdev++;
 	swap_pager_avail += nblks;
+	sw_total += nblks * PAGE_SIZE;
 	swp_sizecheck();
 	mtx_unlock(&sw_dev_mtx);
 }
 
 /*
@@ -2161,10 +2332,11 @@
 	sp->sw_flags |= SW_CLOSING;
 	for (dvbase = 0; dvbase < sp->sw_end; dvbase += dmmax) {
 		swap_pager_avail -= blist_fill(sp->sw_blist,
 		     dvbase, dmmax);
 	}
+	sw_total -= nblks * PAGE_SIZE;
 	mtx_unlock(&sw_dev_mtx);
 
 	/*
 	 * Page in the contents of the device and close it.
 	 */
Index: sys/vm/vm.h
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/vm/vm.h,v
retrieving revision 1.26
diff -U5 -r1.26 vm.h
--- sys/vm/vm.h	1 Apr 2005 20:00:11 -0000	1.26
+++ sys/vm/vm.h	15 Jun 2005 10:43:31 -0000
@@ -94,10 +94,12 @@
 typedef struct vm_map *vm_map_t;
 
 struct vm_object;
 typedef struct vm_object *vm_object_t;
 
+struct vmspace;
+
 #ifndef _KERNEL
 /*
  * This is defined in <sys/types.h> for the kernel so that non-vm kernel
  * sources (mainly Mach-derived ones such as ddb) don't have to include
  * vm stuff.  Defining it there for applications might break things.
@@ -141,7 +143,24 @@
 };
 
 extern struct kva_md_info	kmi;
 extern void vm_ksubmap_init(struct kva_md_info *);
 
+struct uidinfo;
+int swap_reserve(const char *who, vm_pindex_t incr);
+int swap_reserve_by_uid(const char *who, vm_pindex_t incr, struct uidinfo *uip);
+void swap_reserve_force(vm_pindex_t incr);
+void swap_release(const char *who, vm_pindex_t decr);
+void swap_release_by_uid(const char *who, vm_pindex_t decr, struct uidinfo *uip);
+vm_pindex_t swap_vmspace_charge(struct vmspace *vm);
+int swap_charge_fork(struct vmspace *vm, vm_pindex_t *charge);
+/* XXXOVERCOMMIT */
+struct proc;
+extern int overcommit_trace;
+void dump_vm_map_entry(vm_map_entry_t e);
+void swap_dump_proc_vmspace(const char *caller, struct proc *p);
+void swap_dump_vmspace(struct vmspace *vm);
+void swap_show_reserved(const char *banner);
+void swap_check_reserve(void);
+
 #endif				/* VM_H */
 
Index: sys/vm/vm_contig.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/vm/vm_contig.c,v
retrieving revision 1.43
diff -U5 -r1.43 vm_contig.c
--- sys/vm/vm_contig.c	11 Jun 2005 00:05:16 -0000	1.43
+++ sys/vm/vm_contig.c	15 Jun 2005 10:43:31 -0000
@@ -308,11 +308,11 @@
 			vm_map_unlock(map);
 			return (NULL);
 		}
 		vm_object_reference(kernel_object);
 		vm_map_insert(map, kernel_object, addr - VM_MIN_KERNEL_ADDRESS,
-		    addr, addr + size, VM_PROT_ALL, VM_PROT_ALL, 0);
+		    addr, addr + size, VM_PROT_ALL, VM_PROT_ALL, MAP_ACC_NO_CHARGE);
 		vm_map_unlock(map);
 
 		tmp_addr = addr;
 		VM_OBJECT_LOCK(kernel_object);
 		for (i = start; i < (start + size / PAGE_SIZE); i++) {
@@ -520,11 +520,11 @@
 		vm_map_unlock(map);
 		return (NULL);
 	}
 	vm_object_reference(object);
 	vm_map_insert(map, object, addr - VM_MIN_KERNEL_ADDRESS,
-	    addr, addr + (npages << PAGE_SHIFT), VM_PROT_ALL, VM_PROT_ALL, 0);
+	    addr, addr + (npages << PAGE_SHIFT), VM_PROT_ALL, VM_PROT_ALL, MAP_ACC_NO_CHARGE);
 	vm_map_unlock(map);
 	tmp_addr = addr;
 	VM_OBJECT_LOCK(object);
 	for (i = 0; i < npages; i++) {
 		vm_page_insert(&m[i], object,
Index: sys/vm/vm_fault.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/vm/vm_fault.c,v
retrieving revision 1.205
diff -U5 -r1.205 vm_fault.c
--- sys/vm/vm_fault.c	12 May 2005 04:09:41 -0000	1.205
+++ sys/vm/vm_fault.c	15 Jun 2005 10:43:31 -0000
@@ -1137,10 +1137,12 @@
 	    (vm_size_t) OFF_TO_IDX(dst_entry->end - dst_entry->start));
 
 	VM_OBJECT_LOCK(dst_object);
 	dst_entry->object.vm_object = dst_object;
 	dst_entry->offset = 0;
+	dst_object->uip = dst_entry->uip;
+	dst_entry->uip = NULL;
 
 	prot = dst_entry->max_protection;
 
 	/*
 	 * Loop through all of the pages in the entry's range, copying each
Index: sys/vm/vm_glue.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/vm/vm_glue.c,v
retrieving revision 1.213
diff -U5 -r1.213 vm_glue.c
--- sys/vm/vm_glue.c	23 May 2005 23:01:53 -0000	1.213
+++ sys/vm/vm_glue.c	15 Jun 2005 10:43:31 -0000
@@ -439,22 +439,11 @@
 	int flags;
 {
 	struct proc *p1 = td->td_proc;
 
 	if ((flags & RFPROC) == 0) {
-		/*
-		 * Divorce the memory, if it is shared, essentially
-		 * this changes shared memory amongst threads, into
-		 * COW locally.
-		 */
-		if ((flags & RFMEM) == 0) {
-			if (p1->p_vmspace->vm_refcnt > 1) {
-				vmspace_unshare(p1);
-			}
-		}
 		cpu_fork(td, p2, td2, flags);
-		return;
 	}
 
 	if (flags & RFMEM) {
 		p2->p_vmspace = p1->p_vmspace;
 		atomic_add_int(&p1->p_vmspace->vm_refcnt, 1);
@@ -464,10 +453,11 @@
 		VM_WAIT;
 	}
 
 	if ((flags & RFMEM) == 0) {
 		p2->p_vmspace = vmspace_fork(p1->p_vmspace);
+		vm_map_unlock(&p1->p_vmspace->vm_map);
 		if (p1->p_vmspace->vm_shm)
 			shmfork(p1, p2);
 	}
 
 	/*
Index: sys/vm/vm_kern.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/vm/vm_kern.c,v
retrieving revision 1.122
diff -U5 -r1.122 vm_kern.c
--- sys/vm/vm_kern.c	7 Jan 2005 02:29:27 -0000	1.122
+++ sys/vm/vm_kern.c	15 Jun 2005 10:43:31 -0000
@@ -106,11 +106,11 @@
 	int result;
 
 	size = round_page(size);
 	addr = vm_map_min(map);
 	result = vm_map_find(map, NULL, 0,
-	    &addr, size, TRUE, VM_PROT_ALL, VM_PROT_ALL, MAP_NOFAULT);
+	    &addr, size, TRUE, VM_PROT_ALL, VM_PROT_ALL, MAP_NOFAULT | MAP_ACC_NO_CHARGE);
 	if (result != KERN_SUCCESS) {
 		return (0);
 	}
 	return (addr);
 }
@@ -232,11 +232,11 @@
 
 	size = round_page(size);
 
 	*min = (vm_offset_t) vm_map_min(parent);
 	ret = vm_map_find(parent, NULL, (vm_offset_t) 0,
-	    min, size, TRUE, VM_PROT_ALL, VM_PROT_ALL, 0);
+	    min, size, TRUE, VM_PROT_ALL, VM_PROT_ALL, MAP_ACC_NO_CHARGE);
 	if (ret != KERN_SUCCESS) {
 		printf("kmem_suballoc: bad status return of %d.\n", ret);
 		panic("kmem_suballoc");
 	}
 	*max = *min + size;
@@ -433,21 +433,24 @@
 		/*
 		 * To make this work for more than one map, use the map's lock
 		 * to lock out sleepers/wakers.
 		 */
 		vm_map_lock(map);
-		if (vm_map_findspace(map, vm_map_min(map), size, &addr) == 0)
-			break;
+		if (vm_map_findspace(map, vm_map_min(map), size, &addr) == 0) {
+/*  			printf("%d(%s) kmem_alloc_wait %x\n", curproc->p_pid, curproc->p_comm, size); */ /* XXXOVERCOMMIT */
+			if (swap_reserve("kmem_alloc_wait", size)) /* XXXOVERCOMMIT */
+				break;
+		}
 		/* no space now; see if we can ever get space */
 		if (vm_map_max(map) - vm_map_min(map) < size) {
 			vm_map_unlock(map);
 			return (0);
 		}
 		map->needs_wakeup = TRUE;
 		vm_map_unlock_and_wait(map, FALSE);
 	}
-	vm_map_insert(map, NULL, 0, addr, addr + size, VM_PROT_ALL, VM_PROT_ALL, 0);
+	vm_map_insert(map, NULL, 0, addr, addr + size, VM_PROT_ALL, VM_PROT_ALL, MAP_ACC_CHARGED);
 	vm_map_unlock(map);
 	return (addr);
 }
 
 /*
@@ -490,9 +493,9 @@
 	m->system_map = 1;
 	vm_map_lock(m);
 	/* N.B.: cannot use kgdb to debug, starting with this assignment ... */
 	kernel_map = m;
 	(void) vm_map_insert(m, NULL, (vm_ooffset_t) 0,
-	    VM_MIN_KERNEL_ADDRESS, start, VM_PROT_ALL, VM_PROT_ALL, 0);
+	    VM_MIN_KERNEL_ADDRESS, start, VM_PROT_ALL, VM_PROT_ALL, MAP_ACC_NO_CHARGE);
 	/* ... and ending with the completion of the above `insert' */
 	vm_map_unlock(m);
 }
Index: sys/vm/vm_map.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/vm/vm_map.c,v
retrieving revision 1.366
diff -U5 -r1.366 vm_map.c
--- sys/vm/vm_map.c	2 May 2005 07:05:20 -0000	1.366
+++ sys/vm/vm_map.c	15 Jun 2005 10:43:31 -0000
@@ -146,10 +146,40 @@
 #ifdef INVARIANTS
 static void vm_map_zdtor(void *mem, int size, void *arg);
 static void vmspace_zdtor(void *mem, int size, void *arg);
 #endif
 
+#define ENTRY_CHARGED(e) ((e)->uip || \
+	((e)->object.vm_object && (e)->object.vm_object->uip \
+		&& !((e)->eflags & MAP_ENTRY_NEEDS_COPY)))
+
+void
+dump_vm_map_entry(vm_map_entry_t e)
+{
+	static const char *inheritance_name[4] =
+		{"share", "copy", "none", "donate_copy"};
+
+	static const char *objt_name[] =
+		{"default", "swap", "vnode", "device", "phys", "dead"};
+
+	printf(" %x - %x sz %x p %x/%x/%s o %p %llx %llx %s",
+	       e->start, e->end, e->end - e->start, e->protection, e->max_protection,
+	       inheritance_name[(int)(unsigned char)e->inheritance], e->object.vm_object,
+	       e->offset, e->object.vm_object ? ptoa(e->object.vm_object->size) : 0,
+	       e->object.vm_object ? objt_name[(int)(unsigned char)e->object.vm_object->type] : "NULL");
+	if (e->eflags & MAP_ENTRY_COW)
+		printf(" copy (%s)",
+		       (e->eflags & MAP_ENTRY_NEEDS_COPY) ? "needed" : "done");
+	if (ENTRY_CHARGED(e))
+		printf(" CHG");
+	if (e->uip)
+		printf(" EC(%d)", e->uip->ui_uid);
+	if (e->object.vm_object && e->object.vm_object->uip)
+		printf(" OC(%d %llx)", e->object.vm_object->uip->ui_uid, e->object.vm_object->charge);
+	printf("\n");
+}
+
 void
 vm_map_startup(void)
 {
 	mtx_init(&map_sleep_mtx, "vm map sleep mutex", NULL, MTX_DEF);
 	mapzone = uma_zcreate("MAP", sizeof(struct vm_map), NULL,
@@ -844,10 +874,11 @@
 {
 	vm_map_entry_t new_entry;
 	vm_map_entry_t prev_entry;
 	vm_map_entry_t temp_entry;
 	vm_eflags_t protoeflags;
+	struct uidinfo *uip = NULL;
 
 	/*
 	 * Check that the start and end points are not bogus.
 	 */
 	if ((start < map->min_offset) || (end > map->max_offset) ||
@@ -884,10 +915,28 @@
 	if (cow & MAP_DISABLE_SYNCER)
 		protoeflags |= MAP_ENTRY_NOSYNC;
 	if (cow & MAP_DISABLE_COREDUMP)
 		protoeflags |= MAP_ENTRY_NOCOREDUMP;
 
+	if ((cow & MAP_ACC_NO_CHARGE) == 0) {
+		if ((cow & MAP_ACC_CHARGED) ||
+		    ((prot & VM_PROT_WRITE) &&
+		     ((protoeflags & MAP_ENTRY_NEEDS_COPY) || (object == NULL)))) {
+			if (((cow & MAP_ACC_CHARGED) == 0) &&
+			    !swap_reserve("vm_map_insert", end - start))
+				return KERN_RESOURCE_SHORTAGE;
+			KASSERT((object == NULL) || (cow & MAP_ENTRY_NEEDS_COPY) || (object->uip == NULL),
+				("OVERCOMMIT: vm_map_insert o %p", object));
+			uip = curthread->td_ucred->cr_ruidinfo;
+			if (uip == NULL)
+				printf("pid %d: allocates swap and cr_ruidinfo == NULL\n",
+				       curproc->p_pid);
+			else
+				uihold(uip);
+		}
+	}
+
 	if (object != NULL) {
 		/*
 		 * OBJ_ONEMAPPING must be cleared unless this mapping
 		 * is trivially proven to be the only mapping for any
 		 * of the object's pages.  (Object granularity
@@ -901,15 +950,17 @@
 	}
 	else if ((prev_entry != &map->header) &&
 		 (prev_entry->eflags == protoeflags) &&
 		 (prev_entry->end == start) &&
 		 (prev_entry->wired_count == 0) &&
-		 ((prev_entry->object.vm_object == NULL) ||
-		  vm_object_coalesce(prev_entry->object.vm_object,
-				     prev_entry->offset,
-				     (vm_size_t)(prev_entry->end - prev_entry->start),
-				     (vm_size_t)(end - prev_entry->end)))) {
+		 (prev_entry->uip == uip ||
+		  (prev_entry->object.vm_object &&
+		   (prev_entry->object.vm_object->uip == uip))) &&
+		   vm_object_coalesce(prev_entry->object.vm_object,
+				      prev_entry->offset,
+				      (vm_size_t)(prev_entry->end - prev_entry->start),
+				      (vm_size_t)(end - prev_entry->end))) {
 		/*
 		 * We were able to extend the object.  Determine if we
 		 * can extend the previous map entry to include the
 		 * new range as well.
 		 */
@@ -918,10 +969,13 @@
 		    (prev_entry->max_protection == max)) {
 			map->size += (end - prev_entry->end);
 			prev_entry->end = end;
 			vm_map_entry_resize_free(map, prev_entry);
 			vm_map_simplify_entry(map, prev_entry);
+			if (uip)
+				uifree(uip);
+			swap_check_reserve();
 			return (KERN_SUCCESS);
 		}
 
 		/*
 		 * If we can extend the object but cannot extend the
@@ -931,10 +985,15 @@
 		 */
 		object = prev_entry->object.vm_object;
 		offset = prev_entry->offset +
 			(prev_entry->end - prev_entry->start);
 		vm_object_reference(object);
+		if (uip && object && object->uip && !(prev_entry->eflags & MAP_ENTRY_NEEDS_COPY)) {
+			/* Object already accounts for this uid. */
+			uifree(uip);
+			uip = NULL;
+		}
 	}
 
 	/*
 	 * NOTE: if conditionals fail, object can be NULL here.  This occurs
 	 * in things like the buffer map where we manage kva but do not manage
@@ -945,10 +1004,11 @@
 	 * Create a new entry
 	 */
 	new_entry = vm_map_entry_create(map);
 	new_entry->start = start;
 	new_entry->end = end;
+	new_entry->uip = NULL;
 
 	new_entry->eflags = protoeflags;
 	new_entry->object.vm_object = object;
 	new_entry->offset = offset;
 	new_entry->avail_ssize = 0;
@@ -956,17 +1016,27 @@
 	new_entry->inheritance = VM_INHERIT_DEFAULT;
 	new_entry->protection = prot;
 	new_entry->max_protection = max;
 	new_entry->wired_count = 0;
 
+	KASSERT(!uip || !ENTRY_CHARGED(new_entry),
+		("OVERCOMMIT: vm_map_insert leaks vm_map %p", new_entry));
+	new_entry->uip = uip;
+	swap_check_reserve();
+
 	/*
 	 * Insert the new entry into the list
 	 */
 	vm_map_entry_link(map, prev_entry, new_entry);
 	map->size += new_entry->end - new_entry->start;
 
 #if 0
+	/* XXXOVERCOMMIT */
+	printf("%d(%s) vm_map_insert: ", curproc->p_pid, curproc->p_comm);
+	dump_vm_map_entry(new_entry);
+#endif
+#if 0
 	/*
 	 * Temporarily removed to avoid MAP_STACK panic, due to
 	 * MAP_STACK being a huge hack.  Will be added back in
 	 * when MAP_STACK (and the user stack mapping) is fixed.
 	 */
@@ -1141,18 +1211,21 @@
 			(prev->offset + prevsize == entry->offset)) &&
 		     (prev->eflags == entry->eflags) &&
 		     (prev->protection == entry->protection) &&
 		     (prev->max_protection == entry->max_protection) &&
 		     (prev->inheritance == entry->inheritance) &&
-		     (prev->wired_count == entry->wired_count)) {
+		     (prev->wired_count == entry->wired_count) &&
+		     (prev->uip == entry->uip)) {
 			vm_map_entry_unlink(map, prev);
 			entry->start = prev->start;
 			entry->offset = prev->offset;
 			if (entry->prev != &map->header)
 				vm_map_entry_resize_free(map, entry->prev);
 			if (prev->object.vm_object)
 				vm_object_deallocate(prev->object.vm_object);
+			if (prev->uip)
+				uifree(prev->uip);
 			vm_map_entry_dispose(map, prev);
 		}
 	}
 
 	next = entry->next;
@@ -1164,19 +1237,23 @@
 			(entry->offset + esize == next->offset)) &&
 		    (next->eflags == entry->eflags) &&
 		    (next->protection == entry->protection) &&
 		    (next->max_protection == entry->max_protection) &&
 		    (next->inheritance == entry->inheritance) &&
-		    (next->wired_count == entry->wired_count)) {
+		    (next->wired_count == entry->wired_count) &&
+		    (next->uip == entry->uip)) {
 			vm_map_entry_unlink(map, next);
 			entry->end = next->end;
 			vm_map_entry_resize_free(map, entry);
 			if (next->object.vm_object)
 				vm_object_deallocate(next->object.vm_object);
+			if (next->uip)
+				uifree(next->uip);
 			vm_map_entry_dispose(map, next);
 		}
 	}
+	swap_check_reserve();
 }
 /*
  *	vm_map_clip_start:	[ internal use only ]
  *
  *	Asserts that the given entry begins at or after
@@ -1216,24 +1293,39 @@
 		vm_object_t object;
 		object = vm_object_allocate(OBJT_DEFAULT,
 				atop(entry->end - entry->start));
 		entry->object.vm_object = object;
 		entry->offset = 0;
+		object->uip = entry->uip;
+		object->charge = entry->end - entry->start;
+		entry->uip = NULL;
+	} else if (entry->object.vm_object &&
+		   ((entry->eflags & MAP_ENTRY_NEEDS_COPY) == 0) && entry->uip)
+	{
+		KASSERT(!entry->object.vm_object->uip,
+			("OVERCOMMIT: vm_entry_clip_start: both uip e %p", entry));
+		entry->object.vm_object->uip = entry->uip;
+		entry->object.vm_object->charge = entry->end - entry->start;
+		entry->uip = NULL;
 	}
 
 	new_entry = vm_map_entry_create(map);
 	*new_entry = *entry;
 
 	new_entry->end = start;
 	entry->offset += (start - entry->start);
 	entry->start = start;
+	if (new_entry->uip)
+		uihold(entry->uip);
 
 	vm_map_entry_link(map, entry->prev, new_entry);
 
 	if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) == 0) {
 		vm_object_reference(new_entry->object.vm_object);
 	}
+
+	swap_check_reserve();
 }
 
 /*
  *	vm_map_clip_end:	[ internal use only ]
  *
@@ -1267,26 +1359,41 @@
 		vm_object_t object;
 		object = vm_object_allocate(OBJT_DEFAULT,
 				atop(entry->end - entry->start));
 		entry->object.vm_object = object;
 		entry->offset = 0;
+		object->uip = entry->uip;
+		object->charge = entry->end - entry->start;
+		entry->uip = NULL;
+	} else if (entry->object.vm_object &&
+		   ((entry->eflags & MAP_ENTRY_NEEDS_COPY) == 0) && entry->uip)
+	{
+		KASSERT(!entry->object.vm_object->uip,
+			("OVERCOMMIT: vm_entry_clip_end: both uip e %p", entry));
+		entry->object.vm_object->uip = entry->uip;
+		entry->object.vm_object->charge = entry->end - entry->start;
+		entry->uip = NULL;
 	}
 
 	/*
 	 * Create a new entry and insert it AFTER the specified entry
 	 */
 	new_entry = vm_map_entry_create(map);
 	*new_entry = *entry;
 
 	new_entry->start = entry->end = end;
 	new_entry->offset += (end - entry->start);
+	if (new_entry->uip)
+		uihold(entry->uip);
 
 	vm_map_entry_link(map, entry, new_entry);
 
 	if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) == 0) {
 		vm_object_reference(new_entry->object.vm_object);
 	}
+
+	swap_check_reserve();
 }
 
 /*
  *	VM_MAP_RANGE_CHECK:	[ internal use only ]
  *
@@ -1481,20 +1588,51 @@
 			return (KERN_PROTECTION_FAILURE);
 		}
 		current = current->next;
 	}
 
+
+       /* Do an accounting pass for private read-only mappings that
+          now will do cow due to allowed write (e.g. debugger sets
+          breakpoint on text segment) */
+	current = entry;
+	while ((current != &map->header) && (current->start < end)) {
+
+		vm_map_clip_end(map, current, end);
+				
+		if (!set_max &&
+		    ((new_prot & ~(current->protection)) & VM_PROT_WRITE) &&
+		    !ENTRY_CHARGED(current)) {
+			struct uidinfo *uip;
+			if (!swap_reserve("mprotect", current->end - current->start)) {
+				vm_map_unlock(map);
+				return (KERN_RESOURCE_SHORTAGE);
+			}
+			uip = curthread->td_ucred->cr_ruidinfo;
+			uihold(uip);
+			if ((current->eflags & MAP_ENTRY_NEEDS_COPY) ||
+			    (current->object.vm_object == NULL)) {
+				current->uip = uip;
+			} else {
+				KASSERT(ptoa(current->object.vm_object->size) == current->end - current->start,
+					("OVERCOMMIT: vm_map_protect size e %p o %p", current, current->object.vm_object));
+				current->object.vm_object->uip = uip;
+			}
+		}
+		current = current->next;
+	}
+
+	swap_check_reserve();
+
 	/*
 	 * Go back and fix up protections. [Note that clipping is not
 	 * necessary the second time.]
 	 */
 	current = entry;
 	while ((current != &map->header) && (current->start < end)) {
 		vm_prot_t old_prot;
 
-		vm_map_clip_end(map, current, end);
-
 		old_prot = current->protection;
 		if (set_max)
 			current->protection =
 			    (current->max_protection = new_prot) &
 			    old_prot;
@@ -2181,18 +2319,35 @@
 {
 	vm_object_t object;
 	vm_pindex_t offidxstart, offidxend, count;
 
 	vm_map_entry_unlink(map, entry);
+	object = entry->object.vm_object;
 	map->size -= entry->end - entry->start;
 
+	if (entry->uip) {
+		/* XXXOVERCOMMIT */
+/* 		printf("%d(%s) map_entry_del: ", curproc->p_pid, curproc->p_comm); */
+/* 		dump_vm_map_entry(entry); */
+		swap_release_by_uid("vm_map_entry_delete", entry->end - entry->start, entry->uip);
+		uifree(entry->uip);
+	}
+
 	if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) == 0 &&
-	    (object = entry->object.vm_object) != NULL) {
+	    (object != NULL)) {
+#ifdef INVARIANTS
+		if (entry->uip && object->uip && !(entry->eflags & MAP_ENTRY_NEEDS_COPY)) {
+			printf("OVERCOMMIT vm_map_entry_delete: both uip ");
+			dump_vm_map_entry(entry);
+			panic("vm_map_entry_delete");
+		}
+#endif
 		count = OFF_TO_IDX(entry->end - entry->start);
 		offidxstart = OFF_TO_IDX(entry->offset);
 		offidxend = offidxstart + count;
 		VM_OBJECT_LOCK(object);
+
 		if (object->ref_count != 1 &&
 		    ((object->flags & (OBJ_NOSPLIT|OBJ_ONEMAPPING)) == OBJ_ONEMAPPING ||
 		     object == kernel_object || object == kmem_object) &&
 		    (object->type == OBJT_DEFAULT || object->type == OBJT_SWAP)) {
 			vm_object_collapse(object);
@@ -2206,10 +2361,12 @@
 		VM_OBJECT_UNLOCK(object);
 		vm_object_deallocate(object);
 	}
 
 	vm_map_entry_dispose(map, entry);
+
+	swap_check_reserve();
 }
 
 /*
  *	vm_map_delete:	[ internal use only ]
  *
@@ -2375,11 +2532,12 @@
 static void
 vm_map_copy_entry(
 	vm_map_t src_map,
 	vm_map_t dst_map,
 	vm_map_entry_t src_entry,
-	vm_map_entry_t dst_entry)
+	vm_map_entry_t dst_entry,
+	vm_pindex_t *fork_charge)
 {
 	vm_object_t src_object;
 
 	if ((dst_entry->eflags|src_entry->eflags) & MAP_ENTRY_IS_SUB_MAP)
 		return;
@@ -2399,10 +2557,12 @@
 
 		/*
 		 * Make a copy of the object.
 		 */
 		if ((src_object = src_entry->object.vm_object) != NULL) {
+			/* because vm_object_split clear object->uip */
+			int charged = ENTRY_CHARGED(src_entry);
 			VM_OBJECT_LOCK(src_object);
 			if ((src_object->handle == NULL) &&
 				(src_object->type == OBJT_DEFAULT ||
 				 src_object->type == OBJT_SWAP)) {
 				vm_object_collapse(src_object);
@@ -2413,16 +2573,52 @@
 			}
 			vm_object_reference_locked(src_object);
 			vm_object_clear_flag(src_object, OBJ_ONEMAPPING);
 			VM_OBJECT_UNLOCK(src_object);
 			dst_entry->object.vm_object = src_object;
+			if (charged) {
+				vm_offset_t size = src_entry->end - src_entry->start;
+				vm_pindex_t chg = 0;
+				if (src_entry->uip) {
+					if (src_entry->eflags & MAP_ENTRY_NEEDS_COPY) {
+						swap_release_by_uid("vm_map_entry_copy", size, src_entry->uip);
+						uifree(src_entry->uip);
+						src_entry->uip = NULL;
+					} else {
+						KASSERT(!src_object->uip,
+							("OVERCOMMIT: vm_map_entry_copy: uip %p", src_object));
+						KASSERT(ptoa(src_object->size) == size,
+							("OVERCOMMIT: vm_map_entry_copy: size %p", src_object));
+						src_object->uip = src_entry->uip;
+						src_object->charge = size;
+						src_entry->uip = NULL;
+					}
+				}
+				dst_entry->uip = src_entry->uip = curthread->td_ucred->cr_ruidinfo;
+				*fork_charge += 2 * size;
+				chg = 2 * size;
+				uihold(src_entry->uip);
+				uihold(dst_entry->uip);
+				if (overcommit_trace) {
+					printf("CHARGE 2 %llx ", chg);
+					dump_vm_map_entry(src_entry);
+				}
+			}
 			src_entry->eflags |= (MAP_ENTRY_COW|MAP_ENTRY_NEEDS_COPY);
 			dst_entry->eflags |= (MAP_ENTRY_COW|MAP_ENTRY_NEEDS_COPY);
 			dst_entry->offset = src_entry->offset;
 		} else {
 			dst_entry->object.vm_object = NULL;
 			dst_entry->offset = 0;
+			if (src_entry->uip) {
+				uihold(dst_entry->uip = curthread->td_ucred->cr_ruidinfo);
+				*fork_charge += src_entry->end - src_entry->start;
+				if (overcommit_trace) {
+					printf("CHARGE 2 %x ", src_entry->end - src_entry->start);
+					dump_vm_map_entry(src_entry);
+				}
+			}
 		}
 
 		pmap_copy(dst_map->pmap, src_map->pmap, dst_entry->start,
 		    dst_entry->end - dst_entry->start, src_entry->start);
 	} else {
@@ -2472,23 +2668,24 @@
  * is based on the old map, according to the inheritance
  * values on the regions in that map.
  *
  * XXX It might be worth coalescing the entries added to the new vmspace.
  *
- * The source map must not be locked.
+ * The source map must be locked.
  */
 struct vmspace *
 vmspace_fork(struct vmspace *vm1)
 {
 	struct vmspace *vm2;
 	vm_map_t old_map = &vm1->vm_map;
 	vm_map_t new_map;
 	vm_map_entry_t old_entry;
 	vm_map_entry_t new_entry;
 	vm_object_t object;
+	vm_pindex_t fork_charge = 0;
 
-	vm_map_lock(old_map);
+/* 	swap_dump_vmspace("before fork", vm1); */ /* XXXOVERCOMMIT */
 
 	vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset);
 	vm2->vm_taddr = vm1->vm_taddr;
 	vm2->vm_daddr = vm1->vm_daddr;
 	vm2->vm_maxsaddr = vm1->vm_maxsaddr;
@@ -2517,10 +2714,13 @@
 			if (object == NULL) {
 				object = vm_object_allocate(OBJT_DEFAULT,
 					atop(old_entry->end - old_entry->start));
 				old_entry->object.vm_object = object;
 				old_entry->offset = (vm_offset_t) 0;
+				object->uip = old_entry->uip;
+				object->charge = old_entry->end - old_entry->start;
+				old_entry->uip = NULL;
 			}
 
 			/*
 			 * Add the reference before calling vm_object_shadow
 			 * to insure that a shadow object is created.
@@ -2537,10 +2737,16 @@
 				vm_object_deallocate(object);
 				object = old_entry->object.vm_object;
 			}
 			VM_OBJECT_LOCK(object);
 			vm_object_clear_flag(object, OBJ_ONEMAPPING);
+			if (old_entry->uip) {
+				KASSERT(object->uip == NULL, ("vmspace_fork both uip"));
+				object->uip = old_entry->uip;
+				object->charge = old_entry->end - old_entry->start;
+				old_entry->uip = NULL;
+			}
 			VM_OBJECT_UNLOCK(object);
 
 			/*
 			 * Clone the entry, referencing the shared object.
 			 */
@@ -2577,21 +2783,78 @@
 			new_entry->object.vm_object = NULL;
 			vm_map_entry_link(new_map, new_map->header.prev,
 			    new_entry);
 			vmspace_map_entry_forked(vm1, vm2, new_entry);
 			vm_map_copy_entry(old_map, new_map, old_entry,
-			    new_entry);
+			    new_entry, &fork_charge);
 			break;
 		}
 		old_entry = old_entry->next;
 	}
 
-	vm_map_unlock(old_map);
-
+	/* XXXOVERCOMMIT */
+	if (fork_charge != vm1->vm_fork_charge) {
+		printf("vmspace_fork: actual fc %llx calc fc %llx\n",
+		       fork_charge, vm1->vm_fork_charge);
+		printf("old vm\n");
+		swap_dump_vmspace(vm1);
+		printf("new vm\n");
+		swap_dump_vmspace(vm2);
+	}
 	return (vm2);
 }
 
+vm_pindex_t
+swap_vmspace_charge(struct vmspace *vm)
+{
+	vm_pindex_t charge = 0;
+	vm_pindex_t size;
+	vm_map_t map = &vm->vm_map;
+	vm_map_entry_t e;
+
+	e = map->header.next;
+	while (e != &map->header) {
+		if (e->eflags & MAP_ENTRY_IS_SUB_MAP)
+			panic("swap_charge_fork: encountered a submap");
+
+		switch (e->inheritance) {
+		case VM_INHERIT_NONE:
+		case VM_INHERIT_SHARE:
+			break;
+
+		case VM_INHERIT_COPY:
+			size = e->end - e->start;
+			if (ENTRY_CHARGED(e)) {
+				if ((e -> wired_count) || !(e->object.vm_object)) {
+					charge += size;
+/*					printf("CHARGE 1 %llx ", size);
+					dump_vm_map_entry(e); */
+				} else {
+					charge += 2 * size;
+/*					printf("CHARGE 1 %llx ", 2 * size);
+					dump_vm_map_entry(e); */
+				}
+			}
+			break;
+		}
+		e = e->next;
+	}
+
+	return charge;
+}
+
+int
+swap_charge_fork(struct vmspace *vm, vm_pindex_t *chargea)
+{
+	vm_pindex_t charge = swap_vmspace_charge(vm);
+	int res = swap_reserve("charge_fork", charge);
+	if (res && chargea)
+		*chargea = charge;
+
+	return res;
+}
+
 int
 vm_map_stack(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize,
     vm_prot_t prot, vm_prot_t max, int cow)
 {
 	vm_map_entry_t new_entry, prev_entry;
@@ -2834,11 +3097,11 @@
 			stack_entry->avail_ssize = max_grow;
 			addr = end;
 		}
 
 		rv = vm_map_insert(map, NULL, 0, addr, stack_entry->start,
-		    p->p_sysent->sv_stackprot, VM_PROT_ALL, 0);
+				   p->p_sysent->sv_stackprot, VM_PROT_ALL, 0);
 
 		/* Adjust the available stack space by the amount we grew. */
 		if (rv == KERN_SUCCESS) {
 			if (prev_entry != &map->header)
 				vm_map_clip_end(map, prev_entry, addr);
@@ -2866,17 +3129,19 @@
 			stack_entry->avail_ssize = end - stack_entry->end;
 			addr = end;
 		}
 
 		grow_amount = addr - stack_entry->end;
-
+		/* XXXOVERCOMMIT need to reserve for right uid */
+		if (!swap_reserve("grow_stack", grow_amount))
+			rv = KERN_NO_SPACE;
 		/* Grow the underlying object if applicable. */
-		if (stack_entry->object.vm_object == NULL ||
-		    vm_object_coalesce(stack_entry->object.vm_object,
-		    stack_entry->offset,
-		    (vm_size_t)(stack_entry->end - stack_entry->start),
-		    (vm_size_t)grow_amount)) {
+		else if (stack_entry->object.vm_object == NULL ||
+			 vm_object_coalesce(stack_entry->object.vm_object,
+					    stack_entry->offset,
+					    (vm_size_t)(stack_entry->end - stack_entry->start),
+					    (vm_size_t)grow_amount)) {
 			map->size += (addr - stack_entry->end);
 			/* Update the current entry. */
 			stack_entry->end = addr;
 			stack_entry->avail_ssize -= grow_amount;
 			vm_map_entry_resize_free(map, stack_entry);
@@ -2941,14 +3206,17 @@
 vmspace_unshare(struct proc *p)
 {
 	struct vmspace *oldvmspace = p->p_vmspace;
 	struct vmspace *newvmspace;
 
-	if (oldvmspace->vm_refcnt == 1)
+	if (oldvmspace->vm_refcnt == 1) {
+		vm_map_unlock(&oldvmspace->vm_map);
 		return;
+	}
 	newvmspace = vmspace_fork(oldvmspace);
 	p->p_vmspace = newvmspace;
+	vm_map_unlock(&oldvmspace->vm_map);
 	if (p == curthread->td_proc)		/* XXXKSE ? */
 		pmap_activate(curthread);
 	vmspace_free(oldvmspace);
 }
 
@@ -3083,10 +3351,22 @@
 			vm_object_shadow(
 			    &entry->object.vm_object,
 			    &entry->offset,
 			    atop(entry->end - entry->start));
 			entry->eflags &= ~MAP_ENTRY_NEEDS_COPY;
+			if (entry->uip) {
+				if (entry->object.vm_object->uip) {
+					swap_release_by_uid("vm_object_shadow", entry->end - entry->start, entry->uip);
+					uifree(entry->uip);
+					entry->uip = NULL;
+				} else {
+					entry->object.vm_object->uip = entry->uip;
+					entry->object.vm_object->charge = entry->end - entry->start;
+					entry->uip = NULL;
+				}
+			}
+			swap_check_reserve();
 
 			vm_map_lock_downgrade(map);
 		} else {
 			/*
 			 * We're attempting to read a copy-on-write page --
@@ -3104,12 +3384,16 @@
 		if (vm_map_lock_upgrade(map))
 			goto RetryLookup;
 		entry->object.vm_object = vm_object_allocate(OBJT_DEFAULT,
 		    atop(entry->end - entry->start));
 		entry->offset = 0;
+		entry->object.vm_object->uip = entry->uip;
+		entry->object.vm_object->charge = entry->end - entry->start;
+		entry->uip = NULL;
 		vm_map_lock_downgrade(map);
 	}
+	swap_check_reserve();
 
 	/*
 	 * Return the object/offset from this entry.  If the entry was
 	 * copy-on-write or empty, it has been fixed up.
 	 */
@@ -3295,13 +3579,19 @@
 					     entry->object.sub_map,
 					     full, 0, (char *)0);
 				db_indent -= 2;
 			}
 		} else {
+			if (entry->uip)
+				db_printf(", uip %d", entry->uip->ui_uid);
 			db_printf(", object=%p, offset=0x%jx",
 			    (void *)entry->object.vm_object,
 			    (uintmax_t)entry->offset);
+			if (entry->object.vm_object && entry->object.vm_object->uip)
+				db_printf(", obj uip %d charge %llx",
+					  entry->object.vm_object->uip->ui_uid,
+					  entry->object.vm_object->charge);
 			if (entry->eflags & MAP_ENTRY_COW)
 				db_printf(", copy (%s)",
 				    (entry->eflags & MAP_ENTRY_NEEDS_COPY) ? "needed" : "done");
 			db_printf("\n");
 			nlines++;
Index: sys/vm/vm_map.h
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/vm/vm_map.h,v
retrieving revision 1.117
diff -U5 -r1.117 vm_map.h
--- sys/vm/vm_map.h	7 Jan 2005 02:29:27 -0000	1.117
+++ sys/vm/vm_map.h	15 Jun 2005 10:43:31 -0000
@@ -113,10 +113,11 @@
 	vm_prot_t protection;		/* protection code */
 	vm_prot_t max_protection;	/* maximum protection */
 	vm_inherit_t inheritance;	/* inheritance */
 	int wired_count;		/* can be paged if = 0 */
 	vm_pindex_t lastr;		/* last read */
+	struct uidinfo *uip;		/* tmp storage for creator ref */
 };
 
 #define MAP_ENTRY_NOSYNC		0x0001
 #define MAP_ENTRY_IS_SUB_MAP		0x0002
 #define MAP_ENTRY_COW			0x0004
@@ -242,10 +243,11 @@
 	caddr_t vm_taddr;	/* (c) user virtual address of text */
 	caddr_t vm_daddr;	/* (c) user virtual address of data */
 	caddr_t vm_maxsaddr;	/* user VA at max stack growth */
 	int	vm_exitingcnt;	/* several processes zombied in exit1  */
 	int	vm_refcnt;	/* number of references */
+	vm_pindex_t vm_fork_charge;	/* XXXOVERCOMMIT swap charge calculated on last fork */
 };
 
 #ifdef	_KERNEL
 static __inline pmap_t
 vmspace_pmap(struct vmspace *vmspace)
@@ -309,10 +311,12 @@
 #define MAP_DISABLE_SYNCER	0x0020
 #define MAP_DISABLE_COREDUMP	0x0100
 #define MAP_PREFAULT_MADVISE	0x0200	/* from (user) madvise request */
 #define	MAP_STACK_GROWS_DOWN	0x1000
 #define	MAP_STACK_GROWS_UP	0x2000
+#define MAP_ACC_CHARGED		0x4000
+#define MAP_ACC_NO_CHARGE	0x8000
 
 /*
  * vm_fault option flags
  */
 #define VM_FAULT_NORMAL 0		/* Nothing special */
Index: sys/vm/vm_mmap.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/vm/vm_mmap.c,v
retrieving revision 1.200
diff -U5 -r1.200 vm_mmap.c
--- sys/vm/vm_mmap.c	14 Apr 2005 16:03:30 -0000	1.200
+++ sys/vm/vm_mmap.c	15 Jun 2005 10:43:31 -0000
@@ -1281,11 +1281,11 @@
 		error = vm_mmap_cdev(td, size, prot, &maxprot, &flags,
 		    handle, foff, &object);
 		break;
 	case OBJT_VNODE:
 		error = vm_mmap_vnode(td, size, prot, &maxprot, &flags,
-		    handle, foff, &object);
+			handle, foff, &object);
 		break;
 	case OBJT_DEFAULT:
 		if (handle == NULL) {
 			error = 0;
 			break;
Index: sys/vm/vm_object.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/vm/vm_object.c,v
retrieving revision 1.349
diff -U5 -r1.349 vm_object.c
--- sys/vm/vm_object.c	4 May 2005 20:54:16 -0000	1.349
+++ sys/vm/vm_object.c	15 Jun 2005 10:43:31 -0000
@@ -76,10 +76,11 @@
 #include <sys/proc.h>		/* for curproc, pageproc */
 #include <sys/socket.h>
 #include <sys/vnode.h>
 #include <sys/vmmeter.h>
 #include <sys/sx.h>
+#include <sys/resourcevar.h>
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
 #include <vm/pmap.h>
 #include <vm/vm_map.h>
@@ -212,10 +213,12 @@
 	object->type = type;
 	object->size = size;
 	object->generation = 1;
 	object->ref_count = 1;
 	object->flags = 0;
+	object->uip = NULL;
+	object->charge = 0;
 	if ((object->type == OBJT_DEFAULT) || (object->type == OBJT_SWAP))
 		object->flags = OBJ_ONEMAPPING;
 	if (size > (PQ_L2_SIZE / 3 + PQ_PRIME1))
 		incr = PQ_L2_SIZE / 3 + PQ_PRIME1;
 	else
@@ -642,10 +645,18 @@
 	 */
 	mtx_lock(&vm_object_list_mtx);
 	TAILQ_REMOVE(&vm_object_list, object, object_list);
 	mtx_unlock(&vm_object_list_mtx);
 
+	if (object->uip != NULL) {
+		KASSERT(object->type == OBJT_DEFAULT || object->type == OBJT_SWAP,
+			("vm_object_terminate: non-swap obj %p has uip", object));
+		swap_release_by_uid("vm_object_terminate", object->charge, object->uip);
+		object->charge = 0;
+		uifree(object->uip);
+		object->uip = NULL;
+	}
 	/*
 	 * Free the space for the object.
 	 */
 	uma_zfree(obj_zone, object);
 }
@@ -1290,10 +1301,17 @@
 		VM_OBJECT_UNLOCK(source);
 		new_object->backing_object_offset = 
 			orig_object->backing_object_offset + entry->offset;
 		new_object->backing_object = source;
 	}
+	/* The vm_object_split is called only for entries that are
+	   going to be marked with MAP_ENTRY_NEEDS_COPY.
+	 */
+	new_object->uip = orig_object->uip; /* XXXOVERCOMMIT */
+	uihold(orig_object->uip);
+	new_object->charge = ptoa(size);
+	orig_object->charge -= ptoa(size);
 	new_object->flags |= orig_object->flags & OBJ_NEEDGIANT;
 	vm_page_lock_queues();
 	for (idx = 0; idx < size; idx++) {
 	retry:
 		m = vm_page_lookup(orig_object, offidxstart + idx);
@@ -1671,10 +1689,16 @@
 			    &vm_object_list, 
 			    backing_object,
 			    object_list
 			);
 			mtx_unlock(&vm_object_list_mtx);
+			if (backing_object->uip) {
+				swap_release_by_uid("vm_object_collapse", backing_object->charge, backing_object->uip);
+				backing_object->charge = 0;
+				uifree(backing_object->uip);
+				backing_object->uip = NULL;
+			}
 
 			uma_zfree(obj_zone, backing_object);
 
 			object_collapses++;
 		} else {
@@ -1865,17 +1889,22 @@
 				      next_pindex,
 				      next_pindex + next_size, FALSE);
 		if (prev_object->type == OBJT_SWAP)
 			swap_pager_freespace(prev_object,
 					     next_pindex, next_size);
+		if (prev_object->uip)
+			prev_object->charge -= ptoa(next_size);
 	}
 
 	/*
 	 * Extend the object if necessary.
 	 */
-	if (next_pindex + next_size > prev_object->size)
+	if (next_pindex + next_size > prev_object->size) {
 		prev_object->size = next_pindex + next_size;
+		if (prev_object->uip)
+			prev_object->charge += ptoa(next_size);
+	}
 
 	VM_OBJECT_UNLOCK(prev_object);
 	return (TRUE);
 }
 
@@ -2015,13 +2044,14 @@
 
 	if (object == NULL)
 		return;
 
 	db_iprintf(
-	    "Object %p: type=%d, size=0x%jx, res=%d, ref=%d, flags=0x%x\n",
+	    "Object %p: type=%d, size=0x%jx, res=%d, ref=%d, flags=0x%x uip %d charge %llx\n",
 	    object, (int)object->type, (uintmax_t)object->size,
-	    object->resident_page_count, object->ref_count, object->flags);
+	    object->resident_page_count, object->ref_count, object->flags,
+	    object->uip ? object->uip->ui_uid : -1, object->charge);
 	db_iprintf(" sref=%d, backing_object(%d)=(%p)+0x%jx\n",
 	    object->shadow_count, 
 	    object->backing_object ? object->backing_object->ref_count : 0,
 	    object->backing_object, (uintmax_t)object->backing_object_offset);
 
Index: sys/vm/vm_object.h
===================================================================
RCS file: /usr/local/arch/ncvs/src/sys/vm/vm_object.h,v
retrieving revision 1.111
diff -U5 -r1.111 vm_object.h
--- sys/vm/vm_object.h	3 May 2005 11:11:26 -0000	1.111
+++ sys/vm/vm_object.h	15 Jun 2005 10:43:31 -0000
@@ -129,10 +129,12 @@
 		 */
 		struct {
 			int swp_bcount;
 		} swp;
 	} un_pager;
+	struct uidinfo *uip;
+	vm_pindex_t charge;
 };
 
 /*
  * Flags
  */
Index: usr.bin/limits/limits.c
===================================================================
RCS file: /usr/local/arch/ncvs/src/usr.bin/limits/limits.c,v
retrieving revision 1.14
diff -U5 -r1.14 limits.c
--- usr.bin/limits/limits.c	19 Dec 2004 13:29:25 -0000	1.14
+++ usr.bin/limits/limits.c	15 Jun 2005 10:43:37 -0000
@@ -84,11 +84,12 @@
 	  { "  memoryuse%-4s    %8s", " kB\n",    1024 },
 	  { "  memorylocked%-4s %8s", " kB\n",    1024 },
 	  { "  maxprocesses%-4s %8s", "\n",       1    },
 	  { "  openfiles%-4s    %8s", "\n",       1    },
 	  { "  sbsize%-4s       %8s", " bytes\n", 1    },
-	  { "  vmemoryuse%-4s   %8s", " kB\n",    1024 }
+	  { "  vmemoryuse%-4s   %8s", " kB\n",    1024 },
+	  { "  swapuse%-4s      %8s", " kB\n",    1024 }
       }
     },
     { "sh", "unlimited", "", " -H", " -S", "",
       {
 	  { "ulimit%s -t %s", ";\n",  1    },
@@ -99,11 +100,12 @@
 	  { "ulimit%s -m %s", ";\n",  1024 },
 	  { "ulimit%s -l %s", ";\n",  1024 },
 	  { "ulimit%s -u %s", ";\n",  1    },
 	  { "ulimit%s -n %s", ";\n",  1    },
 	  { "ulimit%s -b %s", ";\n",  1    },
-	  { "ulimit%s -v %s", ";\n",  1024 }
+	  { "ulimit%s -v %s", ";\n",  1024 },
+	  { "ulimit%s -w %s", ";\n",  1024 }
       }
     },
     { "csh", "unlimited", "", " -h", "", NULL,
       {
 	  { "limit%s cputime %s",      ";\n",  1    },
@@ -114,11 +116,12 @@
 	  { "limit%s memoryuse %s",    ";\n",  1024 },
 	  { "limit%s memorylocked %s", ";\n",  1024 },
 	  { "limit%s maxproc %s",      ";\n",  1    },
 	  { "limit%s openfiles %s",    ";\n",  1    },
 	  { "limit%s sbsize %s",       ";\n",  1    },
-	  { "limit%s vmemoryuse %s",   ";\n",  1024 }
+	  { "limit%s vmemoryuse %s",   ";\n",  1024 },
+	  { "limit%s swapuse %s",      ";\n",  1024 }
       }
     },
     { "bash|bash2", "unlimited", "", " -H", " -S", "",
       {
 	  { "ulimit%s -t %s", ";\n",  1    },
@@ -129,11 +132,12 @@
 	  { "ulimit%s -m %s", ";\n",  1024 },
 	  { "ulimit%s -l %s", ";\n",  1024 },
 	  { "ulimit%s -u %s", ";\n",  1    },
 	  { "ulimit%s -n %s", ";\n",  1    },
 	  { "ulimit%s -b %s", ";\n",  1    },
-	  { "ulimit%s -v %s", ";\n",  1024 }
+	  { "ulimit%s -v %s", ";\n",  1024 },
+	  { "ulimit%s -w %s", ";\n",  1024 }
       }
     },
     { "tcsh", "unlimited", "", " -h", "", NULL,
       {
 	  { "limit%s cputime %s",      ";\n",  1    },
@@ -144,11 +148,12 @@
 	  { "limit%s memoryuse %s",    ";\n",  1024 },
 	  { "limit%s memorylocked %s", ";\n",  1024 },
 	  { "limit%s maxproc %s",      ";\n",  1    },
 	  { "limit%s descriptors %s",  ";\n",  1    },
 	  { "limit%s sbsize %s",       ";\n",  1    },
-	  { "limit%s vmemoryuse %s",   ";\n",  1024 }
+	  { "limit%s vmemoryuse %s",   ";\n",  1024 },
+	  { "limit%s swapuse %s",      ";\n",  1024 }
       }
     },
     { "ksh|pdksh", "unlimited", "", " -H", " -S", "",
       {
 	  { "ulimit%s -t %s", ";\n",  1    },
@@ -159,11 +164,12 @@
 	  { "ulimit%s -m %s", ";\n",  1024 },
 	  { "ulimit%s -l %s", ";\n",  1024 },
 	  { "ulimit%s -p %s", ";\n",  1    },
 	  { "ulimit%s -n %s", ";\n",  1    },
 	  { "ulimit%s -b %s", ";\n",  1    },
-	  { "ulimit%s -v %s", ";\n",  1024 }
+	  { "ulimit%s -v %s", ";\n",  1024 },
+	  { "ulimit%s -w %s", ";\n",  1024 }
       }
     },
     { "zsh", "unlimited", "", " -H", " -S", "",
       {
 	  { "ulimit%s -t %s", ";\n",  1    },
@@ -174,11 +180,12 @@
 	  { "ulimit%s -m %s", ";\n",  1024 },
 	  { "ulimit%s -l %s", ";\n",  1024 },
 	  { "ulimit%s -u %s", ";\n",  1    },
 	  { "ulimit%s -n %s", ";\n",  1    },
 	  { "ulimit%s -b %s", ";\n",  1    },
-	  { "ulimit%s -v %s", ";\n",  1024 }
+	  { "ulimit%s -v %s", ";\n",  1024 },
+	  { "ulimit%s -w %s", ";\n",  1024 }
       }
     },
     { "rc|es", "unlimited", "", " -h", "", NULL,
       {
 	  { "limit%s cputime %s",      ";\n",  1    },
@@ -189,11 +196,12 @@
 	  { "limit%s memoryuse %s",    ";\n",  1024 },
 	  { "limit%s lockedmemory %s", ";\n",  1024 },
 	  { "limit%s processes %s",    ";\n",  1    },
 	  { "limit%s descriptors %s",  ";\n",  1    },
 	  { "limit%s sbsize %s",       ";\n",  1    },
-	  { "limit%s vmemoryuse %s",   ";\n",  1024 }
+	  { "limit%s vmemoryuse %s",   ";\n",  1024 },
+	  { "limit%s swapuse %s",      ";\n",  1024 }
       }
     },
     { NULL, NULL, NULL, NULL, NULL, NULL,
       { }
     }
@@ -210,23 +218,24 @@
     { "coredumpsize",	login_getcapsize },
     { "memoryuse",	login_getcapsize },
     { "memorylocked",	login_getcapsize },
     { "maxproc",	login_getcapnum  },
     { "openfiles",	login_getcapnum  },
-    { "sbsize",		login_getcapsize  },
-    { "vmemoryuse",	login_getcapsize  }
+    { "sbsize",		login_getcapsize },
+    { "vmemoryuse",	login_getcapsize },
+    { "swapuse",	login_getcapsize }
 };
 
 /*
  * One letter for each resource levels.
  * NOTE: There is a dependancy on the corresponding
  * letter index being equal to the resource number.
  * If sys/resource.h defines are changed, this needs
  * to be modified accordingly!
  */
 
-#define RCS_STRING  "tfdscmlunbv"
+#define RCS_STRING  "tfdscmlunbvw"
 
 static rlim_t resource_num(int which, int ch, const char *str);
 static void usage(void);
 static int getshelltype(void);
 static void print_limit(rlim_t limit, unsigned divisor, const char *inf,
@@ -258,11 +267,11 @@
 	/* Get current resource values */
 	getrlimit(i, &limits[i]);
     }
 
     optarg = NULL;
-    while ((ch = getopt(argc, argv, ":EeC:U:BSHab:c:d:f:l:m:n:s:t:u:v:")) != -1) {
+    while ((ch = getopt(argc, argv, ":EeC:U:BSHab:c:d:f:l:m:n:s:t:u:v:w:")) != -1) {
 	switch(ch) {
 	case 'a':
 	    doall = 1;
 	    break;
 	case 'E':
@@ -467,11 +476,11 @@
 
 static void
 usage(void)
 {
     (void)fprintf(stderr,
-"usage: limits [-C class|-U user] [-eaSHBE] [-bcdflmnstuv [val]] [[name=val ...] cmd]\n");
+"usage: limits [-C class|-U user] [-eaSHBE] [-bcdflmnstuvw [val]] [[name=val ...] cmd]\n");
     exit(EXIT_FAILURE);
 }
 
 static void
 print_limit(rlim_t limit, unsigned divisor, const char * inf, const char * pfx, const char * sfx, const char * which)
@@ -539,10 +548,11 @@
 	case RLIMIT_CORE:
 	case RLIMIT_RSS:
 	case RLIMIT_MEMLOCK:
 	case RLIMIT_SBSIZE:
 	case RLIMIT_VMEM:
+	case RLIMIT_SWAP:
 	    errno = 0;
 	    res = 0;
 	    while (*s) {
 		rlim_t mult, tim = strtoq(s, &e, 0);
 		if (e == NULL || e == s || errno)
