--- linux-2.6.18.3-vs2.1.1.2.3/include/linux/vs_memory.h	2006-11-27 03:08:42 +0100
+++ linux-2.6.18.3-vs2.1.1.2.3/include/linux/vs_memory.h	2006-11-27 03:08:42 +0100
@@ -59,7 +59,7 @@
 #define vx_acc_vmlpage(m,d) \
 	vx_acc_page(m, d, locked_vm, RLIMIT_MEMLOCK)
 #define vx_acc_file_rsspage(m,d) \
-	vx_acc_page_atomic(m, d, _file_rss, RLIMIT_RSS)
+	vx_acc_page_atomic(m, d, _file_rss, VLIMIT_MAPPED)
 #define vx_acc_anon_rsspage(m,d) \
 	vx_acc_page_atomic(m, d, _anon_rss, VLIMIT_ANON)
 
@@ -68,7 +68,7 @@
 #define vx_acc_vmlpages(m,p) \
 	vx_acc_pages(m, p, locked_vm, RLIMIT_MEMLOCK)
 #define vx_acc_file_rsspages(m,p) \
-	vx_acc_pages_atomic(m, p, _file_rss, RLIMIT_RSS)
+	vx_acc_pages_atomic(m, p, _file_rss, VLIMIT_MAPPED)
 #define vx_acc_anon_rsspages(m,p) \
 	vx_acc_pages_atomic(m, p, _anon_rss, VLIMIT_ANON)
 
@@ -101,8 +101,12 @@
 
 #define vx_vmpages_avail(m,p)	vx_pages_avail(m, p, RLIMIT_AS)
 #define vx_vmlocked_avail(m,p)	vx_pages_avail(m, p, RLIMIT_MEMLOCK)
-#define vx_rsspages_avail(m,p)	vx_pages_avail(m, p, RLIMIT_RSS)
-#define vx_anonpages_avail(m,p)	vx_pages_avail(m, p, VLIMIT_ANON)
+#define vx_anon_avail(m,p)	vx_pages_avail(m, p, VLIMIT_ANON)
+#define vx_mapped_avail(m,p)	vx_pages_avail(m, p, VLIMIT_MAPPED)
+
+#define vx_rss_avail(m,p) \
+	__vx_cres_array_avail((m)->mm_vx_info, VLA_RSS, p, __FILE__, __LINE__)
+
 
 enum {
 	VXPT_UNKNOWN = 0,
@@ -146,6 +150,9 @@
 #define	vx_page_fault(mm,vma,type,ret)	__vx_page_fault(mm,vma,type,ret)
 #endif
 
+
+extern unsigned long vx_badness(struct task_struct *task, struct mm_struct *mm);
+
 #else
 #warning duplicate inclusion
 #endif
--- linux-2.6.18.3-vs2.1.1.2.3/kernel/fork.c	2006-11-26 20:58:01 +0100
+++ linux-2.6.18.3-vs2.1.1.2.3/kernel/fork.c	2006-11-26 20:58:01 +0100
@@ -1004,7 +1004,7 @@
 			goto bad_fork_free;
 	}
 	if (p->mm && vx_flags(VXF_FORK_RSS, 0)) {
-		if (!vx_rsspages_avail(p->mm, get_mm_counter(p->mm, file_rss)))
+		if (!vx_rss_avail(p->mm, get_mm_counter(p->mm, file_rss)))
 			goto bad_fork_cleanup_vm;
 	}
 
--- linux-2.6.18.3-vs2.1.1.2/include/linux/vserver/limit.h	2006-09-25 15:40:02 +0200
+++ linux-2.6.18.3-vs2.1.1.2.3/include/linux/vserver/limit.h	2006-11-24 02:25:47 +0100
@@ -9,10 +9,12 @@
 #define VLIMIT_SEMARY	20
 #define VLIMIT_NSEMS	21
 #define VLIMIT_DENTRY	22
+#define VLIMIT_MAPPED	23
+
 
 #ifdef	__KERNEL__
 
