* finding or making overcommit--main--1.0--patch-10
* auto-adding kostikbel@ukr.net--2005-freebsd/overcommit--main--1.0--patch-10 to greedy revision library /usr/home/kostik/tla-libraries
* found immediate ancestor revision in library (kostikbel@ukr.net--2005-freebsd/overcommit--main--1.0--patch-9)
* patching for this revision (kostikbel@ukr.net--2005-freebsd/overcommit--main--1.0--patch-10)
* finding or making overcommit--patch--1.0--patch-14
* auto-adding kostikbel@ukr.net--2005-freebsd/overcommit--patch--1.0--patch-14 to greedy revision library /usr/home/kostik/tla-libraries
* found immediate ancestor revision in library (kostikbel@ukr.net--2005-freebsd/overcommit--patch--1.0--patch-13)
* patching for this revision (kostikbel@ukr.net--2005-freebsd/overcommit--patch--1.0--patch-14)
* computing changeset
A/ {arch}/overcommit/overcommit--patch
A/ {arch}/overcommit/overcommit--patch/overcommit--patch--1.0
A/ {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd
A/ {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/base-0
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-1
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-10
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-11
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-12
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-13
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-14
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-2
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-3
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-4
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-5
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-6
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-7
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-8
A  {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-9
M  bin/sh/miscbltin.c
M  etc/login.conf
M  lib/libutil/login_class.c
M  share/mk/bsd.compat.mk
M  sys/dev/md/md.c
M  sys/fs/procfs/procfs_map.c
M  sys/kern/init_main.c
M  sys/kern/init_sysent.c
M  sys/kern/kern_exec.c
M  sys/kern/kern_fork.c
M  sys/kern/kern_resource.c
M  sys/kern/sys_process.c
M  sys/kern/syscalls.c
M  sys/kern/syscalls.master
M  sys/kern/sysv_shm.c
M  sys/kern/vfs_bio.c
M  sys/sys/resource.h
M  sys/sys/resourcevar.h
M  sys/sys/shm.h
M  sys/sys/syscall.h
M  sys/sys/syscall.mk
M  sys/sys/sysproto.h
M  sys/vm/swap_pager.c
M  sys/vm/vm.h
M  sys/vm/vm_contig.c
M  sys/vm/vm_fault.c
M  sys/vm/vm_glue.c
M  sys/vm/vm_kern.c
M  sys/vm/vm_map.c
M  sys/vm/vm_map.h
M  sys/vm/vm_mmap.c
M  sys/vm/vm_object.c
M  sys/vm/vm_object.h
M  usr.bin/limits/limits.c
* changeset report
* added directories

    {arch}/overcommit/overcommit--patch
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log

* added files

    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/base-0
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-1
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-10
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-11
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-12
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-13
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-14
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-2
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-3
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-4
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-5
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-6
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-7
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-8
    {arch}/overcommit/overcommit--patch/overcommit--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-9

* modified files

--- orig/bin/sh/miscbltin.c
+++ mod/bin/sh/miscbltin.c
@@ -358,7 +358,7 @@
 	struct rlimit	limit;
 
 	what = 'f';
-	while ((optc = nextopt("HSatfdsmcnuvlb")) != '\0')
+	while ((optc = nextopt("HSatfdsmcnuvlbw")) != '\0')
 		switch (optc) {
 		case 'H':
 			how = HARD;


--- orig/etc/login.conf
+++ mod/etc/login.conf
@@ -35,6 +35,7 @@
 	:maxproc=unlimited:\
 	:sbsize=unlimited:\
 	:vmemoryuse=unlimited:\
+	:swapuse=unlimited:\
 	:priority=0:\
 	:ignoretime@:\
 	:umask=022:


--- orig/lib/libutil/login_class.c
+++ mod/lib/libutil/login_class.c
@@ -59,6 +59,7 @@
     { "coredumpsize", login_getcapsize, RLIMIT_CORE     },
     { "sbsize",       login_getcapsize,	RLIMIT_SBSIZE	},
     { "vmemoryuse",   login_getcapsize,	RLIMIT_VMEM	},
+    { "swapuse",      login_getcapsize, RLIMIT_SWAP	},
     { NULL,	      0,		0 	        }
 };
 


--- orig/share/mk/bsd.compat.mk
+++ mod/share/mk/bsd.compat.mk
@@ -33,7 +33,7 @@
 .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


--- orig/sys/dev/md/md.c
+++ mod/sys/dev/md/md.c
@@ -75,6 +75,7 @@
 #include <sys/sf_buf.h>
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
+#include <sys/resourcevar.h>
 
 #include <geom/geom.h>
 
@@ -533,7 +534,7 @@
 	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
@@ -988,10 +989,15 @@
 		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) {


--- orig/sys/fs/procfs/procfs_map.c
+++ mod/sys/fs/procfs/procfs_map.c
@@ -46,6 +46,7 @@
 #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>
@@ -87,10 +88,11 @@
 	vm_map_entry_t entry;
 	char mebuffer[MEBUFFERSIZE];
 	char *fullpath, *freepath;
+	struct uidinfo *uip;
 #ifdef COMPAT_IA32
-	int wrap32 = 0;
+ 	int wrap32 = 0;
 #endif
-
+  
 	GIANT_REQUIRED;
 
 	PROC_LOCK(p);
@@ -133,6 +135,8 @@
 		else
 			privateresident = 0;
 
+		uip = (entry->uip) ? entry->uip : (obj ? obj->uip : NULL);
+
 		resident = 0;
 		addr = entry->start;
 		while (addr < entry->end) {
@@ -179,10 +183,11 @@
 
 		/*
 		 * 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,
 #ifdef COMPAT_IA32
@@ -196,7 +201,8 @@
 			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);


--- orig/sys/kern/init_main.c
+++ mod/sys/kern/init_main.c
@@ -530,8 +530,9 @@
 	 * 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;
@@ -673,3 +674,4 @@
 	mtx_unlock_spin(&sched_lock);
 }
 SYSINIT(kickinit, SI_SUB_KTHREAD_INIT, SI_ORDER_FIRST, kick_init, NULL)
+


--- orig/sys/kern/init_sysent.c
+++ mod/sys/kern/init_sysent.c
@@ -2,7 +2,7 @@
  * 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 
  */
 


--- orig/sys/kern/kern_exec.c
+++ mod/sys/kern/kern_exec.c
@@ -976,8 +976,7 @@
 	 * 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;


--- orig/sys/kern/kern_fork.c
+++ mod/sys/kern/kern_fork.c
@@ -204,6 +204,8 @@
 	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. */
@@ -217,6 +219,21 @@
 	 * 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);
 
 		/*
@@ -305,6 +322,17 @@
 		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.
@@ -722,10 +750,15 @@
 	*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);


--- orig/sys/kern/kern_resource.c
+++ mod/sys/kern/kern_resource.c
@@ -1117,6 +1117,9 @@
 		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;
@@ -1176,3 +1179,26 @@
 		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);
+}


--- orig/sys/kern/sys_process.c
+++ mod/sys/kern/sys_process.c
@@ -56,6 +56,7 @@
 #include <vm/vm_kern.h>
 #include <vm/vm_object.h>
 #include <vm/vm_page.h>
+#include <vm/vm_param.h>
 
 #ifdef COMPAT_IA32
 #include <sys/procfs.h>
@@ -274,7 +275,10 @@
 		 */
 		error = vm_fault(map, pageno, reqprot, VM_FAULT_NORMAL);
 		if (error) {
-			error = EFAULT;
+			if (error == KERN_RESOURCE_SHORTAGE)
+				error = ENOMEM;
+			else
+				error = EFAULT;
 			break;
 		}
 


--- orig/sys/kern/syscalls.c
+++ mod/sys/kern/syscalls.c
@@ -2,7 +2,7 @@
  * 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 
  */
 


--- orig/sys/kern/syscalls.master
+++ mod/sys/kern/syscalls.master
@@ -790,6 +790,5 @@
 				    long id, void *uaddr, void *uaddr2); }
 455	AUE_NULL	MSTD	{ int thr_new(struct thr_param *param, \
 				    int param_size); }
-
 ; Please copy any additions and changes to the following compatability tables:
 ; sys/compat/freebsd32/syscalls.master


--- orig/sys/kern/sysv_shm.c
+++ mod/sys/kern/sysv_shm.c
@@ -247,12 +247,21 @@
 	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;
@@ -773,6 +782,18 @@
 		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.


--- orig/sys/kern/vfs_bio.c
+++ mod/sys/kern/vfs_bio.c
@@ -1920,7 +1920,7 @@
 			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;


--- orig/sys/sys/resource.h
+++ mod/sys/sys/resource.h
@@ -95,8 +95,9 @@
 #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 */
@@ -119,6 +120,7 @@
 	"nofile",
 	"sbsize",
 	"vmem",
+	"swap",
 };
 #endif
 


