--- linux-2.6.11-rc1/fs/fcntl.c	2004-12-25 01:55:20 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/fcntl.c	2005-01-15 11:27:52 +0100
@@ -108,6 +109,8 @@ repeat:
 	error = -EMFILE;
 	if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
 		goto out;
+	if (!vx_files_avail(1))
+		goto out;
 
 	error = expand_files(files, newfd);
 	if (error < 0)
--- linux-2.6.11-rc1/fs/fcntl.c	2004-12-25 01:55:20 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/fcntl.c	2005-01-15 11:27:52 +0100
@@ -140,6 +143,7 @@ static int dupfd(struct file *file, unsi
 		FD_SET(fd, files->open_fds);
 		FD_CLR(fd, files->close_on_exec);
 		spin_unlock(&files->file_lock);
+		// vx_openfd_inc(fd);
 		fd_install(fd, file);
 	} else {
 		spin_unlock(&files->file_lock);
--- linux-2.6.11-rc1/fs/fcntl.c	2004-12-25 01:55:20 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/fcntl.c	2005-01-15 11:27:52 +0100
@@ -187,6 +191,7 @@ asmlinkage long sys_dup2(unsigned int ol
 	FD_SET(newfd, files->open_fds);
 	FD_CLR(newfd, files->close_on_exec);
 	spin_unlock(&files->file_lock);
+	// vx_openfd_inc(newfd);
 
 	if (tofree)
 		filp_close(tofree, files);
--- linux-2.6.11-rc1/fs/file_table.c	2005-01-14 12:35:55 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/file_table.c	2005-01-15 11:27:52 +0100
@@ -85,6 +87,9 @@ static int old_max;
 			rwlock_init(&f->f_owner.lock);
 			/* f->f_version: 0 */
 			INIT_LIST_HEAD(&f->f_list);
+			// set_vx_info(&f->f_vx_info, current->vx_info);
+			f->f_xid = vx_current_xid();
+			vx_files_inc(f);
 			return f;
 		}
 	}
--- linux-2.6.11-rc1/fs/file_table.c	2005-01-14 12:35:55 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/file_table.c	2005-01-15 11:27:52 +0100
@@ -137,6 +142,8 @@ void fastcall __fput(struct file *file)
 	fops_put(file->f_op);
 	if (file->f_mode & FMODE_WRITE)
 		put_write_access(inode);
+	vx_files_dec(file);
+	file->f_xid = 0;
 	file_kill(file);
 	file->f_dentry = NULL;
 	file->f_vfsmnt = NULL;