-#define	VLIM_NOCHECK	(1L << VLIMIT_DENTRY)
+#define	VLIM_NOCHECK	((1L << VLIMIT_DENTRY) | (1L << RLIMIT_RSS))
 
 /*	keep in sync with CRLIM_INFINITY */
 
--- linux-2.6.18.3-vs2.1.1.2/include/linux/vserver/limit_int.h	2006-09-25 15:40:02 +0200
+++ linux-2.6.18.3-vs2.1.1.2.3/include/linux/vserver/limit_int.h	2006-11-24 04:31:53 +0100
@@ -41,9 +41,43 @@ static inline void __vx_add_cres(struct 
 	__rlim_add(&vxi->limit, res, amount);
 }
 
+static inline
+int __vx_cres_adjust_max(struct _vx_limit *limit, int res, rlim_t value)
+{
+	int cond = (value > __rlim_rmax(limit, res));
+
+	if (cond)
+		__rlim_rmax(limit, res) = value;
+	return cond;
+}
+
+static inline
+int __vx_cres_adjust_min(struct _vx_limit *limit, int res, rlim_t value)
+{
+	int cond = (value < __rlim_rmin(limit, res));
+
+	if (cond)
+		__rlim_rmin(limit, res) = value;
+	return cond;
+}
+
+static inline
+void __vx_cres_fixup(struct _vx_limit *limit, int res, rlim_t value)
+{
+	if (!__vx_cres_adjust_max(limit, res, value))
+		__vx_cres_adjust_min(limit, res, value);
+}
+
+
+/*	return values:
+	 +1 ... no limit hit
+	 -1 ... over soft limit
+	  0 ... over hard limit		*/
+
 static inline int __vx_cres_avail(struct vx_info *vxi,
-		int res, int num, char *_file, int _line)
+	int res, int num, char *_file, int _line)
 {
+	struct _vx_limit *limit;
 	rlim_t value;
 
 	if (VXD_RLIMIT_COND(res))
@@ -53,31 +87,89 @@ static inline int __vx_cres_avail(struct
 			(vxi ? (long)__rlim_hard(&vxi->limit, res) : -1),
 			(vxi ? (long)__rlim_get(&vxi->limit, res) : 0),
 			num, _file, _line);
-	if (num == 0)
-		return 1;
 	if (!vxi)
 		return 1;
 
-	value = __rlim_get(&vxi->limit, res);
+	limit = &vxi->limit;
+	value = __rlim_get(limit, res);
 
-	if (value > __rlim_rmax(&vxi->limit, res))
-		__rlim_rmax(&vxi->limit, res) = value;
-	else if (value < __rlim_rmin(&vxi->limit, res))
-		__rlim_rmin(&vxi->limit, res) = value;
+	if (!__vx_cres_adjust_max(limit, res, value))
+		__vx_cres_adjust_min(limit, res, value);
 
-	if (__rlim_soft(&vxi->limit, res) == RLIM_INFINITY)
+	if (num == 0)
+		return 1;
+
+	if (__rlim_soft(limit, res) == RLIM_INFINITY)
 		return -1;
-	if (value + num <= __rlim_soft(&vxi->limit, res))
+	if (value + num <= __rlim_soft(limit, res))
 		return -1;
 
-	if (__rlim_hard(&vxi->limit, res) == RLIM_INFINITY)
+	if (__rlim_hard(limit, res) == RLIM_INFINITY)
 		return 1;
-	if (value + num <= __rlim_hard(&vxi->limit, res))
+	if (value + num <= __rlim_hard(limit, res))
 		return 1;
 
-	__rlim_hit(&vxi->limit, res);
+	printk("··· %d limit hit @ %s:%d\n", res, _file, _line);
+	__rlim_hit(limit, res);
 	return 0;
 }
 