--- orig/sys/sys/resourcevar.h
+++ mod/sys/sys/resourcevar.h
@@ -95,6 +95,7 @@
  */
 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 */
@@ -116,6 +117,7 @@
 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);


--- orig/sys/sys/shm.h
+++ mod/sys/sys/shm.h
@@ -108,6 +108,7 @@
 struct shmid_kernel {
 	struct shmid_ds u;
 	struct label *label;	/* MAC label */
+	struct uidinfo *uip;
 };
 
 extern struct shminfo	shminfo;


--- orig/sys/sys/syscall.h
+++ mod/sys/sys/syscall.h
@@ -2,7 +2,7 @@
  * 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 
  */
 


--- orig/sys/sys/syscall.mk
+++ mod/sys/sys/syscall.mk
@@ -1,6 +1,6 @@
 # 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 \


--- orig/sys/sys/sysproto.h
+++ mod/sys/sys/sysproto.h
@@ -2,7 +2,7 @@
  * 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 
  */
 


--- orig/sys/vm/swap_pager.c
+++ mod/sys/vm/swap_pager.c
@@ -93,6 +93,8 @@
 #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>
@@ -182,6 +184,131 @@
 int swap_pager_avail;
 static int swdev_syscall_active = 0; /* serialize swap(on|off) */
 