--- linux-2.6.11-rc1/fs/file_table.c	2005-01-14 12:35:55 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/file_table.c	2005-01-15 11:27:52 +0100
@@ -192,6 +199,8 @@ void put_filp(struct file *file)
 {
 	if (atomic_dec_and_test(&file->f_count)) {
 		security_file_free(file);
+		vx_files_dec(file);
+		file->f_xid = 0;
 		file_kill(file);
 		file_free(file);
 	}
--- linux-2.6.11-rc1/fs/open.c	2005-01-14 12:35:55 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/open.c	2005-01-15 11:27:52 +0100
@@ -880,6 +886,7 @@ repeat:
 	FD_SET(fd, files->open_fds);
 	FD_CLR(fd, files->close_on_exec);
 	files->next_fd = fd + 1;
+	// vx_openfd_inc(fd);
 #if 1
 	/* Sanity check */
 	if (files->fd[fd] != NULL) {
--- linux-2.6.11-rc1/fs/open.c	2005-01-14 12:35:55 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/fs/open.c	2005-01-15 11:27:52 +0100
@@ -901,6 +908,7 @@ static inline void __put_unused_fd(struc
 	__FD_CLR(fd, files->open_fds);
 	if (fd < files->next_fd)
 		files->next_fd = fd;
+	// vx_openfd_dec(fd);
 }
 
 void fastcall put_unused_fd(unsigned int fd)
--- linux-2.6.11-rc1/include/linux/vserver/limit.h	1970-01-01 01:00:00 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/include/linux/vserver/limit.h	2005-01-15 11:27:52 +0100
@@ -0,0 +1,20 @@
+#ifndef _VX_LIMIT_H
+#define _VX_LIMIT_H
+
+#ifdef	__KERNEL__
+
+struct sysinfo;
+
+void vx_vsi_meminfo(struct sysinfo *);
+void vx_vsi_swapinfo(struct sysinfo *);
+
+#define VXD_RLIMIT(r,l)		(VXD_CBIT(limit, (l)) && ((r) == (l)))
+
+#define NUM_LIMITS	20
+
+#define VLIMIT_NSOCK	16
+
+extern const char *vlimit_name[NUM_LIMITS];
+
+#endif	/* __KERNEL__ */
+#endif	/* _VX_LIMIT_H */
--- linux-2.6.11-rc1/kernel/exit.c	2005-01-14 12:36:00 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/kernel/exit.c	2005-01-15 11:27:52 +0100
@@ -40,6 +41,11 @@ int getrusage(struct task_struct *, int,
 static void __unhash_process(struct task_struct *p)
 {
 	nr_threads--;
+	/* tasklist_lock is held, is this sufficient? */
+	if (p->vx_info) {
+		atomic_dec(&p->vx_info->cvirt.nr_threads);
+		vx_nproc_dec(p);
+	}
 	detach_pid(p, PIDTYPE_PID);
 	detach_pid(p, PIDTYPE_TGID);
 	if (thread_group_leader(p)) {
--- linux-2.6.11-rc1/kernel/exit.c	2005-01-14 12:36:00 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/kernel/exit.c	2005-01-15 11:27:52 +0100
@@ -372,6 +379,7 @@ static inline void close_files(struct fi
 				struct file * file = xchg(&files->fd[i], NULL);
 				if (file)
 					filp_close(file, files);
+				// vx_openfd_dec(i);
 			}
 			i++;
 			set >>= 1;
--- linux-2.6.11-rc1/kernel/fork.c	2005-01-14 12:36:00 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/kernel/fork.c	2005-01-15 12:42:27 +0100
@@ -1036,6 +1065,12 @@ static task_t *copy_process(unsigned lon
 
 	nr_threads++;
 	total_forks++;
+	/* p is copy of current */
+	vxi = p->vx_info;
+	if (vxi) {
+		atomic_inc(&vxi->cvirt.nr_threads);
+		vx_nproc_inc(p);
+	}
 	write_unlock_irq(&tasklist_lock);
 	retval = 0;
 
--- linux-2.6.11-rc1/kernel/sys.c	2005-01-14 12:36:01 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/kernel/sys.c	2005-01-15 12:54:14 +0100
@@ -1489,7 +1509,7 @@ asmlinkage long sys_setrlimit(unsigned i
                return -EINVAL;
 	old_rlim = current->signal->rlim + resource;
 	if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
-	    !capable(CAP_SYS_RESOURCE))
+	    !capable(CAP_SYS_RESOURCE) && !vx_ccaps(VXC_SET_RLIMIT))
 		return -EPERM;
 	if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > NR_OPEN)
 			return -EPERM;
--- linux-2.6.11-rc1/kernel/vserver/limit.c	1970-01-01 01:00:00 +0100
+++ linux-2.6.11-rc1-vs1.9.4-rc2/kernel/vserver/limit.c	2005-01-15 11:27:52 +0100
@@ -0,0 +1,165 @@
+/*
+ *  linux/kernel/vserver/limit.c
+ *
+ *  Virtual Server: Context Limits
+ *
+ *  Copyright (C) 2004  Herbert Pötzl
+ *
+ *  V0.01  broken out from vcontext V0.05
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/vs_context.h>
+#include <linux/vs_limit.h>
+#include <linux/vserver/limit.h>
+#include <linux/vserver/switch.h>
+#include <linux/vserver/limit_cmd.h>
+
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+
+const char *vlimit_name[NUM_LIMITS] = {
+	[RLIMIT_CPU]		= "CPU",
+	[RLIMIT_RSS]		= "RSS",
+	[RLIMIT_NPROC]		= "NPROC",
+	[RLIMIT_NOFILE]	= "NOFILE",
+	[RLIMIT_MEMLOCK]	= "VML",
+	[RLIMIT_AS]		= "VM",
+	[RLIMIT_LOCKS]		= "LOCKS",
+	[RLIMIT_MSGQUEUE]	= "MSGQ",
+	[VLIMIT_NSOCK]		= "NSOCK",
+};
+
+EXPORT_SYMBOL_GPL(vlimit_name);
+
+
+static int is_valid_rlimit(int id)
+{
+	int valid = 0;
+
+	switch (id) {
+		case RLIMIT_NPROC:
+		case RLIMIT_AS:
+		case RLIMIT_RSS:
+		case RLIMIT_MEMLOCK:
+		case RLIMIT_NOFILE:
+			valid = 1;
+			break;
+	}
+	return valid;
+}
+
+static inline uint64_t vc_get_rlim(struct vx_info *vxi, int id)
+{
+	unsigned long limit;
+
+	limit = vxi->limit.rlim[id];
+	if (limit == RLIM_INFINITY)
+		return CRLIM_INFINITY;
+	return limit;
+}
+
+int vc_get_rlimit(uint32_t id, void __user *data)
+{
+	struct vx_info *vxi;
+	struct vcmd_ctx_rlimit_v0 vc_data;
+
+	if (copy_from_user (&vc_data, data, sizeof(vc_data)))
+		return -EFAULT;
+	if (!is_valid_rlimit(vc_data.id))
+		return -ENOTSUPP;
+
+	vxi = locate_vx_info(id);
+	if (!vxi)
+		return -ESRCH;
+
+	vc_data.maximum = vc_get_rlim(vxi, vc_data.id);
+	vc_data.minimum = CRLIM_UNSET;
+	vc_data.softlimit = CRLIM_UNSET;
+	put_vx_info(vxi);
+
+	if (copy_to_user (data, &vc_data, sizeof(vc_data)))
+		return -EFAULT;
+	return 0;
+}
+
+int vc_set_rlimit(uint32_t id, void __user *data)
+{
+	struct vx_info *vxi;
+	struct vcmd_ctx_rlimit_v0 vc_data;
+
+	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
+		return -EPERM;
+	if (copy_from_user (&vc_data, data, sizeof(vc_data)))
+		return -EFAULT;
+	if (!is_valid_rlimit(vc_data.id))
+		return -ENOTSUPP;
+
+	vxi = locate_vx_info(id);
+	if (!vxi)
+		return -ESRCH;
+
+	if (vc_data.maximum != CRLIM_KEEP)
+		vxi->limit.rlim[vc_data.id] = vc_data.maximum;
+	put_vx_info(vxi);
+
+	return 0;
+}
+
+int vc_get_rlimit_mask(uint32_t id, void __user *data)
+{
+	static struct vcmd_ctx_rlimit_mask_v0 mask = {
+			/* minimum */
+		0
+		,	/* softlimit */
+		0
+		,	/* maximum */
+		(1 << RLIMIT_NPROC) |
+		(1 << RLIMIT_NOFILE) |
+		(1 << RLIMIT_MEMLOCK) |
+		(1 << RLIMIT_AS) |
+		(1 << RLIMIT_RSS)
+		};
+
+	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
+		return -EPERM;
+	if (copy_to_user(data, &mask, sizeof(mask)))
+		return -EFAULT;
+	return 0;
+}
+
+
+void vx_vsi_meminfo(struct sysinfo *val)
+{
+	struct vx_info *vxi = current->vx_info;
+	unsigned long v;
+
+	v = vxi->limit.rlim[RLIMIT_RSS];
+	if (v != RLIM_INFINITY)
+		val->totalram = min(val->totalram, v);
+	v = atomic_read(&vxi->limit.rcur[RLIMIT_RSS]);
+	val->freeram = (v < val->totalram) ? val->totalram - v : 0;
+	val->bufferram = 0;
+	val->totalhigh = 0;
+	val->freehigh = 0;
+	return;
+}
+
+void vx_vsi_swapinfo(struct sysinfo *val)
+{
+	struct vx_info *vxi = current->vx_info;
+	unsigned long v, w;
+
+	v = vxi->limit.rlim[RLIMIT_RSS];
+	w = vxi->limit.rlim[RLIMIT_AS];
+	if (w != RLIM_INFINITY)
+		val->totalswap = min(val->totalswap, w -
+		((v != RLIM_INFINITY) ? v : 0));
+	w = atomic_read(&vxi->limit.rcur[RLIMIT_AS]);
+	val->freeswap = (w < val->totalswap) ? val->totalswap - w : 0;
+	return;
+}
+
