diff -NurpP --minimal linux-2.4.23-vs1.3.2/Makefile linux-2.4.23-vs1.3.3/Makefile
--- linux-2.4.23-vs1.3.2/Makefile	Sun Dec 28 01:47:15 2003
+++ linux-2.4.23-vs1.3.3/Makefile	Sun Jan  4 05:29:57 2004
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 23
-EXTRAVERSION = -vs1.3.2
+EXTRAVERSION = -vs1.3.3
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -NurpP --minimal linux-2.4.23-vs1.3.2/fs/proc/array.c linux-2.4.23-vs1.3.3/fs/proc/array.c
--- linux-2.4.23-vs1.3.2/fs/proc/array.c	Sun Dec 28 01:47:15 2003
+++ linux-2.4.23-vs1.3.3/fs/proc/array.c	Sun Jan  4 05:29:57 2004
@@ -287,6 +287,7 @@ int proc_pid_status(struct task_struct *
 	char * orig = buffer;
 	struct mm_struct *mm;
 	struct vx_info *vxi;
+	struct ip_info *ipi;
 
 	buffer = task_name(task, buffer);
 	buffer = task_state(task, buffer);
@@ -319,25 +320,26 @@ int proc_pid_status(struct task_struct *
 		buffer += sprintf (buffer,"initpid: none\n");
 	}
 	put_vx_info(vxi);
-
-	if (task->ip_info) {
+	ipi = task_get_ip_info(task);
+	if (ipi) {
 		int i;
 
 		buffer += sprintf (buffer,"ipv4root:");
-		for (i=0; i<task->ip_info->nbipv4; i++){
+		for (i=0; i<ipi->nbipv4; i++){
 			buffer += sprintf (buffer," %08x/%08x"
-				,task->ip_info->ipv4[i]
-				,task->ip_info->mask[i]);
+				,ipi->ipv4[i]
+				,ipi->mask[i]);
 		}
 		*buffer++ = '\n';
 		buffer += sprintf (buffer,"ipv4root_bcast: %08x\n"
-			,task->ip_info->v4_bcast);
+			,ipi->v4_bcast);
 		buffer += sprintf (buffer,"ipv4root_refcnt: %d\n"
-			,atomic_read(&task->ip_info->ip_refcount));
+			,atomic_read(&ipi->ip_refcount));
 	} else {
 		buffer += sprintf (buffer,"ipv4root: 0\n");
 		buffer += sprintf (buffer,"ipv4root_bcast: 0\n");
 	}
+	put_ip_info(ipi);
 #if defined(CONFIG_ARCH_S390)
 	buffer = task_show_regs(task, buffer);
 #endif