+static vm_pindex_t swap_total;
+SYSCTL_INT(_vm, OID_AUTO, swap_total, CTLFLAG_RD, &swap_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 */
+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 <= swap_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;
+		}
+	}
+
+	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);
+}
+
+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 (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);
+}
+
+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			*/
@@ -2073,6 +2200,7 @@
 	TAILQ_INSERT_TAIL(&swtailq, sp, sw_list);
 	nswapdev++;
 	swap_pager_avail += nblks;
+	swap_total += nblks * PAGE_SIZE;
 	swp_sizecheck();
 	mtx_unlock(&sw_dev_mtx);
 }
@@ -2163,6 +2291,7 @@
 		swap_pager_avail -= blist_fill(sp->sw_blist,
 		     dvbase, dmmax);
 	}
+	swap_total -= nblks * PAGE_SIZE;
 	mtx_unlock(&sw_dev_mtx);
 
 	/*


--- orig/sys/vm/vm.h
+++ mod/sys/vm/vm.h
@@ -96,6 +96,8 @@
 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
@@ -143,5 +145,15 @@
 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);
+void swap_check_reserve(void);
+
 #endif				/* VM_H */
 


--- orig/sys/vm/vm_contig.c
+++ mod/sys/vm/vm_contig.c
@@ -310,7 +310,7 @@
 		}
 		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;
@@ -522,7 +522,7 @@
 	}
 	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);


--- orig/sys/vm/vm_fault.c
+++ mod/sys/vm/vm_fault.c
@@ -1139,6 +1139,8 @@
 	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;
 


--- orig/sys/vm/vm_glue.c
+++ mod/sys/vm/vm_glue.c
@@ -441,16 +441,6 @@
 	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;
 	}