+
+static const int VLA_RSS[] = { RLIMIT_RSS, VLIMIT_ANON, VLIMIT_MAPPED, 0 };
+
+static inline
+rlim_t __vx_cres_array_sum(struct _vx_limit *limit, const int *array)
+{
+	rlim_t value, sum = 0;
+	int res;
+
+	while ((res = *array++)) {
+		value = __rlim_get(limit, res);
+		__vx_cres_fixup(limit, res, value);
+		sum += value;
+	}
+	return sum;
+}
+
+static inline
+rlim_t __vx_cres_array_fixup(struct _vx_limit *limit, const int *array)
+{
+	rlim_t value = __vx_cres_array_sum(limit, array + 1);
+	int res = *array;
+
+	if (value == __rlim_get(limit, res))
+		return value;
+
+	__rlim_set(limit, res, value);
+	/* now adjust min/max */
+	if (!__vx_cres_adjust_max(limit, res, value))
+		__vx_cres_adjust_min(limit, res, value);
+
+	return value;
+}
+
+static inline int __vx_cres_array_avail(struct vx_info *vxi,
+	const int *array, int num, char *_file, int _line)
+{
+	struct _vx_limit *limit;
+	rlim_t value = 0;
+	int res;
+
+	if (num == 0)
+		return 1;
+	if (!vxi)
+		return 1;
+
+	limit = &vxi->limit;
+	res = *array;
+	value = __vx_cres_array_sum(limit, array+1);
+
+	__rlim_set(limit, res, value);
+	__vx_cres_fixup(limit, res, value);
+
+	return __vx_cres_avail(vxi, res, num, _file, _line);
+}
+
+
 #endif	/* __KERNEL__ */
 #endif	/* _VX_LIMIT_INT_H */
--- linux-2.6.18.3-vs2.1.1.2/kernel/vserver/limit.c	2006-11-21 00:10:27 +0100
+++ linux-2.6.18.3-vs2.1.1.2.3/kernel/vserver/limit.c	2006-11-27 03:25:09 +0100
@@ -47,29 +47,29 @@ const struct vcmd_ctx_rlimit_mask_v0 vli
 		/* minimum */
 	0
 	,	/* softlimit */
-        MASK_ENTRY( RLIMIT_RSS		) |
-        MASK_ENTRY( VLIMIT_ANON		) |
-        0
-        ,       /* maximum */
-        MASK_ENTRY( RLIMIT_RSS		) |
-        MASK_ENTRY( RLIMIT_NPROC	) |
-        MASK_ENTRY( RLIMIT_NOFILE	) |
-        MASK_ENTRY( RLIMIT_MEMLOCK	) |
-        MASK_ENTRY( RLIMIT_AS		) |
-        MASK_ENTRY( RLIMIT_LOCKS	) |
-        MASK_ENTRY( RLIMIT_MSGQUEUE	) |
+	MASK_ENTRY( RLIMIT_RSS		) |
+	MASK_ENTRY( VLIMIT_ANON		) |
+	0
+	,       /* maximum */
+	MASK_ENTRY( RLIMIT_RSS		) |
+	MASK_ENTRY( RLIMIT_NPROC	) |
+	MASK_ENTRY( RLIMIT_NOFILE	) |
+	MASK_ENTRY( RLIMIT_MEMLOCK	) |
+	MASK_ENTRY( RLIMIT_AS		) |
+	MASK_ENTRY( RLIMIT_LOCKS	) |
+	MASK_ENTRY( RLIMIT_MSGQUEUE	) |
 
-        MASK_ENTRY( VLIMIT_NSOCK	) |
-        MASK_ENTRY( VLIMIT_OPENFD	) |
-        MASK_ENTRY( VLIMIT_ANON		) |
-        MASK_ENTRY( VLIMIT_SHMEM	) |
-        MASK_ENTRY( VLIMIT_DENTRY	) |
-        0
+	MASK_ENTRY( VLIMIT_NSOCK	) |
+	MASK_ENTRY( VLIMIT_OPENFD	) |
+	MASK_ENTRY( VLIMIT_ANON		) |
+	MASK_ENTRY( VLIMIT_SHMEM	) |
+	MASK_ENTRY( VLIMIT_DENTRY	) |
+	0
 };
 		/* accounting only */
 uint32_t account_mask =
-        MASK_ENTRY( VLIMIT_SEMARY	) |
-        MASK_ENTRY( VLIMIT_NSEMS	) |
+	MASK_ENTRY( VLIMIT_SEMARY	) |
+	MASK_ENTRY( VLIMIT_NSEMS	) |
 	0;
 
 