@@ -391,9 +393,10 @@ int proc_pid_stat(struct task_struct *ta
 
 	read_lock(&tasklist_lock);
 	ppid = task->pid ? task->p_opptr->pid : 0;
-	if (current->vx_info && current->vx_info->vx_initpid == ppid)
-		ppid = 1;
 	read_unlock(&tasklist_lock);
+	if (current->vx_info &&
+		current->vx_info->vx_initpid == ppid)
+		ppid = 1;
 	res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
 %lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
diff -NurpP --minimal linux-2.4.23-vs1.3.2/fs/proc/virtual.c linux-2.4.23-vs1.3.3/fs/proc/virtual.c
--- linux-2.4.23-vs1.3.2/fs/proc/virtual.c	Sun Dec 28 01:47:15 2003
+++ linux-2.4.23-vs1.3.3/fs/proc/virtual.c	Sun Jan  4 05:29:57 2004
@@ -8,6 +8,7 @@
  *  V0.01  basic structure
  *  V0.02  adaptation vs1.3.0
  *  V0.03  proc permissions
+ *  V0.04  locking/generic
  *
  */
 
@@ -23,26 +24,32 @@
 
 extern struct proc_dir_entry *proc_virtual;
 
-struct proc_dir_entry *proc_virtual_info;
+static struct proc_dir_entry *proc_virtual_info;
 
 
-char *vx_proc_info (struct vx_info *info, char *buffer)
+char *task_vinfo(struct task_struct *p, char *buffer)
 {
-	buffer += sprintf(buffer,
-		"ID:\t%d\n"
-		"Info:\t%p\n"
-		"Init:\t%d\n"
-		,info->vx_id
-		,info, info->vx_initpid);
-	return buffer;
+	return buffer + sprintf(buffer,
+		"VxID:\t%d\n"
+		,p->vx_id);
 }
 
-int vx_info_read_func (char *page, char **start, off_t off, int count, int *eof, void *data)
+int proc_pid_vinfo(struct task_struct *p, char *buffer)
+{
+	char * orig = buffer;
+
+        buffer = task_vinfo(p, buffer);
+        return buffer - orig;
+}
+
+static int __generic_info_read_func(char *page, char **start,
+	off_t off, int count, int *eof, void *data,
+	char *(*info_func)(void *, char *))
 {
 	int len;
 	char *buffer = page;
-	
-	buffer = vx_proc_info(data, buffer);
+
+	buffer = info_func(data, buffer);
 
 	len = buffer-page;
 	if (len <= off+count) *eof = 1;
@@ -54,35 +61,79 @@ int vx_info_read_func (char *page, char 
 	return len;
 }
 
-char *vx_proc_status (struct vx_info *info, char *buffer)
+
+char *vx_proc_info (void *data, char *buffer)
 {
-	buffer += sprintf(buffer,
+	struct vx_info *vxi = find_vx_info((int)data);
+	if (vxi)
+		buffer += sprintf(buffer,
+		"ID:\t%d\n"
+		"Info:\t%p\n"
+		"Init:\t%d\n"
+		,vxi->vx_id
+		,vxi
+		,vxi->vx_initpid);
+	put_vx_info(vxi);
+	return buffer;
+}
+
+int vx_info_read_func (char *page, char **start,
+	off_t off, int count, int *eof, void *data)
+{
+	return __generic_info_read_func(page, start,
+	    off, count, eof, data, vx_proc_info);
+}
+
+
+char *vx_proc_status (void *data, char *buffer)
+{
+	struct vx_info *vxi = find_vx_info((int)data);
+	if (vxi)
+		buffer += sprintf(buffer,
 		"RefC:\t%d\n"		
 		"Flags:\t%08x\n"
 		"Ticks:\t%d\n"		
-		,atomic_read(&info->vx_refcount)
-		,info->vx_flags
-		,atomic_read(&info->limit.ticks));
+		,atomic_read(&vxi->vx_refcount)
+		,vxi->vx_flags
+		,atomic_read(&vxi->limit.ticks));
+	put_vx_info(vxi);
 	return buffer;
 }
 
-int vx_status_read_func (char *page, char **start, off_t off, int count, int *eof, void *data)
+int vx_status_read_func (char *page, char **start,
+	off_t off, int count, int *eof, void *data)
 {
-	int len;
-	char *buffer = page;
-	
-	buffer = vx_proc_status(data, buffer);
+	return __generic_info_read_func(page, start,
+	    off, count, eof, data, vx_proc_status);
+}
 
-	len = buffer-page;
-	if (len <= off+count) *eof = 1;
-	
-	*start = page + off;
-	len -= off;
-	if (len>count) len = count;
-	if (len<0) len = 0;
-	return len;
+
+char *vx_proc_limit (void *data, char *buffer)
+{
+	struct vx_info *vxi = find_vx_info((int)data);
+	if (vxi)
+		buffer += sprintf(buffer,
+		"VM:\t%8d/%ld\n"
+		"VML:\t%8d/%ld\n"		
+		"RSS:\t%8d/%ld\n"
+		,atomic_read(&vxi->limit.res[RLIMIT_AS])
+		,vxi->limit.rlim[RLIMIT_AS]
+		,atomic_read(&vxi->limit.res[RLIMIT_MEMLOCK])
+		,vxi->limit.rlim[RLIMIT_MEMLOCK]
+		,atomic_read(&vxi->limit.res[RLIMIT_RSS])
+		,vxi->limit.rlim[RLIMIT_RSS]);
+	put_vx_info(vxi);
+	return buffer;
 }
 
+int vx_limit_read_func (char *page, char **start,
+	off_t off, int count, int *eof, void *data)
+{
+	return __generic_info_read_func(page, start,
+	    off, count, eof, data, vx_proc_limit);
+}
+
+
 static int vx_proc_permission(struct inode *inode, int mask)
 {
 	vxdprintk("vx_proc_permission(%p) = #%d,%04x\n",
@@ -100,37 +151,60 @@ static struct inode_operations vx_proc_i
 };
 
 
-int vx_proc_create(struct vx_info *info)
+int vx_proc_create(struct vx_info *vxi)
 {
 	struct proc_dir_entry *entry, *sub;
 	char name[8];
 
-	snprintf(name, sizeof(name)-1, "%d", info->vx_id);
+	snprintf(name, sizeof(name)-1, "%d", vxi->vx_id);
 	entry = create_proc_entry(name,
 		S_IFDIR|S_IXUGO, proc_virtual);
+	if (!entry)
+		goto no_entry;
 	entry->vx_flags = VX_ADMIN|VX_WATCH|VX_IDENT;
-	entry->xid = info->vx_id;
+	entry->xid = vxi->vx_id;
 	entry->proc_iops = &vx_proc_inode_operations;
-	info->vx_procent = entry;
+	vxi->vx_procent = entry;
 	sub = create_proc_read_entry("info",
 		S_IFREG|S_IRUGO|S_IWUSR,
-		entry, vx_info_read_func, info);
+		entry, vx_info_read_func, (void *)vxi->vx_id);
+	if (!sub)
+		goto no_info;
 	sub = create_proc_read_entry("status",
 		S_IFREG|S_IRUGO|S_IWUSR,
-		entry, vx_status_read_func, info);
+		entry, vx_status_read_func, (void *)vxi->vx_id);
+	if (!sub)
+		goto no_status;
+	sub = create_proc_read_entry("limit",
+		S_IFREG|S_IRUGO|S_IWUSR,
+		entry, vx_limit_read_func, (void *)vxi->vx_id);
+	if (!sub)
+		goto no_limit;
 	return 0;
+no_limit:
+	remove_proc_entry("status", entry);
+no_status:
+	remove_proc_entry("info", entry);
+no_info:
+	remove_proc_entry(name, proc_virtual);
+no_entry:
+	return -ENOMEM;
 }
 
-int vx_proc_destroy(struct vx_info *info)
+int vx_proc_destroy(struct vx_info *vxi)
 {
-	struct proc_dir_entry *entry = info->vx_procent;
+	struct proc_dir_entry *entry = vxi->vx_procent;
 	if (!entry)
 		return 0;
+	vxi->vx_procent = NULL;
+	remove_proc_entry("limit", entry);
+	remove_proc_entry("status", entry);
+	remove_proc_entry("info", entry);
 	remove_proc_entry(entry->name, proc_virtual);
-	info->vx_procent = NULL;
 	return 0;
 }
 
+
 char *vs_proc_info(void *data, char *buffer)
 {
 	buffer += sprintf(buffer,
@@ -140,21 +214,11 @@ char *vs_proc_info(void *data, char *buf
 	return buffer;
 }
 
-int vs_info_read_func(char *page, char **start, off_t off, int count, int *eof, void *data)
+int vs_info_read_func(char *page, char **start,
+	off_t off, int count, int *eof, void *data)
 {
-	int len;
-	char *buffer = page;
-	
-	buffer = vs_proc_info(data, buffer);
-
-	len = buffer-page;
-	if (len <= off+count) *eof = 1;
-	
-	*start = page + off;
-	len -= off;
-	if (len>count) len = count;
-	if (len<0) len = 0;
-	return len;
+	return __generic_info_read_func(page, start,
+	    off, count, eof, data, vs_proc_info);
 }
 
 
diff -NurpP --minimal linux-2.4.23-vs1.3.2/include/linux/vcontext.h linux-2.4.23-vs1.3.3/include/linux/vcontext.h
--- linux-2.4.23-vs1.3.2/include/linux/vcontext.h	Fri Jan  2 20:28:54 2004
+++ linux-2.4.23-vs1.3.3/include/linux/vcontext.h	Sun Jan  4 05:30:46 2004
@@ -109,6 +109,8 @@ struct ip_info {
 extern spinlock_t iplist_lock;
 extern struct list_head ip_infos;
 
+extern struct vx_info *find_vx_info(int);
+
 int vc_new_s_context(uint32_t, void *);
 int vc_set_ipv4root(uint32_t, void *);
 
diff -NurpP --minimal linux-2.4.23-vs1.3.2/include/linux/vinline.h linux-2.4.23-vs1.3.3/include/linux/vinline.h
--- linux-2.4.23-vs1.3.2/include/linux/vinline.h	Sat Jan  3 08:08:40 2004
+++ linux-2.4.23-vs1.3.3/include/linux/vinline.h	Sun Jan  4 05:32:04 2004
@@ -17,6 +17,7 @@
 void free_vx_info(struct vx_info *);
 
 extern int proc_pid_vinfo(struct task_struct *, char *);
+extern int vx_proc_destroy(struct vx_info *);
 
 
 #define get_vx_info(i)	__get_vx_info(i,__FILE__,__LINE__)
@@ -44,6 +45,7 @@ static __inline__ void __put_vx_info(str
 		vxi->vx_id, atomic_read(&vxi->vx_refcount),
 		_file, _line);
 	if (atomic_dec_and_lock(&vxi->vx_refcount, &vxlist_lock)) {
+		vx_proc_destroy(vxi);
 		list_del(&vxi->vx_list);
 		spin_unlock(&vxlist_lock);
 		free_vx_info(vxi);
diff -NurpP --minimal linux-2.4.23-vs1.3.2/kernel/fork.c linux-2.4.23-vs1.3.3/kernel/fork.c
--- linux-2.4.23-vs1.3.2/kernel/fork.c	Sun Dec 28 01:47:15 2003
+++ linux-2.4.23-vs1.3.3/kernel/fork.c	Sun Jan  4 05:29:57 2004
@@ -640,6 +640,7 @@ int do_fork(unsigned long clone_flags, u
 	int retval;
 	struct task_struct *p;
 	struct completion vfork;
+	struct vx_info *vxi;
 
 	if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
 		return -EINVAL;
@@ -661,11 +662,12 @@ int do_fork(unsigned long clone_flags, u
 		goto fork_out;
 
 	retval = -EAGAIN;
+	vxi = get_vx_info(current->vx_info);
+	get_ip_info(current->ip_info);
 	*p = *current;
 
-	if (p->vx_info &&
-		(atomic_read(&p->vx_info->limit.res[RLIMIT_NPROC])
-		>= p->vx_info->limit.rlim[RLIMIT_NPROC]))
+	if (vxi && (atomic_read(&vxi->limit.res[RLIMIT_NPROC])
+		>= vxi->limit.rlim[RLIMIT_NPROC]))
 		goto bad_fork_free;
 	/*
 	 * Check if we are over our maximum process limit, but be sure to
@@ -677,16 +679,6 @@ int do_fork(unsigned long clone_flags, u
 	              && !capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE))
 		goto bad_fork_free;
 
-	if (current->vx_info)
-		p->vx_info = get_vx_info(current->vx_info);
-	else
-		p->vx_info = NULL;
-	p->vx_id = vx_current_id();
-	if (current->ip_info)
-		p->ip_info = get_ip_info(current->ip_info);
-	else
-		p->ip_info = NULL;
-
 	atomic_inc(&p->user->__count);
 	atomic_inc(&p->user->processes);
 
@@ -821,9 +813,9 @@ int do_fork(unsigned long clone_flags, u
 	SET_LINKS(p);
 	hash_pid(p);
 	nr_threads++;
-	if (p->vx_info) {
-		p->vx_info->virt.nr_threads++;
-		atomic_inc(&p->vx_info->limit.res[RLIMIT_NPROC]);
+	if (vxi) {
+		vxi->virt.nr_threads++;
+		atomic_inc(&vxi->limit.res[RLIMIT_NPROC]);
 	}
 	write_unlock_irq(&tasklist_lock);
 
@@ -832,8 +824,8 @@ int do_fork(unsigned long clone_flags, u
 
 	wake_up_process(p);		/* do this last */
 	++total_forks;
-	if (p->vx_info)
-		p->vx_info->virt.total_forks++;
+	if (vxi)
+		vxi->virt.total_forks++;
 	if (clone_flags & CLONE_VFORK)
 		wait_for_completion(&vfork);
 
@@ -858,6 +850,8 @@ bad_fork_cleanup_count:
 	atomic_dec(&p->user->processes);
 	free_uid(p->user);
 bad_fork_free:
+	put_ip_info(current->ip_info);
+	put_vx_info(vxi);
 	free_task_struct(p);
 	goto fork_out;
 }
diff -NurpP --minimal linux-2.4.23-vs1.3.2/kernel/vcontext.c linux-2.4.23-vs1.3.3/kernel/vcontext.c
--- linux-2.4.23-vs1.3.2/kernel/vcontext.c	Sun Dec 28 01:47:15 2003
+++ linux-2.4.23-vs1.3.3/kernel/vcontext.c	Sun Jan  4 05:29:57 2004
@@ -32,7 +32,7 @@ int vc_ctx_kill(uint32_t id, void *data)
 	struct vcmd_ctx_kill_v0 vc_data;
 	struct siginfo info;
 	struct task_struct *p;
-	pid_t initpid = 0;
+	struct vx_info *vxi;
 
 	if (copy_from_user (&vc_data, data, sizeof(vc_data)))
 		return -EFAULT;
@@ -45,23 +45,27 @@ int vc_ctx_kill(uint32_t id, void *data)
 	info.si_pid = current->pid;
 	info.si_uid = current->uid;
 
+	vxi = find_vx_info(id);
+	if (!vxi)
+		return -ESRCH;
+
 	retval = -ESRCH;
 	read_lock(&tasklist_lock);
 	switch (vc_data.pid) {
 	case -1:
 	case  0:
 		for_each_task(p) {
-			if (!initpid && vx_task_id(p) == id && p->vx_info)
-				initpid = p->vx_info->vx_initpid;
-			if (vx_task_id(p) == id  && p->pid > 1
-				&& (!vc_data.pid || initpid != p->pid)
-				&& thread_group_leader(p)) {
-				int err = send_sig_info(vc_data.sig, &info, p);
+			int err = 0;
 
-				++count;
-				if (err != -EPERM)
-					retval = err;
-			}
+			if (vx_task_id(p) != id || p->pid <= 1 ||
+				(vc_data.pid && vxi->vx_initpid == p->pid) ||
+				!thread_group_leader(p))
+				continue;
+
+			err = send_sig_info(vc_data.sig, &info, p);
+			++count;
+			if (err != -EPERM)
+				retval = err;
 		}
 		break;
 		
@@ -81,6 +85,7 @@ int vc_ctx_kill(uint32_t id, void *data)
 		break;
 	}
 	read_unlock(&tasklist_lock);
+	put_vx_info(vxi);
 	return retval;
 }
 
@@ -117,6 +122,7 @@ spinlock_t vxlist_lock
 static struct vx_info *alloc_vx_info(int id)
 {
 	struct vx_info *new = NULL;
+	int lim;
 	
 	vxdprintk("alloc_vx_info(%d)\n", id);
 	/* would this benefit from a slab cache? */
@@ -126,8 +132,12 @@ static struct vx_info *alloc_vx_info(int
 
 	memset (new, 0, sizeof(struct vx_info));
 	new->vx_id = id;
+	INIT_LIST_HEAD(&new->vx_list);
 	/* rest of init goes here */
 	
+	for (lim=0; lim<RLIM_NLIMITS; lim++)
+		new->limit.rlim[lim] = RLIM_INFINITY;
+	
 	atomic_set(&new->limit.ticks, current->counter);
 	new->virt.nr_threads = 1;
 	new->virt.bias_cswtch = kstat.context_swtch;
@@ -142,12 +152,9 @@ static struct vx_info *alloc_vx_info(int
 	return new;
 }
 
-extern int vx_proc_destroy(struct vx_info *);
-
 void free_vx_info(struct vx_info *vxi)
 {
 	vxdprintk("free_vx_info(%p)\n", vxi);
-	vx_proc_destroy(vxi);
 	kfree(vxi);
 }
 
@@ -172,7 +179,7 @@ static __inline__ struct vx_info *__find
  *	struct vx_info ref stuff
  */
 
-static struct vx_info *find_vx_info(int id)
+struct vx_info *find_vx_info(int id)
 {
 	struct vx_info *vxi;
 	
@@ -235,8 +242,10 @@ static struct vx_info *find_or_create_vx
 	/* new context requested */
 	vxdprintk("find_or_create_vx_info(%d) = %p (new)\n", id, vxi);
 	atomic_set(&new->vx_refcount, 1);
+	if (vx_proc_create(new))
+		/* failed to create proc entry */
+		goto out_unlock;
 	list_add(&new->vx_list, &vx_infos);
-	vx_proc_create(new);
 	vxi = new, new = NULL;
 
 out_unlock:
@@ -275,7 +284,7 @@ static int vx_migrate_user(struct task_s
 
 static int vx_migrate_task(struct task_struct *p, struct vx_info *vxi)
 {
-	struct vx_info *old_vxi;
+	struct vx_info *old_vxi = task_get_vx_info(p);
 	int ret = 0;
 	
 	if (!p || !vxi)
@@ -284,7 +293,7 @@ static int vx_migrate_task(struct task_s
 	vxdprintk("vx_migrate_task(%p,%p[#%d.%d)\n", p, vxi,
 		vxi->vx_id, atomic_read(&vxi->vx_refcount));
 	spin_lock(&p->alloc_lock);
-	if ((old_vxi = p->vx_info) == vxi)
+	if (old_vxi == vxi)
 		goto out;
 
 	if (!(ret = vx_migrate_user(p, vxi))) {
@@ -298,6 +307,7 @@ static int vx_migrate_task(struct task_s
 	}
 out:
 	spin_unlock(&p->alloc_lock);
+	put_vx_info(old_vxi);
 	return ret;
 }
 
@@ -316,7 +326,7 @@ static int vx_set_initpid(struct vx_info
 
 int vc_new_s_context(uint32_t ctx, void *data)
 {
-	int ret = -EPERM;
+	int ret = -ENOMEM;
 	struct vcmd_new_s_context_v1 vc_data;
 	struct vx_info *new_vxi;
 
@@ -364,6 +374,9 @@ int vc_new_s_context(uint32_t ctx, void 
 		new_vxi->vx_flags |= vc_data.flags;
 		if (vc_data.flags & VX_INFO_INIT)
 			vx_set_initpid(new_vxi, current->tgid);
+		if (vc_data.flags & VX_INFO_NPROC)
+			new_vxi->limit.rlim[RLIMIT_NPROC] =
+				current->rlim[RLIMIT_NPROC].rlim_max;
 		ret = new_vxi->vx_id;
 	}
 	put_vx_info(new_vxi);