@@ -466,6 +456,7 @@
 
 	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);
 	}


--- orig/sys/vm/vm_kern.c
+++ mod/sys/vm/vm_kern.c
@@ -108,7 +108,7 @@
 	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);
 	}
@@ -234,7 +234,7 @@
 
 	*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");
@@ -435,8 +435,11 @@
 		 * 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);
@@ -445,7 +448,7 @@
 		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);
 }
@@ -492,7 +495,7 @@
 	/* 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);
 }


--- orig/sys/vm/vm_map.c
+++ mod/sys/vm/vm_map.c
@@ -148,6 +148,10 @@
 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
 vm_map_startup(void)
 {
@@ -846,6 +850,7 @@
 	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.
@@ -886,6 +891,24 @@
 	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
@@ -903,11 +926,13 @@
 		 (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
@@ -920,6 +945,9 @@
 			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);
 		}
 
@@ -933,6 +961,11 @@
 		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;
+		}
 	}
 
 	/*
@@ -947,6 +980,7 @@
 	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;
@@ -958,6 +992,11 @@
 	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
 	 */
@@ -1143,7 +1182,8 @@
 		     (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;
@@ -1151,6 +1191,8 @@
 				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);
 		}
 	}
@@ -1166,15 +1208,19 @@
 		    (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 ]
@@ -1218,6 +1264,17 @@
 				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);
@@ -1226,12 +1283,16 @@
 	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();
 }
 
 /*
@@ -1269,6 +1330,17 @@
 				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;
 	}
 
 	/*
@@ -1279,12 +1351,16 @@
 
 	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();
 }
 
 /*
@@ -1483,6 +1559,39 @@
 		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.]
@@ -1491,8 +1600,6 @@
 	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 =
@@ -2183,14 +2290,23 @@
 	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) {
+		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)) {
+		KASSERT(!entry->uip || !object->uip || (entry->eflags & MAP_ENTRY_NEEDS_COPY),
+			("OVERCOMMIT vm_map_entry_delete: both uip %p", entry));
 		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) &&
@@ -2208,6 +2324,8 @@
 	}
 
 	vm_map_entry_dispose(map, entry);
+
+	swap_check_reserve();
 }
 
 /*
@@ -2377,7 +2495,8 @@
 	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;
 
@@ -2401,6 +2520,7 @@
 		 * Make a copy of the object.
 		 */
 		if ((src_object = src_entry->object.vm_object) != NULL) {
+			int charged = ENTRY_CHARGED(src_entry);
 			VM_OBJECT_LOCK(src_object);
 			if ((src_object->handle == NULL) &&
 				(src_object->type == OBJT_DEFAULT ||
@@ -2415,12 +2535,38 @@
 			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;
+				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;
+				uihold(src_entry->uip);
+				uihold(dst_entry->uip);
+			}
 			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;
+			}
 		}
 
 		pmap_copy(dst_map->pmap, src_map->pmap, dst_entry->start,
@@ -2474,7 +2620,7 @@
  *
  * 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)
@@ -2485,8 +2631,7 @@
 	vm_map_entry_t old_entry;
 	vm_map_entry_t new_entry;
 	vm_object_t object;
-
-	vm_map_lock(old_map);
+	vm_pindex_t fork_charge = 0;
 
 	vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset);
 	vm2->vm_taddr = vm1->vm_taddr;