@@ -259,7 +259,7 @@ void vx_vsi_meminfo(struct sysinfo *val)
 	totalram = (v != RLIM_INFINITY) ? v : val->totalram;
 
 	/* total minus used equals free */
-	v = __rlim_get(&vxi->limit, RLIMIT_RSS);
+	v = __vx_cres_array_fixup(&vxi->limit, VLA_RSS);
 	freeram = (v < totalram) ? totalram - v : 0;
 
 	val->totalram = totalram;
@@ -287,7 +287,7 @@ void vx_vsi_swapinfo(struct sysinfo *val
 	totalswap = (w != RLIM_INFINITY) ? (w - v) : val->totalswap;
 
 	/* currently 'used' swap */
-	w = __rlim_get(&vxi->limit, RLIMIT_RSS);
+	w = __vx_cres_array_fixup(&vxi->limit, VLA_RSS);
 	w -= (w > v) ? v : w;
 
 	/* total minus used equals free */
@@ -298,3 +298,20 @@ void vx_vsi_swapinfo(struct sysinfo *val
 	return;
 }
 
+
+unsigned long vx_badness(struct task_struct *task, struct mm_struct *mm)
+{
+	struct vx_info *vxi = mm->mm_vx_info;
+	unsigned long points;
+	rlim_t v, w;
+
+	if (!vxi)
+		return 0;
+
+	v = __vx_cres_array_fixup(&vxi->limit, VLA_RSS);
+	w = __rlim_soft(&vxi->limit, RLIMIT_RSS);
+	points = (v > w) ? (v - w) : 0;
+
+	return points;
+}
+
--- linux-2.6.18.3-vs2.1.1.2/kernel/vserver/limit_proc.h	2006-09-25 15:40:02 +0200
+++ linux-2.6.18.3-vs2.1.1.2.3/kernel/vserver/limit_proc.h	2006-11-23 21:30:10 +0100
@@ -1,20 +1,23 @@
 #ifndef _VX_LIMIT_PROC_H
 #define _VX_LIMIT_PROC_H
 
+#include <linux/vserver/limit_int.h>
 
 static inline void vx_limit_fixup(struct _vx_limit *limit)
 {
 	rlim_t value;
-	int lim;
+	int res;
 
-	for (lim=0; lim<NUM_LIMITS; lim++) {
-		value = __rlim_get(limit, lim);
-		if (value > __rlim_rmax(limit, lim))
-			__rlim_rmax(limit, lim) = value;
-		if (value < __rlim_rmin(limit, lim))
-			__rlim_rmin(limit, lim) = value;
-		if (__rlim_rmax(limit, lim) > __rlim_hard(limit, lim))
-			__rlim_rmax(limit, lim) = __rlim_hard(limit, lim);
+	/* complex resources first */
+	__vx_cres_array_fixup(limit, VLA_RSS);
+
+	for (res=0; res<NUM_LIMITS; res++) {
+		value = __rlim_get(limit, res);
+		__vx_cres_fixup(limit, res, value);
+
+		/* not supposed to happen, maybe warn? */
+		if (__rlim_rmax(limit, res) > __rlim_hard(limit, res))
+			__rlim_rmax(limit, res) = __rlim_hard(limit, res);
 	}
 }
 
@@ -40,6 +43,7 @@ static inline int vx_info_proc_limit(str
 		"VML"	VX_LIMIT_FMT
 		"RSS"	VX_LIMIT_FMT
 		"ANON"	VX_LIMIT_FMT
+		"RMAP"	VX_LIMIT_FMT
 		"FILES" VX_LIMIT_FMT
 		"OFD"	VX_LIMIT_FMT
 		"LOCKS" VX_LIMIT_FMT
@@ -54,6 +58,7 @@ static inline int vx_info_proc_limit(str
 		VX_LIMIT_ARG(RLIMIT_MEMLOCK)
 		VX_LIMIT_ARG(RLIMIT_RSS)
 		VX_LIMIT_ARG(VLIMIT_ANON)
+		VX_LIMIT_ARG(VLIMIT_MAPPED)
 		VX_LIMIT_ARG(RLIMIT_NOFILE)
 		VX_LIMIT_ARG(VLIMIT_OPENFD)
 		VX_LIMIT_ARG(RLIMIT_LOCKS)
--- linux-2.6.18.3-vs2.1.1.2/mm/fremap.c	2006-09-20 17:01:45 +0200
+++ linux-2.6.18.3-vs2.1.1.2.3/mm/fremap.c	2006-11-26 19:43:50 +0100
@@ -75,7 +75,7 @@ int install_page(struct mm_struct *mm, s
 	err = -ENOMEM;
 	if (page_mapcount(page) > INT_MAX/2)
 		goto unlock;
-	if (!vx_rsspages_avail(mm, 1))
+	if (!vx_rss_avail(mm, 1))
 		goto unlock;
 
 	if (pte_none(*pte) || !zap_pte(mm, vma, addr, pte))
--- linux-2.6.18.3-vs2.1.1.2/mm/memory.c	2006-11-04 19:12:54 +0100
+++ linux-2.6.18.3-vs2.1.1.2.3/mm/memory.c	2006-11-23 23:13:42 +0100
@@ -497,6 +497,9 @@ static int copy_pte_range(struct mm_stru
 	int progress = 0;
 	int rss[2];
 
+	if (!vx_rss_avail(dst_mm, ((end - addr)/PAGE_SIZE + 1)))
+		return -ENOMEM;
+
 again:
 	rss[1] = rss[0] = 0;
 	dst_pte = pte_alloc_map_lock(dst_mm, dst_pmd, addr, &dst_ptl);
@@ -1965,7 +1968,7 @@ static int do_swap_page(struct mm_struct
 		grab_swap_token();
 	}
 
-	if (!vx_rsspages_avail(mm, 1)) {
+	if (!vx_rss_avail(mm, 1)) {
 		ret = VM_FAULT_OOM;
 		goto out;
 	}
@@ -2042,7 +2045,7 @@ static int do_anonymous_page(struct mm_s
 		/* Allocate our own private page. */
 		pte_unmap(page_table);
 
-		if (!vx_rsspages_avail(mm, 1))
+		if (!vx_rss_avail(mm, 1))
 			goto oom;
 		if (unlikely(anon_vma_prepare(vma)))
 			goto oom;
@@ -2116,15 +2119,15 @@ static int do_no_page(struct mm_struct *
 	pte_unmap(page_table);
 	BUG_ON(vma->vm_flags & VM_PFNMAP);
 
+	if (!vx_rss_avail(mm, 1))
+		return VM_FAULT_OOM;
+
 	if (vma->vm_file) {
 		mapping = vma->vm_file->f_mapping;
 		sequence = mapping->truncate_count;
 		smp_rmb(); /* serializes i_size against truncate_count */
 	}
 retry:
-	/* FIXME: is that check useful here? */
-	if (!vx_rsspages_avail(mm, 1))
-		return VM_FAULT_OOM;
 	new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, &ret);
 	/*
 	 * No smp_rmb is needed here as long as there's a full
--- linux-2.6.18.3-vs2.1.1.2/mm/oom_kill.c	2006-11-07 05:55:55 +0100
+++ linux-2.6.18.3-vs2.1.1.2.3/mm/oom_kill.c	2006-11-27 03:01:40 +0100
@@ -21,6 +21,7 @@
 #include <linux/timex.h>
 #include <linux/jiffies.h>
 #include <linux/cpuset.h>
+#include <linux/vs_memory.h>
 
 int sysctl_panic_on_oom;
 /* #define DEBUG */
@@ -62,13 +63,17 @@ unsigned long badness(struct task_struct
 	 */
 	points = mm->total_vm;
 
+	/*
+	 * add points for context badness
+	 */
+
+	points += vx_badness(p, mm);
+
 	/*
 	 * After this unlock we can no longer dereference local variable `mm'
 	 */
 	task_unlock(p);
 
-	/* FIXME: add vserver badness ;) */
-
 	/*
 	 * Processes which fork a lot of child processes are likely
 	 * a good choice. We add half the vmsize of the children if they