@@ -2519,6 +2664,9 @@
 					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;
 			}
 
 			/*
@@ -2539,6 +2687,12 @@
 			}
 			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);
 
 			/*
@@ -2579,17 +2733,62 @@
 			    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);
-
+	KASSERT(fork_charge == vm1->vm_fork_charge, ("fork_charge"));
 	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;
+				} else {
+					charge += 2 * size;
+				}
+			}
+			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)
@@ -2836,7 +3035,7 @@
 		}
 
 		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) {
@@ -2868,13 +3067,15 @@
 		}
 
 		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;
@@ -2943,10 +3144,13 @@
 	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);
@@ -3080,11 +3284,35 @@
 			if (vm_map_lock_upgrade(map))
 				goto RetryLookup;
 
+			if (entry->uip == NULL) {
+				/* The debugger owner is charged for the memory. */
+				struct uidinfo *uip = curthread->td_ucred->cr_ruidinfo;
+				uihold(uip);
+				if (!swap_reserve_by_uid("VM_PROT_OVERRIDE_WRITE",
+							 entry->end - entry->start, uip)) {
+					uifree(uip);
+					vm_map_unlock(map);
+					return (KERN_RESOURCE_SHORTAGE);
+				}
+				entry->uip = uip;
+			}
 			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 {
@@ -3106,8 +3334,12 @@
 		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
@@ -3297,9 +3529,15 @@
 				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");


--- orig/sys/vm/vm_map.h
+++ mod/sys/vm/vm_map.h
@@ -115,6 +115,7 @@
 	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
@@ -244,6 +245,7 @@
 	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
@@ -311,6 +313,8 @@
 #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


--- orig/sys/vm/vm_mmap.c
+++ mod/sys/vm/vm_mmap.c
@@ -571,6 +571,8 @@
 		return (0);
 	case KERN_PROTECTION_FAILURE:
 		return (EACCES);
+	case KERN_RESOURCE_SHORTAGE:
+		return (ENOMEM);
 	}
 	return (EINVAL);
 }
@@ -1283,7 +1285,7 @@
 		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) {


--- orig/sys/vm/vm_object.c
+++ mod/sys/vm/vm_object.c
@@ -78,6 +78,7 @@
 #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>
@@ -214,6 +215,8 @@
 	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))
@@ -644,6 +647,14 @@
 	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.
 	 */
@@ -1292,6 +1303,10 @@
 			orig_object->backing_object_offset + entry->offset;
 		new_object->backing_object = source;
 	}
+	new_object->uip = orig_object->uip;
+	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++) {
@@ -1673,6 +1688,12 @@
 			    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);
 
@@ -1867,13 +1888,18 @@
 		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);
@@ -2017,9 +2043,10 @@
 		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,


--- orig/sys/vm/vm_object.h
+++ mod/sys/vm/vm_object.h
@@ -131,6 +131,8 @@
 			int swp_bcount;
 		} swp;
 	} un_pager;
+	struct uidinfo *uip;
+	vm_pindex_t charge;
 };
 
 /*


--- orig/usr.bin/limits/limits.c
+++ mod/usr.bin/limits/limits.c
@@ -86,7 +86,8 @@
 	  { "  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", "",
@@ -101,7 +102,8 @@
 	  { "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,
@@ -116,7 +118,8 @@
 	  { "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", "",
@@ -131,7 +134,8 @@
 	  { "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,
@@ -146,7 +150,8 @@
 	  { "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", "",
@@ -161,7 +166,8 @@
 	  { "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", "",
@@ -176,7 +182,8 @@
 	  { "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,
@@ -191,7 +198,8 @@
 	  { "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,
@@ -212,8 +220,9 @@
     { "memorylocked",	login_getcapsize },
     { "maxproc",	login_getcapnum  },
     { "openfiles",	login_getcapnum  },
-    { "sbsize",		login_getcapsize  },
-    { "vmemoryuse",	login_getcapsize  }
+    { "sbsize",		login_getcapsize },
+    { "vmemoryuse",	login_getcapsize },
+    { "swapuse",	login_getcapsize }
 };
 
 /*
@@ -224,7 +233,7 @@
  * 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);
@@ -260,7 +269,7 @@
     }
 
     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;
@@ -469,7 +478,7 @@
 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);
 }
 
@@ -541,6 +550,7 @@
 	case RLIMIT_MEMLOCK:
 	case RLIMIT_SBSIZE:
 	case RLIMIT_VMEM:
+	case RLIMIT_SWAP:
 	    errno = 0;
 	    res = 0;
 	    while (*s) {



