diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/etc/mtree/BSD.include.dist head/etc/mtree/BSD.include.dist
--- clean-head/etc/mtree/BSD.include.dist	2013-06-26 09:35:06.000000000 +0200
+++ head/etc/mtree/BSD.include.dist	2013-06-24 14:20:21.000000000 +0200
@@ -335,6 +335,8 @@
     ..
     vm
     ..
+    vps
+    ..
     xlocale
     ..
 ..
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/include/Makefile head/include/Makefile
--- clean-head/include/Makefile	2013-06-26 09:40:39.000000000 +0200
+++ head/include/Makefile	2013-06-24 14:20:20.000000000 +0200
@@ -39,7 +39,7 @@ LHDRS=	aio.h errno.h fcntl.h linker_set.
 LDIRS=	bsm cam geom net net80211 netatalk netgraph netinet netinet6 \
 	netipsec ${_netipx} netnatm \
 	nfs nfsclient nfsserver \
-	sys vm
+	sys vm vps
 
 LSUBDIRS=	cam/ata cam/scsi \
 	dev/acpica dev/agp dev/an dev/bktr dev/ciss dev/filemon dev/firewire \
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sbin/Makefile head/sbin/Makefile
--- clean-head/sbin/Makefile	2013-06-26 09:41:04.000000000 +0200
+++ head/sbin/Makefile	2013-06-24 14:20:21.000000000 +0200
@@ -54,6 +54,7 @@ SUBDIR=adjkerntz \
 	mount_nullfs \
 	mount_udf \
 	mount_unionfs \
+	mount_vpsfs \
 	newfs \
 	newfs_msdos \
 	nfsiod \
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sbin/mount_vpsfs/Makefile head/sbin/mount_vpsfs/Makefile
--- clean-head/sbin/mount_vpsfs/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/sbin/mount_vpsfs/Makefile	2013-06-24 14:20:21.000000000 +0200
@@ -0,0 +1,15 @@
+#	@(#)Makefile	8.3 (Berkeley) 3/27/94
+# $FreeBSD: src/sbin/mount_vpsfs/Makefile,v 1.12.10.1.4.1 2010/06/14 02:09:06 kensmith Exp $
+
+PROG=	mount_vpsfs
+SRCS=	mount_vpsfs.c getmntopts.c
+MAN=	mount_vpsfs.8
+BINDIR= /sbin
+
+MOUNT=	${.CURDIR}/../mount
+CFLAGS+= -I${MOUNT}
+WARNS?=	6
+
+.PATH:	${MOUNT}
+
+.include <bsd.prog.mk>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sbin/mount_vpsfs/mount_vpsfs.8 head/sbin/mount_vpsfs/mount_vpsfs.8
--- clean-head/sbin/mount_vpsfs/mount_vpsfs.8	1970-01-01 01:00:00.000000000 +0100
+++ head/sbin/mount_vpsfs/mount_vpsfs.8	2013-06-24 14:20:21.000000000 +0200
@@ -0,0 +1,111 @@
+.\"
+.\" Copyright (c) 1992, 1993, 1994
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software donated to Berkeley by
+.\" John Heidemann of the UCLA Ficus project.
+.\"
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" This used to be mount_nullfs(8).
+.\"
+.\" $Id: mount_vpsfs.8 120 2012-08-30 11:14:36Z klaus $
+.\"
+.Dd August 29, 2012
+.Dt MOUNT_VPSFS 8
+.Os
+.Sh NAME
+.Nm mount_vpsfs
+.Nd "mount a virtual filesystem layer for use with VPS"
+.Sh SYNOPSIS
+.Nm
+.Op Fl o Ar options
+.Ar target
+.Ar mount-point
+.Sh DESCRIPTION
+The
+.Nm
+utility mounts a virtual filesystem layer for use with
+.Xr vps 4 .
+This implements per-VPS-instance quotas and I/O throttling.
+.Pp
+It is based on 
+.Xr mount_nullfs 8 .
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl o
+Options are specified with a
+.Fl o
+flag followed by a comma separated string of options.
+See the
+.Xr mount 8
+man page for possible options and their meanings.
+.El
+.\"
+.\"
+.\"
+.\"
+.\"
+.\"
+.Sh SEE ALSO
+.Xr mount 8
+.Xr vpsctl 8 ,
+.Xr vps 4 ,
+.Xr vps 9 ,
+.Xr vps.conf 5 ,
+.Ad http://www.7he.at/freebsd/vps/
+.\" 
+.\" 
+.\" .Sh STANDARDS
+.\" 
+.\" 
+.Sh HISTORY
+Work on VPS was started in February 2009.
+.\" 
+.\" 
+.Sh AUTHORS
+.Pp
+Virtual Private Systems for FreeBSD and this manual page as well,
+were written by
+.An "Klaus P. Ohrhallinger" .
+.Pp
+Development of this software was partly funded by:
+.Pp
+TransIP.nl <http://www.transip.nl/>
+.\"
+.\"
+.Sh BUGS
+VPS is in an early stage of development and has to be considered as
+experimental.
+This means many bugs have to be expected.
+.Pp
+Please submit bug reports to
+.Ad freebsd-vps@7he.at .
+.\"
+.\"
+.Sh VERSION
+$Id: mount_vpsfs.8 120 2012-08-30 11:14:36Z klaus $
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sbin/mount_vpsfs/mount_vpsfs.c head/sbin/mount_vpsfs/mount_vpsfs.c
--- clean-head/sbin/mount_vpsfs/mount_vpsfs.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sbin/mount_vpsfs/mount_vpsfs.c	2013-06-24 14:20:21.000000000 +0200
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1992, 1993, 1994\n\
+	The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mount_null.c	8.6 (Berkeley) 4/26/95";
+#endif
+static const char rcsid[] =
+  "$FreeBSD: src/sbin/mount_nullfs/mount_nullfs.c,v 1.26.10.1.4.1 2010/06/14 02:09:06 kensmith Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "mntopts.h"
+
+static struct mntopt mopts[] = {
+	MOPT_STDOPTS,
+	MOPT_END
+};
+
+int	subdir(const char *, const char *);
+static void	usage(void) __dead2;
+
+int
+main(int argc, char *argv[])
+{
+	struct iovec iov[6];
+	int ch, mntflags;
+	char source[MAXPATHLEN];
+	char target[MAXPATHLEN];
+
+	mntflags = 0;
+	while ((ch = getopt(argc, argv, "o:")) != -1)
+		switch(ch) {
+		case 'o':
+			getmntopts(optarg, mopts, &mntflags, 0);
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 2)
+		usage();
+
+	/* resolve target and source with realpath(3) */
+	(void)checkpath(argv[0], target);
+	(void)checkpath(argv[1], source);
+
+	if (subdir(target, source) || subdir(source, target))
+		errx(EX_USAGE, "%s (%s) and %s are not distinct paths",
+		    argv[0], target, argv[1]);
+
+	iov[0].iov_base = strdup("fstype");
+	iov[0].iov_len = sizeof("fstype");
+	iov[1].iov_base = strdup("vpsfs");
+	iov[1].iov_len = strlen(iov[1].iov_base) + 1;
+	iov[2].iov_base = strdup("fspath");
+	iov[2].iov_len = sizeof("fspath");
+	iov[3].iov_base = source;
+	iov[3].iov_len = strlen(source) + 1;
+	iov[4].iov_base = strdup("target");
+	iov[4].iov_len = sizeof("target");
+	iov[5].iov_base = target;
+	iov[5].iov_len = strlen(target) + 1;
+
+	if (nmount(iov, 6, mntflags))
+		err(1, NULL);
+	exit(0);
+}
+
+int
+subdir(const char *p, const char *dir)
+{
+	int l;
+
+	l = strlen(dir);
+	if (l <= 1)
+		return (1);
+
+	if ((strncmp(p, dir, l) == 0) && (p[l] == '/' || p[l] == '\0'))
+		return (1);
+
+	return (0);
+}
+
+static void
+usage(void)
+{
+	(void)fprintf(stderr,
+		"usage: mount_vpsfs [-o options] target mount-point\n");
+	exit(1);
+}
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/Makefile head/sys/Makefile
--- clean-head/sys/Makefile	2013-06-26 09:38:52.000000000 +0200
+++ head/sys/Makefile	2013-06-24 14:20:57.000000000 +0200
@@ -12,7 +12,7 @@ CSCOPEDIRS=	boot bsm cam cddl compat con
 		geom gnu isa kern libkern modules net net80211 netatalk \
 		netgraph netinet netinet6 netipsec netipx netnatm \
 		netsmb nfs nfsclient nfsserver nlm ofed opencrypto \
-		pci rpc security sys ufs vm xdr xen ${CSCOPE_ARCHDIR}
+		pci rpc security sys ufs vm vps xdr xen ${CSCOPE_ARCHDIR}
 .if !defined(CSCOPE_ARCHDIR)
 .if defined(ALL_ARCH)
 CSCOPE_ARCHDIR = amd64 arm i386 ia64 mips pc98 powerpc sparc64 x86
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/amd64/amd64/exception.S head/sys/amd64/amd64/exception.S
--- clean-head/sys/amd64/amd64/exception.S	2013-06-26 09:38:40.000000000 +0200
+++ head/sys/amd64/amd64/exception.S	2013-06-24 14:21:58.000000000 +0200
@@ -350,6 +350,9 @@ IDTVEC(fast_syscall)
 	/* Now emulate a trapframe. Make the 8 byte alignment odd for call. */
 	subq	$TF_SIZE,%rsp
 	/* defer TF_RSP till we have a spare register */
+#ifdef VPS
+	movq	$0x80,TF_TRAPNO(%rsp)
+#endif
 	movq	%r11,TF_RFLAGS(%rsp)
 	movq	%rcx,TF_RIP(%rsp)	/* %rcx original value is in %r10 */
 	movq	PCPU(SCRATCH_RSP),%r11	/* %r11 already saved */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/amd64/amd64/identcpu.c head/sys/amd64/amd64/identcpu.c
--- clean-head/sys/amd64/amd64/identcpu.c	2013-06-26 09:38:40.000000000 +0200
+++ head/sys/amd64/amd64/identcpu.c	2013-06-24 14:21:58.000000000 +0200
@@ -98,8 +98,8 @@ sysctl_hw_machine(SYSCTL_HANDLER_ARGS)
 	return (error);
 
 }
-SYSCTL_PROC(_hw, HW_MACHINE, machine, CTLTYPE_STRING | CTLFLAG_RD,
-    NULL, 0, sysctl_hw_machine, "A", "Machine class");
+_SYSCTL_PROC(_hw, HW_MACHINE, machine, CTLTYPE_STRING | CTLFLAG_RD,
+    NULL, 0, sysctl_hw_machine, "A", "Machine class", VPS_PUBLIC);
 
 static char cpu_model[128];
 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/amd64/amd64/pmap.c head/sys/amd64/amd64/pmap.c
--- clean-head/sys/amd64/amd64/pmap.c	2013-06-26 09:38:40.000000000 +0200
+++ head/sys/amd64/amd64/pmap.c	2013-06-24 14:21:58.000000000 +0200
@@ -122,6 +122,8 @@ __FBSDID("$FreeBSD: head/sys/amd64/amd64
 #include <sys/cpuset.h>
 #endif
 
+#include <vps/vps_account.h>
+
 #include <vm/vm.h>
 #include <vm/vm_param.h>
 #include <vm/vm_kern.h>
@@ -165,6 +167,24 @@ __FBSDID("$FreeBSD: head/sys/amd64/amd64
 #define	pa_index(pa)	((pa) >> PDRSHIFT)
 #define	pa_to_pvh(pa)	(&pv_table[pa_index(pa)])
 
+#if 0
+
+#ifdef VPS
+#define VPS_ACCOUNT_PMAP(_pmap, action, charge)				\
+	do {								\
+		if (_pmap == kernel_map->pmap || 			\
+		    _pmap == kmem_map->pmap ||				\
+		    _pmap == buffer_map->pmap)				\
+			break;						\
+		vps_account(curthread->td_vps, VPS_ACC_PHYS,		\
+			action, charge << PAGE_SHIFT);				\
+	} while (0)
+#endif /* VPS */
+
+#else
+#define VPS_ACCOUNT_PMAP(a, b, c)
+#endif
+
 #define	NPV_LIST_LOCKS	MAXCPU
 
 #define	PHYS_TO_PV_LIST_LOCK(pa)	\
@@ -461,6 +481,7 @@ pmap_resident_count_inc(pmap_t pmap, int
 
 	PMAP_LOCK_ASSERT(pmap, MA_OWNED);
 	pmap->pm_stats.resident_count += count;
+	VPS_ACCOUNT_PMAP(pmap, VPS_ACC_ALLOC, count);
 }
 
 static __inline void
@@ -469,6 +490,7 @@ pmap_resident_count_dec(pmap_t pmap, int
 
 	PMAP_LOCK_ASSERT(pmap, MA_OWNED);
 	pmap->pm_stats.resident_count -= count;
+	VPS_ACCOUNT_PMAP(pmap, VPS_ACC_FREE, count);
 }
 
 PMAP_INLINE pt_entry_t *
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/amd64/amd64/trap.c head/sys/amd64/amd64/trap.c
--- clean-head/sys/amd64/amd64/trap.c	2013-06-26 09:38:40.000000000 +0200
+++ head/sys/amd64/amd64/trap.c	2013-06-24 14:21:58.000000000 +0200
@@ -656,6 +656,9 @@ trap_pfault(frame, usermode)
 	struct proc *p = td->td_proc;
 	vm_offset_t eva = frame->tf_addr;
 
+	ftype = 0;
+	map = NULL;
+
 	if (__predict_false((td->td_pflags & TDP_NOFAULTING) != 0)) {
 		/*
 		 * Due to both processor errata and lazy TLB invalidation when
@@ -789,7 +792,11 @@ nogo:
 		}
 		trap_fatal(frame, eva);
 		return (-1);
+	} else {
+		printf("%s: proc=%p/%d map=%p eva=%016lx prot=%x rv=%d\n",
+			__func__, p, p->p_pid, map, eva, ftype, rv);
 	}
+
 	return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV);
 }
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/amd64/amd64/vps_machdep.c head/sys/amd64/amd64/vps_machdep.c
--- clean-head/sys/amd64/amd64/vps_machdep.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/amd64/amd64/vps_machdep.c	2013-06-24 14:21:58.000000000 +0200
@@ -0,0 +1,538 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id$";
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/libkern.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+
+#include <machine/cputypes.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+#include <machine/frame.h>
+#include <machine/vmparam.h>
+#include <machine/vps_md.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_map.h>
+
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#include <vps/vps_int.h>
+#include <vps/vps_libdump.h>
+#include <vps/vps_snapst.h>
+
+#ifdef VPS
+
+/*__attribute__((inline))*/
+void
+vps_md_print_thread(struct thread *td)
+{
+
+	DBGCORE("%s: thread %p/%d kernel stack:\n"
+		"td->td_pcb->rsp=%016lx\n"
+		"td->td_frame->tf_rax=%016lx\n"
+		"td->td_frame->tf_rsp=%016lx\n"
+		"td->td_frame->tf_rbp=%016lx\n"
+		"td->td_frame->tf_rip=%016lx\n"
+		"trace:\n",
+		__func__,
+		td,
+		td->td_tid,
+		td->td_pcb->pcb_rsp,
+		td->td_frame->tf_rax,
+		td->td_frame->tf_rsp,
+		td->td_frame->tf_rbp,
+		td->td_frame->tf_rip);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_thread(struct vps_dump_thread *vdtd, struct thread *ntd,
+    struct proc *p)
+{
+
+	if (vps_func->vps_restore_return == NULL) {
+		printf("%s: vps_restore module not loaded ? "
+		    "vps_func->vps_restore_return == NULL",
+		    __func__);
+		return (EOPNOTSUPP);
+	}
+
+	ntd->td_pcb->pcb_cr3 =
+	    DMAP_TO_PHYS((vm_offset_t)vmspace_pmap(p->p_vmspace)->pm_pml4);
+	ntd->td_pcb->pcb_r12 = (uint64_t)vps_func->vps_restore_return;
+	ntd->td_pcb->pcb_rbp = 0;
+	ntd->td_pcb->pcb_rsp = (uint64_t)ntd->td_frame - sizeof(void *);
+	ntd->td_pcb->pcb_rbx = (uint64_t)ntd;
+	ntd->td_pcb->pcb_rip = (uint64_t)fork_trampoline;
+	ntd->td_md.md_spinlock_count = 1;
+	ntd->td_md.md_saved_flags = PSL_KERNEL | PSL_I;
+	ntd->td_errno = vdtd->td_errno;
+	ntd->td_retval[0] = vdtd->td_retval[0];
+	ntd->td_retval[1] = vdtd->td_retval[1];
+
+	//db_trace_thread(ntd, 10);
+	DBGCORE("%s: td_pcb = %p; td_frame = %p; pcb_rsp = %016lx\n",
+	    __func__, ntd->td_pcb, ntd->td_frame, ntd->td_pcb->pcb_rsp);
+
+	return (0);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_snapshot_sysentvec(struct sysentvec *sv, long *svtype)
+{
+	int error = 0;
+
+	if (sv == &elf64_freebsd_sysvec) {
+		DBGCORE("%s: elf64_freebsd_sysvec\n", __func__);
+		*svtype = VPS_SYSENTVEC_ELF64;
+#ifdef COMPAT_FREEBSD32
+	} else if (sv == &ia32_freebsd_sysvec) {
+		DBGCORE("%s: ia32_freebsd_sysvec\n", __func__);
+		*svtype = VPS_SYSENTVEC_ELF32;
+#endif
+	} else if (sv == &null_sysvec) {
+		DBGCORE("%s: null_sysvec\n", __func__);
+		*svtype = VPS_SYSENTVEC_NULL;
+        } else {
+		DBGCORE("%s: unknown sysentvec %p\n", __func__, sv);
+		error = EINVAL;
+        }
+
+	return (error);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_sysentvec(long svtype, struct sysentvec **sv)
+{
+	int error = 0;
+
+	if (svtype == VPS_SYSENTVEC_ELF64)
+		*sv = &elf64_freebsd_sysvec;
+#ifdef COMPAT_FREEBSD32
+	else if (svtype == VPS_SYSENTVEC_ELF32)
+		*sv = &ia32_freebsd_sysvec;
+#endif
+	else if (svtype == VPS_SYSENTVEC_NULL)
+		*sv = &null_sysvec;
+	else {
+		DBGCORE("%s: unknown sysentvec type: %ld\n",
+			__func__, svtype);
+		error = EINVAL;
+	}
+
+	return (error);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_checkarch(uint8 ptrsize, uint8 byteorder)
+{
+	int error;
+
+	if (ptrsize == VPS_DUMPH_64BIT && byteorder == VPS_DUMPH_LSB)
+		error = 0;
+	else
+		error = EINVAL;
+
+	return (error);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_snapshot_thread_savefpu(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct thread *td)
+{
+        struct vps_dumpobj *o1;
+        struct vps_dump_savefpu *vdsf;
+
+	KASSERT(td->td_pcb != NULL && td->td_pcb->pcb_save != NULL,
+		("%s: td->td_pcb == NULL || td->td_pcb->pcb_save == NULL\n",
+		__func__));
+
+	if ((o1 = vdo_create(ctx, VPS_DUMPOBJT_SAVEFPU, M_NOWAIT)) ==
+	    NULL) {
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+
+	if ((vdsf = vdo_space(ctx, sizeof(*vdsf), M_NOWAIT)) == NULL) {
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+	vdsf->sf_length = sizeof(struct savefpu);
+
+	if (vdo_append(ctx, (void *)td->td_pcb->pcb_save, vdsf->sf_length,
+	    M_NOWAIT)) {
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+
+	vdo_close(ctx);
+
+	return (0);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_thread_savefpu(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct thread *td)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_savefpu *vdsf;
+
+	/* caller verified type. */
+	o1 = vdo_next(ctx);
+
+	vdsf = (struct vps_dump_savefpu *)o1->data;
+
+	/*
+	 * XXX Verify that we can't harm the system (kernel space)
+	 *     by restoring an invalid savefpu context.
+	 */
+	if (vdsf->sf_length != sizeof(struct savefpu)) {
+		DBGCORE("%s: vdsf->sf_length != sizeof(struct savefpu) "
+		    "(%u != %lu)\n", __func__, vdsf->sf_length,
+		    sizeof(struct savefpu));
+		return (EINVAL);
+	}
+
+	KASSERT(td->td_pcb != NULL && td->td_pcb->pcb_save != NULL,
+		("%s: td->td_pcb == NULL || td->td_pcb->pcb_save == NULL\n",
+		__func__));
+
+	DBGCORE("%s: td->td_pcb->pcb_save=%p\n",
+	    __func__, td->td_pcb->pcb_save);
+	memcpy(td->td_pcb->pcb_save, vdsf->sf_data, vdsf->sf_length);
+
+	return (0);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_reboot_copyout(struct thread *td, struct execve_args *args)
+{
+	vm_offset_t addr;
+	struct proc *p;
+	int error = 0;
+
+	/*
+	 * We push the arguments to execve() onto the
+	 * userspace stack of our process.
+	 */
+	p = td->td_proc;
+	addr = p->p_sysent->sv_usrstack - PAGE_SIZE;
+	if (p->p_vmspace->vm_ssize < 1 /* page */) {
+		/* Should not ever happen in theory ! */
+		return (ENOSPC);
+	}
+
+	if (p->p_sysent == &elf64_freebsd_sysvec) {
+		copyout("/sbin/init", (void *)(addr + 0x40), 11);
+		suword64((void *)(addr + 0x0), (addr + 0x40));
+		suword64((void *)(addr + 0x8), (vm_offset_t)NULL);
+#ifdef COMPAT_FREEBSD32
+	} else if (p->p_sysent == &ia32_freebsd_sysvec) {
+		copyout("/sbin/init", (void *)(addr + 0x40), 11);
+		suword32((void *)(addr + 0x0), (addr + 0x40));
+		suword32((void *)(addr + 0x4), (vm_offset_t)NULL);
+#endif
+	} else {
+		error = EINVAL;
+	}
+
+	args->fname = (char *)(addr + 0x40);
+	args->argv = (char **)addr;
+	args->envv = NULL;
+
+#if 0
+// notyet
+        KASSERT(pargs != NULL,
+            ("%s: vps=%p, lost pargs somewhere, don't know what to boot\n",
+            __func__, vps));
+        arglen = pargs->ar_length;
+        /*
+        if (arglen > PAGE_SIZE)
+                arglen = PAGE_SIZE - 1;
+        copyout(pargs->ar_args, (void *)addr, arglen);
+        subyte((char *)(addr + PAGE_SIZE - 1), 0x0);
+        */
+        if (exec_alloc_args(&imgargs)) {
+                DBGCORE("%s: exec_alloc_args() returned error\n", __func__);
+                pargs_drop(pargs);
+                goto fail;
+        }  
+        if (arglen > PATH_MAX + ARG_MAX)
+                arglen = PATH_MAX + ARG_MAX - 1;
+        memcpy(imgargs.buf, pargs->ar_args, arglen);
+        addr = (vm_offset_t)imgargs.buf;
+        // ---
+        imgargs.fname = (char *)addr;
+        imgargs.begin_argv = (char *)(addr + 0x0);
+        imgargs.begin_envv = (char *)(addr + arglen);
+        imgargs.endp = (char *)(addr + arglen);
+        imgargs.envc = 0;
+        imgargs.argc = 1; /* XXX */
+        imgargs.stringspace = 0;
+#endif
+
+	return (error);
+}
+
+/*__attribute__((noinline))*/
+int
+vps_md_syscall_fixup(struct vps *vps, struct thread *td,
+    register_t *ret_code, register_t **ret_args, int *ret_narg)
+{
+	struct trapframe *frame;
+	struct sysentvec *sv;
+	struct proc *p;
+	caddr_t params;
+	register_t code;
+	register_t args[8];
+	int narg;
+	int error = 0;
+	int i;
+	int ia32_emul = 0;
+	struct ucred *save_ucred = curthread->td_ucred;
+
+	if (vps_func->vps_access_vmspace == NULL)
+		return (EOPNOTSUPP);
+
+	p = td->td_proc;
+	frame = td->td_frame;
+	sv = p->p_sysent;
+
+	if (frame->tf_trapno != 0x80) {
+		DBGCORE("%s: thread %p was not in syscall: "
+		    "tf_trapno=0x%x tf_rip=%p\n", __func__, td,
+		    frame->tf_trapno, (void*)frame->tf_rip);
+
+		/* nothing to do ? */
+		error = 0;
+		goto out;
+	}
+
+	if (sv == &elf64_freebsd_sysvec) {
+		DBGCORE("%s: proc=%p/%u elf64_freebsd_sysvec\n",
+		    __func__, p, p->p_pid);
+#ifdef COMPAT_FREEBSD32
+	} else if (sv == &ia32_freebsd_sysvec) {
+		DBGCORE("%s: proc=%p/%u ia32_freebsd_sysvec\n",
+		    __func__, p, p->p_pid);
+		ia32_emul = 1;
+#endif
+	} else {
+		DBGCORE("%s: proc=%p/%u unknown sysentvec %p\n",
+		    __func__, p, p->p_pid, sv);
+		panic("%s: proc=%p/%u unknown sysentvec %p\n",
+		    __func__, p, p->p_pid, sv);
+	}
+
+	/* Just in case vm objects are split/copied/... */
+	curthread->td_ucred = td->td_ucred;
+
+	/*
+	 * XXX: special handling for
+	 *      sa->code == SYS_syscall || sa->code == SYS___syscall
+	 */
+
+	memset((caddr_t)args, 0, sizeof(args));
+
+	code = frame->tf_rax;
+
+	if (sv->sv_mask)
+		code &= sv->sv_mask;
+	if (code >= sv->sv_size)
+		code = 0;
+
+	narg = (&sv->sv_table[code])->sy_narg;
+
+	KASSERT(narg * sizeof(register_t) <= sizeof(args),
+	    ("%s: argument space on stack too small, narg=%d\n",
+	    __func__, narg));
+
+	if (ia32_emul) {
+		uint32_t args32[8];
+
+		memset(args32, 0, sizeof(args32));
+
+		params = (caddr_t)frame->tf_rsp + sizeof(uint32_t);
+
+		if (params != NULL && narg > 0)
+			if ((vps_func->vps_access_vmspace(p->p_vmspace,
+			    (vm_offset_t)params, narg * sizeof(uint32_t),
+			    (caddr_t)args32, VM_PROT_READ))) {
+				error = EFAULT;
+				goto out;
+			}
+
+		for (i = 0; i < narg; i++)
+			args[i] = (uint64_t)args32[i];
+
+	} else {
+
+		params = (caddr_t)frame->tf_rsp + sizeof(register_t);
+
+		args[0] = frame->tf_rdi;
+		args[1] = frame->tf_rsi;
+		args[2] = frame->tf_rdx;
+		args[3] = frame->tf_rcx;
+		args[4] = frame->tf_r8;
+		args[5] = frame->tf_r9;
+
+		for (i = 0; i < 6; i++)
+			if (i >= narg)
+				args[i] = 0;
+
+		/* XXX only need this in case narg > regcnt (6 on amd64)
+		if ((vps_func->vps_access_vmspace(p->p_vmspace,
+		    (vm_offset_t)params, narg * sizeof(register_t),
+		    (caddr_t)args, VM_PROT_READ))) {
+			error = EFAULT;
+			goto out;
+		}
+		*/
+
+	}
+
+	DBGCORE("%s: code=%lu/0x%lx narg=%u args: %016lx %016lx %016lx "
+	    "%016lx %016lx %016lx\n", __func__, code, code, narg,
+	    args[0], args[1], args[2], args[3], args[4], args[5]);
+
+	DBGCORE("SYSCALL: tid=%d pid=%d syscall=%ld retval[0]=%zx "
+	    "retval[1]=%zx errno=%d\n",
+	    td->td_tid, td->td_proc->p_pid, code, td->td_retval[0],
+	    td->td_retval[1], td->td_errno);
+
+	KASSERT(*ret_narg >= narg,
+	    ("%s: supplied args array too small (narg=%d *ret_narg=%d)\n",
+	    __func__, narg, *ret_narg));
+	*ret_code = code;
+	*ret_narg= narg;
+	memcpy(ret_args, &args, narg * sizeof(args[0]));
+
+ out:
+	curthread->td_ucred = save_ucred;
+
+	return (error);
+}
+
+int
+vps_md_syscall_fixup_setup_inthread(struct vps *vps, struct thread *td,
+    register_t code)
+{
+
+	DBGCORE("%s\n", __func__);
+
+	if (vps_func->vps_syscall_fixup_inthread == NULL)
+		return (EOPNOTSUPP);
+
+	td->td_pcb->pcb_r12 =
+	    (uint64_t)vps_func->vps_syscall_fixup_inthread;
+	td->td_pcb->pcb_rip = (uint64_t)fork_trampoline;
+	td->td_pcb->pcb_rsp = (uint64_t)td->td_frame -
+	    sizeof(void *);
+	td->td_pcb->pcb_rbx = (uint64_t)code;
+	td->td_pcb->pcb_rbp = 0;
+
+	return (0);
+}
+
+__attribute__((noinline))
+void
+vps_md_print_pcb(struct thread *td)
+{
+        struct pcb *p;
+
+        p = td->td_pcb;
+
+#if 0
+// XXX
+        DBGCORE("%s: td=%p\n"
+                "pcb_cr3: 0x%08x\n"
+                "pcb_edi: 0x%08x\n"
+                "pcb_esi: 0x%08x\n"
+                "pcb_ebp: 0x%08x\n"
+                "pcb_esp: 0x%08x\n"
+                "pcb_ebx: 0x%08x\n"
+                "pcb_eip: 0x%08x\n"
+                "pcb_psl: 0x%08x\n"
+                "pcb_ext: 0x%08x\n"
+                , __func__, td
+                , p->pcb_cr3
+                , p->pcb_edi
+                , p->pcb_esi
+                , p->pcb_ebp
+                , p->pcb_esp
+                , p->pcb_ebx
+                , p->pcb_eip
+                , p->pcb_psl
+                , (int)p->pcb_ext
+                );
+#endif
+}
+
+#if 0
+/* --------------------------- 8< --------------------------- */
+
+// vps_suspend():
+#if defined(CPU_X86)
+              DBGCORE("td->td_frame=%p tf_rax=%p tf_rsp=%p\n", td->td_frame,
+                 (void*)td->td_frame->tf_rax, (void*)td->td_frame->tf_rsp);
+#elif defined(CPU_386)
+              DBGCORE("td->td_frame=%p tf_eax=%p tf_esp=%p\n", td->td_frame,
+                 (void*)td->td_frame->tf_eax, (void*)td->td_frame->tf_esp);
+#else
+#error "unsupported architecture"
+#endif
+
+// 
+/* --------------------------- 8< --------------------------- */
+#endif /* 0 */
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/amd64/conf/VPS_DBG head/sys/amd64/conf/VPS_DBG
--- clean-head/sys/amd64/conf/VPS_DBG	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/amd64/conf/VPS_DBG	2013-06-24 14:21:58.000000000 +0200
@@ -0,0 +1,346 @@
+#
+# GENERIC -- Generic kernel configuration file for FreeBSD/amd64
+#
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
+#
+#    http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD: head/sys/amd64/conf/GENERIC 249083 2013-04-04 07:12:24Z mav $
+
+cpu		HAMMER
+ident		VPS_DBG
+
+makeoptions	DEBUG=-g		# Build kernel with gdb(1) debug symbols
+makeoptions	WITH_CTF=1		# Run ctfconvert(1) for DTrace support
+
+options 	SCHED_ULE		# ULE scheduler
+options 	PREEMPTION		# Enable kernel thread preemption
+options 	INET			# InterNETworking
+options 	INET6			# IPv6 communications protocols
+options 	TCP_OFFLOAD		# TCP offload
+options 	SCTP			# Stream Control Transmission Protocol
+options 	FFS			# Berkeley Fast Filesystem
+options 	SOFTUPDATES		# Enable FFS soft updates support
+options 	UFS_ACL			# Support for access control lists
+options 	UFS_DIRHASH		# Improve performance on big directories
+options 	UFS_GJOURNAL		# Enable gjournal-based UFS journaling
+options 	QUOTA			# Enable disk quotas for UFS
+options 	MD_ROOT			# MD is a potential root device
+options 	NFSCL			# New Network Filesystem Client
+options 	NFSD			# New Network Filesystem Server
+options 	NFSLOCKD		# Network Lock Manager
+options 	NFS_ROOT		# NFS usable as /, requires NFSCL
+options 	MSDOSFS			# MSDOS Filesystem
+options 	CD9660			# ISO 9660 Filesystem
+options 	PROCFS			# Process filesystem (requires PSEUDOFS)
+options 	PSEUDOFS		# Pseudo-filesystem framework
+options 	GEOM_PART_GPT		# GUID Partition Tables.
+options 	GEOM_RAID		# Soft RAID functionality.
+options 	GEOM_LABEL		# Provides labelization
+options 	COMPAT_FREEBSD32	# Compatible with i386 binaries
+options 	COMPAT_FREEBSD4		# Compatible with FreeBSD4
+options 	COMPAT_FREEBSD5		# Compatible with FreeBSD5
+options 	COMPAT_FREEBSD6		# Compatible with FreeBSD6
+options 	COMPAT_FREEBSD7		# Compatible with FreeBSD7
+options 	SCSI_DELAY=5000		# Delay (in ms) before probing SCSI
+options 	KTRACE			# ktrace(1) support
+options 	STACK			# stack(9) support
+options 	SYSVSHM			# SYSV-style shared memory
+options 	SYSVMSG			# SYSV-style message queues
+options 	SYSVSEM			# SYSV-style semaphores
+options 	_KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions
+options 	PRINTF_BUFR_SIZE=128	# Prevent printf output being interspersed.
+options 	KBD_INSTALL_CDEV	# install a CDEV entry in /dev
+options 	HWPMC_HOOKS		# Necessary kernel hooks for hwpmc(4)
+options 	AUDIT			# Security event auditing
+options 	CAPABILITY_MODE		# Capsicum capability mode
+options 	CAPABILITIES		# Capsicum capabilities
+options 	MAC			# TrustedBSD MAC Framework
+options 	KDTRACE_FRAME		# Ensure frames are compiled in
+options 	KDTRACE_HOOKS		# Kernel DTrace hooks
+options 	DDB_CTF			# Kernel ELF linker loads CTF data
+options 	INCLUDE_CONFIG_FILE     # Include this file in kernel
+
+# Debugging support.  Always need this:
+options 	KDB			# Enable kernel debugger support.
+# For minimum debugger support (stable branch) use:
+#options 	KDB_TRACE		# Print a stack trace for a panic.
+# For full debugger support use this instead:
+options 	DDB			# Support DDB.
+options 	GDB			# Support remote GDB.
+options 	DEADLKRES		# Enable the deadlock resolver
+options 	INVARIANTS		# Enable calls of extra sanity checking
+options 	INVARIANT_SUPPORT	# Extra sanity checks of internal structures, required by INVARIANTS
+options 	WITNESS			# Enable checks to detect deadlocks and cycles
+options 	WITNESS_SKIPSPIN	# Don't run witness on spinlocks for speed
+options 	MALLOC_DEBUG_MAXZONES=8	# Separate malloc(9) zones
+
+# VPS
+options		VPS
+options		VIMAGE
+options		DIAGNOSTIC
+
+# Make an SMP-capable kernel by default
+options 	SMP			# Symmetric MultiProcessor Kernel
+
+# CPU frequency control
+device		cpufreq
+
+# Bus support.
+device		acpi
+device		pci
+
+# Floppy drives
+device		fdc
+
+# ATA controllers
+device		ahci		# AHCI-compatible SATA controllers
+device		ata		# Legacy ATA/SATA controllers
+options 	ATA_STATIC_ID	# Static device numbering
+device		mvs		# Marvell 88SX50XX/88SX60XX/88SX70XX/SoC SATA
+device		siis		# SiliconImage SiI3124/SiI3132/SiI3531 SATA
+
+# SCSI Controllers
+device		ahc		# AHA2940 and onboard AIC7xxx devices
+options 	AHC_REG_PRETTY_PRINT	# Print register bitfields in debug
+					# output.  Adds ~128k to driver.
+device		ahd		# AHA39320/29320 and onboard AIC79xx devices
+options 	AHD_REG_PRETTY_PRINT	# Print register bitfields in debug
+					# output.  Adds ~215k to driver.
+device		esp		# AMD Am53C974 (Tekram DC-390(T))
+device		hptiop		# Highpoint RocketRaid 3xxx series
+device		isp		# Qlogic family
+#device		ispfw		# Firmware for QLogic HBAs- normally a module
+device		mpt		# LSI-Logic MPT-Fusion
+device		mps		# LSI-Logic MPT-Fusion 2
+#device		ncr		# NCR/Symbios Logic
+device		sym		# NCR/Symbios Logic (newer chipsets + those of `ncr')
+device		trm		# Tekram DC395U/UW/F DC315U adapters
+
+device		adv		# Advansys SCSI adapters
+device		adw		# Advansys wide SCSI adapters
+device		aic		# Adaptec 15[012]x SCSI adapters, AIC-6[23]60.
+device		bt		# Buslogic/Mylex MultiMaster SCSI adapters
+device		isci		# Intel C600 SAS controller
+
+# ATA/SCSI peripherals
+device		scbus		# SCSI bus (required for ATA/SCSI)
+device		ch		# SCSI media changers
+device		da		# Direct Access (disks)
+device		sa		# Sequential Access (tape etc)
+device		cd		# CD
+device		pass		# Passthrough device (direct ATA/SCSI access)
+device		ses		# Enclosure Services (SES and SAF-TE)
+#device		ctl		# CAM Target Layer
+
+# RAID controllers interfaced to the SCSI subsystem
+device		amr		# AMI MegaRAID
+device		arcmsr		# Areca SATA II RAID
+#XXX it is not 64-bit clean, -scottl
+#device		asr		# DPT SmartRAID V, VI and Adaptec SCSI RAID
+device		ciss		# Compaq Smart RAID 5*
+device		dpt		# DPT Smartcache III, IV - See NOTES for options
+device		hptmv		# Highpoint RocketRAID 182x
+device		hptrr		# Highpoint RocketRAID 17xx, 22xx, 23xx, 25xx
+device		hpt27xx		# Highpoint RocketRAID 27xx
+device		iir		# Intel Integrated RAID
+device		ips		# IBM (Adaptec) ServeRAID
+device		mly		# Mylex AcceleRAID/eXtremeRAID
+device		twa		# 3ware 9000 series PATA/SATA RAID
+device		tws		# LSI 3ware 9750 SATA+SAS 6Gb/s RAID controller
+
+# RAID controllers
+device		aac		# Adaptec FSA RAID
+device		aacp		# SCSI passthrough for aac (requires CAM)
+device		aacraid		# Adaptec by PMC RAID
+device		ida		# Compaq Smart RAID
+device		mfi		# LSI MegaRAID SAS
+device		mlx		# Mylex DAC960 family
+#XXX pointer/int warnings
+#device		pst		# Promise Supertrak SX6000
+device		twe		# 3ware ATA RAID
+
+# atkbdc0 controls both the keyboard and the PS/2 mouse
+device		atkbdc		# AT keyboard controller
+device		atkbd		# AT keyboard
+device		psm		# PS/2 mouse
+
+device		kbdmux		# keyboard multiplexer
+
+device		vga		# VGA video card driver
+options 	VESA		# Add support for VESA BIOS Extensions (VBE)
+
+device		splash		# Splash screen and screen saver support
+
+# syscons is the default console driver, resembling an SCO console
+device		sc
+options 	SC_PIXEL_MODE	# add support for the raster text mode
+
+device		agp		# support several AGP chipsets
+
+# PCCARD (PCMCIA) support
+# PCMCIA and cardbus bridge support
+device		cbb		# cardbus (yenta) bridge
+device		pccard		# PC Card (16-bit) bus
+device		cardbus		# CardBus (32-bit) bus
+
+# Serial (COM) ports
+device		uart		# Generic UART driver
+
+# Parallel port
+device		ppc
+device		ppbus		# Parallel port bus (required)
+device		lpt		# Printer
+device		ppi		# Parallel port interface device
+#device		vpo		# Requires scbus and da
+
+device		puc		# Multi I/O cards and multi-channel UARTs
+
+# PCI Ethernet NICs.
+device		bxe		# Broadcom BCM57710/BCM57711/BCM57711E 10Gb Ethernet
+device		de		# DEC/Intel DC21x4x (``Tulip'')
+device		em		# Intel PRO/1000 Gigabit Ethernet Family
+device		igb		# Intel PRO/1000 PCIE Server Gigabit Family
+device		ixgbe		# Intel PRO/10GbE PCIE Ethernet Family
+device		le		# AMD Am7900 LANCE and Am79C9xx PCnet
+device		ti		# Alteon Networks Tigon I/II gigabit Ethernet
+device		txp		# 3Com 3cR990 (``Typhoon'')
+device		vx		# 3Com 3c590, 3c595 (``Vortex'')
+
+# PCI Ethernet NICs that use the common MII bus controller code.
+# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
+device		miibus		# MII bus support
+device		ae		# Attansic/Atheros L2 FastEthernet
+device		age		# Attansic/Atheros L1 Gigabit Ethernet
+device		alc		# Atheros AR8131/AR8132 Ethernet
+device		ale		# Atheros AR8121/AR8113/AR8114 Ethernet
+device		bce		# Broadcom BCM5706/BCM5708 Gigabit Ethernet
+device		bfe		# Broadcom BCM440x 10/100 Ethernet
+device		bge		# Broadcom BCM570xx Gigabit Ethernet
+device		cas		# Sun Cassini/Cassini+ and NS DP83065 Saturn
+device		dc		# DEC/Intel 21143 and various workalikes
+device		et		# Agere ET1310 10/100/Gigabit Ethernet
+device		fxp		# Intel EtherExpress PRO/100B (82557, 82558)
+device		gem		# Sun GEM/Sun ERI/Apple GMAC
+device		hme		# Sun HME (Happy Meal Ethernet)
+device		jme		# JMicron JMC250 Gigabit/JMC260 Fast Ethernet
+device		lge		# Level 1 LXT1001 gigabit Ethernet
+device		msk		# Marvell/SysKonnect Yukon II Gigabit Ethernet
+device		nfe		# nVidia nForce MCP on-board Ethernet
+device		nge		# NatSemi DP83820 gigabit Ethernet
+#device		nve		# nVidia nForce MCP on-board Ethernet Networking
+device		pcn		# AMD Am79C97x PCI 10/100 (precedence over 'le')
+device		re		# RealTek 8139C+/8169/8169S/8110S
+device		rl		# RealTek 8129/8139
+device		sf		# Adaptec AIC-6915 (``Starfire'')
+device		sge		# Silicon Integrated Systems SiS190/191
+device		sis		# Silicon Integrated Systems SiS 900/SiS 7016
+device		sk		# SysKonnect SK-984x & SK-982x gigabit Ethernet
+device		ste		# Sundance ST201 (D-Link DFE-550TX)
+device		stge		# Sundance/Tamarack TC9021 gigabit Ethernet
+device		tl		# Texas Instruments ThunderLAN
+device		tx		# SMC EtherPower II (83c170 ``EPIC'')
+device		vge		# VIA VT612x gigabit Ethernet
+device		vr		# VIA Rhine, Rhine II
+device		wb		# Winbond W89C840F
+device		xl		# 3Com 3c90x (``Boomerang'', ``Cyclone'')
+
+# ISA Ethernet NICs.  pccard NICs included.
+device		cs		# Crystal Semiconductor CS89x0 NIC
+# 'device ed' requires 'device miibus'
+device		ed		# NE[12]000, SMC Ultra, 3c503, DS8390 cards
+device		ex		# Intel EtherExpress Pro/10 and Pro/10+
+device		ep		# Etherlink III based cards
+device		fe		# Fujitsu MB8696x based cards
+device		sn		# SMC's 9000 series of Ethernet chips
+device		xe		# Xircom pccard Ethernet
+
+# Wireless NIC cards
+device		wlan		# 802.11 support
+options 	IEEE80211_DEBUG	# enable debug msgs
+options 	IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's
+options 	IEEE80211_SUPPORT_MESH	# enable 802.11s draft support
+device		wlan_wep	# 802.11 WEP support
+device		wlan_ccmp	# 802.11 CCMP support
+device		wlan_tkip	# 802.11 TKIP support
+device		wlan_amrr	# AMRR transmit rate control algorithm
+device		an		# Aironet 4500/4800 802.11 wireless NICs.
+device		ath		# Atheros NICs
+device		ath_pci		# Atheros pci/cardbus glue
+device		ath_hal		# pci/cardbus chip support
+options 	AH_SUPPORT_AR5416	# enable AR5416 tx/rx descriptors
+options 	AH_AR5416_INTERRUPT_MITIGATION	# AR5416 interrupt mitigation
+options 	ATH_ENABLE_11N	# Enable 802.11n support for AR5416 and later
+device		ath_rate_sample	# SampleRate tx rate control for ath
+#device		bwi		# Broadcom BCM430x/BCM431x wireless NICs.
+#device		bwn		# Broadcom BCM43xx wireless NICs.
+device		ipw		# Intel 2100 wireless NICs.
+device		iwi		# Intel 2200BG/2225BG/2915ABG wireless NICs.
+device		iwn		# Intel 4965/1000/5000/6000 wireless NICs.
+device		malo		# Marvell Libertas wireless NICs.
+device		mwl		# Marvell 88W8363 802.11n wireless NICs.
+device		ral		# Ralink Technology RT2500 wireless NICs.
+device		wi		# WaveLAN/Intersil/Symbol 802.11 wireless NICs.
+device		wpi		# Intel 3945ABG wireless NICs.
+
+# Pseudo devices.
+device		loop		# Network loopback
+device		random		# Entropy device
+options 	PADLOCK_RNG	# VIA Padlock RNG
+options 	RDRAND_RNG	# Intel Bull Mountain RNG
+device		ether		# Ethernet support
+device		vlan		# 802.1Q VLAN support
+device		tun		# Packet tunnel.
+device		md		# Memory "disks"
+device		gif		# IPv6 and IPv4 tunneling
+device		faith		# IPv6-to-IPv4 relaying (translation)
+device		firmware	# firmware assist module
+
+# The `bpf' device enables the Berkeley Packet Filter.
+# Be aware of the administrative consequences of enabling this!
+# Note that 'bpf' is required for DHCP.
+device		bpf		# Berkeley packet filter
+
+# USB support
+options 	USB_DEBUG	# enable debug msgs
+device		uhci		# UHCI PCI->USB interface
+device		ohci		# OHCI PCI->USB interface
+device		ehci		# EHCI PCI->USB interface (USB 2.0)
+device		xhci		# XHCI PCI->USB interface (USB 3.0)
+device		usb		# USB Bus (required)
+device		ukbd		# Keyboard
+device		umass		# Disks/Mass storage - Requires scbus and da
+
+# Sound support
+device		sound		# Generic sound driver (required)
+device		snd_cmi		# CMedia CMI8338/CMI8738
+device		snd_csa		# Crystal Semiconductor CS461x/428x
+device		snd_emu10kx	# Creative SoundBlaster Live! and Audigy
+device		snd_es137x	# Ensoniq AudioPCI ES137x
+device		snd_hda		# Intel High Definition Audio
+device		snd_ich		# Intel, NVidia and other ICH AC'97 Audio
+device		snd_via8233	# VIA VT8233x Audio
+
+# MMC/SD
+device		mmc		# MMC/SD bus
+device		mmcsd		# MMC/SD memory card
+device		sdhci		# Generic PCI SD Host Controller
+
+# VirtIO support
+device		virtio		# Generic VirtIO bus (required)
+device		virtio_pci	# VirtIO PCI device
+device		vtnet		# VirtIO Ethernet device
+device		virtio_blk	# VirtIO Block device
+device		virtio_scsi	# VirtIO SCSI device
+device		virtio_balloon	# VirtIO Memory Balloon device
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/amd64/ia32/ia32_exception.S head/sys/amd64/ia32/ia32_exception.S
--- clean-head/sys/amd64/ia32/ia32_exception.S	2013-06-26 09:38:36.000000000 +0200
+++ head/sys/amd64/ia32/ia32_exception.S	2013-06-24 14:21:58.000000000 +0200
@@ -44,6 +44,9 @@ IDTVEC(int0x80_syscall)
 	swapgs
 	pushq	$2			/* sizeof "int 0x80" */
 	subq	$TF_ERR,%rsp		/* skip over tf_trapno */
+#ifdef VPS
+	movl	$0x80,TF_TRAPNO(%rsp)
+#endif	
 	movq	%rdi,TF_RDI(%rsp)
 	movq	PCPU(CURPCB),%rdi
 	andl	$~PCB_FULL_IRET,PCB_FLAGS(%rdi)
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/amd64/include/vps_md.h head/sys/amd64/include/vps_md.h
--- clean-head/sys/amd64/include/vps_md.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/amd64/include/vps_md.h	2013-06-24 14:21:57.000000000 +0200
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifndef _VPS_MD_H
+#define _VPS_MD_H
+
+#define VPS_ARCH_AMD64
+
+#define VPS_MD_SNAPCTX_NPAGES		131072 /* 512 MB */
+
+#define VPS_MD_DUMPHDR_PTRSIZE		VPS_DUMPH_64BIT
+
+#define VPS_MD_DUMPHDR_BYTEORDER	VPS_DUMPH_LSB
+
+extern struct sysentvec elf64_freebsd_sysvec;
+#ifdef COMPAT_FREEBSD32
+extern struct sysentvec ia32_freebsd_sysvec;   
+#endif
+
+#ifdef _VPS_MD_FUNCTIONS
+
+inline
+static void
+vps_md_syscallret(struct thread *td, struct syscall_args *sa)
+{
+
+	/* re-setting tf_rax */
+	td->td_frame->tf_rax = sa->code;
+	DBGCORE("%s: td=%p tf_rax=%p\n",
+	    __func__, td, (void*)td->td_frame->tf_rax);
+}
+
+#endif /* _VPS_MD_FUNCTIONS */
+
+#endif /* _VPS_MD_H */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/amd64/linux32/linux32_machdep.c head/sys/amd64/linux32/linux32_machdep.c
--- clean-head/sys/amd64/linux32/linux32_machdep.c	2013-06-26 09:38:38.000000000 +0200
+++ head/sys/amd64/linux32/linux32_machdep.c	2013-06-24 14:21:58.000000000 +0200
@@ -60,6 +60,8 @@ __FBSDID("$FreeBSD: head/sys/amd64/linux
 #include <machine/segments.h>
 #include <machine/specialreg.h>
 
+#include <vps/vps.h>
+
 #include <vm/vm.h>
 #include <vm/pmap.h>
 #include <vm/vm_map.h>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/cddl/compat/opensolaris/kern/opensolaris.c head/sys/cddl/compat/opensolaris/kern/opensolaris.c
--- clean-head/sys/cddl/compat/opensolaris/kern/opensolaris.c	2013-06-26 09:35:40.000000000 +0200
+++ head/sys/cddl/compat/opensolaris/kern/opensolaris.c	2013-06-24 14:21:55.000000000 +0200
@@ -82,7 +82,7 @@ opensolaris_modevent(module_t mod __unus
 
 	switch (type) {
 	case MOD_LOAD:
-		utsname.nodename = prison0.pr_hostname;
+		utsname.nodename = V_prison0->pr_hostname;
 		break;
 
 	case MOD_UNLOAD:
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c head/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c
--- clean-head/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c	2013-06-26 09:35:40.000000000 +0200
+++ head/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c	2013-06-24 14:21:55.000000000 +0200
@@ -46,7 +46,7 @@ opensolaris_utsname_init(void *arg)
 {
 
 	utsname.sysname = ostype;
-	utsname.nodename = prison0.pr_hostname;
+	utsname.nodename = V_prison0->pr_hostname;
 	utsname.release = osrelease;
 	snprintf(utsname.version, sizeof(utsname.version), "%d", osreldate);
 }
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/cddl/compat/opensolaris/kern/opensolaris_sunddi.c head/sys/cddl/compat/opensolaris/kern/opensolaris_sunddi.c
--- clean-head/sys/cddl/compat/opensolaris/kern/opensolaris_sunddi.c	2013-06-26 09:35:40.000000000 +0200
+++ head/sys/cddl/compat/opensolaris/kern/opensolaris_sunddi.c	2013-06-24 14:21:55.000000000 +0200
@@ -53,7 +53,7 @@ ddi_strtoul(const char *str, char **nptr
 {
 
 	if (str == hw_serial) {
-		*result = prison0.pr_hostid;
+		*result = V_prison0->pr_hostid;
 		return (0);
 	}
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/compat/linprocfs/linprocfs.c head/sys/compat/linprocfs/linprocfs.c
--- clean-head/sys/compat/linprocfs/linprocfs.c	2013-06-26 09:39:19.000000000 +0200
+++ head/sys/compat/linprocfs/linprocfs.c	2013-06-24 14:21:32.000000000 +0200
@@ -76,6 +76,8 @@ __FBSDID("$FreeBSD: head/sys/compat/linp
 #include <sys/vnode.h>
 #include <sys/bus.h>
 
+#include <vps/vps.h>
+
 #include <net/if.h>
 #include <net/vnet.h>
 
@@ -87,6 +89,8 @@ __FBSDID("$FreeBSD: head/sys/compat/linp
 #include <vm/vm_object.h>
 #include <vm/swap_pager.h>
 
+#include <vps/vps.h>
+
 #include <machine/clock.h>
 
 #include <geom/geom.h>
@@ -108,6 +112,10 @@ __FBSDID("$FreeBSD: head/sys/compat/linp
 #include <fs/pseudofs/pseudofs.h>
 #include <fs/procfs/procfs.h>
 
+#define V_msginfo       VPSV(msginfo)
+#define V_seminfo       VPSV(seminfo)
+#define V_shminfo       VPSV(shminfo)
+
 /*
  * Various conversion macros
  */
@@ -490,7 +498,7 @@ linprocfs_dostat(PFS_FILL_ARGS)
 	    cnt.v_swappgsout,
 	    cnt.v_intr,
 	    cnt.v_swtch,
-	    (long long)boottime.tv_sec);
+	    (long long)G_boottime.tv_sec);
 	return (0);
 }
 
@@ -626,8 +634,8 @@ linprocfs_doloadavg(PFS_FILL_ARGS)
 	    (int)(averunnable.ldavg[2] / averunnable.fscale),
 	    (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
 	    1,				/* number of running tasks */
-	    nprocs,			/* number of tasks */
-	    lastpid			/* the last pid */
+	    VPSV(nprocs),			/* number of tasks */
+	    VPSV(lastpid)			/* the last pid */
 	);
 	return (0);
 }
@@ -685,7 +693,7 @@ linprocfs_doprocstat(PFS_FILL_ARGS)
 	PS_ADD("nice",		"%d",	kp.ki_nice); /* 19 (nicest) to -19 */
 	PS_ADD("0",		"%d",	0); /* removed field */
 	PS_ADD("itrealvalue",	"%d",	0); /* XXX */
-	PS_ADD("starttime",	"%lu",	TV2J(&kp.ki_start) - TV2J(&boottime));
+	PS_ADD("starttime",	"%lu",	TV2J(&kp.ki_start) - TV2J(&G_boottime));
 	PS_ADD("vsize",		"%ju",	P2K((uintmax_t)kp.ki_size));
 	PS_ADD("rss",		"%ju",	(uintmax_t)kp.ki_rssize);
 	PS_ADD("rlim",		"%lu",	kp.ki_rusage.ru_maxrss);
@@ -1208,7 +1216,7 @@ static int
 linprocfs_domsgmni(PFS_FILL_ARGS)
 {
 
-	sbuf_printf(sb, "%d\n", msginfo.msgmni);
+	sbuf_printf(sb, "%d\n", V_msginfo.msgmni);
 	return (0);
 }
 
@@ -1230,8 +1238,8 @@ static int
 linprocfs_dosem(PFS_FILL_ARGS)
 {
 
-	sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
-	    seminfo.semopm, seminfo.semmni);
+	sbuf_printf(sb, "%d %d %d %d\n", V_seminfo.semmsl, V_seminfo.semmns,
+	    V_seminfo.semopm, V_seminfo.semmni);
 	return (0);
 }
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/compat/linux/linux_emul.c head/sys/compat/linux/linux_emul.c
--- clean-head/sys/compat/linux/linux_emul.c	2013-06-26 09:39:20.000000000 +0200
+++ head/sys/compat/linux/linux_emul.c	2013-06-24 14:21:32.000000000 +0200
@@ -47,6 +47,8 @@ __FBSDID("$FreeBSD: head/sys/compat/linu
 #include <sys/sysproto.h>
 #include <sys/unistd.h>
 
+#include <vps/vps.h>
+
 #ifdef COMPAT_LINUX32
 #include <machine/../linux32/linux.h>
 #include <machine/../linux32/linux32_proto.h>
@@ -242,20 +244,20 @@ linux_proc_exit(void *arg __unused, stru
 
 	KASSERT(em != NULL, ("proc_exit: emuldata not found.\n"));
 
-	/* reparent all procs that are not a thread leader to initproc */
+	/* reparent all procs that are not a thread leader to V_initproc */
 	if (em->shared->group_pid != p->p_pid) {
 		LIN_SDT_PROBE3(emul, proc_exit, reparent,
 		    em->shared->group_pid, p->p_pid, p);
 
 		child_clear_tid = em->child_clear_tid;
 		EMUL_UNLOCK(&emul_lock);
-		sx_xlock(&proctree_lock);
-		wakeup(initproc);
+		sx_xlock(&V_proctree_lock);
+		wakeup(V_initproc);
 		PROC_LOCK(p);
-		proc_reparent(p, initproc);
+		proc_reparent(p, V_initproc);
 		p->p_sigparent = SIGCHLD;
 		PROC_UNLOCK(p);
-		sx_xunlock(&proctree_lock);
+		sx_xunlock(&V_proctree_lock);
 	} else {
 		child_clear_tid = em->child_clear_tid;
 		EMUL_UNLOCK(&emul_lock);	
@@ -313,7 +315,7 @@ linux_proc_exit(void *arg __unused, stru
 	free(em, M_LINUX);
 
 	/* this is a little weird but rewritten from exit1() */
-	sx_xlock(&proctree_lock);
+	sx_xlock(&V_proctree_lock);
 	q = LIST_FIRST(&p->p_children);
 	for (; q != NULL; q = nq) {
 		nq = LIST_NEXT(q, p_sibling);
@@ -330,7 +332,7 @@ linux_proc_exit(void *arg __unused, stru
 		PROC_UNLOCK(q);
 		EMUL_UNLOCK(&emul_lock);
 	}
-	sx_xunlock(&proctree_lock);
+	sx_xunlock(&V_proctree_lock);
 
 	LIN_SDT_PROBE0(emul, proc_exit, return);
 }
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/compat/linux/linux_file.c head/sys/compat/linux/linux_file.c
--- clean-head/sys/compat/linux/linux_file.c	2013-06-26 09:39:20.000000000 +0200
+++ head/sys/compat/linux/linux_file.c	2013-06-24 14:21:32.000000000 +0200
@@ -53,6 +53,8 @@ __FBSDID("$FreeBSD: head/sys/compat/linu
 #include <sys/unistd.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+
 #include <security/mac/mac_framework.h>
 
 #include <ufs/ufs/extattr.h>
@@ -145,19 +147,19 @@ linux_common_open(struct thread *td, int
 	     */
 	    error = fget(td, fd, CAP_IOCTL, &fp);
 	    if (!error) {
-		    sx_slock(&proctree_lock);
+		    sx_slock(&V_proctree_lock);
 		    PROC_LOCK(p);
 		    if (!(bsd_flags & O_NOCTTY) &&
 			SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
 			    PROC_UNLOCK(p);
-			    sx_unlock(&proctree_lock);
+			    sx_unlock(&V_proctree_lock);
 			    /* XXXPJD: Verify if TIOCSCTTY is allowed. */
 			    if (fp->f_type == DTYPE_VNODE)
 				    (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
 					     td->td_ucred, td);
 		    } else {
 			    PROC_UNLOCK(p);
-			    sx_sunlock(&proctree_lock);
+			    sx_sunlock(&V_proctree_lock);
 		    }
 		    fdrop(fp, td);
 		    /*
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/compat/linux/linux_fork.c head/sys/compat/linux/linux_fork.c
--- clean-head/sys/compat/linux/linux_fork.c	2013-06-26 09:39:20.000000000 +0200
+++ head/sys/compat/linux/linux_fork.c	2013-06-24 14:21:32.000000000 +0200
@@ -43,6 +43,8 @@ __FBSDID("$FreeBSD: head/sys/compat/linu
 #include <sys/sx.h>
 #include <sys/unistd.h>
 
+#include <vps/vps.h>
+
 #ifdef COMPAT_LINUX32
 #include <machine/../linux32/linux.h>
 #include <machine/../linux32/linux32_proto.h>
@@ -208,11 +210,11 @@ linux_clone(struct thread *td, struct li
 		return (error);
 
 	if (args->flags & (LINUX_CLONE_PARENT | LINUX_CLONE_THREAD)) {
-	   	sx_xlock(&proctree_lock);
+	   	sx_xlock(&V_proctree_lock);
 		PROC_LOCK(p2);
 		proc_reparent(p2, td->td_proc->p_pptr);
 		PROC_UNLOCK(p2);
-		sx_xunlock(&proctree_lock);
+		sx_xunlock(&V_proctree_lock);
 	}
 
 	/* create the emuldata */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/compat/linux/linux_ioctl.c head/sys/compat/linux/linux_ioctl.c
--- clean-head/sys/compat/linux/linux_ioctl.c	2013-06-26 09:39:20.000000000 +0200
+++ head/sys/compat/linux/linux_ioctl.c	2013-06-24 14:21:32.000000000 +0200
@@ -72,6 +72,8 @@ __FBSDID("$FreeBSD: head/sys/compat/linu
 
 #include <dev/usb/usb_ioctl.h>
 
+#include <vps/vps.h>
+
 #ifdef COMPAT_LINUX32
 #include <machine/../linux32/linux.h>
 #include <machine/../linux32/linux32_proto.h>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/compat/linux/linux_ipc.c head/sys/compat/linux/linux_ipc.c
--- clean-head/sys/compat/linux/linux_ipc.c	2013-06-26 09:39:20.000000000 +0200
+++ head/sys/compat/linux/linux_ipc.c	2013-06-24 14:21:32.000000000 +0200
@@ -35,9 +35,11 @@ __FBSDID("$FreeBSD: head/sys/compat/linu
 #include <sys/sysproto.h>
 #include <sys/proc.h>
 #include <sys/limits.h>
-#include <sys/msg.h>
 #include <sys/sem.h>
 #include <sys/shm.h>
+#include <sys/msg.h>
+
+#include <vps/vps.h>
 
 #include "opt_compat.h"
 
@@ -53,6 +55,10 @@ __FBSDID("$FreeBSD: head/sys/compat/linu
 #include <compat/linux/linux_ipc.h>
 #include <compat/linux/linux_util.h>
 
+#define V_msginfo       VPSV(msginfo)
+#define V_seminfo       VPSV(seminfo)
+#define V_shminfo       VPSV(shminfo)
+
 struct l_seminfo {
 	l_int semmap;
 	l_int semmni;
@@ -575,7 +581,7 @@ linux_semctl(struct thread *td, struct l
 		return (error);
 	case LINUX_IPC_INFO:
 	case LINUX_SEM_INFO:
-		bcopy(&seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) -
+		bcopy(&V_seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) -
 		    sizeof(linux_seminfo.semmap) );
 		/*
 		 * Linux does not use the semmap field but populates it with
@@ -594,7 +600,7 @@ linux_semctl(struct thread *td, struct l
 		    PTRIN(args->arg.buf), sizeof(linux_seminfo));
 		if (error)
 			return (error);
-		td->td_retval[0] = seminfo.semmni;
+		td->td_retval[0] = V_seminfo.semmni;
 		return (0);			/* No need for __semctl call */
 	case LINUX_GETALL:
 		cmd = GETALL;
@@ -621,7 +627,7 @@ linux_msgsnd(struct thread *td, struct l
 	l_long lmtype;
 	int error;
 
-	if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax)
+	if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)V_msginfo.msgmax)
 		return (EINVAL);
 	msgp = PTRIN(args->msgp);
 	if ((error = copyin(msgp, &lmtype, sizeof(lmtype))) != 0)
@@ -640,7 +646,7 @@ linux_msgrcv(struct thread *td, struct l
 	l_long lmtype;
 	int error;
 
-	if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax)
+	if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)V_msginfo.msgmax)
 		return (EINVAL);
 	msgp = PTRIN(args->msgp);
 	if ((error = kern_msgrcv(td, args->msqid,
@@ -681,19 +687,19 @@ linux_msgctl(struct thread *td, struct l
 		 * XXX MSG_INFO uses the same data structure but returns different
 		 * dynamic counters in msgpool, msgmap, and msgtql fields.
 		 */
-		linux_msginfo.msgpool = (long)msginfo.msgmni *
-		    (long)msginfo.msgmnb / 1024L;	/* XXX MSG_INFO. */
-		linux_msginfo.msgmap = msginfo.msgmnb;	/* XXX MSG_INFO. */
-		linux_msginfo.msgmax = msginfo.msgmax;
-		linux_msginfo.msgmnb = msginfo.msgmnb;
-		linux_msginfo.msgmni = msginfo.msgmni;
-		linux_msginfo.msgssz = msginfo.msgssz;
-		linux_msginfo.msgtql = msginfo.msgtql;	/* XXX MSG_INFO. */
-		linux_msginfo.msgseg = msginfo.msgseg;
+		linux_msginfo.msgpool = (long)V_msginfo.msgmni *
+		    (long)V_msginfo.msgmnb / 1024L;	/* XXX MSG_INFO. */
+		linux_msginfo.msgmap = V_msginfo.msgmnb;	/* XXX MSG_INFO. */
+		linux_msginfo.msgmax = V_msginfo.msgmax;
+		linux_msginfo.msgmnb = V_msginfo.msgmnb;
+		linux_msginfo.msgmni = V_msginfo.msgmni;
+		linux_msginfo.msgssz = V_msginfo.msgssz;
+		linux_msginfo.msgtql = V_msginfo.msgtql;	/* XXX MSG_INFO. */
+		linux_msginfo.msgseg = V_msginfo.msgseg;
 		error = copyout(&linux_msginfo, PTRIN(args->buf),
 		    sizeof(linux_msginfo));
 		if (error == 0)
-		    td->td_retval[0] = msginfo.msgmni;	/* XXX */
+		    td->td_retval[0] = V_msginfo.msgmni;	/* XXX */
 
 		return (error);
 	}
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/compat/linux/linux_mib.c head/sys/compat/linux/linux_mib.c
--- clean-head/sys/compat/linux/linux_mib.c	2013-06-26 09:39:20.000000000 +0200
+++ head/sys/compat/linux/linux_mib.c	2013-06-24 14:21:32.000000000 +0200
@@ -45,6 +45,8 @@ __FBSDID("$FreeBSD: head/sys/compat/linu
 #include <sys/mutex.h>
 #include <sys/sx.h>
 
+#include <vps/vps.h>
+
 #ifdef COMPAT_LINUX32
 #include <machine/../linux32/linux.h>
 #else
@@ -282,10 +284,10 @@ linux_find_prison(struct prison *spr, st
 
 	if (!linux_osd_jail_slot)
 		/* In case osd_register failed. */
-		spr = &prison0;
+		spr = V_prison0;
 	for (pr = spr;; pr = pr->pr_parent) {
 		mtx_lock(&pr->pr_mtx);
-		lpr = (pr == &prison0)
+		lpr = (pr == V_prison0)
 		    ? &lprison0
 		    : osd_jail_get(pr, linux_osd_jail_slot);
 		if (lpr != NULL)
@@ -660,7 +662,7 @@ linux_osd_jail_register(void)
 	if (linux_osd_jail_slot > 0) {
 		/* Copy the system linux info to any current prisons. */
 		sx_xlock(&allprison_lock);
-		TAILQ_FOREACH(pr, &allprison, pr_list)
+		TAILQ_FOREACH(pr, &V_allprison, pr_list)
 			(void)linux_alloc_prison(pr, NULL);
 		sx_xunlock(&allprison_lock);
 	}
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/compat/linux/linux_misc.c head/sys/compat/linux/linux_misc.c
--- clean-head/sys/compat/linux/linux_misc.c	2013-06-26 09:39:20.000000000 +0200
+++ head/sys/compat/linux/linux_misc.c	2013-06-24 14:21:32.000000000 +0200
@@ -67,6 +67,8 @@ __FBSDID("$FreeBSD: head/sys/compat/linu
 #include <sys/wait.h>
 #include <sys/cpuset.h>
 
+#include <vps/vps.h>
+
 #include <security/mac/mac_framework.h>
 
 #include <vm/vm.h>
@@ -165,7 +167,7 @@ linux_sysinfo(struct thread *td, struct 
 	sysinfo.totalswap = i * PAGE_SIZE;
 	sysinfo.freeswap = (i - j) * PAGE_SIZE;
 
-	sysinfo.procs = nprocs;
+	sysinfo.procs = V_nprocs;
 
 	/* The following are only present in newer Linux kernels. */
 	sysinfo.totalbig = 0;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/compat/svr4/svr4_misc.c head/sys/compat/svr4/svr4_misc.c
--- clean-head/sys/compat/svr4/svr4_misc.c	2013-06-26 09:39:16.000000000 +0200
+++ head/sys/compat/svr4/svr4_misc.c	2013-06-24 14:21:33.000000000 +0200
@@ -68,6 +68,8 @@ __FBSDID("$FreeBSD: head/sys/compat/svr4
 #include <sys/vnode.h>
 #include <sys/wait.h>
 
+#include <vps/vps.h>
+
 #include <compat/svr4/svr4.h>
 #include <compat/svr4/svr4_types.h>
 #include <compat/svr4/svr4_signal.h>
@@ -738,7 +740,7 @@ svr4_sys_sysconfig(td, uap)
 		*retval = 0;	/* No delaytimer support */
 		break;
 	case SVR4_CONFIG_MQ_OPEN_MAX:
-		*retval = msginfo.msgmni;
+		*retval = V_msginfo.msgmni;
 		break;
 	case SVR4_CONFIG_MQ_PRIO_MAX:
 		*retval = 0;	/* XXX: Don't know */
@@ -747,10 +749,10 @@ svr4_sys_sysconfig(td, uap)
 		*retval = 0;
 		break;
 	case SVR4_CONFIG_SEM_NSEMS_MAX:
-		*retval = seminfo.semmni;
+		*retval = V_seminfo.semmni;
 		break;
 	case SVR4_CONFIG_SEM_VALUE_MAX:
-		*retval = seminfo.semvmx;
+		*retval = V_seminfo.semvmx;
 		break;
 	case SVR4_CONFIG_SIGQUEUE_MAX:
 		*retval = 0;	/* XXX: Don't know */
@@ -1236,7 +1238,7 @@ svr4_sys_waitsys(td, uap)
 	 */
 loop:
 	nfound = 0;
-	sx_slock(&proctree_lock);
+	sx_slock(&V_proctree_lock);
 	LIST_FOREACH(p, &q->p_children, p_sibling) {
 		PROC_LOCK(p);
 		if (pid != WAIT_ANY &&
@@ -1272,7 +1274,7 @@ loop:
 			calcru(p, &ru.ru_utime, &ru.ru_stime);
 			PROC_SUNLOCK(p);
 			PROC_UNLOCK(p);
-			sx_sunlock(&proctree_lock);
+			sx_sunlock(&V_proctree_lock);
 
 			/* Copy the info out to userland. */
 			*retval = 0;
@@ -1291,7 +1293,7 @@ loop:
 			PROC_SUNLOCK(p);
 		        if (((uap->options & SVR4_WNOWAIT)) == 0)
 				p->p_flag |= P_WAITED;
-			sx_sunlock(&proctree_lock);
+			sx_sunlock(&V_proctree_lock);
 			pid = p->p_pid;
 			status = W_STOPCODE(p->p_xstat);
 			ru = p->p_ru;
@@ -1313,7 +1315,7 @@ loop:
 		PROC_SUNLOCK(p);
 		if (uap->options & SVR4_WCONTINUED &&
 		    (p->p_flag & P_CONTINUED)) {
-			sx_sunlock(&proctree_lock);
+			sx_sunlock(&V_proctree_lock);
 		        if (((uap->options & SVR4_WNOWAIT)) == 0)
 				p->p_flag &= ~P_CONTINUED;
 			pid = p->p_pid;
@@ -1338,18 +1340,18 @@ loop:
 	}
 
 	if (nfound == 0) {
-		sx_sunlock(&proctree_lock);
+		sx_sunlock(&V_proctree_lock);
 		return (ECHILD);
 	}
 
 	if (uap->options & SVR4_WNOHANG) {
-		sx_sunlock(&proctree_lock);
+		sx_sunlock(&V_proctree_lock);
 		*retval = 0;
 		return (svr4_setinfo(0, NULL, 0, uap->info));
 	}
 
 	PROC_LOCK(q);
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 	if (q->p_flag & P_STATCHILD) {
 		q->p_flag &= ~P_STATCHILD;
 		error = 0;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/conf/files head/sys/conf/files
--- clean-head/sys/conf/files	2013-06-26 09:37:34.000000000 +0200
+++ head/sys/conf/files	2013-06-24 14:20:29.000000000 +0200
@@ -4,6 +4,7 @@
 # limitations in config: backslash-newline doesn't work in strings, and
 # dependency lines other than the first are silently ignored.
 #
+
 acpi_quirks.h			optional acpi				   \
 	dependency	"$S/tools/acpi_quirks2h.awk $S/dev/acpica/acpi_quirks" \
 	compile-with	"${AWK} -f $S/tools/acpi_quirks2h.awk $S/dev/acpica/acpi_quirks" \
@@ -3706,6 +3707,32 @@ vm/vm_reserv.c			standard
 vm/vm_unix.c			standard
 vm/vm_zeroidle.c		standard
 vm/vnode_pager.c		standard
+#
+vps/vps_core.c			optional vps
+vps/vps_priv.c			optional vps
+vps/vps_console.c		optional vps
+vps/vps_pager.c			optional vps
+#
+vps/vps_account.c		optional vps_static
+#
+vps/vps_suspend.c		optional vps_static
+#
+vps/vps_dev.c			optional vps_static
+vps/vps_user.c			optional vps_static
+#
+vps/if_vps.c			optional vps_static
+#
+vps/vps_snapst.c		optional vps_static
+vps/vps_restore.c		optional vps_static
+vps/vps_libdump.c		optional vps_static
+#
+vps/vps_ddb.c			optional vps_static
+#
+fs/vpsfs/vpsfs_subr.c		optional vps_static
+fs/vpsfs/vpsfs_vfsops.c		optional vps_static
+fs/vpsfs/vpsfs_vnops.c		optional vps_static
+fs/vpsfs/vpsfs_quota.c		optional vps_static
+#
 xen/gnttab.c			optional xen | xenhvm
 xen/features.c			optional xen | xenhvm
 xen/evtchn/evtchn.c		optional xen
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/conf/files.amd64 head/sys/conf/files.amd64
--- clean-head/sys/conf/files.amd64	2013-06-26 09:37:34.000000000 +0200
+++ head/sys/conf/files.amd64	2013-06-24 14:20:29.000000000 +0200
@@ -129,6 +129,7 @@ amd64/amd64/trap.c		standard
 amd64/amd64/uio_machdep.c	standard
 amd64/amd64/uma_machdep.c	standard
 amd64/amd64/vm_machdep.c	standard
+amd64/amd64/vps_machdep.c	optional	vps
 amd64/pci/pci_cfgreg.c		optional	pci
 cddl/contrib/opensolaris/common/atomic/amd64/opensolaris_atomic.S	optional zfs compile-with "${ZFS_S}"
 crypto/aesni/aesencdec_amd64.S	optional aesni
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/conf/files.i386 head/sys/conf/files.i386
--- clean-head/sys/conf/files.i386	2013-06-26 09:37:34.000000000 +0200
+++ head/sys/conf/files.i386	2013-06-24 14:20:29.000000000 +0200
@@ -452,6 +452,7 @@ i386/i386/trap.c		standard
 i386/i386/uio_machdep.c		standard
 i386/i386/vm86.c		standard
 i386/i386/vm_machdep.c		standard
+i386/i386/vps_machdep.c		optional vps
 i386/ibcs2/ibcs2_errno.c	optional ibcs2
 i386/ibcs2/ibcs2_fcntl.c	optional ibcs2
 i386/ibcs2/ibcs2_ioctl.c	optional ibcs2
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/conf/files.mips head/sys/conf/files.mips
--- clean-head/sys/conf/files.mips	2013-06-26 09:37:34.000000000 +0200
+++ head/sys/conf/files.mips	2013-06-24 14:20:29.000000000 +0200
@@ -45,6 +45,7 @@ mips/mips/trap.c			standard
 mips/mips/uio_machdep.c			standard
 mips/mips/uma_machdep.c			standard
 mips/mips/vm_machdep.c			standard
+mips/mips/vps_machdep.c			optional	vps
 
 # misc opt-in bits
 kern/kern_clocksource.c			standard
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/conf/options head/sys/conf/options
--- clean-head/sys/conf/options	2013-06-26 09:37:34.000000000 +0200
+++ head/sys/conf/options	2013-06-24 14:20:29.000000000 +0200
@@ -877,6 +877,9 @@ SND_FEEDER_RATE_HP	opt_snd.h
 SND_PCM_64		opt_snd.h
 SND_OLDSTEREO		opt_snd.h
 
+VPS			opt_global.h
+VPS_STATIC		opt_global.h
+
 X86BIOS
 
 # Flattened device tree options
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/ddb/db_command.c head/sys/ddb/db_command.c
--- clean-head/sys/ddb/db_command.c	2013-06-26 09:37:39.000000000 +0200
+++ head/sys/ddb/db_command.c	2013-06-24 14:21:40.000000000 +0200
@@ -56,6 +56,8 @@ __FBSDID("$FreeBSD: head/sys/ddb/db_comm
 #include <machine/cpu.h>
 #include <machine/setjmp.h>
 
+#include <vps/vps.h>
+
 /*
  * Exported global variables
  */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/ddb/db_ps.c head/sys/ddb/db_ps.c
--- clean-head/sys/ddb/db_ps.c	2013-06-26 09:37:39.000000000 +0200
+++ head/sys/ddb/db_ps.c	2013-06-24 14:21:40.000000000 +0200
@@ -42,6 +42,8 @@ __FBSDID("$FreeBSD: head/sys/ddb/db_ps.c
 #include <vm/vm_param.h>
 #include <vm/pmap.h>
 
+#include <vps/vps.h>
+
 #include <ddb/ddb.h>
 
 static void	dumpthread(volatile struct proc *p, volatile struct thread *td,
@@ -84,10 +86,10 @@ db_ps(db_expr_t addr, boolean_t hasaddr,
 	char state[9];
 	int np, rflag, sflag, dflag, lflag, wflag;
 
-	np = nprocs;
+	np = V_nprocs;
 
-	if (!LIST_EMPTY(&allproc))
-		p = LIST_FIRST(&allproc);
+	if (!LIST_EMPTY(&V_allproc))
+		p = LIST_FIRST(&V_allproc);
 	else
 		p = &proc0;
 
@@ -210,7 +212,7 @@ db_ps(db_expr_t addr, boolean_t hasaddr,
 
 		p = LIST_NEXT(p, p_list);
 		if (p == NULL && np > 0)
-			p = LIST_FIRST(&zombproc);
+			p = LIST_FIRST(&V_zombproc);
     	}
 }
 
@@ -374,6 +376,11 @@ DB_SHOW_COMMAND(thread, db_show_thread)
 		    td->td_wchan);
 	db_printf(" priority: %d\n", td->td_priority);
 	db_printf(" container lock: %s (%p)\n", lock->lo_name, lock);
+#ifdef VPS
+	db_printf(" td_vps: %p\n", td->td_vps);
+	if (td->td_ucred)
+		db_printf(" td_ucred->cr_vps: %p\n", td->td_ucred->cr_vps);
+#endif
 }
 
 DB_SHOW_COMMAND(proc, db_show_proc)
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/ddb/db_thread.c head/sys/ddb/db_thread.c
--- clean-head/sys/ddb/db_thread.c	2013-06-26 09:37:39.000000000 +0200
+++ head/sys/ddb/db_thread.c	2013-06-24 14:21:40.000000000 +0200
@@ -38,6 +38,8 @@ __FBSDID("$FreeBSD: head/sys/ddb/db_thre
 #include <ddb/db_command.h>
 #include <ddb/db_sym.h>
 
+#include <vps/vps.h>
+
 void
 db_print_thread(void)
 {
@@ -137,7 +139,7 @@ db_lookup_thread(db_expr_t addr, boolean
 			if (p->p_pid == decaddr)
 				return (FIRST_THREAD_IN_PROC(p));
 		}
-		LIST_FOREACH(p, &zombproc, p_list) {
+		LIST_FOREACH(p, &V_zombproc, p_list) {
 			if (p->p_pid == decaddr)
 				return (FIRST_THREAD_IN_PROC(p));
 		}
@@ -163,7 +165,7 @@ db_lookup_proc(db_expr_t addr)
 			if (p->p_pid == decaddr)
 				return (p);
 		}
-		LIST_FOREACH(p, &zombproc, p_list) {
+		LIST_FOREACH(p, &V_zombproc, p_list) {
 			if (p->p_pid == decaddr)
 				return (p);
 		}
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/dev/firewire/firewire.c head/sys/dev/firewire/firewire.c
--- clean-head/sys/dev/firewire/firewire.c	2013-06-26 09:36:57.000000000 +0200
+++ head/sys/dev/firewire/firewire.c	2013-06-24 14:21:02.000000000 +0200
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD: head/sys/dev/firewir
 #include <sys/malloc.h>
 #include <sys/conf.h>
 #include <sys/sysctl.h>
+#include <sys/proc.h>
 #include <sys/kthread.h>
 
 #include <sys/kdb.h>
@@ -56,6 +57,8 @@ __FBSDID("$FreeBSD: head/sys/dev/firewir
 #include <sys/bus.h>		/* used by smbus and newbus */
 #include <machine/bus.h>
 
+#include <vps/vps.h>
+
 #ifdef __DragonFly__
 #include "firewire.h"
 #include "firewirereg.h"
@@ -724,9 +727,9 @@ fw_reset_crom(struct firewire_comm *fc)
 	crom_add_simple_text(src, root, &buf->vendor, "FreeBSD Project");
 	crom_add_entry(root, CSRKEY_HW, __FreeBSD_version);
 #endif
-	mtx_lock(&prison0.pr_mtx);
-	crom_add_simple_text(src, root, &buf->hw, prison0.pr_hostname);
-	mtx_unlock(&prison0.pr_mtx);
+	mtx_lock(&V_prison0->pr_mtx);
+	crom_add_simple_text(src, root, &buf->hw, V_prison0->pr_hostname);
+	mtx_unlock(&V_prison0->pr_mtx);
 }
 
 /*
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/dev/hwpmc/hwpmc_mod.c head/sys/dev/hwpmc/hwpmc_mod.c
--- clean-head/sys/dev/hwpmc/hwpmc_mod.c	2013-06-26 09:36:30.000000000 +0200
+++ head/sys/dev/hwpmc/hwpmc_mod.c	2013-06-24 14:21:05.000000000 +0200
@@ -62,6 +62,8 @@ __FBSDID("$FreeBSD: head/sys/dev/hwpmc/h
 
 #include <sys/linker.h>		/* needs to be after <sys/malloc.h> */
 
+#include <vps/vps.h>
+
 #include <machine/atomic.h>
 #include <machine/md_var.h>
 
@@ -1057,7 +1059,7 @@ pmc_attach_process(struct proc *p, struc
 	 * this PMC.
 	 */
 
-	sx_slock(&proctree_lock);
+	sx_slock(&V_proctree_lock);
 
 	top = p;
 
@@ -1081,7 +1083,7 @@ pmc_attach_process(struct proc *p, struc
 		(void) pmc_detach_process(top, pm);
 
  done:
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 	return error;
 }
 
@@ -1166,7 +1168,7 @@ pmc_detach_process(struct proc *p, struc
 	 * partially attached proc tree.
 	 */
 
-	sx_slock(&proctree_lock);
+	sx_slock(&V_proctree_lock);
 
 	top = p;
 
@@ -1187,7 +1189,7 @@ pmc_detach_process(struct proc *p, struc
 	}
 
  done:
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 
 	if (LIST_EMPTY(&pm->pm_targets))
 		pm->pm_flags &= ~PMC_F_ATTACH_DONE;
@@ -1798,7 +1800,7 @@ pmc_log_all_process_mappings(struct pmc_
 
 	PROC_UNLOCK(p);
 
-	sx_slock(&proctree_lock);
+	sx_slock(&V_proctree_lock);
 
 	top = p;
 
@@ -1817,7 +1819,7 @@ pmc_log_all_process_mappings(struct pmc_
 		}
 	}
  done:
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 }
 
 /*
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/dev/syscons/daemon/daemon_saver.c head/sys/dev/syscons/daemon/daemon_saver.c
--- clean-head/sys/dev/syscons/daemon/daemon_saver.c	2013-06-26 09:37:23.000000000 +0200
+++ head/sys/dev/syscons/daemon/daemon_saver.c	2013-06-24 14:21:15.000000000 +0200
@@ -37,6 +37,9 @@
 #include <sys/sysctl.h>
 #include <sys/consio.h>
 #include <sys/fbio.h>
+#include <sys/proc.h>
+
+#include <vps/vps.h>
 
 #include <machine/pc/display.h>
 
@@ -353,23 +356,23 @@ daemon_init(video_adapter_t *adp)
 {
 	size_t hostlen;
 
-	mtx_lock(&prison0.pr_mtx);
+	mtx_lock(&V_prison0->pr_mtx);
 	for (;;) {
-		hostlen = strlen(prison0.pr_hostname);
-		mtx_unlock(&prison0.pr_mtx);
+		hostlen = strlen(V_prison0->pr_hostname);
+		mtx_unlock(&V_prison0->pr_mtx);
 	
 		messagelen = hostlen + 3 + strlen(ostype) + 1 +
 		    strlen(osrelease);
 		message = malloc(messagelen + 1, M_DEVBUF, M_WAITOK);
-		mtx_lock(&prison0.pr_mtx);
-		if (hostlen < strlen(prison0.pr_hostname)) {
+		mtx_lock(&V_prison0->pr_mtx);
+		if (hostlen < strlen(V_prison0->pr_hostname)) {
 			free(message, M_DEVBUF);
 			continue;
 		}
 		break;
 	}
-	sprintf(message, "%s - %s %s", prison0.pr_hostname, ostype, osrelease);
-	mtx_unlock(&prison0.pr_mtx);
+	sprintf(message, "%s - %s %s", V_prison0->pr_hostname, ostype, osrelease);
+	mtx_unlock(&V_prison0->pr_mtx);
 	blanked = 0;
 	switch (adp->va_mode) {
 	case M_PC98_80x25:
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/dev/syscons/syscons.c head/sys/dev/syscons/syscons.c
--- clean-head/sys/dev/syscons/syscons.c	2013-06-26 09:37:23.000000000 +0200
+++ head/sys/dev/syscons/syscons.c	2013-06-24 14:21:15.000000000 +0200
@@ -61,6 +61,9 @@ __FBSDID("$FreeBSD: head/sys/dev/syscons
 #include <sys/tty.h>
 #include <sys/power.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <machine/clock.h>
 #if defined(__arm__) || defined(__mips__) || \
 	defined(__powerpc__) || defined(__sparc64__)
@@ -360,7 +363,11 @@ sc_alloc_tty(int index, int devnum)
 	tp = tty_alloc_mutex(&sc_ttydevsw, stc, &Giant);
 
 	/* Create device node. */
+#ifdef VPS
+	tty_makedev(tp, vps0->vps_ucred, "v%r", devnum);
+#else
 	tty_makedev(tp, NULL, "v%r", devnum);
+#endif
 
 	return (tp);
 }
@@ -565,8 +572,13 @@ sc_attach_unit(int unit, int flags)
 	 */
     }
 
+#ifdef VPS
+    dev = make_dev_cred(&consolectl_devsw, 0, vps0->vps_ucred,
+	UID_ROOT, GID_WHEEL, 0600, "consolectl");
+#else
     dev = make_dev(&consolectl_devsw, 0, UID_ROOT, GID_WHEEL, 0600,
         "consolectl");
+#endif
     dev->si_drv1 = sc->dev[0];
 
     return 0;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/devfs/devfs.h head/sys/fs/devfs/devfs.h
--- clean-head/sys/fs/devfs/devfs.h	2013-06-26 09:38:35.000000000 +0200
+++ head/sys/fs/devfs/devfs.h	2013-06-24 14:20:41.000000000 +0200
@@ -161,6 +161,10 @@ struct devfs_mount {
 	int			dm_holdcnt;
 	struct sx		dm_lock;
 	devfs_rsnum		dm_ruleset;
+#ifdef VPS
+	struct vps		*dm_vps;
+	int			dm_vps_rsnum;
+#endif
 };
 
 #define DEVFS_ROOTINO 2
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/devfs/devfs_devs.c head/sys/fs/devfs/devfs_devs.c
--- clean-head/sys/fs/devfs/devfs_devs.c	2013-06-26 09:38:35.000000000 +0200
+++ head/sys/fs/devfs/devfs_devs.c	2013-06-24 14:20:41.000000000 +0200
@@ -43,6 +43,9 @@
 
 #include <sys/kdb.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <fs/devfs/devfs.h>
 #include <fs/devfs/devfs_int.h>
 
@@ -145,12 +148,23 @@ int
 devfs_dev_exists(const char *name)
 {
 	struct cdev_priv *cdp;
+#ifdef VPS
+	struct vps *vps = curthread->td_vps;
+#endif
 
 	mtx_assert(&devmtx, MA_OWNED);
 
 	TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) {
 		if ((cdp->cdp_flags & CDP_ACTIVE) == 0)
 			continue;
+#ifdef VPS
+		if ((cdp->cdp_c.si_cred && cdp->cdp_c.si_cred->cr_vps != vps))
+			/* 
+			 * This device does not belong to the
+			 * vps instance that is asking.
+			 */
+			continue;
+#endif
 		if (devfs_pathpath(cdp->cdp_c.si_name, name) != 0)
 			return (1);
 		if (devfs_pathpath(name, cdp->cdp_c.si_name) != 0)
@@ -546,6 +560,10 @@ devfs_populate_loop(struct devfs_mount *
 			continue;
 		}
 
+#ifdef VPS
+		if (vps_devfs_whiteout_cb(dm, cdp))
+			continue;
+#endif /* VPS */
 
 		cdp->cdp_inuse++;
 		dev_unlock();
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/devfs/devfs_rule.c head/sys/fs/devfs/devfs_rule.c
--- clean-head/sys/fs/devfs/devfs_rule.c	2013-06-26 09:38:35.000000000 +0200
+++ head/sys/fs/devfs/devfs_rule.c	2013-06-24 14:20:41.000000000 +0200
@@ -105,10 +105,8 @@ static void devfs_rule_applyde_recursive
 static void devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm);
 static int  devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnp);
 static struct devfs_krule *devfs_rule_byid(devfs_rid rid);
-static int  devfs_rule_delete(struct devfs_krule *dkp);
 static struct cdev *devfs_rule_getdev(struct devfs_dirent *de);
 static int  devfs_rule_input(struct devfs_rule *dr, struct devfs_mount *dm);
-static int  devfs_rule_insert(struct devfs_rule *dr);
 static int  devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de);
 static int  devfs_rule_matchpath(struct devfs_krule *dk,
 		struct devfs_dirent *de);
@@ -118,10 +116,12 @@ static void devfs_ruleset_applyde(struct
 		struct devfs_dirent *de, unsigned depth);
 static void devfs_ruleset_applydm(struct devfs_ruleset *ds,
 		struct devfs_mount *dm);
-static struct devfs_ruleset *devfs_ruleset_bynum(devfs_rsnum rsnum);
 static struct devfs_ruleset *devfs_ruleset_create(devfs_rsnum rsnum);
 static void devfs_ruleset_reap(struct devfs_ruleset *dsp);
+static struct devfs_ruleset *devfs_ruleset_bynum(devfs_rsnum rsnum);
+static int  devfs_rule_delete(struct devfs_krule *dkp);
 static int  devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm);
+static int  devfs_rule_insert(struct devfs_rule *dr);
 
 static struct sx sx_rules;
 SX_SYSINIT(sx_rules, &sx_rules, "DEVFS ruleset lock");
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/devfs/devfs_vfsops.c head/sys/fs/devfs/devfs_vfsops.c
--- clean-head/sys/fs/devfs/devfs_vfsops.c	2013-06-26 09:38:35.000000000 +0200
+++ head/sys/fs/devfs/devfs_vfsops.c	2013-06-24 14:20:41.000000000 +0200
@@ -46,6 +46,9 @@
 #include <sys/limits.h>
 #include <sys/jail.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <fs/devfs/devfs.h>
 
 static struct unrhdr	*devfs_unr;
@@ -142,6 +145,17 @@ devfs_mount(struct mount *mp)
 
 	fmp->dm_rootdir = devfs_vmkdir(fmp, NULL, 0, NULL, DEVFS_ROOTINO);
 
+#ifdef VPS
+	/* Get number of an apropriate ruleset. */
+	error = vps_devfs_mount_cb(fmp, &rsnum);
+	if (error != 0) {
+		sx_destroy(&fmp->dm_lock);
+		free_unr(devfs_unr, fmp->dm_idx);
+		free(fmp, M_DEVFS);
+		return (error);
+	}
+#endif /* VPS */
+
 	error = devfs_root(mp, LK_EXCLUSIVE, &rvp);
 	if (error) {
 		sx_destroy(&fmp->dm_lock);
@@ -195,6 +209,9 @@ devfs_unmount(struct mount *mp, int mntf
 	idx = fmp->dm_idx;
 	sx_xunlock(&fmp->dm_lock);
 	free_unr(devfs_unr, idx);
+#ifdef VPS
+	(void)vps_devfs_unmount_cb(fmp);
+#endif /* VPS */
 	if (hold == 0)
 		devfs_unmount_final(fmp);
 	return 0;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/devfs/devfs_vnops.c head/sys/fs/devfs/devfs_vnops.c
--- clean-head/sys/fs/devfs/devfs_vnops.c	2013-06-26 09:38:35.000000000 +0200
+++ head/sys/fs/devfs/devfs_vnops.c	2013-06-24 14:20:41.000000000 +0200
@@ -62,6 +62,9 @@
 #include <sys/unistd.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 static struct vop_vector devfs_vnodeops;
 static struct vop_vector devfs_specops;
 static struct fileops devfs_ops_f;
@@ -546,7 +549,7 @@ devfs_close(struct vop_close_args *ap)
 	 * plus the session), release the reference from the session.
 	 */
 	oldvp = NULL;
-	sx_xlock(&proctree_lock);
+	sx_xlock(&V_proctree_lock);
 	if (td && vp == td->td_proc->p_session->s_ttyvp) {
 		SESS_LOCK(td->td_proc->p_session);
 		VI_LOCK(vp);
@@ -558,7 +561,7 @@ devfs_close(struct vop_close_args *ap)
 		VI_UNLOCK(vp);
 		SESS_UNLOCK(td->td_proc->p_session);
 	}
-	sx_xunlock(&proctree_lock);
+	sx_xunlock(&V_proctree_lock);
 	if (oldvp != NULL)
 		vrele(oldvp);
 	/*
@@ -684,12 +687,12 @@ devfs_getattr(struct vop_getattr_args *a
 	vap->va_blocksize = DEV_BSIZE;
 	vap->va_type = vp->v_type;
 
-#define fix(aa)							\
-	do {							\
-		if ((aa).tv_sec <= 3600) {			\
-			(aa).tv_sec = boottime.tv_sec;		\
-			(aa).tv_nsec = boottime.tv_usec * 1000; \
-		}						\
+#define fix(aa)								\
+	do {								\
+		if ((aa).tv_sec <= 3600) {				\
+			(aa).tv_sec = G_boottime.tv_sec;		\
+			(aa).tv_nsec = G_boottime.tv_usec * 1000; 	\
+		}							\
 	} while (0)
 
 	if (vp->v_type != VCHR)  {
@@ -763,9 +766,9 @@ devfs_ioctl_f(struct file *fp, u_long co
 		vp = fp->f_vnode;
 
 		/* Do nothing if reassigning same control tty */
-		sx_slock(&proctree_lock);
+		sx_slock(&V_proctree_lock);
 		if (td->td_proc->p_session->s_ttyvp == vp) {
-			sx_sunlock(&proctree_lock);
+			sx_sunlock(&V_proctree_lock);
 			return (0);
 		}
 
@@ -776,7 +779,7 @@ devfs_ioctl_f(struct file *fp, u_long co
 		td->td_proc->p_session->s_ttydp = cdev2priv(dev);
 		SESS_UNLOCK(td->td_proc->p_session);
 
-		sx_sunlock(&proctree_lock);
+		sx_sunlock(&V_proctree_lock);
 
 		/* Get rid of reference to old control tty */
 		if (vpold)
@@ -1364,6 +1367,10 @@ devfs_remove(struct vop_remove_args *ap)
  * as well so that we create a new one next time around.
  *
  */
+#ifdef VPS
+extern struct cdev *dev_console;
+#endif
+
 static int
 devfs_revoke(struct vop_revoke_args *ap)
 {
@@ -1377,6 +1384,16 @@ devfs_revoke(struct vop_revoke_args *ap)
 
 	dev = vp->v_rdev;
 	cdp = cdev2priv(dev);
+
+#ifdef VPS
+	if (dev != dev_console && !strcmp(dev->si_name, "console")) {
+		/* 
+		 * This is a virtual console device, and we don't
+		 * like being revoked.
+		 */
+	   return (EPERM);
+	}
+#endif
  
 	dev_lock();
 	cdp->cdp_inuse++;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/fdescfs/fdesc_vnops.c head/sys/fs/fdescfs/fdesc_vnops.c
--- clean-head/sys/fs/fdescfs/fdesc_vnops.c	2013-06-26 09:38:32.000000000 +0200
+++ head/sys/fs/fdescfs/fdesc_vnops.c	2013-06-24 14:20:41.000000000 +0200
@@ -55,6 +55,8 @@
 #include <sys/stat.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+
 #include <fs/fdescfs/fdesc.h>
 
 #define	NFDCACHE 4
@@ -399,7 +401,7 @@ fdesc_getattr(ap)
 	vap->va_uid = 0;
 	vap->va_gid = 0;
 	vap->va_blocksize = DEV_BSIZE;
-	vap->va_atime.tv_sec = boottime.tv_sec;
+	vap->va_atime.tv_sec = G_boottime.tv_sec;
 	vap->va_atime.tv_nsec = 0;
 	vap->va_mtime = vap->va_atime;
 	vap->va_ctime = vap->va_mtime;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/nfs/nfsport.h head/sys/fs/nfs/nfsport.h
--- clean-head/sys/fs/nfs/nfsport.h	2013-06-26 09:38:34.000000000 +0200
+++ head/sys/fs/nfs/nfsport.h	2013-06-24 14:20:40.000000000 +0200
@@ -99,6 +99,8 @@
 #include <rpc/rpc.h>
 #include <rpc/rpcsec_gss.h>
 
+#include <vps/vps.h>
+
 /*
  * For Darwin, these functions should be "static" when built in a kext.
  * (This is always defined as nil otherwise.)
@@ -636,8 +638,8 @@ void nfsrvd_rcv(struct socket *, void *,
 #define	NFSUNLOCKMNT(m)		mtx_unlock(&((m)->nm_mtx))
 #define	NFSLOCKREQUEST(r)	mtx_lock(&((r)->r_mtx))
 #define	NFSUNLOCKREQUEST(r)	mtx_unlock(&((r)->r_mtx))
-#define	NFSPROCLISTLOCK()	sx_slock(&allproc_lock)
-#define	NFSPROCLISTUNLOCK()	sx_sunlock(&allproc_lock)
+#define	NFSPROCLISTLOCK()	sx_slock(&V_allproc_lock)
+#define	NFSPROCLISTUNLOCK()	sx_sunlock(&V_allproc_lock)
 #define	NFSLOCKSOCKREQ(r)	mtx_lock(&((r)->nr_mtx))
 #define	NFSUNLOCKSOCKREQ(r)	mtx_unlock(&((r)->nr_mtx))
 #define	NFSLOCKDS(d)		mtx_lock(&((d)->nfsclds_mtx))
@@ -869,7 +871,7 @@ int newnfs_realign(struct mbuf **, int);
 /*
  * Set boottime.
  */
-#define	NFSSETBOOTTIME(b)	((b) = boottime)
+#define	NFSSETBOOTTIME(b)	((b) = G_boottime)
 
 /*
  * The size of directory blocks in the buffer cache.
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/nfsclient/nfs_clvfsops.c head/sys/fs/nfsclient/nfs_clvfsops.c
--- clean-head/sys/fs/nfsclient/nfs_clvfsops.c	2013-06-26 09:38:34.000000000 +0200
+++ head/sys/fs/nfsclient/nfs_clvfsops.c	2013-06-24 14:20:40.000000000 +0200
@@ -496,10 +496,10 @@ nfs_mountroot(struct mount *mp)
 	 * set hostname here and then let the "/etc/rc.xxx" files
 	 * mount the right /var based upon its preset value.
 	 */
-	mtx_lock(&prison0.pr_mtx);
-	strlcpy(prison0.pr_hostname, nd->my_hostnam,
-	    sizeof(prison0.pr_hostname));
-	mtx_unlock(&prison0.pr_mtx);
+	mtx_lock(&V_prison0->pr_mtx);
+	strlcpy(V_prison0->pr_hostname, nd->my_hostnam,
+	    sizeof(V_prison0->pr_hostname));
+	mtx_unlock(&V_prison0->pr_mtx);
 	inittodr(ntohl(nd->root_time));
 	return (0);
 }
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/procfs/procfs_ctl.c head/sys/fs/procfs/procfs_ctl.c
--- clean-head/sys/fs/procfs/procfs_ctl.c	2013-06-26 09:38:35.000000000 +0200
+++ head/sys/fs/procfs/procfs_ctl.c	2013-06-24 14:20:40.000000000 +0200
@@ -47,6 +47,7 @@
 #include <sys/signalvar.h>
 #include <sys/sx.h>
 #include <sys/uio.h>
+#include <vps/vps.h>
 
 #include <fs/pseudofs/pseudofs.h>
 #include <fs/procfs/procfs.h>
@@ -117,7 +118,7 @@ procfs_control(struct thread *td, struct
 	 * by the calling process.
 	 */
 	if (op == PROCFS_CTL_ATTACH) {
-		sx_xlock(&proctree_lock);
+		sx_xlock(&V_proctree_lock);
 		PROC_LOCK(p);
 		if ((error = p_candebug(td, p)) != 0)
 			goto out;
@@ -150,7 +151,7 @@ procfs_control(struct thread *td, struct
 		kern_psignal(p, SIGSTOP);
 out:
 		PROC_UNLOCK(p);
-		sx_xunlock(&proctree_lock);
+		sx_xunlock(&V_proctree_lock);
 		return (error);
 	}
 
@@ -222,7 +223,7 @@ out:
 		PROC_UNLOCK(p);
 
 		/* give process back to original parent */
-		sx_xlock(&proctree_lock);
+		sx_xlock(&V_proctree_lock);
 		if (p->p_oppid != p->p_pptr->p_pid) {
 			struct proc *pp;
 
@@ -236,7 +237,7 @@ out:
 			PROC_LOCK(p);
 		p->p_oppid = 0;
 		p->p_flag &= ~P_WAITED;	/* XXX ? */
-		sx_xunlock(&proctree_lock);
+		sx_xunlock(&V_proctree_lock);
 
 		wakeup(td->td_proc);	/* XXX for CTL_WAIT below ? */
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/procfs/procfs_status.c head/sys/fs/procfs/procfs_status.c
--- clean-head/sys/fs/procfs/procfs_status.c	2013-06-26 09:38:35.000000000 +0200
+++ head/sys/fs/procfs/procfs_status.c	2013-06-24 14:20:40.000000000 +0200
@@ -53,6 +53,9 @@
 #include <sys/sysent.h>
 #include <sys/tty.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <vm/vm.h>
 #include <vm/pmap.h>
 #include <vm/vm_param.h>
@@ -129,7 +132,7 @@ procfs_doprocstatus(PFS_FILL_ARGS)
 		calcru(p, &ut, &st);
 		PROC_SUNLOCK(p);
 		start = p->p_stats->p_start;
-		timevaladd(&start, &boottime);
+		timevaladd(&start, &G_boottime);
 		sbuf_printf(sb, " %jd,%ld %jd,%ld %jd,%ld",
 		    (intmax_t)start.tv_sec, start.tv_usec,
 		    (intmax_t)ut.tv_sec, ut.tv_usec,
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/pseudofs/pseudofs_vnops.c head/sys/fs/pseudofs/pseudofs_vnops.c
--- clean-head/sys/fs/pseudofs/pseudofs_vnops.c	2013-06-26 09:38:34.000000000 +0200
+++ head/sys/fs/pseudofs/pseudofs_vnops.c	2013-06-24 14:20:40.000000000 +0200
@@ -49,6 +49,8 @@ __FBSDID("$FreeBSD: head/sys/fs/pseudofs
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+
 #include <fs/pseudofs/pseudofs.h>
 #include <fs/pseudofs/pseudofs_internal.h>
 
@@ -704,7 +706,7 @@ pfs_iterate(struct thread *td, struct pr
 {
 	int visible;
 
-	sx_assert(&allproc_lock, SX_SLOCKED);
+	sx_assert(&V_allproc_lock, SX_SLOCKED);
 	pfs_assert_owned(pd);
  again:
 	if (*pn == NULL) {
@@ -717,7 +719,7 @@ pfs_iterate(struct thread *td, struct pr
 	if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) {
 		/* next process */
 		if (*p == NULL)
-			*p = LIST_FIRST(&allproc);
+			*p = LIST_FIRST(&V_allproc);
 		else
 			*p = LIST_NEXT(*p, p_list);
 		/* out of processes: next node */
@@ -790,12 +792,12 @@ pfs_readdir(struct vop_readdir_args *va)
 	if (resid == 0)
 		PFS_RETURN (0);
 
-	sx_slock(&allproc_lock);
+	sx_slock(&V_allproc_lock);
 	pfs_lock(pd);
 
         /* check if the directory is visible to the caller */
         if (!pfs_visible(curthread, pd, pid, &proc)) {
-		sx_sunlock(&allproc_lock);
+		sx_sunlock(&V_allproc_lock);
 		pfs_unlock(pd);
                 PFS_RETURN (ENOENT);
 	}
@@ -809,7 +811,7 @@ pfs_readdir(struct vop_readdir_args *va)
 			if (proc != NULL)
 				PROC_UNLOCK(proc);
 			pfs_unlock(pd);
-			sx_sunlock(&allproc_lock);
+			sx_sunlock(&V_allproc_lock);
 			PFS_RETURN (0);
 		}
 	}
@@ -859,7 +861,7 @@ pfs_readdir(struct vop_readdir_args *va)
 	if (proc != NULL)
 		PROC_UNLOCK(proc);
 	pfs_unlock(pd);
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
 	i = 0;
 	STAILQ_FOREACH_SAFE(pfsent, &lst, link, pfsent2) {
 		if (error == 0)
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/vpsfs/vpsfs.h head/sys/fs/vpsfs/vpsfs.h
--- clean-head/sys/fs/vpsfs/vpsfs.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/fs/vpsfs/vpsfs.h	2013-06-24 14:20:41.000000000 +0200
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)vpsfs.h	8.3 (Berkeley) 8/20/94
+ *
+ * $FreeBSD: head/sys/fs/vpsfsfs/vpsfs.h 250505 2013-05-11 11:17:44Z kib $
+ */
+
+#ifndef	FS_VPSFS_H
+#define	FS_VPSFS_H
+
+/* based on fs/nullfs r250505 */
+
+/*
+#define VPSFS_DEBUG
+*/
+
+#define	VPSFSM_CACHE	0x0001
+
+struct vpsfs_limits;
+
+struct vpsfs_mount {
+	struct mount	*vpsfsm_vfs;
+	struct vnode	*vpsfsm_rootvp;	/* Reference to root vpsfs_node */
+	uint64_t	vpsfsm_flags;
+	struct vpsfs_limits *vpsfsm_limits;
+	int	     limits_last_sync;
+	struct task	limits_sync_task;
+	char		limits_sync_task_enqueued;
+	struct mtx	vpsfs_mtx;
+};
+
+#ifdef _KERNEL
+/*
+ * A cache of vnode references
+ */
+struct vpsfs_node {
+	LIST_ENTRY(vpsfs_node)	vpsfs_hash;	/* Hash list */
+	struct vnode		*vpsfs_lowervp;	/* VREFed once */
+	struct vnode		*vpsfs_vnode;	/* Back pointer */
+	u_int			vpsfs_flags;
+};
+
+struct vpsfs_limits {
+	size_t space_used;
+	size_t nodes_used;
+	size_t space_soft;
+	size_t nodes_soft;
+	size_t space_hard;
+	size_t nodes_hard;
+};	  
+
+#define	VPSFSV_NOUNLOCK		0x0001
+#define	VPSFSV_DROP		0x0002
+#define VPSFSV_FORBIDDEN	0x0003
+
+#define	MOUNTTOVPSFSMOUNT(mp) ((struct vpsfs_mount *)((mp)->mnt_data))
+#define	VTOVPSFS(vp) ((struct vpsfs_node *)(vp)->v_data)
+#define	VPSFSTOV(xp) ((xp)->vpsfs_vnode)
+
+int vpsfs_init(struct vfsconf *vfsp);
+int vpsfs_uninit(struct vfsconf *vfsp);
+int vpsfs_nodeget(struct mount *mp, struct vnode *target,
+    struct vnode **vpp);
+struct vnode *vpsfs_hashget(struct mount *mp, struct vnode *lowervp);
+void vpsfs_hashrem(struct vpsfs_node *xp);
+int vpsfs_bypass(struct vop_generic_args *ap);
+
+int vpsfs_calcusage(struct vpsfs_mount *, struct vpsfs_limits *);
+int vpsfs_calcusage_path(const char *, struct vpsfs_limits *);
+int vpsfs_mount_is_vpsfs(struct mount *mp);
+int vpsfs_read_usage(struct vpsfs_mount *mount,
+    struct vpsfs_limits *limits);
+int vpsfs_write_usage(struct vpsfs_mount *mount,
+    struct vpsfs_limits *limits);
+int vpsfs_limit_alloc(struct vpsfs_mount *mount, size_t space,
+    size_t nodes);
+int vpsfs_limit_free(struct vpsfs_mount *mount, size_t space,
+    size_t nodes);
+
+#ifdef DIAGNOSTIC
+struct vnode *vpsfs_checkvp(struct vnode *vp, char *fil, int lno);
+#define	VPSFSVPTOLOWERVP(vp) vpsfs_checkvp((vp), __FILE__, __LINE__)
+#else
+#define	VPSFSVPTOLOWERVP(vp) (VTOVPSFS(vp)->vpsfs_lowervp)
+#endif
+
+extern struct vop_vector vpsfs_vnodeops;
+
+/*
+extern int (*vpsfs_calcusage_path_p)(const char *, struct vpsfs_limits *);
+*/
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_VPSFSNODE);
+#endif
+
+#ifdef VPSFS_DEBUG
+#define VPSFSDEBUG(format, args...) printf(format ,## args)
+#else
+#define VPSFSDEBUG(format, args...)
+#endif /* VPSFS_DEBUG */
+
+#endif /* _KERNEL */
+
+#endif
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/vpsfs/vpsfs_quota.c head/sys/fs/vpsfs/vpsfs_quota.c
--- clean-head/sys/fs/vpsfs/vpsfs_quota.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/fs/vpsfs/vpsfs_quota.c	2013-06-24 14:20:41.000000000 +0200
@@ -0,0 +1,672 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: vpsfs_quota.c 178 2013-06-13 10:36:51Z klaus $";
+
+
+#include "opt_global.h"
+
+#ifdef VPS
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/dirent.h>
+#include <sys/namei.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/proc.h>
+#include <sys/filedesc.h>
+#include <sys/taskqueue.h>
+
+#include <security/audit/audit.h>
+#include <security/mac/mac_framework.h>
+
+#include <fs/vpsfs/vpsfs.h>
+
+int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
+    char *buf, char **retbuf, u_int buflen);
+
+#define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN+1) + 4)
+
+static int vpsfs_readdir(struct thread *td, struct vnode *vp,
+    int dirbuflen, struct vpsfs_limits *,
+    void (*cbfunc)(struct vnode *, struct vpsfs_limits *, struct thread *));
+
+static int get_next_dirent(struct vnode *vp, struct dirent **dpp,
+    char *dirbuf, int dirbuflen, off_t *off, char **cpos, int *len,
+    int *eofflag, struct thread *td);
+
+static void vpsfs_calcvnode(struct vnode *vp, struct vpsfs_limits *limits,
+    struct thread *td);
+
+/*
+ *
+ * Read a file with quota information from disk when mounting.
+ * XXX Hide this quota file in upper layer.
+ * Keep information from file up to date with all allocations/removals
+ * and sync to disk every now and then.
+ * Recalculate and write file to disk on request (ioctl).
+ *
+ */
+
+static void
+vpsfs_sync_task(void *context, int pending)
+{
+	struct vpsfs_mount *mount;
+
+	mount = (struct vpsfs_mount *)context;
+
+	mtx_lock(&mount->vpsfs_mtx);
+	mount->limits_sync_task_enqueued = 0;
+	mtx_unlock(&mount->vpsfs_mtx);
+
+	if (vpsfs_write_usage(mount, mount->vpsfsm_limits) != 0)
+		printf("%s: WARNING: couldn't sync!\n", __func__);
+
+	mount->limits_last_sync = ticks;
+}
+
+static void
+vpsfs_sched_sync(struct vpsfs_mount *mount)
+{
+
+	mtx_lock(&mount->vpsfs_mtx);
+	if (!mount->limits_sync_task_enqueued &&
+	    (ticks - mount->limits_last_sync) > (hz * 60)) {
+		VPSFSDEBUG("%s: ticks=%u mount->limits_last_sync=%u "
+		    "hz=%u\n", __func__, ticks, mount->limits_last_sync,
+		    hz);
+		TASK_INIT(&mount->limits_sync_task, 0, vpsfs_sync_task,
+		    mount);
+		taskqueue_enqueue(taskqueue_thread,
+		    &mount->limits_sync_task);
+		mount->limits_sync_task_enqueued = 1;
+	}
+	mtx_unlock(&mount->vpsfs_mtx);
+}
+
+int
+vpsfs_limit_alloc(struct vpsfs_mount *mount, size_t space, size_t nodes)
+{
+	struct vpsfs_limits *lp;
+	int rs, rn;
+	int warn;
+	int error;
+
+	lp = mount->vpsfsm_limits;
+
+	/* XXX lock */
+	if (lp->space_hard != 0 && (lp->space_used + space >
+	    lp->space_hard))
+		/* hard */
+		rs = 2;
+	else if (lp->space_soft != 0 && (lp->space_used + space >
+	    lp->space_soft))
+		/* soft */
+		rs = 1;
+	else
+		/* fine */
+		rs = 0;
+
+	if (lp->nodes_hard != 0 && (lp->nodes_used + nodes >
+	    lp->nodes_hard))
+		/* hard */
+		rn = 2;
+	else if (lp->nodes_soft != 0 && (lp->nodes_used + nodes >
+	    lp->nodes_soft))
+		/* soft */
+		rn = 1;
+	else
+		/* fine */
+		rn = 0;
+
+	error = warn = 0;
+	if (rs == 0 && rn == 0)
+		/* fine */
+		;
+	else if (rs <= 1 && rn <= 1)
+		/* warning */
+		warn = 1;
+	else
+		/* deny */
+		error = ENOSPC;
+
+	if (warn)
+		VPSFSDEBUG("%s: WARNING: hit soft limit !\n", __func__);
+
+	if (error == 0) {
+		VPSFSDEBUG("%s: space_used: %zu -> %zu    "
+		    "nodes_used: %zu -> %zu\n", __func__,
+		    lp->space_used, lp->space_used + space,
+		    lp->nodes_used, lp->nodes_used + nodes);
+
+		/* actually allocate */
+		lp->space_used += space;
+		lp->nodes_used += nodes;
+	} else {
+		VPSFSDEBUG("%s: DENIED allocation\n", __func__);
+	}
+
+	/* XXX unlock */
+
+	vpsfs_sched_sync(mount);
+
+	return (0);
+}
+
+int
+vpsfs_limit_free(struct vpsfs_mount *mount, size_t space, size_t nodes)
+{
+	struct vpsfs_limits *lp;
+
+	lp = mount->vpsfsm_limits;
+
+	/* XXX lock */
+
+	VPSFSDEBUG("%s: space_used: %zu -> %zu    nodes_used: %zu -> %zu\n",
+		__func__,
+		lp->space_used, lp->space_used - space,
+		lp->nodes_used, lp->nodes_used - nodes);
+
+	lp->space_used -= space;
+	lp->nodes_used -= nodes;
+
+	/* XXX unlock */
+
+	vpsfs_sched_sync(mount);
+
+	return (0);
+}
+
+int
+vpsfs_write_usage(struct vpsfs_mount *mount, struct vpsfs_limits *limits)
+{
+	struct nameidata nd;
+	struct iovec aiov[1];
+	struct uio auio;
+	struct thread *td;
+	struct vnode *vp2;
+	struct vnode *vp;
+	struct mount *mp;
+	char *filename;
+	char *retbuf;
+	char *buf;
+	int error;
+	int flags;
+
+	VPSFSDEBUG("%s: mount=%p limits=%p\n", __func__, mount, limits);
+
+	error = 0;
+	td = curthread;
+	vp = VPSFSVPTOLOWERVP(mount->vpsfsm_rootvp);
+	vref(vp);
+
+	/* determine pathname of quota file */
+
+	filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK | M_ZERO);
+
+	buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK | M_ZERO);
+	retbuf = "-";
+
+	error = vn_fullpath1(td, vp, td->td_proc->p_fd->fd_rdir, buf,
+	    &retbuf, MAXPATHLEN);
+	if (error) {
+		VPSFSDEBUG("%s: vn_fullpath1(): error=%d\n",
+		    __func__, error);
+		goto out;
+	}
+
+	VPSFSDEBUG("%s: fullpath of lower fs root vnode relative to "
+	    "processes rootdir is [%s]\n", __func__, retbuf);
+	snprintf(filename, MAXPATHLEN, "%s/%s", retbuf, "vpsfs_usage");
+	VPSFSDEBUG("%s: filename [%s]\n", __func__, filename);
+
+	/* now open/create file */
+	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, filename, td);
+	flags = FWRITE | O_NOFOLLOW | O_CREAT;
+	error = vn_open(&nd, &flags, 0, NULL);
+	if (error) {
+		VPSFSDEBUG("%s: vn_open(): error=%d\n", __func__, error);
+		goto out;
+	}
+	NDFREE(&nd, NDF_ONLY_PNBUF);
+	vp2 = nd.ni_vp;
+	vref(vp2);
+	VOP_UNLOCK(vp2, 0);
+
+	/* write information to file */
+
+	auio.uio_iov = &aiov[0];
+	auio.uio_offset = 0;
+	auio.uio_segflg = UIO_SYSSPACE;
+	auio.uio_rw = UIO_WRITE;
+	aiov[0].iov_base = (caddr_t)limits;
+	aiov[0].iov_len = sizeof(*limits);
+	auio.uio_resid = sizeof(*limits);
+	auio.uio_iovcnt = 1;
+	auio.uio_td = td;
+
+	crhold(td->td_ucred);
+	vn_start_write(vp2, &mp, V_WAIT);
+	vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY);
+	error = VOP_WRITE(vp2, &auio, IO_UNIT | IO_SYNC, td->td_ucred);
+	VOP_UNLOCK(vp2, 0);
+	vn_finished_write(mp);
+	(void) vn_close(vp2, FWRITE, td->td_ucred, td);
+	crfree(td->td_ucred);
+	vrele(vp2);
+	if (error) {
+		VPSFSDEBUG("%s: VOP_WRITE(): error=%d\n", __func__, error);
+		goto out;
+	}
+
+	VPSFSDEBUG("%s: usage: space=%zu nodes=%zu\n",
+		__func__, limits->space_used, limits->nodes_used);
+
+  out:
+	free(buf, M_TEMP);
+	free(filename, M_TEMP);
+
+	vrele(vp);
+
+	return (error);
+}
+
+/* Read usage information from disk. */
+int
+vpsfs_read_usage(struct vpsfs_mount *mount, struct vpsfs_limits *limits)
+{
+	struct nameidata nd;
+	struct iovec aiov[1];
+	struct uio auio;
+	struct thread *td;
+	struct vnode *vp2;
+	struct vnode *vp;
+	char *filename;
+	char *retbuf;
+	char *buf;
+	int needs_recalc;
+	int error;
+	int flags;
+
+	VPSFSDEBUG("%s: mount=%p limits=%p\n", __func__, mount, limits);
+
+	error = 0;
+	needs_recalc = 0;
+	td = curthread;
+	vp = VPSFSVPTOLOWERVP(mount->vpsfsm_rootvp);
+	vref(vp);
+
+	/* determine pathname of quota file */
+
+	filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK | M_ZERO);
+
+	buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK | M_ZERO);
+	retbuf = "-";
+
+	error = vn_fullpath1(td, vp, td->td_proc->p_fd->fd_rdir, buf,
+	    &retbuf, MAXPATHLEN);
+	if (error) {
+		VPSFSDEBUG("%s: vn_fullpath1(): error=%d\n",
+		    __func__, error);
+		goto out;
+	}
+
+	VPSFSDEBUG("%s: fullpath of lower fs root vnode relative to "
+	    "processes rootdir is [%s]\n", __func__, retbuf);
+	snprintf(filename, MAXPATHLEN, "%s/%s", retbuf, "vpsfs_usage");
+	VPSFSDEBUG("%s: filename [%s]\n", __func__, filename);
+
+	/* now open file */
+	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, filename, td);
+	flags = FREAD | O_NOFOLLOW;
+	error = vn_open(&nd, &flags, 0, NULL);
+	if (error == ENOENT) {
+		VPSFSDEBUG("%s: file [%s] doesn't exist, recalculating!\n",
+			__func__, filename);
+		needs_recalc = 1;
+		goto out;
+	} else if (error != 0) {
+		VPSFSDEBUG("%s: vn_open(): error=%d\n", __func__, error);
+		goto out;
+	}
+	NDFREE(&nd, NDF_ONLY_PNBUF);
+	vp2 = nd.ni_vp;
+	vref(vp2);
+	VOP_UNLOCK(vp2, 0);
+
+	/* read information from file */
+
+	auio.uio_iov = &aiov[0];
+	auio.uio_offset = 0;
+	auio.uio_segflg = UIO_SYSSPACE;
+	auio.uio_rw = UIO_READ;
+	aiov[0].iov_base = (caddr_t)limits;
+	aiov[0].iov_len = sizeof(*limits);
+	auio.uio_resid = sizeof(*limits);
+	auio.uio_iovcnt = 1;
+	auio.uio_td = td;
+
+	crhold(td->td_ucred);
+	vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY);
+	error = VOP_READ(vp2, &auio, IO_UNIT | IO_SYNC, td->td_ucred);
+	VOP_UNLOCK(vp2, 0);
+	(void) vn_close(vp2, FREAD, td->td_ucred, td);
+	crfree(td->td_ucred);
+	vrele(vp2);
+	if (error) {
+		VPSFSDEBUG("%s: VOP_READ(): error=%d\n", __func__, error);
+		goto out;
+	}
+
+  out:
+	free(buf, M_TEMP);
+	free(filename, M_TEMP);
+
+	vrele(vp);
+
+	if (needs_recalc)
+		error = vpsfs_calcusage(mount, limits);
+
+	VPSFSDEBUG("%s: usage: space=%zu nodes=%zu\n",
+		__func__, limits->space_used, limits->nodes_used);
+
+	return (error);
+}
+
+int
+vpsfs_calcusage_path(const char *path, struct vpsfs_limits *limits)
+{
+	struct nameidata nd;
+	struct thread *td;
+	struct mount *mp;
+	int error;
+
+	td = curthread;
+
+	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_SYSSPACE,
+	    path, td);
+	if ((error = namei(&nd)))
+		return (error);
+	NDFREE(&nd, NDF_ONLY_PNBUF);
+	mp = nd.ni_vp->v_mount;
+	vfs_ref(mp);
+	vput(nd.ni_vp);
+
+	if (vpsfs_mount_is_vpsfs(mp) == 0) {
+		error = EINVAL;
+		goto fail;
+	}
+
+	error = vpsfs_calcusage(MOUNTTOVPSFSMOUNT(mp), limits);
+
+  fail:
+	vfs_rel(mp);
+
+	return (error);
+}
+
+int
+vpsfs_calcusage(struct vpsfs_mount *mount, struct vpsfs_limits *limits)
+{
+	struct thread *td = curthread;
+	//struct vpsfs_limits *limits;
+	struct vnode *lrootvp;
+	struct vnode *vp;
+	struct vattr va;
+	int dirbuflen;
+	int error = 0;
+
+	VPSFSDEBUG("%s: mount=%p\n", __func__, mount);
+
+	//limits = malloc(sizeof(*limits), M_TEMP, M_WAITOK | M_ZERO);
+
+	vp = lrootvp = VPSFSVPTOLOWERVP(mount->vpsfsm_rootvp);
+	VOP_LOCK(lrootvp, LK_SHARED | LK_RETRY);
+
+	error = VOP_GETATTR(lrootvp, &va, td->td_ucred);
+	if (error) {
+		//free(limits, M_TEMP);
+		return (error);
+	}
+
+	dirbuflen = DEV_BSIZE;
+	if (dirbuflen < va.va_blocksize)
+		dirbuflen = va.va_blocksize;
+
+	error = vpsfs_readdir(td, lrootvp, dirbuflen, limits,
+	    vpsfs_calcvnode);
+
+	VOP_UNLOCK(lrootvp, 0);
+
+	VPSFSDEBUG("%s: limits: space_used=%zu nodes_used=%zu\n",
+		__func__, limits->space_used, limits->nodes_used);
+
+	if (mount->vpsfsm_limits != limits)
+		memcpy(mount->vpsfsm_limits, limits, sizeof(*limits));
+
+	error = vpsfs_write_usage(mount, limits);
+
+	//free(limits, M_TEMP);
+
+	return (error);
+}
+
+static void
+vpsfs_calcvnode(struct vnode *vp, struct vpsfs_limits *limits,
+    struct thread *td)
+{
+	struct stat *sb;
+	int error;
+
+	if (vp->v_type != VREG)
+		return;
+
+	sb = malloc(sizeof(*sb), M_TEMP, M_WAITOK | M_ZERO);
+
+	error = vn_stat(vp, sb, td->td_ucred, td->td_ucred, td);
+	if (error) {
+		VPSFSDEBUG("%s: vn_stat() error=%d\n",
+			__func__, error);
+		goto out;
+	}
+
+	/* multiple links are counted only as (size / link count) */
+
+	limits->space_used += sb->st_size / sb->st_nlink;
+	limits->nodes_used += 1;
+
+ out:
+	free(sb, M_TEMP);
+	return;
+}
+
+/*
+ * XXX Better perform it without recursing functions !
+ */
+
+static int
+vpsfs_readdir(struct thread *td, struct vnode *vp, int dirbuflen,
+    struct vpsfs_limits *limits,
+    void (*cbfunc)(struct vnode *, struct vpsfs_limits *, struct thread *))
+{
+	struct componentname *cnp;
+	struct dirent *dp;
+	struct vnode *vp2;
+	char *dirbuf;
+	char *cpos = NULL;
+	off_t off;
+	int eofflag;
+	int len;
+	int error = 0;
+
+	//VPSFSDEBUG("%s: vp=%p\n", __func__, vp);
+	dirbuf = (char *)malloc(dirbuflen, M_TEMP, M_WAITOK);
+
+	/* Walk directory tree ... */
+	off = 0;
+	len = 0;
+	do {
+		error = get_next_dirent(vp, &dp, dirbuf, dirbuflen, &off,
+					&cpos, &len, &eofflag, td);
+		if (error) {
+			VPSFSDEBUG("%s: get_next_dirent() error=%d\n",
+				__func__, error);
+			goto out;
+		}
+
+		/*
+		VPSFSDEBUG("%s: dp=%p dp->d_type=%d dp->d_name=[%s]\n",
+			__func__, dp, dp->d_type, dp->d_name);
+		*/
+
+		if (dp->d_type == DT_DIR &&
+		    (strcmp(dp->d_name, ".")==0 ||
+		    strcmp(dp->d_name, "..")==0))
+			continue;
+
+		cnp = malloc(sizeof(*cnp), M_TEMP, M_WAITOK | M_ZERO);
+		cnp->cn_thread = td;
+		cnp->cn_cred = td->td_ucred;
+		cnp->cn_lkflags = LK_SHARED;
+		cnp->cn_nameiop = LOOKUP;
+		cnp->cn_pnbuf = dp->d_name;
+		cnp->cn_consume = strlen(dp->d_name);
+		cnp->cn_nameptr = dp->d_name;
+		cnp->cn_namelen = strlen(dp->d_name);
+
+		error = VOP_LOOKUP(vp, &vp2, cnp);
+		free(cnp, M_TEMP);
+		if (error) {
+			VPSFSDEBUG("%s: VOP_LOOKUP() error=%d\n",
+				__func__, error);
+			goto out;
+		}
+
+		cbfunc(vp2, limits, td);
+
+		if (dp->d_type == DT_DIR &&
+		    strcmp(dp->d_name, ".") &&
+		    strcmp(dp->d_name, "..")) {
+
+			if (vp2->v_mount != vp->v_mount) {
+				VPSFSDEBUG("%s: vp=%p vp2=%p have different"
+				    " mounts\n", __func__, vp, vp2);
+				goto next;
+			}
+
+			error = vpsfs_readdir(td, vp2, dirbuflen, limits,
+			    cbfunc);
+			if (error) {
+				VPSFSDEBUG("%s: vpsfs_readdir() error=%d\n",
+					__func__, error);
+				vput(vp2);
+				goto out;
+			}
+		}
+
+	  next:
+		vput(vp2);
+
+	} while (len > 0 || !eofflag);
+
+ out:
+	free(dirbuf, M_TEMP);
+	return (error);
+}
+
+/* copied from kern/vfs_default.c */
+static int
+get_next_dirent(struct vnode *vp, struct dirent **dpp, char *dirbuf,
+		int dirbuflen, off_t *off, char **cpos, int *len,
+		int *eofflag, struct thread *td)
+{
+	int error, reclen;
+	struct uio uio;
+	struct iovec iov;
+	struct dirent *dp;
+
+	KASSERT(VOP_ISLOCKED(vp), ("vp %p is not locked", vp));
+	KASSERT(vp->v_type == VDIR, ("vp %p is not a directory", vp));
+
+	if (*len == 0) {
+		iov.iov_base = dirbuf;
+		iov.iov_len = dirbuflen;
+
+		uio.uio_iov = &iov;
+		uio.uio_iovcnt = 1;
+		uio.uio_offset = *off;
+		uio.uio_resid = dirbuflen;
+		uio.uio_segflg = UIO_SYSSPACE;
+		uio.uio_rw = UIO_READ;
+		uio.uio_td = td;
+
+		*eofflag = 0;
+
+#ifdef MAC
+		error = mac_vnode_check_readdir(td->td_ucred, vp);
+		if (error == 0)
+#endif
+			error = VOP_READDIR(vp, &uio, td->td_ucred, eofflag,
+				NULL, NULL);
+		if (error)
+			return (error);
+
+		*off = uio.uio_offset;
+
+		*cpos = dirbuf;
+		*len = (dirbuflen - uio.uio_resid);
+	}
+
+	dp = (struct dirent *)(*cpos);
+	reclen = dp->d_reclen;
+	*dpp = dp;
+
+	/* check for malformed directory.. */
+	if (reclen < DIRENT_MINSIZE)
+		return (EINVAL);
+
+	*cpos += reclen;
+	*len -= reclen;
+
+	return (0);
+}
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/vpsfs/vpsfs_subr.c head/sys/fs/vpsfs/vpsfs_subr.c
--- clean-head/sys/fs/vpsfs/vpsfs_subr.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/fs/vpsfs/vpsfs_subr.c	2013-06-24 14:20:41.000000000 +0200
@@ -0,0 +1,346 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)vpsfs_subr.c	8.7 (Berkeley) 5/14/95
+ *
+ * $FreeBSD: head/sys/fs/vpsfs/vpsfs_subr.c 250505 2013-05-11 11:17:44Z kib $
+ */
+
+#ifdef VPS
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/taskqueue.h>
+
+#include <vps/vps_account.h>
+
+#include <fs/vpsfs/vpsfs.h>
+
+/*
+ * Null layer cache:
+ * Each cache entry holds a reference to the lower vnode
+ * along with a pointer to the alias vnode.  When an
+ * entry is added the lower vnode is VREF'd.  When the
+ * alias is removed the lower vnode is vrele'd.
+ */
+
+#define	VPSFS_NHASH(vp) \
+    (&vpsfs_node_hashtbl[vfs_hash_index(vp) & vpsfs_hash_mask])
+
+static LIST_HEAD(vpsfs_node_hashhead, vpsfs_node) *vpsfs_node_hashtbl;
+static struct mtx vpsfs_hashmtx;
+static u_long vpsfs_hash_mask;
+
+static MALLOC_DEFINE(M_VPSFSHASH, "vpsfs_hash", "VPSFS hash table");
+MALLOC_DEFINE(M_VPSFSNODE, "vpsfs_node", "VPSFS vnode private part");
+
+static struct vnode * vpsfs_hashins(struct mount *, struct vpsfs_node *);
+
+static const char *vpsfs_tag = "vpsfs";
+
+/*
+ * Initialise cache headers
+ */
+int
+vpsfs_init(vfsp)
+	struct vfsconf *vfsp;
+{
+
+	vpsfs_node_hashtbl = hashinit(desiredvnodes, M_VPSFSHASH,
+	    &vpsfs_hash_mask);
+	mtx_init(&vpsfs_hashmtx, "vpsfshs", NULL, MTX_DEF);
+
+	vps_func->vpsfs_calcusage_path = vpsfs_calcusage_path;
+	vps_func->vpsfs_nodeget = vpsfs_nodeget;
+	vps_func->vpsfs_tag = vpsfs_tag;
+
+	return (0);
+}
+
+int
+vpsfs_uninit(vfsp)
+	struct vfsconf *vfsp;
+{
+
+	vps_func->vpsfs_calcusage_path = NULL;
+	vps_func->vpsfs_nodeget = NULL;
+	vps_func->vpsfs_tag = NULL;
+
+	mtx_destroy(&vpsfs_hashmtx);
+	hashdestroy(vpsfs_node_hashtbl, M_VPSFSHASH, vpsfs_hash_mask);
+	return (0);
+}
+
+/*
+ * Return a VREF'ed alias for lower vnode if already exists, else 0.
+ * Lower vnode should be locked on entry and will be left locked on exit.
+ */
+struct vnode *
+vpsfs_hashget(mp, lowervp)
+	struct mount *mp;
+	struct vnode *lowervp;
+{
+	struct vpsfs_node_hashhead *hd;
+	struct vpsfs_node *a;
+	struct vnode *vp;
+
+	ASSERT_VOP_LOCKED(lowervp, "vpsfs_hashget");
+
+	/*
+	 * Find hash base, and then search the (two-way) linked
+	 * list looking for a vpsfs_node structure which is referencing
+	 * the lower vnode.  If found, the increment the vpsfs_node
+	 * reference count (but NOT the lower vnode's VREF counter).
+	 */
+	hd = VPSFS_NHASH(lowervp);
+	mtx_lock(&vpsfs_hashmtx);
+	LIST_FOREACH(a, hd, vpsfs_hash) {
+		if (a->vpsfs_lowervp == lowervp &&
+		    VPSFSTOV(a)->v_mount == mp) {
+			/*
+			 * Since we have the lower node locked the vpsfs
+			 * node can not be in the process of recycling.  If
+			 * it had been recycled before we grabed the lower
+			 * lock it would not have been found on the hash.
+			 */
+			vp = VPSFSTOV(a);
+			vref(vp);
+			mtx_unlock(&vpsfs_hashmtx);
+			return (vp);
+		}
+	}
+	mtx_unlock(&vpsfs_hashmtx);
+	return (NULLVP);
+}
+
+/*
+ * Act like vpsfs_hashget, but add passed vpsfs_node to hash if no existing
+ * node found.
+ */
+static struct vnode *
+vpsfs_hashins(mp, xp)
+	struct mount *mp;
+	struct vpsfs_node *xp;
+{
+	struct vpsfs_node_hashhead *hd;
+	struct vpsfs_node *oxp;
+	struct vnode *ovp;
+
+	hd = VPSFS_NHASH(xp->vpsfs_lowervp);
+	mtx_lock(&vpsfs_hashmtx);
+	LIST_FOREACH(oxp, hd, vpsfs_hash) {
+		if (oxp->vpsfs_lowervp == xp->vpsfs_lowervp &&
+		    VPSFSTOV(oxp)->v_mount == mp) {
+			/*
+			 * See vpsfs_hashget for a description of this
+			 * operation.
+			 */
+			ovp = VPSFSTOV(oxp);
+			vref(ovp);
+			mtx_unlock(&vpsfs_hashmtx);
+			return (ovp);
+		}
+	}
+	LIST_INSERT_HEAD(hd, xp, vpsfs_hash);
+	mtx_unlock(&vpsfs_hashmtx);
+	return (NULLVP);
+}
+
+static void
+vpsfs_destroy_proto(struct vnode *vp, void *xp)
+{
+
+	lockmgr(&vp->v_lock, LK_EXCLUSIVE, NULL);
+	VI_LOCK(vp);
+	vp->v_data = NULL;
+	vp->v_vnlock = &vp->v_lock;
+	vp->v_op = &dead_vnodeops;
+	VI_UNLOCK(vp);
+	vgone(vp);
+	vput(vp);
+	free(xp, M_VPSFSNODE);
+}
+
+static void
+vpsfs_insmntque_dtr(struct vnode *vp, void *xp)
+{
+
+	vput(((struct vpsfs_node *)xp)->vpsfs_lowervp);
+	vpsfs_destroy_proto(vp, xp);
+}
+
+/*
+ * Make a new or get existing vpsfs node.
+ * Vp is the alias vnode, lowervp is the lower vnode.
+ * 
+ * The lowervp assumed to be locked and having "spare" reference.
+ * This routine * vrele lowervp if vpsfs node was taken from hash.
+ * Otherwise it "transfers" * the caller's "spare" reference to
+ * created vpsfs vnode.
+ */
+int
+vpsfs_nodeget(mp, lowervp, vpp)
+	struct mount *mp;
+	struct vnode *lowervp;
+	struct vnode **vpp;
+{
+	struct vpsfs_node *xp;
+	struct vnode *vp;
+	int error;
+
+	ASSERT_VOP_LOCKED(lowervp, "lowervp");
+	KASSERT(lowervp->v_usecount >= 1,
+	    ("Unreferenced vnode %p", lowervp));
+
+	/* Lookup the hash firstly. */
+	*vpp = vpsfs_hashget(mp, lowervp);
+	if (*vpp != NULL) {
+		vrele(lowervp);
+		return (0);
+	}
+
+	/*
+	 * The insmntque1() call below requires the exclusive lock on
+	 * the vpsfs vnode.  Upgrade the lock now if hash failed to
+	 * provide ready to use vnode.
+	 */
+	if (VOP_ISLOCKED(lowervp) != LK_EXCLUSIVE) {
+		KASSERT((MOUNTTOVPSFSMOUNT(mp)->vpsfsm_flags &
+		    VPSFSM_CACHE) != 0,
+		    ("lowervp %p is not excl locked and cache is disabled",
+		    lowervp));
+		vn_lock(lowervp, LK_UPGRADE | LK_RETRY);
+		if ((lowervp->v_iflag & VI_DOOMED) != 0) {
+			vput(lowervp);
+			return (ENOENT);
+		}
+	}
+
+	/*
+	 * We do not serialize vnode creation, instead we will check for
+	 * duplicates later, when adding new vnode to hash.
+	 * Note that duplicate can only appear in hash if the lowervp is
+	 * locked LK_SHARED.
+	 */
+	xp = malloc(sizeof(struct vpsfs_node), M_VPSFSNODE, M_WAITOK);
+
+	error = getnewvnode(vpsfs_tag, mp, &vpsfs_vnodeops, &vp);
+	if (error) {
+		vput(lowervp);
+		free(xp, M_VPSFSNODE);
+		return (error);
+	}
+
+	xp->vpsfs_vnode = vp;
+	xp->vpsfs_lowervp = lowervp;
+	xp->vpsfs_flags = 0;
+	vp->v_type = lowervp->v_type;
+	vp->v_data = xp;
+	vp->v_vnlock = lowervp->v_vnlock;
+	error = insmntque1(vp, mp, vpsfs_insmntque_dtr, xp);
+	if (error != 0)
+		return (error);
+	/*
+	 * Atomically insert our new node into the hash or vget existing 
+	 * if someone else has beaten us to it.
+	 */
+	*vpp = vpsfs_hashins(mp, xp);
+	if (*vpp != NULL) {
+		vrele(lowervp);
+		vpsfs_destroy_proto(vp, xp);
+		return (0);
+	}
+	*vpp = vp;
+
+	return (0);
+}
+
+/*
+ * Remove node from hash.
+ */
+void
+vpsfs_hashrem(xp)
+	struct vpsfs_node *xp;
+{
+
+	mtx_lock(&vpsfs_hashmtx);
+	LIST_REMOVE(xp, vpsfs_hash);
+	mtx_unlock(&vpsfs_hashmtx);
+}
+
+#ifdef DIAGNOSTIC
+
+struct vnode *
+vpsfs_checkvp(vp, fil, lno)
+	struct vnode *vp;
+	char *fil;
+	int lno;
+{
+	struct vpsfs_node *a = VTOVPSFS(vp);
+
+#ifdef notyet
+	/*
+	 * Can't do this check because vop_reclaim runs
+	 * with a funny vop vector.
+	 */
+	if (vp->v_op != vpsfs_vnodeop_p) {
+		printf ("vpsfs_checkvp: on non-vpsfs-node\n");
+		panic("vpsfs_checkvp");
+	}
+#endif
+	if (a->vpsfs_lowervp == NULLVP) {
+		/* Should never happen */
+		panic("vpsfs_checkvp %p", vp);
+	}
+	VI_LOCK_FLAGS(a->vpsfs_lowervp, MTX_DUPOK);
+	if (a->vpsfs_lowervp->v_usecount < 1)
+		panic ("vpsfs with unref'ed lowervp, vp %p lvp %p",
+		    vp, a->vpsfs_lowervp);
+	VI_UNLOCK(a->vpsfs_lowervp);
+#ifdef notyet
+	printf("vpsfs %x/%d -> %x/%d [%s, %d]\n",
+		VPSFSTOV(a), vrefcnt(VPSFSTOV(a)),
+		a->vpsfs_lowervp, vrefcnt(a->vpsfs_lowervp),
+		fil, lno);
+#endif
+	return (a->vpsfs_lowervp);
+}
+#endif
+
+#endif /* VPS */
+
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/vpsfs/vpsfs_vfsops.c head/sys/fs/vpsfs/vpsfs_vfsops.c
--- clean-head/sys/fs/vpsfs/vpsfs_vfsops.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/fs/vpsfs/vpsfs_vfsops.c	2013-06-24 14:20:41.000000000 +0200
@@ -0,0 +1,555 @@
+/*-
+ * Copyright (c) 1992, 1993, 1995
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)vpsfs_vfsops.c	8.2 (Berkeley) 1/21/94
+ *
+ * @(#)lofs_vfsops.c	1.2 (Berkeley) 6/18/92
+ * $FreeBSD: head/sys/fs/vpsfs/vpsfs_vfsops.c 250505 2013-05-11 11:17:44Z kib $
+ */
+
+#ifdef VPS
+
+/*
+ * Null Layer
+ * (See vpsfs_vnops.c for a description of what this does.)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/jail.h>
+
+#include <fs/vpsfs/vpsfs.h>
+
+static MALLOC_DEFINE(M_VPSFSMNT, "vpsfs_mount", "VPSFS mount structure");
+
+static vfs_fhtovp_t	vpsfs_fhtovp;
+static vfs_mount_t	vpsfs_mount;
+static vfs_quotactl_t	vpsfs_quotactl;
+static vfs_root_t	vpsfs_root;
+static vfs_sync_t	vpsfs_sync;
+static vfs_statfs_t	vpsfs_statfs;
+static vfs_unmount_t	vpsfs_unmount;
+static vfs_vget_t	vpsfs_vget;
+static vfs_extattrctl_t	vpsfs_extattrctl;
+
+/*
+ * Mount vpsfs layer
+ */
+static int
+vpsfs_mount(struct mount *mp)
+{
+	int error = 0;
+	struct vnode *lowerrootvp, *vp;
+	struct vnode *vpsfsm_rootvp;
+	struct vpsfs_mount *xmp;
+	/*
+	struct thread *td = curthread;
+	*/
+	char *target;
+	int isvnunlocked = 0, len;
+	struct nameidata nd, *ndp = &nd;
+
+	VPSFSDEBUG("vpsfs_mount(mp = %p)\n", (void *)mp);
+
+	/*
+	if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_VPSFS))
+		return (EPERM);
+	*/
+	if (mp->mnt_flag & MNT_ROOTFS)
+		return (EOPNOTSUPP);
+
+	/*
+	 * Update is a no-op
+	 */
+	if (mp->mnt_flag & MNT_UPDATE) {
+		/*
+		 * Only support update mounts for NFS export.
+		 */
+		if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0))
+			return (0);
+		else
+			return (EOPNOTSUPP);
+	}
+
+	/*
+	 * Get argument
+	 */
+	error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target,
+	    &len);
+	if (error || target[len - 1] != '\0')
+		return (EINVAL);
+
+	/*
+	 * Unlock lower node to avoid possible deadlock.
+	 */
+	if ((mp->mnt_vnodecovered->v_op == &vpsfs_vnodeops) &&
+	    VOP_ISLOCKED(mp->mnt_vnodecovered) == LK_EXCLUSIVE) {
+		VOP_UNLOCK(mp->mnt_vnodecovered, 0);
+		isvnunlocked = 1;
+	}
+	/*
+	 * Find lower node
+	 */
+	NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target,
+	    curthread);
+	error = namei(ndp);
+
+	/*
+	 * Re-lock vnode.
+	 * XXXKIB This is deadlock-prone as well.
+	 */
+	if (isvnunlocked)
+		vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY);
+
+	if (error)
+		return (error);
+	NDFREE(ndp, NDF_ONLY_PNBUF);
+
+	/*
+	 * Sanity check on lower vnode
+	 */
+	lowerrootvp = ndp->ni_vp;
+
+	/*
+	 * Check multi vpsfs mount to avoid `lock against myself' panic.
+	 */
+	if (lowerrootvp == VTOVPSFS(mp->mnt_vnodecovered)->vpsfs_lowervp) {
+		VPSFSDEBUG("vpsfs_mount: multi vpsfs mount?\n");
+		vput(lowerrootvp);
+		return (EDEADLK);
+	}
+
+	xmp = (struct vpsfs_mount *) malloc(sizeof(struct vpsfs_mount),
+	    M_VPSFSMNT, M_WAITOK | M_ZERO);
+
+	/*
+	 * Save reference to underlying FS
+	 */
+	xmp->vpsfsm_vfs = lowerrootvp->v_mount;
+
+	/*
+	 * Save reference.  Each mount also holds
+	 * a reference on the root vnode.
+	 */
+	error = vpsfs_nodeget(mp, lowerrootvp, &vp);
+	/*
+	 * Make sure the node alias worked
+	 */
+	if (error) {
+		free(xmp, M_VPSFSMNT);
+		return (error);
+	}
+
+	/*
+	 * Keep a held reference to the root vnode.
+	 * It is vrele'd in vpsfs_unmount.
+	 */
+	vpsfsm_rootvp = vp;
+	vpsfsm_rootvp->v_vflag |= VV_ROOT;
+	xmp->vpsfsm_rootvp = vpsfsm_rootvp;
+
+	/*
+	 * Unlock the node (either the lower or the alias)
+	 */
+	VOP_UNLOCK(vp, 0);
+
+	if (VPSFSVPTOLOWERVP(vpsfsm_rootvp)->v_mount->mnt_flag &
+	    MNT_LOCAL) {
+		MNT_ILOCK(mp);
+		mp->mnt_flag |= MNT_LOCAL;
+		MNT_IUNLOCK(mp);
+	}
+
+	xmp->vpsfsm_flags |= VPSFSM_CACHE;
+	if (vfs_getopt(mp->mnt_optnew, "nocache", NULL, NULL) == 0)
+		xmp->vpsfsm_flags &= ~VPSFSM_CACHE;
+
+	MNT_ILOCK(mp);
+	if ((xmp->vpsfsm_flags & VPSFSM_CACHE) != 0) {
+		mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag &
+		    (MNTK_SHARED_WRITES | MNTK_LOOKUP_SHARED |
+		    MNTK_EXTENDED_SHARED);
+	}
+	mp->mnt_kern_flag |= MNTK_LOOKUP_EXCL_DOTDOT;
+	MNT_IUNLOCK(mp);
+	mp->mnt_data = xmp;
+	vfs_getnewfsid(mp);
+	if ((xmp->vpsfsm_flags & VPSFSM_CACHE) != 0) {
+		MNT_ILOCK(xmp->vpsfsm_vfs);
+		TAILQ_INSERT_TAIL(&xmp->vpsfsm_vfs->mnt_uppers, mp,
+		    mnt_upper_link);
+		MNT_IUNLOCK(xmp->vpsfsm_vfs);
+	}
+
+	vfs_mountedfrom(mp, target);
+
+	mtx_init(&MOUNTTOVPSFSMOUNT(mp)->vpsfs_mtx, "vpsfs mtx", NULL,
+	    MTX_DEF | MTX_DUPOK);
+	MOUNTTOVPSFSMOUNT(mp)->limits_last_sync = 0;
+	MOUNTTOVPSFSMOUNT(mp)->limits_sync_task_enqueued = 0;
+	MOUNTTOVPSFSMOUNT(mp)->vpsfsm_limits =
+	    malloc(sizeof(struct vpsfs_limits),
+	    M_VPSFSMNT, M_WAITOK | M_ZERO);
+	vpsfs_read_usage(MOUNTTOVPSFSMOUNT(mp),
+	    MOUNTTOVPSFSMOUNT(mp)->vpsfsm_limits);
+
+	VPSFSDEBUG("vpsfs_mount: lower %s, alias at %s\n",
+		mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
+	return (0);
+}
+
+/*
+ * Free reference to vpsfs layer
+ */
+static int
+vpsfs_unmount(mp, mntflags)
+	struct mount *mp;
+	int mntflags;
+{
+	struct vpsfs_mount *mntdata;
+	struct mount *ump;
+	int error, flags;
+
+	VPSFSDEBUG("vpsfs_unmount: mp = %p\n", (void *)mp);
+
+	if (mntflags & MNT_FORCE)
+		flags = FORCECLOSE;
+	else
+		flags = 0;
+
+	vpsfs_write_usage(MOUNTTOVPSFSMOUNT(mp),
+	    MOUNTTOVPSFSMOUNT(mp)->vpsfsm_limits);
+
+	mtx_destroy(&MOUNTTOVPSFSMOUNT(mp)->vpsfs_mtx);
+
+	/* There is 1 extra root vnode reference (vpsfsm_rootvp). */
+	error = vflush(mp, 1, flags, curthread);
+	if (error)
+		return (error);
+
+	/*
+	 * Finally, throw away the vpsfs_mount structure
+	 */
+	mntdata = mp->mnt_data;
+	ump = mntdata->vpsfsm_vfs;
+	if ((mntdata->vpsfsm_flags & VPSFSM_CACHE) != 0) {
+		MNT_ILOCK(ump);
+		while ((ump->mnt_kern_flag & MNTK_VGONE_UPPER) != 0) {
+			ump->mnt_kern_flag |= MNTK_VGONE_WAITER;
+			msleep(&ump->mnt_uppers, &ump->mnt_mtx, 0,
+			    "vgnupw", 0);
+		}
+		TAILQ_REMOVE(&ump->mnt_uppers, mp, mnt_upper_link);
+		MNT_IUNLOCK(ump);
+	}
+	mp->mnt_data = NULL;
+	free(mntdata, M_VPSFSMNT);
+	return (0);
+}
+
+static int
+vpsfs_root(mp, flags, vpp)
+	struct mount *mp;
+	int flags;
+	struct vnode **vpp;
+{
+	struct vnode *vp;
+
+	VPSFSDEBUG("vpsfs_root(mp = %p, vp = %p->%p)\n", (void *)mp,
+	    (void *)MOUNTTOVPSFSMOUNT(mp)->vpsfsm_rootvp,
+	    (void *)VPSFSVPTOLOWERVP(MOUNTTOVPSFSMOUNT(mp)->vpsfsm_rootvp));
+
+	/*
+	 * Return locked reference to root.
+	 */
+	vp = MOUNTTOVPSFSMOUNT(mp)->vpsfsm_rootvp;
+	VREF(vp);
+
+	ASSERT_VOP_UNLOCKED(vp, "root vnode is locked");
+	vn_lock(vp, flags | LK_RETRY);
+	*vpp = vp;
+	return 0;
+}
+
+static int
+vpsfs_quotactl(mp, cmd, uid, arg)
+	struct mount *mp;
+	int cmd;
+	uid_t uid;
+	void *arg;
+{
+
+	/*
+	return VFS_QUOTACTL(MOUNTTOVPSFSMOUNT(mp)->vpsfsm_vfs, cmd,
+	    uid, arg);
+	*/
+
+	VPSFSDEBUG("vpsfs_quotactl()\n");
+
+	return (ENOTSUP);
+}
+
+static int
+vpsfs_statfs(mp, sbp)
+	struct mount *mp;
+	struct statfs *sbp;
+{
+#if 0
+	int error;
+	struct statfs mstat;
+
+	VPSFSDEBUG("vpsfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp,
+	    (void *)MOUNTTOVPSFSMOUNT(mp)->vpsfsm_rootvp,
+	    (void *)VPSFSVPTOLOWERVP(MOUNTTOVPSFSMOUNT(mp)->vpsfsm_rootvp));
+
+	bzero(&mstat, sizeof(mstat));
+
+	error = VFS_STATFS(MOUNTTOVPSFSMOUNT(mp)->vpsfsm_vfs, &mstat);
+	if (error)
+		return (error);
+
+	/* now copy across the "interesting" information and
+	   fake the rest */
+	sbp->f_type = mstat.f_type;
+	sbp->f_flags = (sbp->f_flags & (MNT_RDONLY | MNT_NOEXEC |
+	    MNT_NOSUID | MNT_UNION | MNT_NOSYMFOLLOW)) |
+	    (mstat.f_flags & ~MNT_ROOTFS);
+	sbp->f_bsize = mstat.f_bsize;
+	sbp->f_iosize = mstat.f_iosize;
+	sbp->f_blocks = mstat.f_blocks;
+	sbp->f_bfree = mstat.f_bfree;
+	sbp->f_bavail = mstat.f_bavail;
+	sbp->f_files = mstat.f_files;
+	sbp->f_ffree = mstat.f_ffree;
+	return (0);
+#endif /* 0 */
+
+#if 1
+	int error;
+	struct statfs mstat;
+	struct vpsfs_mount *nmp;
+	struct vpsfs_limits *lp;
+
+	nmp = MOUNTTOVPSFSMOUNT(mp);
+	lp = nmp->vpsfsm_limits;
+
+	VPSFSDEBUG("vpsfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp,
+	    (void *)MOUNTTOVPSFSMOUNT(mp)->vpsfsm_rootvp,
+	    (void *)VPSFSVPTOLOWERVP(MOUNTTOVPSFSMOUNT(mp)->vpsfsm_rootvp));
+
+	bzero(&mstat, sizeof(mstat));
+
+	error = VFS_STATFS(MOUNTTOVPSFSMOUNT(mp)->vpsfsm_vfs, &mstat);
+	if (error)
+		return (error);
+
+	sbp->f_bsize = mstat.f_bsize;
+	sbp->f_iosize = mstat.f_iosize;
+	sbp->f_flags = mstat.f_flags;
+	sbp->f_type = mstat.f_type;
+
+	if (lp->space_soft == 0) {
+		sbp->f_blocks = mstat.f_bavail +
+		    (lp->space_used / mstat.f_bsize);
+		sbp->f_bavail = mstat.f_bavail;
+		sbp->f_bfree = mstat.f_bavail;
+	} else {
+		sbp->f_blocks = lp->space_soft / mstat.f_bsize;
+		sbp->f_bavail = (lp->space_soft - lp->space_used) /
+		    mstat.f_bsize;
+		sbp->f_bfree = (lp->space_soft - lp->space_used) /
+		    mstat.f_bsize;
+	}
+
+	if (lp->nodes_soft == 0) {
+		sbp->f_files = mstat.f_ffree + lp->nodes_used;
+		sbp->f_ffree = mstat.f_ffree;
+	} else {
+		sbp->f_files = lp->nodes_soft;
+		sbp->f_ffree = lp->nodes_soft - lp->nodes_used;
+	}
+
+	VPSFSDEBUG("lp: space_soft=%zu space_used=%zu\n",
+	    lp->space_soft, lp->space_used);
+	VPSFSDEBUG("sbp: f_blocks=%016llu f_bavail=%016llu "
+	    "f_bfree=%016llu\n",
+	    (long long unsigned int)sbp->f_blocks,
+	    (long long unsigned int)sbp->f_bavail,
+	    (long long unsigned int)sbp->f_bfree);
+
+	/*
+	vpsfs_calcusage(MOUNTTOVPSFSMOUNT(mp));
+	*/
+
+	VPSFSDEBUG("sbp: f_flags=%016llx f_type=%08x\n",
+		(long long unsigned int)sbp->f_flags, sbp->f_type);
+
+	return (0);
+#endif /* 1 */
+}
+
+static int
+vpsfs_sync(mp, waitfor)
+	struct mount *mp;
+	int waitfor;
+{
+	/*
+	 * XXX - Assumes no data cached at vpsfs layer.
+	 */
+	return (0);
+}
+
+static int
+vpsfs_vget(mp, ino, flags, vpp)
+	struct mount *mp;
+	ino_t ino;
+	int flags;
+	struct vnode **vpp;
+{
+	int error;
+
+	KASSERT((flags & LK_TYPE_MASK) != 0,
+	    ("vpsfs_vget: no lock requested"));
+
+	error = VFS_VGET(MOUNTTOVPSFSMOUNT(mp)->vpsfsm_vfs, ino,
+	    flags, vpp);
+	if (error != 0)
+		return (error);
+	return (vpsfs_nodeget(mp, *vpp, vpp));
+}
+
+static int
+vpsfs_fhtovp(mp, fidp, flags, vpp)
+	struct mount *mp;
+	struct fid *fidp;
+	int flags;
+	struct vnode **vpp;
+{
+	int error;
+
+	error = VFS_FHTOVP(MOUNTTOVPSFSMOUNT(mp)->vpsfsm_vfs, fidp, flags,
+	    vpp);
+	if (error != 0)
+		return (error);
+	return (vpsfs_nodeget(mp, *vpp, vpp));
+}
+
+static int			   
+vpsfs_extattrctl(mp, cmd, filename_vp, namespace, attrname)
+	struct mount *mp;
+	int cmd;
+	struct vnode *filename_vp;
+	int namespace;
+	const char *attrname;
+{
+
+	return (VFS_EXTATTRCTL(MOUNTTOVPSFSMOUNT(mp)->vpsfsm_vfs, cmd,
+	    filename_vp, namespace, attrname));
+}
+
+static void
+vpsfs_reclaim_lowervp(struct mount *mp, struct vnode *lowervp)
+{
+	struct vnode *vp;
+
+	vp = vpsfs_hashget(mp, lowervp);
+	if (vp == NULL)
+		return;
+	VTOVPSFS(vp)->vpsfs_flags |= VPSFSV_NOUNLOCK;
+	vgone(vp);
+	vput(vp);
+}
+
+static void
+vpsfs_unlink_lowervp(struct mount *mp, struct vnode *lowervp)
+{
+	struct vnode *vp;
+	struct vpsfs_node *xp;
+
+	vp = vpsfs_hashget(mp, lowervp);
+	if (vp == NULL)
+		return;
+	xp = VTOVPSFS(vp);
+	xp->vpsfs_flags |= VPSFSV_DROP | VPSFSV_NOUNLOCK;
+	vhold(vp);
+	vunref(vp);
+
+	/*
+	 * If vunref() dropped the last use reference on the vpsfs
+	 * vnode, it must be reclaimed, and its lock was split from
+	 * the lower vnode lock.  Need to do extra unlock before
+	 * allowing the final vdrop() to free the vnode.
+	 */
+	if (vp->v_usecount == 0) {
+		KASSERT((vp->v_iflag & VI_DOOMED) != 0,
+		    ("not reclaimed %p", vp));
+		VOP_UNLOCK(vp, 0);
+	}
+	vdrop(vp);
+}
+
+static struct vfsops vpsfs_vfsops = {
+	.vfs_extattrctl =	vpsfs_extattrctl,
+	.vfs_fhtovp =		vpsfs_fhtovp,
+	.vfs_init =		vpsfs_init,
+	.vfs_mount =		vpsfs_mount,
+	.vfs_quotactl =		vpsfs_quotactl,
+	.vfs_root =		vpsfs_root,
+	.vfs_statfs =		vpsfs_statfs,
+	.vfs_sync =		vpsfs_sync,
+	.vfs_uninit =		vpsfs_uninit,
+	.vfs_unmount =		vpsfs_unmount,
+	.vfs_vget =		vpsfs_vget,
+	.vfs_reclaim_lowervp =	vpsfs_reclaim_lowervp,
+	.vfs_unlink_lowervp =	vpsfs_unlink_lowervp,
+};
+
+int
+vpsfs_mount_is_vpsfs(struct mount *mp)
+{
+
+	if (mp->mnt_op == &vpsfs_vfsops)
+		return (1);
+	else
+		return (0);
+}
+
+VFS_SET(vpsfs_vfsops, vpsfs, VFCF_LOOPBACK | VFCF_JAIL);
+
+#endif /* VPS */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/fs/vpsfs/vpsfs_vnops.c head/sys/fs/vpsfs/vpsfs_vnops.c
--- clean-head/sys/fs/vpsfs/vpsfs_vnops.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/fs/vpsfs/vpsfs_vnops.c	2013-06-24 14:20:41.000000000 +0200
@@ -0,0 +1,1232 @@
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * John Heidemann of the UCLA Ficus project.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)vpsfs_vnops.c	8.6 (Berkeley) 5/27/95
+ *
+ * Ancestors:
+ *	@(#)lofs_vnops.c	1.2 (Berkeley) 6/18/92
+ *	...and...
+ *	@(#)vpsfs_vnodeops.c 1.20 92/07/07 UCLA Ficus project
+ *
+ * $FreeBSD: head/sys/fs/nullfs/vpsfs_vnops.c 250505 2013-05-11 11:17:44Z kib $
+ */
+
+/*
+ * Null Layer
+ *
+ * (See mount_nullfs(8) for more information.)
+ *
+ * The null layer duplicates a portion of the filesystem
+ * name space under a new name.  In this respect, it is
+ * similar to the loopback filesystem.  It differs from
+ * the loopback fs in two respects:  it is implemented using
+ * a stackable layers techniques, and its "null-node"s stack above
+ * all lower-layer vnodes, not just over directory vnodes.
+ *
+ * The null layer has two purposes.  First, it serves as a demonstration
+ * of layering by proving a layer which does nothing.  (It actually
+ * does everything the loopback filesystem does, which is slightly
+ * more than nothing.)  Second, the null layer can serve as a prototype
+ * layer.  Since it provides all necessary layer framework,
+ * new filesystem layers can be created very easily be starting
+ * with a null layer.
+ *
+ * The remainder of this man page examines the null layer as a basis
+ * for constructing new layers.
+ *
+ *
+ * INSTANTIATING NEW VPSFS LAYERS
+ *
+ * New null layers are created with mount_nullfs(8).
+ * Mount_nullfs(8) takes two arguments, the pathname
+ * of the lower vfs (target-pn) and the pathname where the null
+ * layer will appear in the namespace (alias-pn).  After
+ * the null layer is put into place, the contents
+ * of target-pn subtree will be aliased under alias-pn.
+ *
+ *
+ * OPERATION OF A VPSFS LAYER
+ *
+ * The null layer is the minimum filesystem layer,
+ * simply bypassing all possible operations to the lower layer
+ * for processing there.  The majority of its activity centers
+ * on the bypass routine, through which nearly all vnode operations
+ * pass.
+ *
+ * The bypass routine accepts arbitrary vnode operations for
+ * handling by the lower layer.  It begins by examing vnode
+ * operation arguments and replacing any null-nodes by their
+ * lower-layer equivlants.  It then invokes the operation
+ * on the lower layer.  Finally, it replaces the null-nodes
+ * in the arguments and, if a vnode is return by the operation,
+ * stacks a null-node on top of the returned vnode.
+ *
+ * Although bypass handles most operations, vop_getattr, vop_lock,
+ * vop_unlock, vop_inactive, vop_reclaim, and vop_print are not
+ * bypassed. Vop_getattr must change the fsid being returned.
+ * Vop_lock and vop_unlock must handle any locking for the
+ * current vnode as well as pass the lock request down.
+ * Vop_inactive and vop_reclaim are not bypassed so that
+ * they can handle freeing null-layer specific data. Vop_print
+ * is not bypassed to avoid excessive debugging information.
+ * Also, certain vnode operations change the locking state within
+ * the operation (create, mknod, remove, link, rename, mkdir, rmdir,
+ * and symlink). Ideally these operations should not change the
+ * lock state, but should be changed to let the caller of the
+ * function unlock them. Otherwise all intermediate vnode layers
+ * (such as union, umapfs, etc) must catch these functions to do
+ * the necessary locking at their layer.
+ *
+ *
+ * INSTANTIATING VNODE STACKS
+ *
+ * Mounting associates the null layer with a lower layer,
+ * effect stacking two VFSes.  Vnode stacks are instead
+ * created on demand as files are accessed.
+ *
+ * The initial mount creates a single vnode stack for the
+ * root of the new null layer.  All other vnode stacks
+ * are created as a result of vnode operations on
+ * this or other null vnode stacks.
+ *
+ * New vnode stacks come into existance as a result of
+ * an operation which returns a vnode.
+ * The bypass routine stacks a null-node above the new
+ * vnode before returning it to the caller.
+ *
+ * For example, imagine mounting a null layer with
+ * "mount_nullfs /usr/include /dev/layer/null".
+ * Changing directory to /dev/layer/null will assign
+ * the root null-node (which was created when the null layer was mounted).
+ * Now consider opening "sys".  A vop_lookup would be
+ * done on the root null-node.  This operation would bypass through
+ * to the lower layer which would return a vnode representing
+ * the UFS "sys".  Null_bypass then builds a null-node
+ * aliasing the UFS "sys" and returns this to the caller.
+ * Later operations on the null-node "sys" will repeat this
+ * process when constructing other vnode stacks.
+ *
+ *
+ * CREATING OTHER FILE SYSTEM LAYERS
+ *
+ * One of the easiest ways to construct new filesystem layers is to make
+ * a copy of the null layer, rename all files and variables, and
+ * then begin modifing the copy.  Sed can be used to easily rename
+ * all variables.
+ *
+ * The umap layer is an example of a layer descended from the
+ * null layer.
+ *
+ *
+ * INVOKING OPERATIONS ON LOWER LAYERS
+ *
+ * There are two techniques to invoke operations on a lower layer
+ * when the operation cannot be completely bypassed.  Each method
+ * is appropriate in different situations.  In both cases,
+ * it is the responsibility of the aliasing layer to make
+ * the operation arguments "correct" for the lower layer
+ * by mapping a vnode arguments to the lower layer.
+ *
+ * The first approach is to call the aliasing layer's bypass routine.
+ * This method is most suitable when you wish to invoke the operation
+ * currently being handled on the lower layer.  It has the advantage
+ * that the bypass routine already must do argument mapping.
+ * An example of this is vpsfs_getattrs in the null layer.
+ *
+ * A second approach is to directly invoke vnode operations on
+ * the lower layer with the VOP_OPERATIONNAME interface.
+ * The advantage of this method is that it is easy to invoke
+ * arbitrary operations on the lower layer.  The disadvantage
+ * is that vnode arguments must be manualy mapped.
+ *
+ */
+
+#ifdef VPS
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/mutex.h>
+#include <sys/namei.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+#include <sys/stat.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/taskqueue.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_object.h>
+#include <vm/vnode_pager.h>
+
+#include <fs/vpsfs/vpsfs.h>
+
+static int vpsfs_bug_bypass = 0;   /* for debugging:
+    enables bypass printf'ing */
+SYSCTL_INT(_debug, OID_AUTO, nullfs_bug_bypass, CTLFLAG_RW, 
+	&vpsfs_bug_bypass, 0, "");
+
+/*
+ * This is the 10-Apr-92 bypass routine.
+ *    This version has been optimized for speed, throwing away some
+ * safety checks.  It should still always work, but it's not as
+ * robust to programmer errors.
+ *
+ * In general, we map all vnodes going down and unmap them on the way back.
+ * As an exception to this, vnodes can be marked "unmapped" by setting
+ * the Nth bit in operation's vdesc_flags.
+ *
+ * Also, some BSD vnode operations have the side effect of vrele'ing
+ * their arguments.  With stacking, the reference counts are held
+ * by the upper node, not the lower one, so we must handle these
+ * side-effects here.  This is not of concern in Sun-derived systems
+ * since there are no such side-effects.
+ *
+ * This makes the following assumptions:
+ * - only one returned vpp
+ * - no INOUT vpp's (Sun's vop_open has one of these)
+ * - the vnode operation vector of the first vnode should be used
+ *   to determine what implementation of the op should be invoked
+ * - all mapped vnodes are of our vnode-type (NEEDSWORK:
+ *   problems on rmdir'ing mount points and renaming?)
+ */
+int
+vpsfs_bypass(struct vop_generic_args *ap)
+{
+	struct vnode **this_vp_p;
+	int error;
+	struct vnode *old_vps[VDESC_MAX_VPS];
+	struct vnode **vps_p[VDESC_MAX_VPS];
+	struct vnode ***vppp;
+	struct vnodeop_desc *descp = ap->a_desc;
+	int reles, i;
+
+	if (vpsfs_bug_bypass)
+		printf ("vpsfs_bypass: %s\n", descp->vdesc_name);
+
+#ifdef DIAGNOSTIC
+	/*
+	 * We require at least one vp.
+	 */
+	if (descp->vdesc_vp_offsets == NULL ||
+	    descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET)
+		panic ("vpsfs_bypass: no vp's in map");
+#endif
+
+	/*
+	 * Map the vnodes going in.
+	 * Later, we'll invoke the operation based on
+	 * the first mapped vnode's operation vector.
+	 */
+	reles = descp->vdesc_flags;
+	for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
+		if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
+			break;   /* bail out at end of list */
+		vps_p[i] = this_vp_p =
+		     VOPARG_OFFSETTO(struct vnode**,
+		     descp->vdesc_vp_offsets[i], ap);
+		/*
+		 * We're not guaranteed that any but the first vnode
+		 * are of our type.  Check for and don't map any
+		 * that aren't.
+		 * (We must always map first vp or vclean fails.)
+		 */
+		if (i && (*this_vp_p == NULLVP ||
+		    (*this_vp_p)->v_op != &vpsfs_vnodeops)) {
+			old_vps[i] = NULLVP;
+		} else {
+			old_vps[i] = *this_vp_p;
+			*(vps_p[i]) = VPSFSVPTOLOWERVP(*this_vp_p);
+			/*
+			 * XXX - Several operations have the side effect
+			 * of vrele'ing their vp's.  We must account for
+			 * that.  (This should go away in the future.)
+			 */
+			if (reles & VDESC_VP0_WILLRELE)
+				VREF(*this_vp_p);
+		}
+
+	}
+
+	/*
+	 * Call the operation on the lower layer
+	 * with the modified argument structure.
+	 */
+	if (vps_p[0] && *vps_p[0])
+		error = VCALL(ap);
+	else {
+		printf("vpsfs_bypass: no map for %s\n", descp->vdesc_name);
+		error = EINVAL;
+	}
+
+	/*
+	 * Maintain the illusion of call-by-value
+	 * by restoring vnodes in the argument structure
+	 * to their original value.
+	 */
+	reles = descp->vdesc_flags;
+	for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
+		if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
+			break;   /* bail out at end of list */
+		if (old_vps[i]) {
+			*(vps_p[i]) = old_vps[i];
+#if 0
+			if (reles & VDESC_VP0_WILLUNLOCK)
+				VOP_UNLOCK(*(vps_p[i]), 0);
+#endif
+			if (reles & VDESC_VP0_WILLRELE)
+				vrele(*(vps_p[i]));
+		}
+	}
+
+	/*
+	 * Map the possible out-going vpp
+	 * (Assumes that the lower layer always returns
+	 * a VREF'ed vpp unless it gets an error.)
+	 */
+	if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
+	    !(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
+	    !error) {
+		/*
+		 * XXX - even though some ops have vpp returned vp's,
+		 * several ops actually vrele this before returning.
+		 * We must avoid these ops.
+		 * (This should go away when these ops are regularized.)
+		 */
+		if (descp->vdesc_flags & VDESC_VPP_WILLRELE)
+			goto out;
+		vppp = VOPARG_OFFSETTO(struct vnode***,
+				 descp->vdesc_vpp_offset,ap);
+		if (*vppp)
+			error = vpsfs_nodeget(old_vps[0]->v_mount,
+			    **vppp, *vppp);
+	}
+
+ out:
+	VPSFSDEBUG("%s: vps_p[0]=%p old_vps[0]=%p error=%d\n",
+	    __func__, vps_p[0], old_vps[0], error);
+	return (error);
+}
+
+static int
+vpsfs_add_writecount(struct vop_add_writecount_args *ap)
+{
+	struct vnode *lvp, *vp;
+	int error;
+
+	vp = ap->a_vp;
+	lvp = VPSFSVPTOLOWERVP(vp);
+	KASSERT(vp->v_writecount + ap->a_inc >= 0,
+	    ("wrong writecount inc"));
+	if (vp->v_writecount > 0 && vp->v_writecount + ap->a_inc == 0)
+		error = VOP_ADD_WRITECOUNT(lvp, -1);
+	else if (vp->v_writecount == 0 && vp->v_writecount + ap->a_inc > 0)
+		error = VOP_ADD_WRITECOUNT(lvp, 1);
+	else
+		error = 0;
+	if (error == 0)
+		vp->v_writecount += ap->a_inc;
+	return (error);
+}
+
+/*
+ * We have to carry on the locking protocol on the null layer vnodes
+ * as we progress through the tree. We also have to enforce read-only
+ * if this layer is mounted read-only.
+ */
+static int
+vpsfs_lookup(struct vop_lookup_args *ap)
+{
+	struct componentname *cnp = ap->a_cnp;
+	struct vnode *dvp = ap->a_dvp;
+	int flags = cnp->cn_flags;
+	struct vnode *vp, *ldvp, *lvp;
+	int error;
+	int deny = 0;
+
+	if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
+	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
+		return (EROFS);
+	/*
+	 * Although it is possible to call vpsfs_bypass(), we'll do
+	 * a direct call to reduce overhead
+	 */
+	ldvp = VPSFSVPTOLOWERVP(dvp);
+	vp = lvp = NULL;
+	error = VOP_LOOKUP(ldvp, &lvp, cnp);
+	if (error == EJUSTRETURN && (flags & ISLASTCN) &&
+	    (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
+	    (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME))
+		error = EROFS;
+
+	if (error == 0 && strcmp(cnp->cn_nameptr, "vpsfs_usage") == 0)
+		deny = 1;
+
+	if ((error == 0 || error == EJUSTRETURN) && lvp != NULL) {
+		if (ldvp == lvp) {
+			*ap->a_vpp = dvp;
+			VREF(dvp);
+			vrele(lvp);
+		} else {
+			error = vpsfs_nodeget(dvp->v_mount, lvp, &vp);
+			if (error == 0)
+				*ap->a_vpp = vp;
+			if (deny == 1) {
+				VTOVPSFS(vp)->vpsfs_flags |= VPSFSV_FORBIDDEN;
+				VPSFSDEBUG("%s: setting VPSFSV_FORBIDDEN vp=%p\n",
+				    __func__, vp);
+			}
+		}
+	}
+	return (error);
+}
+
+static int
+vpsfs_open(struct vop_open_args *ap)
+{
+	struct vnode *vp, *ldvp;
+	struct vattr va;
+	size_t osize;
+	int retval;
+	int error;
+
+	vp = ap->a_vp;
+	ldvp = VPSFSVPTOLOWERVP(vp);
+
+	if (VTOVPSFS(vp)->vpsfs_flags & VPSFSV_FORBIDDEN)
+		return (EPERM);
+
+	/* XXX apparently vop_setattr() is called to set size to
+	   0 anyways ! */
+	if (0 && ap->a_mode & (FWRITE | O_TRUNC)) {
+		vhold(ldvp);
+		error = VOP_GETATTR(ldvp, &va, ap->a_cred);
+		vdrop(ldvp);
+		if (error)
+			return (error);
+		osize = va.va_size;
+		if (osize > 0) {
+			VPSFSDEBUG("%s: a_mode & (FWRITE | O_TRUNC): "
+			    "osize=%zu\n --> freeing %zu bytes\n",
+			    __func__, osize, osize);
+			vpsfs_limit_free(
+			    MOUNTTOVPSFSMOUNT(vp->v_mount), osize, 0);
+		}
+	}
+
+	retval = vpsfs_bypass(&ap->a_gen);
+	if (retval == 0)
+		vp->v_object = ldvp->v_object;
+	return (retval);
+}
+
+/*
+ * Setattr call. Disallow write attempts if the layer is mounted read-only.
+ */
+static int
+vpsfs_setattr(struct vop_setattr_args *ap)
+{
+	struct vnode *vp = ap->a_vp;
+	struct vattr *vap = ap->a_vap;
+	struct vnode *lvp;
+	struct vattr va2;
+	size_t osize;
+	size_t nsize;
+	int error;
+
+	if (VTOVPSFS(vp)->vpsfs_flags & VPSFSV_FORBIDDEN)
+		return (EPERM);
+
+  	if ((vap->va_flags != VNOVAL ||
+	    vap->va_uid != (uid_t)VNOVAL ||
+	    vap->va_gid != (gid_t)VNOVAL ||
+	    vap->va_atime.tv_sec != VNOVAL ||
+	    vap->va_mtime.tv_sec != VNOVAL ||
+	    vap->va_mode != (mode_t)VNOVAL) &&
+	    (vp->v_mount->mnt_flag & MNT_RDONLY))
+		return (EROFS);
+#if 1   
+	/*
+	 * The point of this is to share common files (binaries, libraries)
+	 * accross vpsfs mounts by using hard links on the backing layer.
+	 * XXX This was only meant as a quick hack for some tests.
+	 */
+	if (vap->va_flags != VNOVAL) {
+		lvp = VPSFSVPTOLOWERVP(vp);
+		vhold(lvp);
+		error = VOP_GETATTR(lvp, &va2, ap->a_cred);
+		vdrop(lvp);
+		if (error)
+			return (error);
+
+		/* Explicitely check for this flag and deny any
+		   operation. */
+		if (va2.va_flags & SF_IMMUTABLE) {
+			return (EPERM);
+		}
+	}
+#endif  
+
+	if (vap->va_size != VNOVAL) {
+ 		switch (vp->v_type) {
+ 		case VDIR:
+ 			return (EISDIR);
+ 		case VCHR:
+ 		case VBLK:
+ 		case VSOCK:
+ 		case VFIFO:
+			if (vap->va_flags != VNOVAL)
+				return (EOPNOTSUPP);
+			return (0);
+		case VREG:
+		case VLNK:
+ 		default:
+			/*
+			 * Disallow write attempts if the filesystem is
+			 * mounted read-only.
+			 */
+			if (vp->v_mount->mnt_flag & MNT_RDONLY)
+				return (EROFS);
+		}
+
+		lvp = VPSFSVPTOLOWERVP(vp);
+		vhold(lvp);
+		error = VOP_GETATTR(lvp, &va2, ap->a_cred);
+		vdrop(lvp);
+		if (error)
+			return (error);
+		osize = va2.va_size;
+		nsize = vap->va_size;
+		if (nsize > osize) {
+			VPSFSDEBUG("%s: allocating %zu bytes: osize=%zu "
+			    "nsize=%zu\n",
+			    __func__, (nsize - osize), osize, nsize);
+			if ((error = vpsfs_limit_alloc(
+			    MOUNTTOVPSFSMOUNT(vp->v_mount), (nsize - osize),
+			    0)) != 0)
+				return (error);
+		} else if (osize > nsize) {
+			VPSFSDEBUG("%s: freeing %zu bytes: osize=%zu "
+			    "nsize=%zu\n",
+			    __func__, (osize - nsize), osize, nsize);
+			vpsfs_limit_free(MOUNTTOVPSFSMOUNT(vp->v_mount),
+			    (osize - nsize), 0);
+		} else {
+			VPSFSDEBUG("%s: no size change: %zu/%zu\n",
+				__func__, osize, nsize);
+		}
+
+	}
+
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+/*
+ *  We handle getattr only to change the fsid.
+ */
+static int
+vpsfs_getattr(struct vop_getattr_args *ap)
+{
+	int error;
+
+	VPSFSDEBUG("%s: ap=%p\n", __func__, ap);
+
+	if ((error = vpsfs_bypass((struct vop_generic_args *)ap)) != 0)
+		return (error);
+
+	ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
+	return (0);
+}
+
+/*
+ * Handle to disallow write access if mounted read-only.
+ */
+static int
+vpsfs_access(struct vop_access_args *ap)
+{
+	struct vnode *vp = ap->a_vp;
+	accmode_t accmode = ap->a_accmode;
+
+	VPSFSDEBUG("%s: vp=%p accmode=%08x\n", __func__, vp, accmode);
+
+	if (VTOVPSFS(vp)->vpsfs_flags & VPSFSV_FORBIDDEN) {
+		VPSFSDEBUG("%s: vp=%p f_deny==1\n", __func__, vp);
+		return (EPERM);
+	}
+
+	/*
+	 * Disallow write attempts on read-only layers;
+	 * unless the file is a socket, fifo, or a block or
+	 * character device resident on the filesystem.
+	 */
+	if (accmode & VWRITE) {
+		switch (vp->v_type) {
+		case VDIR:
+		case VLNK:
+		case VREG:
+			if (vp->v_mount->mnt_flag & MNT_RDONLY)
+				return (EROFS);
+			break;
+		default:
+			break;
+		}
+	}
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+static int
+vpsfs_accessx(struct vop_accessx_args *ap)
+{
+	struct vnode *vp = ap->a_vp;
+	accmode_t accmode = ap->a_accmode;
+
+	VPSFSDEBUG("%s: vp=%p accmode=%08x\n", __func__, vp, accmode);
+
+	if (VTOVPSFS(vp)->vpsfs_flags & VPSFSV_FORBIDDEN) {
+		VPSFSDEBUG("%s: vp=%p f_deny==1\n", __func__, vp);
+		return (EPERM);
+	}
+
+	/*
+	 * Disallow write attempts on read-only layers;
+	 * unless the file is a socket, fifo, or a block or
+	 * character device resident on the filesystem.
+	 */
+	if (accmode & VWRITE) {
+		switch (vp->v_type) {
+		case VDIR:
+		case VLNK:
+		case VREG:
+			if (vp->v_mount->mnt_flag & MNT_RDONLY)
+				return (EROFS);
+			break;
+		default:
+			break;
+		}
+	}
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+/*
+ * Increasing refcount of lower vnode is needed at least for the case
+ * when lower FS is NFS to do sillyrename if the file is in use.
+ * Unfortunately v_usecount is incremented in many places in
+ * the kernel and, as such, there may be races that result in
+ * the NFS client doing an extraneous silly rename, but that seems
+ * preferable to not doing a silly rename when it is needed.
+ */
+static int
+vpsfs_remove(struct vop_remove_args *ap)
+{
+	int retval, vreleit;
+	struct vnode *lvp;
+	struct vnode *uvp;
+	struct vattr *vap;
+	struct vattr va;
+	size_t osize;
+	int error;
+
+	/* --- */
+	uvp = ap->a_vp;
+
+	if (VTOVPSFS(uvp)->vpsfs_flags & VPSFSV_FORBIDDEN)
+		return (EPERM);
+
+	lvp = VPSFSVPTOLOWERVP(uvp);
+	vhold(lvp);
+	vap = &va;
+
+	error = VOP_GETATTR(lvp, vap, curthread->td_ucred);
+	if (error) {
+		vdrop(lvp);
+		return (error);
+	}
+	osize = va.va_size;
+	vdrop(lvp);
+
+	if (va.va_nlink == 1) {
+		VPSFSDEBUG("%s: freeing %zu bytes, 1 node\n",
+		    __func__, osize);
+		vpsfs_limit_free(MOUNTTOVPSFSMOUNT(uvp->v_mount),
+		    va.va_size, 1);
+	} else {
+		VPSFSDEBUG("%s: va_nlink=%d, not freeing space, 1 node\n",
+		    __func__, va.va_nlink);
+		vpsfs_limit_free(MOUNTTOVPSFSMOUNT(uvp->v_mount), 0, 1);
+	}
+
+	VPSFSDEBUG("%s: va_nlink=%d uvp=%p lvp=%p uvp->v_usecount=%d "
+	    "lvp->v_usecount=%d\n",
+	    __func__, va.va_nlink, uvp, lvp,
+	    uvp->v_usecount, lvp->v_usecount);
+
+	if (uvp->v_usecount > 1 && va.va_nlink == 1) {
+		/*
+		 * This vnode is still referenced (open) by some process,
+		 * but we are about to delete it.
+		 */
+		VPSFSDEBUG("%s: #########################\n", __func__);
+	}
+	/* --- */
+
+	if (vrefcnt(ap->a_vp) > 1) {
+		lvp = VPSFSVPTOLOWERVP(ap->a_vp);
+		VREF(lvp);
+		vreleit = 1;
+	} else
+		vreleit = 0;
+
+	retval = vpsfs_bypass(&ap->a_gen);
+	if (vreleit != 0)
+		vrele(lvp);
+	return (retval);
+}
+
+/*
+ * We handle this to eliminate null FS to lower FS
+ * file moving. Don't know why we don't allow this,
+ * possibly we should.
+ */
+static int
+vpsfs_rename(struct vop_rename_args *ap)
+{
+	struct vnode *tdvp = ap->a_tdvp;
+	struct vnode *fvp = ap->a_fvp;
+	struct vnode *fdvp = ap->a_fdvp;
+	struct vnode *tvp = ap->a_tvp;
+
+	if (VTOVPSFS(fvp)->vpsfs_flags & VPSFSV_FORBIDDEN) {
+		if (tdvp == tvp)
+			vrele(tdvp);
+		else
+			vput(tdvp);
+		if (tvp)
+			vput(tvp);
+		vrele(fdvp);
+		vrele(fvp);
+		return (EPERM);
+	}
+
+	/* Check for cross-device rename. */
+	if ((fvp->v_mount != tdvp->v_mount) ||
+	    (tvp && (fvp->v_mount != tvp->v_mount))) {
+		if (tdvp == tvp)
+			vrele(tdvp);
+		else
+			vput(tdvp);
+		if (tvp)
+			vput(tvp);
+		vrele(fdvp);
+		vrele(fvp);
+		return (EXDEV);
+	}
+	
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+/*
+ * We need to process our own vnode lock and then clear the
+ * interlock flag as it applies only to our vnode, not the
+ * vnodes below us on the stack.
+ */
+static int
+vpsfs_lock(struct vop_lock1_args *ap)
+{
+	struct vnode *vp = ap->a_vp;
+	int flags = ap->a_flags;
+	struct vpsfs_node *nn;
+	struct vnode *lvp;
+	int error;
+
+
+	if ((flags & LK_INTERLOCK) == 0) {
+		VI_LOCK(vp);
+		ap->a_flags = flags |= LK_INTERLOCK;
+	}
+	nn = VTOVPSFS(vp);
+	/*
+	 * If we're still active we must ask the lower layer to
+	 * lock as ffs has special lock considerations in it's
+	 * vop lock.
+	 */
+	if (nn != NULL && (lvp = VPSFSVPTOLOWERVP(vp)) != NULL) {
+		VI_LOCK_FLAGS(lvp, MTX_DUPOK);
+		VI_UNLOCK(vp);
+		/*
+		 * We have to hold the vnode here to solve a potential
+		 * reclaim race.  If we're forcibly vgone'd while we
+		 * still have refs, a thread could be sleeping inside
+		 * the lowervp's vop_lock routine.  When we vgone we will
+		 * drop our last ref to the lowervp, which would allow it
+		 * to be reclaimed.  The lowervp could then be recycled,
+		 * in which case it is not legal to be sleeping in it's VOP.
+		 * We prevent it from being recycled by holding the vnode
+		 * here.
+		 */
+		vholdl(lvp);
+		error = VOP_LOCK(lvp, flags);
+
+		/*
+		 * We might have slept to get the lock and someone might
+		 * have clean our vnode already, switching vnode lock from
+		 * one in lowervp to v_lock in our own vnode structure.
+		 * Handle this case by reacquiring correct lock in
+		 * requested mode.
+		 */
+		if (VTOVPSFS(vp) == NULL && error == 0) {
+			ap->a_flags &= ~(LK_TYPE_MASK | LK_INTERLOCK);
+			switch (flags & LK_TYPE_MASK) {
+			case LK_SHARED:
+				ap->a_flags |= LK_SHARED;
+				break;
+			case LK_UPGRADE:
+			case LK_EXCLUSIVE:
+				ap->a_flags |= LK_EXCLUSIVE;
+				break;
+			default:
+				panic("Unsupported lock request %d\n",
+				    ap->a_flags);
+			}
+			VOP_UNLOCK(lvp, 0);
+			error = vop_stdlock(ap);
+		}
+		vdrop(lvp);
+	} else
+		error = vop_stdlock(ap);
+
+	return (error);
+}
+
+/*
+ * We need to process our own vnode unlock and then clear the
+ * interlock flag as it applies only to our vnode, not the
+ * vnodes below us on the stack.
+ */
+static int
+vpsfs_unlock(struct vop_unlock_args *ap)
+{
+	struct vnode *vp = ap->a_vp;
+	int flags = ap->a_flags;
+	int mtxlkflag = 0;
+	struct vpsfs_node *nn;
+	struct vnode *lvp;
+	int error;
+
+	if ((flags & LK_INTERLOCK) != 0)
+		mtxlkflag = 1;
+	else if (mtx_owned(VI_MTX(vp)) == 0) {
+		VI_LOCK(vp);
+		mtxlkflag = 2;
+	}
+	nn = VTOVPSFS(vp);
+	if (nn != NULL && (lvp = VPSFSVPTOLOWERVP(vp)) != NULL) {
+		VI_LOCK_FLAGS(lvp, MTX_DUPOK);
+		flags |= LK_INTERLOCK;
+		vholdl(lvp);
+		VI_UNLOCK(vp);
+		error = VOP_UNLOCK(lvp, flags);
+		vdrop(lvp);
+		if (mtxlkflag == 0)
+			VI_LOCK(vp);
+	} else {
+		if (mtxlkflag == 2)
+			VI_UNLOCK(vp);
+		error = vop_stdunlock(ap);
+	}
+
+	return (error);
+}
+
+/*
+ * Do not allow the VOP_INACTIVE to be passed to the lower layer,
+ * since the reference count on the lower vnode is not related to
+ * ours.
+ */
+static int
+vpsfs_inactive(struct vop_inactive_args *ap __unused)
+{
+	struct vnode *vp, *lvp;
+	struct vpsfs_node *xp;
+	struct mount *mp;
+	struct vpsfs_mount *xmp;
+
+	vp = ap->a_vp;
+	xp = VTOVPSFS(vp);
+	lvp = VPSFSVPTOLOWERVP(vp);
+	mp = vp->v_mount;
+	xmp = MOUNTTOVPSFSMOUNT(mp);
+	if ((xmp->vpsfsm_flags & VPSFSM_CACHE) == 0 ||
+	    (xp->vpsfs_flags & VPSFSV_DROP) != 0 ||
+	    (lvp->v_vflag & VV_NOSYNC) != 0) {
+		/*
+		 * If this is the last reference and caching of the
+		 * nullfs vnodes is not enabled, or the lower vnode is
+		 * deleted, then free up the vnode so as not to tie up
+		 * the lower vnodes.
+		 */
+		vp->v_object = NULL;
+		vrecycle(vp);
+	}
+	return (0);
+}
+
+/*
+ * Now, the nullfs vnode and, due to the sharing lock, the lower
+ * vnode, are exclusively locked, and we shall destroy the null vnode.
+ */
+static int
+vpsfs_reclaim(struct vop_reclaim_args *ap)
+{
+	struct vnode *vp;
+	struct vpsfs_node *xp;
+	struct vnode *lowervp;
+
+	vp = ap->a_vp;
+	xp = VTOVPSFS(vp);
+	lowervp = xp->vpsfs_lowervp;
+
+	KASSERT(lowervp != NULL && vp->v_vnlock != &vp->v_lock,
+	    ("Reclaiming inclomplete null vnode %p", vp));
+
+	vpsfs_hashrem(xp);
+	/*
+	 * Use the interlock to protect the clearing of v_data to
+	 * prevent faults in vpsfs_lock().
+	 */
+	lockmgr(&vp->v_lock, LK_EXCLUSIVE, NULL);
+	VI_LOCK(vp);
+	vp->v_data = NULL;
+	vp->v_object = NULL;
+	vp->v_vnlock = &vp->v_lock;
+	VI_UNLOCK(vp);
+
+	/*
+	 * If we were opened for write, we leased one write reference
+	 * to the lower vnode.  If this is a reclamation due to the
+	 * forced unmount, undo the reference now.
+	 */
+	if (vp->v_writecount > 0)
+		VOP_ADD_WRITECOUNT(lowervp, -1);
+	if ((xp->vpsfs_flags & VPSFSV_NOUNLOCK) != 0)
+		vunref(lowervp);
+	else
+		vput(lowervp);
+	free(xp, M_VPSFSNODE);
+
+	return (0);
+}
+
+static int
+vpsfs_print(struct vop_print_args *ap)
+{
+	struct vnode *vp = ap->a_vp;
+
+	printf("\tvp=%p, lowervp=%p\n", vp, VTOVPSFS(vp)->vpsfs_lowervp);
+	return (0);
+}
+
+/* ARGSUSED */
+static int
+vpsfs_getwritemount(struct vop_getwritemount_args *ap)
+{
+	struct vpsfs_node *xp;
+	struct vnode *lowervp;
+	struct vnode *vp;
+
+	vp = ap->a_vp;
+	VI_LOCK(vp);
+	xp = VTOVPSFS(vp);
+	if (xp && (lowervp = xp->vpsfs_lowervp)) {
+		VI_LOCK_FLAGS(lowervp, MTX_DUPOK);
+		VI_UNLOCK(vp);
+		vholdl(lowervp);
+		VI_UNLOCK(lowervp);
+		VOP_GETWRITEMOUNT(lowervp, ap->a_mpp);
+		vdrop(lowervp);
+	} else {
+		VI_UNLOCK(vp);
+		*(ap->a_mpp) = NULL;
+	}
+	return (0);
+}
+
+static int
+vpsfs_vptofh(struct vop_vptofh_args *ap)
+{
+	struct vnode *lvp;
+
+	lvp = VPSFSVPTOLOWERVP(ap->a_vp);
+	return VOP_VPTOFH(lvp, ap->a_fhp);
+}
+
+static int
+vpsfs_vptocnp(struct vop_vptocnp_args *ap)
+{
+	struct vnode *vp = ap->a_vp;
+	struct vnode **dvp = ap->a_vpp;
+	struct vnode *lvp, *ldvp;
+	struct ucred *cred = ap->a_cred;
+	int error, locked;
+
+	if (0 && vp->v_type == VDIR)
+		return (vop_stdvptocnp(ap));
+
+	locked = VOP_ISLOCKED(vp);
+	lvp = VPSFSVPTOLOWERVP(vp);
+	vhold(lvp);
+	VOP_UNLOCK(vp, 0); /* vp is held by vn_vptocnp_locked that
+	    called us */
+	ldvp = lvp;
+	vref(lvp);
+	error = vn_vptocnp(&ldvp, cred, ap->a_buf, ap->a_buflen);
+	VPSFSDEBUG("vn_vptocnp(&ldvp, ...) = %d ap->a_buf[%s]/[%s] "
+	    "*ap->a_buflen=%d\n",
+	    error, ap->a_buf, &ap->a_buf[*ap->a_buflen], *ap->a_buflen);
+	vdrop(lvp);
+	if (error != 0) {
+		vn_lock(vp, locked | LK_RETRY);
+		return (ENOENT);
+	}
+
+	/*
+	 * Exclusive lock is required by insmntque1 call in
+	 * vpsfs_nodeget()
+	 */
+	error = vn_lock(ldvp, LK_EXCLUSIVE);
+	if (error != 0) {
+		vrele(ldvp);
+		vn_lock(vp, locked | LK_RETRY);
+		return (ENOENT);
+	}
+	vref(ldvp);
+	error = vpsfs_nodeget(vp->v_mount, ldvp, dvp);
+	if (error == 0) {
+#ifdef DIAGNOSTIC
+		VPSFSVPTOLOWERVP(*dvp);
+#endif
+		VOP_UNLOCK(*dvp, 0); /* keep reference on *dvp */
+	}
+	vn_lock(vp, locked | LK_RETRY);
+	return (error);
+}
+
+/* --- */
+
+static int
+vpsfs_write(struct vop_write_args *ap)
+{
+	struct vnode *lvp;
+	struct vnode *uvp;
+	struct uio *uio;
+	struct vattr *vap;
+	struct vattr va;
+	size_t osize;
+	size_t asize;
+	int error;
+
+	uio = ap->a_uio;
+	uvp = ap->a_vp;
+	lvp = VPSFSVPTOLOWERVP(uvp);
+	vhold(lvp);
+	vap = &va;
+
+	error = VOP_GETATTR(lvp, vap, ap->a_cred);
+	if (error) {
+		vdrop(lvp);
+		return (error);
+	}
+	osize = va.va_size;
+	VPSFSDEBUG("%s: vap->va_type=%d vap->va_size=%llu "
+	    "vap->va_bytes=%llu\n",
+	    __func__, vap->va_type,
+	    (long long unsigned int)vap->va_size,
+	    (long long unsigned int)vap->va_bytes);
+	vdrop(lvp);
+
+	if ((uio->uio_offset + uio->uio_resid) > osize) {
+		VPSFSDEBUG("%s: allocating %zu bytes\n",
+		    __func__, ((size_t)uio->uio_offset + uio->uio_resid) -
+		    osize);
+		asize = (uio->uio_offset + uio->uio_resid) - osize;
+		if ((error = vpsfs_limit_alloc(
+		    MOUNTTOVPSFSMOUNT(uvp->v_mount), asize, 0)) != 0)
+			return (error);
+	}
+
+	VPSFSDEBUG("%s: uio->uio_offset=%zu uio->uio_resid=%zu\n",
+	    __func__, (size_t)uio->uio_offset, uio->uio_resid);
+
+	error = vpsfs_bypass((struct vop_generic_args *)ap);
+
+	return (error);
+}
+
+static int
+vpsfs_read(struct vop_read_args *ap)
+{
+
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+static int
+vpsfs_readdir(struct vop_readdir_args *ap)
+{
+
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+static int
+vpsfs_link(struct vop_link_args *ap)
+{
+	int error;
+
+	if (VTOVPSFS(ap->a_vp)->vpsfs_flags & VPSFSV_FORBIDDEN)
+		return (EPERM);
+
+	VPSFSDEBUG("%s: allocating 1 node\n", __func__);
+	if ((error = vpsfs_limit_alloc(
+	    MOUNTTOVPSFSMOUNT(ap->a_vp->v_mount), 0, 1)) != 0)
+		return (error);
+
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+static int
+vpsfs_create(struct vop_create_args *ap)
+{
+	int error;
+
+	VPSFSDEBUG("%s: allocating 1 node\n", __func__);
+	if ((error = vpsfs_limit_alloc(
+	    MOUNTTOVPSFSMOUNT(ap->a_dvp->v_mount), 0, 1)) != 0)
+		return (error);
+
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+static int
+vpsfs_symlink(struct vop_symlink_args *ap)
+{
+	size_t size;
+	int error;
+
+	size = strlen(ap->a_target);
+
+	VPSFSDEBUG("%s: allocating %zu bytes, 1 node\n", __func__, size);
+	if ((error = vpsfs_limit_alloc(
+	    MOUNTTOVPSFSMOUNT(ap->a_dvp->v_mount), size, 1)) != 0)
+		return (error);
+
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+static int
+vpsfs_mkdir(struct vop_mkdir_args *ap)
+{
+	int error;
+
+	VPSFSDEBUG("%s: allocating 1 node\n", __func__);
+	if ((error = vpsfs_limit_alloc(
+	    MOUNTTOVPSFSMOUNT(ap->a_dvp->v_mount), 0, 1)) != 0)
+		return (error);
+
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+static int
+vpsfs_mknod(struct vop_mknod_args *ap)
+{
+	int error;
+
+	VPSFSDEBUG("%s: allocating 1 node\n", __func__);
+	if ((error = vpsfs_limit_alloc(
+	    MOUNTTOVPSFSMOUNT(ap->a_dvp->v_mount), 0, 1)) != 0)
+		return (error);
+
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+static int
+vpsfs_rmdir(struct vop_rmdir_args *ap)
+{
+
+	VPSFSDEBUG("%s: freeing 1 node\n", __func__);
+	vpsfs_limit_free(MOUNTTOVPSFSMOUNT(ap->a_vp->v_mount), 0, 1);
+
+	return (vpsfs_bypass((struct vop_generic_args *)ap));
+}
+
+/* --- */
+
+/*
+ * Global vfs data structures
+ */
+struct vop_vector vpsfs_vnodeops = {
+	.vop_bypass =		vpsfs_bypass,
+	.vop_access =		vpsfs_access,
+	.vop_accessx =		vpsfs_accessx,
+	.vop_advlockpurge =	vop_stdadvlockpurge,
+	.vop_bmap =		VOP_EOPNOTSUPP,
+	.vop_getattr =		vpsfs_getattr,
+	.vop_getwritemount =	vpsfs_getwritemount,
+	.vop_inactive =		vpsfs_inactive,
+	.vop_islocked =		vop_stdislocked,
+	.vop_lock1 =		vpsfs_lock,
+	.vop_lookup =		vpsfs_lookup,
+	.vop_open =		vpsfs_open,
+	.vop_print =		vpsfs_print,
+	.vop_reclaim =		vpsfs_reclaim,
+	.vop_remove =		vpsfs_remove,
+	.vop_rename =		vpsfs_rename,
+	.vop_setattr =		vpsfs_setattr,
+	.vop_strategy =		VOP_EOPNOTSUPP,
+	.vop_unlock =		vpsfs_unlock,
+	.vop_vptocnp =		vpsfs_vptocnp,
+	.vop_vptofh =		vpsfs_vptofh,
+	.vop_add_writecount =	vpsfs_add_writecount,
+	.vop_write =		vpsfs_write,
+	.vop_read =		vpsfs_read,
+	.vop_readdir =		vpsfs_readdir,
+	.vop_link =		vpsfs_link,
+	.vop_create =		vpsfs_create,
+	.vop_symlink =		vpsfs_symlink,
+	.vop_mkdir =		vpsfs_mkdir,
+	.vop_mknod =		vpsfs_mknod,
+	.vop_rmdir =		vpsfs_rmdir,
+};
+
+#endif /* VPS */
+
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/i386/conf/VPS_DBG head/sys/i386/conf/VPS_DBG
--- clean-head/sys/i386/conf/VPS_DBG	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/i386/conf/VPS_DBG	2013-06-24 14:21:39.000000000 +0200
@@ -0,0 +1,359 @@
+#
+# GENERIC -- Generic kernel configuration file for FreeBSD/i386
+#
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
+#
+#    http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD: head/sys/i386/conf/GENERIC 249410 2013-04-12 16:25:03Z trasz $
+
+cpu		I486_CPU
+cpu		I586_CPU
+cpu		I686_CPU
+ident		VPS_DBG
+# VPS
+options		VPS
+options		VIMAGE
+options		DIAGNOSTIC
+
+makeoptions	DEBUG=-g		# Build kernel with gdb(1) debug symbols
+makeoptions	WITH_CTF=1		# Run ctfconvert(1) for DTrace support
+
+options 	SCHED_ULE		# ULE scheduler
+options 	PREEMPTION		# Enable kernel thread preemption
+options 	INET			# InterNETworking
+options 	INET6			# IPv6 communications protocols
+options 	TCP_OFFLOAD		# TCP offload
+options 	SCTP			# Stream Control Transmission Protocol
+options 	FFS			# Berkeley Fast Filesystem
+options 	SOFTUPDATES		# Enable FFS soft updates support
+options 	UFS_ACL			# Support for access control lists
+options 	UFS_DIRHASH		# Improve performance on big directories
+options 	UFS_GJOURNAL		# Enable gjournal-based UFS journaling
+options 	QUOTA			# Enable disk quotas for UFS
+options 	MD_ROOT			# MD is a potential root device
+options 	NFSCL			# New Network Filesystem Client
+options 	NFSD			# New Network Filesystem Server
+options 	NFSLOCKD		# Network Lock Manager
+options 	NFS_ROOT		# NFS usable as /, requires NFSCL
+options 	MSDOSFS			# MSDOS Filesystem
+options 	CD9660			# ISO 9660 Filesystem
+options 	PROCFS			# Process filesystem (requires PSEUDOFS)
+options 	PSEUDOFS		# Pseudo-filesystem framework
+options 	GEOM_PART_GPT		# GUID Partition Tables.
+options 	GEOM_RAID		# Soft RAID functionality.
+options 	GEOM_LABEL		# Provides labelization
+options 	COMPAT_FREEBSD4		# Compatible with FreeBSD4
+options 	COMPAT_FREEBSD5		# Compatible with FreeBSD5
+options 	COMPAT_FREEBSD6		# Compatible with FreeBSD6
+options 	COMPAT_FREEBSD7		# Compatible with FreeBSD7
+options 	SCSI_DELAY=5000		# Delay (in ms) before probing SCSI
+options 	KTRACE			# ktrace(1) support
+options 	STACK			# stack(9) support
+options 	SYSVSHM			# SYSV-style shared memory
+options 	SYSVMSG			# SYSV-style message queues
+options 	SYSVSEM			# SYSV-style semaphores
+options 	_KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions
+options 	PRINTF_BUFR_SIZE=128	# Prevent printf output being interspersed.
+options 	KBD_INSTALL_CDEV	# install a CDEV entry in /dev
+options 	HWPMC_HOOKS		# Necessary kernel hooks for hwpmc(4)
+options 	AUDIT			# Security event auditing
+options 	CAPABILITY_MODE		# Capsicum capability mode
+options 	CAPABILITIES		# Capsicum capabilities
+options 	MAC			# TrustedBSD MAC Framework
+options 	KDTRACE_HOOKS		# Kernel DTrace hooks
+options 	DDB_CTF			# Kernel ELF linker loads CTF data
+options 	INCLUDE_CONFIG_FILE     # Include this file in kernel
+
+# Debugging support.  Always need this:
+options 	KDB			# Enable kernel debugger support.
+# For minimum debugger support (stable branch) use:
+#options 	KDB_TRACE		# Print a stack trace for a panic.
+# For full debugger support use this instead:
+options 	DDB			# Support DDB.
+options 	GDB			# Support remote GDB.
+options 	DEADLKRES		# Enable the deadlock resolver
+options 	INVARIANTS		# Enable calls of extra sanity checking
+options 	INVARIANT_SUPPORT	# Extra sanity checks of internal structures, required by INVARIANTS
+options 	WITNESS			# Enable checks to detect deadlocks and cycles
+options 	WITNESS_SKIPSPIN	# Don't run witness on spinlocks for speed
+options 	MALLOC_DEBUG_MAXZONES=8	# Separate malloc(9) zones
+
+# To make an SMP kernel, the next two lines are needed
+options 	SMP			# Symmetric MultiProcessor Kernel
+device		apic			# I/O APIC
+
+# CPU frequency control
+device		cpufreq
+
+# Bus support.
+device		acpi
+device		eisa
+device		pci
+
+# Floppy drives
+device		fdc
+
+# ATA controllers
+device		ahci		# AHCI-compatible SATA controllers
+device		ata		# Legacy ATA/SATA controllers
+options 	ATA_STATIC_ID	# Static device numbering
+device		mvs		# Marvell 88SX50XX/88SX60XX/88SX70XX/SoC SATA
+device		siis		# SiliconImage SiI3124/SiI3132/SiI3531 SATA
+
+# SCSI Controllers
+device		ahb		# EISA AHA1742 family
+device		ahc		# AHA2940 and onboard AIC7xxx devices
+options 	AHC_REG_PRETTY_PRINT	# Print register bitfields in debug
+					# output.  Adds ~128k to driver.
+device		ahd		# AHA39320/29320 and onboard AIC79xx devices
+options 	AHD_REG_PRETTY_PRINT	# Print register bitfields in debug
+					# output.  Adds ~215k to driver.
+device		esp		# AMD Am53C974 (Tekram DC-390(T))
+device		hptiop		# Highpoint RocketRaid 3xxx series
+device		isp		# Qlogic family
+#device		ispfw		# Firmware for QLogic HBAs- normally a module
+device		mpt		# LSI-Logic MPT-Fusion
+device		mps		# LSI-Logic MPT-Fusion 2
+#device		ncr		# NCR/Symbios Logic
+device		sym		# NCR/Symbios Logic (newer chipsets + those of `ncr')
+device		trm		# Tekram DC395U/UW/F DC315U adapters
+
+device		adv		# Advansys SCSI adapters
+device		adw		# Advansys wide SCSI adapters
+device		aha		# Adaptec 154x SCSI adapters
+device		aic		# Adaptec 15[012]x SCSI adapters, AIC-6[23]60.
+device		bt		# Buslogic/Mylex MultiMaster SCSI adapters
+
+device		ncv		# NCR 53C500
+device		nsp		# Workbit Ninja SCSI-3
+device		stg		# TMC 18C30/18C50
+device		isci		# Intel C600 SAS controller
+
+# ATA/SCSI peripherals
+device		scbus		# SCSI bus (required for ATA/SCSI)
+device		ch		# SCSI media changers
+device		da		# Direct Access (disks)
+device		sa		# Sequential Access (tape etc)
+device		cd		# CD
+device		pass		# Passthrough device (direct ATA/SCSI access)
+device		ses		# Enclosure Services (SES and SAF-TE)
+#device		ctl		# CAM Target Layer
+
+# RAID controllers interfaced to the SCSI subsystem
+device		amr		# AMI MegaRAID
+device		arcmsr		# Areca SATA II RAID
+device		asr		# DPT SmartRAID V, VI and Adaptec SCSI RAID
+device		ciss		# Compaq Smart RAID 5*
+device		dpt		# DPT Smartcache III, IV - See NOTES for options
+device		hptmv		# Highpoint RocketRAID 182x
+device		hptrr		# Highpoint RocketRAID 17xx, 22xx, 23xx, 25xx
+device		hpt27xx		# Highpoint RocketRAID 27xx
+device		iir		# Intel Integrated RAID
+device		ips		# IBM (Adaptec) ServeRAID
+device		mly		# Mylex AcceleRAID/eXtremeRAID
+device		twa		# 3ware 9000 series PATA/SATA RAID
+device		tws		# LSI 3ware 9750 SATA+SAS 6Gb/s RAID controller
+
+# RAID controllers
+device		aac		# Adaptec FSA RAID
+device		aacp		# SCSI passthrough for aac (requires CAM)
+device		aacraid		# Adaptec by PMC RAID
+device		ida		# Compaq Smart RAID
+device		mfi		# LSI MegaRAID SAS
+device		mlx		# Mylex DAC960 family
+device		pst		# Promise Supertrak SX6000
+device		twe		# 3ware ATA RAID
+
+# atkbdc0 controls both the keyboard and the PS/2 mouse
+device		atkbdc		# AT keyboard controller
+device		atkbd		# AT keyboard
+device		psm		# PS/2 mouse
+
+device		kbdmux		# keyboard multiplexer
+
+device		vga		# VGA video card driver
+options 	VESA		# Add support for VESA BIOS Extensions (VBE)
+
+device		splash		# Splash screen and screen saver support
+
+# syscons is the default console driver, resembling an SCO console
+device		sc
+options 	SC_PIXEL_MODE	# add support for the raster text mode
+
+device		agp		# support several AGP chipsets
+
+# Power management support (see NOTES for more options)
+#device		apm
+# Add suspend/resume support for the i8254.
+device		pmtimer
+
+# PCCARD (PCMCIA) support
+# PCMCIA and cardbus bridge support
+device		cbb		# cardbus (yenta) bridge
+device		pccard		# PC Card (16-bit) bus
+device		cardbus		# CardBus (32-bit) bus
+
+# Serial (COM) ports
+device		uart		# Generic UART driver
+
+# Parallel port
+device		ppc
+device		ppbus		# Parallel port bus (required)
+device		lpt		# Printer
+device		ppi		# Parallel port interface device
+#device		vpo		# Requires scbus and da
+
+device		puc		# Multi I/O cards and multi-channel UARTs
+
+# PCI Ethernet NICs.
+device		bxe		# Broadcom BCM57710/BCM57711/BCM57711E 10Gb Ethernet
+device		de		# DEC/Intel DC21x4x (``Tulip'')
+device		em		# Intel PRO/1000 Gigabit Ethernet Family
+device		igb		# Intel PRO/1000 PCIE Server Gigabit Family
+device		ixgb		# Intel PRO/10GbE Ethernet Card
+device		le		# AMD Am7900 LANCE and Am79C9xx PCnet
+device		ti		# Alteon Networks Tigon I/II gigabit Ethernet
+device		txp		# 3Com 3cR990 (``Typhoon'')
+device		vx		# 3Com 3c590, 3c595 (``Vortex'')
+
+# PCI Ethernet NICs that use the common MII bus controller code.
+# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
+device		miibus		# MII bus support
+device		ae		# Attansic/Atheros L2 FastEthernet
+device		age		# Attansic/Atheros L1 Gigabit Ethernet
+device		alc		# Atheros AR8131/AR8132 Ethernet
+device		ale		# Atheros AR8121/AR8113/AR8114 Ethernet
+device		bce		# Broadcom BCM5706/BCM5708 Gigabit Ethernet
+device		bfe		# Broadcom BCM440x 10/100 Ethernet
+device		bge		# Broadcom BCM570xx Gigabit Ethernet
+device		cas		# Sun Cassini/Cassini+ and NS DP83065 Saturn
+device		dc		# DEC/Intel 21143 and various workalikes
+device		et		# Agere ET1310 10/100/Gigabit Ethernet
+device		fxp		# Intel EtherExpress PRO/100B (82557, 82558)
+device		gem		# Sun GEM/Sun ERI/Apple GMAC
+device		hme		# Sun HME (Happy Meal Ethernet)
+device		jme		# JMicron JMC250 Gigabit/JMC260 Fast Ethernet
+device		lge		# Level 1 LXT1001 gigabit Ethernet
+device		msk		# Marvell/SysKonnect Yukon II Gigabit Ethernet
+device		nfe		# nVidia nForce MCP on-board Ethernet
+device		nge		# NatSemi DP83820 gigabit Ethernet
+#device		nve		# nVidia nForce MCP on-board Ethernet Networking
+device		pcn		# AMD Am79C97x PCI 10/100 (precedence over 'le')
+device		re		# RealTek 8139C+/8169/8169S/8110S
+device		rl		# RealTek 8129/8139
+device		sf		# Adaptec AIC-6915 (``Starfire'')
+device		sge		# Silicon Integrated Systems SiS190/191
+device		sis		# Silicon Integrated Systems SiS 900/SiS 7016
+device		sk		# SysKonnect SK-984x & SK-982x gigabit Ethernet
+device		ste		# Sundance ST201 (D-Link DFE-550TX)
+device		stge		# Sundance/Tamarack TC9021 gigabit Ethernet
+device		tl		# Texas Instruments ThunderLAN
+device		tx		# SMC EtherPower II (83c170 ``EPIC'')
+device		vge		# VIA VT612x gigabit Ethernet
+device		vr		# VIA Rhine, Rhine II
+device		vte		# DM&P Vortex86 RDC R6040 Fast Ethernet
+device		wb		# Winbond W89C840F
+device		xl		# 3Com 3c90x (``Boomerang'', ``Cyclone'')
+
+# ISA Ethernet NICs.  pccard NICs included.
+device		cs		# Crystal Semiconductor CS89x0 NIC
+# 'device ed' requires 'device miibus'
+device		ed		# NE[12]000, SMC Ultra, 3c503, DS8390 cards
+device		ex		# Intel EtherExpress Pro/10 and Pro/10+
+device		ep		# Etherlink III based cards
+device		fe		# Fujitsu MB8696x based cards
+device		ie		# EtherExpress 8/16, 3C507, StarLAN 10 etc.
+device		sn		# SMC's 9000 series of Ethernet chips
+device		xe		# Xircom pccard Ethernet
+
+# Wireless NIC cards
+device		wlan		# 802.11 support
+options 	IEEE80211_DEBUG	# enable debug msgs
+options 	IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's
+options 	IEEE80211_SUPPORT_MESH	# enable 802.11s draft support
+device		wlan_wep	# 802.11 WEP support
+device		wlan_ccmp	# 802.11 CCMP support
+device		wlan_tkip	# 802.11 TKIP support
+device		wlan_amrr	# AMRR transmit rate control algorithm
+device		an		# Aironet 4500/4800 802.11 wireless NICs.
+device		ath		# Atheros NICs
+device		ath_pci		# Atheros pci/cardbus glue
+device		ath_hal		# pci/cardbus chip support
+options 	AH_SUPPORT_AR5416	# enable AR5416 tx/rx descriptors
+options 	AH_AR5416_INTERRUPT_MITIGATION	# AR5416 interrupt mitigation
+options 	ATH_ENABLE_11N	# Enable 802.11n support for AR5416 and later
+device		ath_rate_sample	# SampleRate tx rate control for ath
+#device		bwi		# Broadcom BCM430x/BCM431x wireless NICs.
+#device		bwn		# Broadcom BCM43xx wireless NICs.
+device		ipw		# Intel 2100 wireless NICs.
+device		iwi		# Intel 2200BG/2225BG/2915ABG wireless NICs.
+device		iwn		# Intel 4965/1000/5000/6000 wireless NICs.
+device		malo		# Marvell Libertas wireless NICs.
+device		mwl		# Marvell 88W8363 802.11n wireless NICs.
+device		ral		# Ralink Technology RT2500 wireless NICs.
+device		wi		# WaveLAN/Intersil/Symbol 802.11 wireless NICs.
+#device		wl		# Older non 802.11 Wavelan wireless NIC.
+device		wpi		# Intel 3945ABG wireless NICs.
+
+# Pseudo devices.
+device		loop		# Network loopback
+device		random		# Entropy device
+options 	PADLOCK_RNG	# VIA Padlock RNG
+options 	RDRAND_RNG	# Intel Bull Mountain RNG
+device		ether		# Ethernet support
+device		vlan		# 802.1Q VLAN support
+device		tun		# Packet tunnel.
+device		md		# Memory "disks"
+device		gif		# IPv6 and IPv4 tunneling
+device		faith		# IPv6-to-IPv4 relaying (translation)
+device		firmware	# firmware assist module
+
+# The `bpf' device enables the Berkeley Packet Filter.
+# Be aware of the administrative consequences of enabling this!
+# Note that 'bpf' is required for DHCP.
+device		bpf		# Berkeley packet filter
+
+# USB support
+options 	USB_DEBUG	# enable debug msgs
+device		uhci		# UHCI PCI->USB interface
+device		ohci		# OHCI PCI->USB interface
+device		ehci		# EHCI PCI->USB interface (USB 2.0)
+device		xhci		# XHCI PCI->USB interface (USB 3.0)
+device		usb		# USB Bus (required)
+device		ukbd		# Keyboard
+device		umass		# Disks/Mass storage - Requires scbus and da
+
+# Sound support
+device		sound		# Generic sound driver (required)
+device		snd_cmi		# CMedia CMI8338/CMI8738
+device		snd_csa		# Crystal Semiconductor CS461x/428x
+device		snd_emu10kx	# Creative SoundBlaster Live! and Audigy
+device		snd_es137x	# Ensoniq AudioPCI ES137x
+device		snd_hda		# Intel High Definition Audio
+device		snd_ich		# Intel, NVidia and other ICH AC'97 Audio
+device		snd_via8233	# VIA VT8233x Audio
+
+# MMC/SD
+device		mmc		# MMC/SD bus
+device		mmcsd		# MMC/SD memory card
+device		sdhci		# Generic PCI SD Host Controller
+
+# VirtIO support
+device		virtio		# Generic VirtIO bus (required)
+device		virtio_pci	# VirtIO PCI device
+device		vtnet		# VirtIO Ethernet device
+device		virtio_blk	# VirtIO Block device
+device		virtio_scsi	# VirtIO SCSI device
+device		virtio_balloon	# VirtIO Memory Balloon device
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/i386/i386/exception.s head/sys/i386/i386/exception.s
--- clean-head/sys/i386/i386/exception.s	2013-06-26 09:35:26.000000000 +0200
+++ head/sys/i386/i386/exception.s	2013-06-24 14:21:39.000000000 +0200
@@ -231,7 +231,11 @@ IDTVEC(lcall_syscall)
 	pushfl				/* save eflags */
 	popl	8(%esp)			/* shuffle into tf_eflags */
 	pushl	$7			/* sizeof "lcall 7,0" */
+#ifdef VPS
+	pushl	$0x80
+#else
 	subl	$4,%esp			/* skip over tf_trapno */
+#endif
 	pushal
 	pushl	%ds
 	pushl	%es
@@ -255,7 +259,11 @@ IDTVEC(lcall_syscall)
 	SUPERALIGN_TEXT
 IDTVEC(int0x80_syscall)
 	pushl	$2			/* sizeof "int 0x80" */
+#ifdef VPS
+	pushl	$0x80
+#else
 	subl	$4,%esp			/* skip over tf_trapno */
+#endif
 	pushal
 	pushl	%ds
 	pushl	%es
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/i386/i386/identcpu.c head/sys/i386/i386/identcpu.c
--- clean-head/sys/i386/i386/identcpu.c	2013-06-26 09:35:26.000000000 +0200
+++ head/sys/i386/i386/identcpu.c	2013-06-24 14:21:39.000000000 +0200
@@ -89,8 +89,8 @@ int	cpu_class;
 u_int	cpu_exthigh;		/* Highest arg to extended CPUID */
 u_int	cyrix_did;		/* Device ID of Cyrix CPU */
 char machine[] = MACHINE;
-SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, 
-    machine, 0, "Machine class");
+_SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, 
+    machine, 0, "Machine class", VPS_PUBLIC);
 
 static char cpu_model[128];
 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/i386/i386/mp_machdep.c head/sys/i386/i386/mp_machdep.c
--- clean-head/sys/i386/i386/mp_machdep.c	2013-06-26 09:35:26.000000000 +0200
+++ head/sys/i386/i386/mp_machdep.c	2013-06-24 14:21:39.000000000 +0200
@@ -74,6 +74,7 @@ __FBSDID("$FreeBSD: head/sys/i386/i386/m
 
 #include <x86/apicreg.h>
 #include <machine/clock.h>
+#include <machine/cpu.h>
 #include <machine/cputypes.h>
 #include <x86/mca.h>
 #include <machine/md_var.h>
@@ -1363,6 +1364,8 @@ ipi_bitmap_handler(struct trapframe fram
 #ifdef COUNT_IPIS
 		(*ipi_preempt_counts[cpu])++;
 #endif
+		if (TRAPF_USERMODE(&frame) == 0)
+			curthread->td_flags |= TDF_PREEMPTED;
 		sched_preempt(td);
 	}
 	if (ipi_bitmap & (1 << IPI_AST)) {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/i386/i386/pmap.c head/sys/i386/i386/pmap.c
--- clean-head/sys/i386/i386/pmap.c	2013-06-26 09:35:26.000000000 +0200
+++ head/sys/i386/i386/pmap.c	2013-06-24 14:21:39.000000000 +0200
@@ -155,6 +155,9 @@ __FBSDID("$FreeBSD: head/sys/i386/i386/p
 #include <machine/xbox.h>
 #endif
 
+#include <vps/vps.h>
+#include <vps/vps_account.h>
+
 #if !defined(CPU_DISABLE_SSE) && defined(I686_CPU)
 #define CPU_ENABLE_SSE
 #endif
@@ -198,6 +201,24 @@ __FBSDID("$FreeBSD: head/sys/i386/i386/p
     atomic_clear_int((u_int *)(pte), PG_W))
 #define pmap_pte_set_prot(pte, v) ((*(int *)pte &= ~PG_PROT), (*(int *)pte |= (v)))
 
+#if 0
+
+#ifdef VPS
+#define VPS_ACCOUNT_PMAP(_pmap, action, charge)                         \
+        do {                                                            \
+                if (_pmap == kernel_map->pmap ||                        \
+                    _pmap == kmem_map->pmap ||                          \
+                    _pmap == buffer_map->pmap)                          \
+                        break;                                          \
+                vps_account(curthread->td_vps, VPS_ACC_PHYS,            \
+                        action, charge << PAGE_SHIFT);                  \
+        } while (0)
+#endif /* VPS */
+
+#else
+#define VPS_ACCOUNT_PMAP(a, b, c)
+#endif
+
 struct pmap kernel_pmap_store;
 LIST_HEAD(pmaplist, pmap);
 static struct pmaplist allpmaps;
@@ -746,7 +767,7 @@ pmap_init(void)
 	 * numbers of pv entries.
 	 */
 	TUNABLE_INT_FETCH("vm.pmap.shpgperproc", &shpgperproc);
-	pv_entry_max = shpgperproc * maxproc + cnt.v_page_count;
+	pv_entry_max = shpgperproc * G_maxproc + cnt.v_page_count;
 	TUNABLE_INT_FETCH("vm.pmap.pv_entries", &pv_entry_max);
 	pv_entry_max = roundup(pv_entry_max, _NPCPV);
 	pv_entry_high_water = 9 * (pv_entry_max / 10);
@@ -787,7 +808,7 @@ pmap_init(void)
 	for (i = 0; i < pv_npg; i++)
 		TAILQ_INIT(&pv_table[i].pv_list);
 
-	pv_maxchunks = MAX(pv_entry_max / _NPCPV, maxproc);
+	pv_maxchunks = MAX(pv_entry_max / _NPCPV, G_maxproc);
 	pv_chunkbase = (struct pv_chunk *)kmem_alloc_nofault(kernel_map,
 	    PAGE_SIZE * pv_maxchunks);
 	if (pv_chunkbase == NULL)
@@ -1666,6 +1687,7 @@ _pmap_unwire_ptp(pmap_t pmap, vm_page_t 
 	 */
 	pmap->pm_pdir[m->pindex] = 0;
 	--pmap->pm_stats.resident_count;
+	VPS_ACCOUNT_PMAP(pmap, VPS_ACC_FREE, 1);
 
 	/*
 	 * This is a release store so that the ordinary store unmapping
@@ -1849,6 +1871,7 @@ _pmap_allocpte(pmap_t pmap, u_int ptepin
 	 */
 
 	pmap->pm_stats.resident_count++;
+	VPS_ACCOUNT_PMAP(pmap, VPS_ACC_ALLOC, 1);
 
 	ptepa = VM_PAGE_TO_PHYS(m);
 	pmap->pm_pdir[ptepindex] =
@@ -2259,7 +2282,7 @@ pmap_pv_reclaim(pmap_t locked_pmap)
 					if (TAILQ_EMPTY(&pvh->pv_list)) {
 						vm_page_aflag_clear(m,
 						    PGA_WRITEABLE);
-					}
+				 	}
 				}
 				pc->pc_map[field] |= 1UL << bit;
 				pmap_unuse_pt(pmap, va, &free);
@@ -2301,7 +2324,7 @@ pmap_pv_reclaim(pmap_t locked_pmap)
 			break;
 		}
 	}
-out:
+out:  
 	TAILQ_CONCAT(&pv_chunks, &newtail, pc_lru);
 	if (pmap != NULL) {
 		pmap_invalidate_all(pmap);
@@ -2666,8 +2689,10 @@ pmap_demote_pde(pmap_t pmap, pd_entry_t 
 			    " in pmap %p", va, pmap);
 			return (FALSE);
 		}
-		if (va < VM_MAXUSER_ADDRESS)
+		if (va < VM_MAXUSER_ADDRESS) {
 			pmap->pm_stats.resident_count++;
+			VPS_ACCOUNT_PMAP(pmap, VPS_ACC_ALLOC, 1);
+		}
 	}
 	mptepa = VM_PAGE_TO_PHYS(mpte);
 
@@ -2797,6 +2822,7 @@ pmap_remove_pde(pmap_t pmap, pd_entry_t 
 	if (oldpde & PG_G)
 		pmap_invalidate_page(kernel_pmap, sva);
 	pmap->pm_stats.resident_count -= NBPDR / PAGE_SIZE;
+	VPS_ACCOUNT_PMAP(pmap, VPS_ACC_FREE, NBPDR / PAGE_SIZE);
 	if (oldpde & PG_MANAGED) {
 		pvh = pa_to_pvh(oldpde & PG_PS_FRAME);
 		pmap_pvh_free(pvh, pmap, sva);
@@ -2820,6 +2846,7 @@ pmap_remove_pde(pmap_t pmap, pd_entry_t 
 		if (mpte != NULL) {
 			pmap_remove_pt_page(pmap, mpte);
 			pmap->pm_stats.resident_count--;
+			VPS_ACCOUNT_PMAP(pmap, VPS_ACC_FREE, 1);
 			KASSERT(mpte->wire_count == NPTEPG,
 			    ("pmap_remove_pde: pte page wire count error"));
 			mpte->wire_count = 0;
@@ -2852,6 +2879,7 @@ pmap_remove_pte(pmap_t pmap, pt_entry_t 
 	if (oldpte & PG_G)
 		pmap_invalidate_page(kernel_pmap, va);
 	pmap->pm_stats.resident_count -= 1;
+	VPS_ACCOUNT_PMAP(pmap, VPS_ACC_FREE, 1);
 	if (oldpte & PG_MANAGED) {
 		m = PHYS_TO_VM_PAGE(oldpte & PG_FRAME);
 		if ((oldpte & (PG_M | PG_RW)) == (PG_M | PG_RW))
@@ -3042,6 +3070,7 @@ small_mappings:
 		pmap = PV_PMAP(pv);
 		PMAP_LOCK(pmap);
 		pmap->pm_stats.resident_count--;
+		VPS_ACCOUNT_PMAP(pmap, VPS_ACC_FREE, 1);
 		pde = pmap_pde(pmap, pv->pv_va);
 		KASSERT((*pde & PG_PS) == 0, ("pmap_remove_all: found"
 		    " a 4mpage in page %p's pv list", m));
@@ -3504,8 +3533,10 @@ pmap_enter(pmap_t pmap, vm_offset_t va, 
 			    ("pmap_enter: missing reference to page table page,"
 			     " va: 0x%x", va));
 		}
-	} else
+	} else {
 		pmap->pm_stats.resident_count++;
+		VPS_ACCOUNT_PMAP(pmap, VPS_ACC_ALLOC, 1);
+	}
 
 	/*
 	 * Enter on the PV list if part of our managed memory.
@@ -3645,6 +3676,7 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t 
 	 * Increment counters.
 	 */
 	pmap->pm_stats.resident_count += NBPDR / PAGE_SIZE;
+	VPS_ACCOUNT_PMAP(pmap, VPS_ACC_ALLOC, NBPDR / PAGE_SIZE);
 
 	/*
 	 * Map the superpage.
@@ -3810,6 +3842,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_
 	 * Increment counters
 	 */
 	pmap->pm_stats.resident_count++;
+	VPS_ACCOUNT_PMAP(pmap, VPS_ACC_ALLOC, 1);
 
 	pa = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(m->md.pat_mode, 0);
 #ifdef PAE
@@ -3906,6 +3939,7 @@ pmap_object_init_pt(pmap_t pmap, vm_offs
 				    PG_U | PG_RW | PG_V);
 				pmap->pm_stats.resident_count += NBPDR /
 				    PAGE_SIZE;
+				VPS_ACCOUNT_PMAP(pmap, VPS_ACC_ALLOC, NBPDR / PAGE_SIZE);
 				pmap_pde_mappings++;
 			}
 			/* Else continue on if the PDE is already valid. */
@@ -4028,6 +4062,7 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pm
 				    ~PG_W;
 				dst_pmap->pm_stats.resident_count +=
 				    NBPDR / PAGE_SIZE;
+				VPS_ACCOUNT_PMAP(dst_pmap, VPS_ACC_ALLOC, NBPDR / PAGE_SIZE);
 			}
 			continue;
 		}
@@ -4063,6 +4098,7 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pm
 					*dst_pte = ptetemp & ~(PG_W | PG_M |
 					    PG_A);
 					dst_pmap->pm_stats.resident_count++;
+					VPS_ACCOUNT_PMAP(dst_pmap, VPS_ACC_ALLOC, 1);
 	 			} else {
 					free = NULL;
 					if (pmap_unwire_ptp(dst_pmap, dstmpte,
@@ -4459,6 +4495,7 @@ pmap_remove_pages(pmap_t pmap)
 				pc->pc_map[field] |= bitmask;
 				if ((tpte & PG_PS) != 0) {
 					pmap->pm_stats.resident_count -= NBPDR / PAGE_SIZE;
+					VPS_ACCOUNT_PMAP(pmap, VPS_ACC_FREE, NBPDR / PAGE_SIZE);
 					pvh = pa_to_pvh(tpte & PG_PS_FRAME);
 					TAILQ_REMOVE(&pvh->pv_list, pv, pv_next);
 					if (TAILQ_EMPTY(&pvh->pv_list)) {
@@ -4470,6 +4507,7 @@ pmap_remove_pages(pmap_t pmap)
 					if (mpte != NULL) {
 						pmap_remove_pt_page(pmap, mpte);
 						pmap->pm_stats.resident_count--;
+						VPS_ACCOUNT_PMAP(pmap, VPS_ACC_FREE, 1);
 						KASSERT(mpte->wire_count == NPTEPG,
 						    ("pmap_remove_pages: pte page wire count error"));
 						mpte->wire_count = 0;
@@ -4478,6 +4516,7 @@ pmap_remove_pages(pmap_t pmap)
 					}
 				} else {
 					pmap->pm_stats.resident_count--;
+					VPS_ACCOUNT_PMAP(pmap, VPS_ACC_FREE, 1);
 					TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
 					if (TAILQ_EMPTY(&m->md.pv_list) &&
 					    (m->flags & PG_FICTITIOUS) == 0) {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/i386/i386/vps_machdep.c head/sys/i386/i386/vps_machdep.c
--- clean-head/sys/i386/i386/vps_machdep.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/i386/i386/vps_machdep.c	2013-06-24 14:21:39.000000000 +0200
@@ -0,0 +1,426 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id$";
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/libkern.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+
+#include <machine/cputypes.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+#include <machine/frame.h>
+#include <machine/vmparam.h>
+#include <machine/vps_md.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_map.h>
+
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#include <vps/vps_int.h>
+#include <vps/vps_libdump.h>
+#include <vps/vps_snapst.h>
+
+#ifdef VPS
+
+/*__attribute__((inline))*/
+void
+vps_md_print_thread(struct thread *td)
+{
+
+	DBGCORE("%s: thread %p/%d kernel stack:\n"
+		"td->td_pcb->esp=%08x\n"
+		"td->td_frame->tf_eax=%08x\n"
+		"td->td_frame->tf_esp=%08x\n"
+		"td->td_frame->tf_ebp=%08x\n"
+		"td->td_frame->tf_eip=%08x\n"
+		"trace:\n",
+		__func__,
+		td,
+		td->td_tid,
+		td->td_pcb->pcb_esp,
+		td->td_frame->tf_eax,
+		td->td_frame->tf_esp,
+		td->td_frame->tf_ebp,
+		td->td_frame->tf_eip);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_thread(struct vps_dump_thread *vdtd, struct thread *ntd,
+    struct proc *p)
+{
+
+	if (vps_func->vps_restore_return == NULL) {
+		printf("%s: vps_restore module not loaded ? "
+		    "vps_func->vps_restore_return == NULL",
+		    __func__);
+		return (EOPNOTSUPP);
+	}
+
+	ntd->td_pcb->pcb_cr3 = vtophys(vmspace_pmap(p->p_vmspace)->pm_pdir);
+	ntd->td_pcb->pcb_edi = 0;
+	ntd->td_pcb->pcb_esi = (uint32_t)vps_func->vps_restore_return;
+	ntd->td_pcb->pcb_ebp = 0;
+	ntd->td_pcb->pcb_esp = (uint32_t)ntd->td_frame - sizeof(void *);
+	ntd->td_pcb->pcb_ebx = (uint32_t)ntd;
+	ntd->td_pcb->pcb_eip = (uint32_t)fork_trampoline;
+	ntd->td_pcb->pcb_psl = PSL_KERNEL;
+	ntd->td_pcb->pcb_ext = NULL;
+	ntd->td_md.md_spinlock_count = 1;
+	ntd->td_md.md_saved_flags = PSL_KERNEL | PSL_I;
+	ntd->td_errno = vdtd->td_errno;
+	ntd->td_retval[0] = vdtd->td_retval[0];
+	ntd->td_retval[1] = vdtd->td_retval[1];
+
+	//db_trace_thread(ntd, 10);
+	DBGCORE("%s: td_pcb = %p; td_frame = %p; pcb_esp = %08x\n",
+		__func__, ntd->td_pcb, ntd->td_frame, ntd->td_pcb->pcb_esp);
+
+	return (0);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_snapshot_sysentvec(struct sysentvec *sv, long *svtype)
+{
+	int error = 0;
+
+	if (sv == &elf32_freebsd_sysvec) {
+		DBGCORE("%s: elf32_freebsd_sysvec\n", __func__);
+		*svtype = VPS_SYSENTVEC_ELF32;
+	} else if (sv == &null_sysvec) {
+		DBGCORE("%s: null_sysvec\n", __func__);
+		*svtype = VPS_SYSENTVEC_NULL;
+        } else {
+		DBGCORE("%s: unknown sysentvec %p\n", __func__, sv);
+		error = EINVAL;
+        }
+
+	return (error);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_sysentvec(long svtype, struct sysentvec **sv)
+{
+	int error = 0;
+
+	if (svtype == VPS_SYSENTVEC_ELF32)
+		*sv = &elf32_freebsd_sysvec;
+	else if (svtype == VPS_SYSENTVEC_NULL)
+		*sv = &null_sysvec;
+	else {
+		DBGCORE("%s: unknown sysentvec type: %ld\n",
+			__func__, svtype);
+		error = EINVAL;
+	}
+
+	return (error);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_checkarch(uint8 ptrsize, uint8 byteorder)
+{
+	int error;
+
+	if (ptrsize == VPS_DUMPH_32BIT && byteorder == VPS_DUMPH_LSB)
+		error = 0;
+	else
+		error = EINVAL;
+
+	return (error);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_snapshot_thread_savefpu(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct thread *td)
+{
+
+	return (0);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_thread_savefpu(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct thread *td)
+{
+
+	return (0);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_reboot_copyout(struct thread *td, struct execve_args *args)
+{
+	vm_offset_t addr;
+	struct proc *p;
+	int error = 0;
+
+	/*
+	 * We push the arguments to execve() onto the
+	 * userspace stack of our process.
+	 */
+	p = td->td_proc;
+	addr = p->p_sysent->sv_usrstack - PAGE_SIZE;
+	if (p->p_vmspace->vm_ssize < 1 /* page */) {
+		/* Should not ever happen in theory ! */
+		return (ENOSPC);
+	}
+
+	if (p->p_sysent == &elf32_freebsd_sysvec) {
+		copyout("/sbin/init", (void *)(addr + 0x40), 11);
+		suword32((void *)(addr + 0x0), (addr + 0x40));
+		suword32((void *)(addr + 0x4), (vm_offset_t)NULL);
+	} else {
+		error = EINVAL;
+	}
+
+	args->fname = (char *)(addr + 0x40);
+	args->argv = (char **)addr;
+	args->envv = NULL;
+
+#if 0
+// notyet
+        KASSERT(pargs != NULL,
+            ("%s: vps=%p, lost pargs somewhere, don't know what to boot\n",
+            __func__, vps));
+        arglen = pargs->ar_length;
+        /*
+        if (arglen > PAGE_SIZE)
+                arglen = PAGE_SIZE - 1;
+        copyout(pargs->ar_args, (void *)addr, arglen);
+        subyte((char *)(addr + PAGE_SIZE - 1), 0x0);
+        */
+        if (exec_alloc_args(&imgargs)) {
+                DBGCORE("%s: exec_alloc_args() returned error\n", __func__);
+                pargs_drop(pargs);
+                goto fail;
+        }  
+        if (arglen > PATH_MAX + ARG_MAX)
+                arglen = PATH_MAX + ARG_MAX - 1;
+        memcpy(imgargs.buf, pargs->ar_args, arglen);
+        addr = (vm_offset_t)imgargs.buf;
+        // ---
+        imgargs.fname = (char *)addr;
+        imgargs.begin_argv = (char *)(addr + 0x0);
+        imgargs.begin_envv = (char *)(addr + arglen);
+        imgargs.endp = (char *)(addr + arglen);
+        imgargs.envc = 0;
+        imgargs.argc = 1; /* XXX */
+        imgargs.stringspace = 0;
+#endif
+
+	return (error);
+}
+
+/*__attribute__((noinline))*/
+int
+vps_md_syscall_fixup(struct vps *vps, struct thread *td,
+    register_t *ret_code, register_t **ret_args, int *ret_narg)
+{
+	struct trapframe *frame;
+	struct sysentvec *sv;
+	struct proc *p;
+	caddr_t params;
+	register_t code;
+	register_t args[8];
+	int narg;
+	int error = 0;
+	struct ucred *save_ucred = curthread->td_ucred;
+
+	if (vps_func->vps_access_vmspace == NULL)
+		return (EOPNOTSUPP);
+
+	p = td->td_proc;
+	frame = td->td_frame;
+	sv = p->p_sysent;
+
+	if (frame->tf_trapno != 0x80) {
+		DBGCORE("%s: thread %p was not in syscall: "
+		    "tf_trapno=0x%x tf_eip=%p\n", __func__, td,
+		    frame->tf_trapno, (void*)frame->tf_eip);
+
+		/* nothing to do ? */
+		error = 0;
+		goto out;
+	}
+
+	if (sv == &elf32_freebsd_sysvec) {
+		DBGCORE("%s: proc=%p/%u elf32_freebsd_sysvec\n",
+		    __func__, p, p->p_pid);
+	} else {
+		DBGCORE("%s: proc=%p/%u unknown sysentvec %p\n",
+		    __func__, p, p->p_pid, sv);
+		panic("%s: proc=%p/%u unknown sysentvec %p\n",
+		    __func__, p, p->p_pid, sv);
+	}
+
+	/* Just in case vm objects are split/copied/... */
+	curthread->td_ucred = td->td_ucred;
+
+	/*
+	 * XXX: special handling for
+	 *      sa->code == SYS_syscall || sa->code == SYS___syscall
+	 */
+
+	memset((caddr_t)args, 0, sizeof(args));
+
+	code = frame->tf_eax;
+
+	if (sv->sv_mask)
+		code &= sv->sv_mask;
+	if (code >= sv->sv_size)
+		code = 0;
+
+	narg = (&sv->sv_table[code])->sy_narg;
+
+	params = (caddr_t)frame->tf_esp + sizeof(register_t);
+
+	KASSERT(narg * sizeof(register_t) <= sizeof(args),
+	    ("%s: argument space on stack too small, narg=%d\n",
+	    __func__, narg));
+
+	if ((vps_func->vps_access_vmspace(p->p_vmspace, (vm_offset_t)params,
+	    narg * sizeof(register_t), (caddr_t)args, VM_PROT_READ))) {
+		error = EFAULT;
+		goto out;
+	}
+
+	DBGCORE("%s: code=%u/0x%x narg=%u args: %08x %08x %08x %08x "
+	    "%08x %08x\n", __func__, code, code, narg, args[0],
+	    args[1], args[2], args[3], args[4], args[5]);
+
+	DBGCORE("SYSCALL: tid=%d pid=%d syscall=%d retval[0]=%zx "
+	    "retval[1]=%zx errno=%d\n",
+	    td->td_tid, td->td_proc->p_pid, code, td->td_retval[0],
+	    td->td_retval[1], td->td_errno);
+
+	KASSERT(*ret_narg >= narg,
+	    ("%s: supplied args array too small (narg=%d *ret_narg=%d)\n",
+	    __func__, narg, *ret_narg));
+	*ret_code = code;
+	*ret_narg= narg;
+	memcpy(ret_args, &args, narg * sizeof(args[0]));
+
+ out:
+	curthread->td_ucred = save_ucred;
+
+	return (error);
+}
+
+int
+vps_md_syscall_fixup_setup_inthread(struct vps *vps, struct thread *td,
+    register_t code)
+{
+
+	DBGCORE("%s\n", __func__);
+
+	if (vps_func->vps_syscall_fixup_inthread == NULL)
+		return (EOPNOTSUPP);
+
+	td->td_pcb->pcb_esi =
+	    (uint32_t)vps_func->vps_syscall_fixup_inthread;
+	td->td_pcb->pcb_eip = (uint32_t)fork_trampoline;
+	td->td_pcb->pcb_esp = (uint32_t)td->td_frame -
+	    sizeof(void *);
+	td->td_pcb->pcb_ebx = (uint32_t)code;
+	td->td_pcb->pcb_ebp = 0;
+
+	return (0);
+}
+
+__attribute__((noinline))
+void
+vps_md_print_pcb(struct thread *td)
+{
+        struct pcb *p;
+
+        p = td->td_pcb;
+
+        DBGCORE("%s: td=%p\n"
+                "pcb_cr3: 0x%08x\n"
+                "pcb_edi: 0x%08x\n"
+                "pcb_esi: 0x%08x\n"
+                "pcb_ebp: 0x%08x\n"
+                "pcb_esp: 0x%08x\n"
+                "pcb_ebx: 0x%08x\n"
+                "pcb_eip: 0x%08x\n"
+                "pcb_psl: 0x%08x\n"
+                "pcb_ext: 0x%08x\n"
+                , __func__, td
+                , p->pcb_cr3
+                , p->pcb_edi
+                , p->pcb_esi
+                , p->pcb_ebp
+                , p->pcb_esp
+                , p->pcb_ebx
+                , p->pcb_eip
+                , p->pcb_psl
+                , (int)p->pcb_ext
+                );
+}
+
+#if 0
+/* --------------------------- 8< --------------------------- */
+
+// vps_suspend():
+#if defined(CPU_X86)
+              DBGCORE("td->td_frame=%p tf_rax=%p tf_rsp=%p\n", td->td_frame,
+                 (void*)td->td_frame->tf_rax, (void*)td->td_frame->tf_rsp);
+#elif defined(CPU_386)
+              DBGCORE("td->td_frame=%p tf_eax=%p tf_esp=%p\n", td->td_frame,
+                 (void*)td->td_frame->tf_eax, (void*)td->td_frame->tf_esp);
+#else
+#error "unsupported architecture"
+#endif
+
+// 
+/* --------------------------- 8< --------------------------- */
+#endif /* 0 */
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/i386/ibcs2/ibcs2_sysvec.c head/sys/i386/ibcs2/ibcs2_sysvec.c
--- clean-head/sys/i386/ibcs2/ibcs2_sysvec.c	2013-06-26 09:35:17.000000000 +0200
+++ head/sys/i386/ibcs2/ibcs2_sysvec.c	2013-06-24 14:21:38.000000000 +0200
@@ -47,6 +47,8 @@ __FBSDID("$FreeBSD: head/sys/i386/ibcs2/
 #include <vm/pmap.h>
 #include <vm/vm_param.h>
 
+#include <vps/vps.h>
+
 #include <i386/ibcs2/ibcs2_syscall.h>
 #include <i386/ibcs2/ibcs2_signal.h>
 
@@ -115,14 +117,14 @@ ibcs2_modevent(module_t mod, int type, v
 		break;
 	case MOD_UNLOAD:
 		/* if this was an ELF module we'd use elf_brand_inuse()... */
-		sx_slock(&allproc_lock);
+		sx_slock(&V_allproc_lock);
 		FOREACH_PROC_IN_SYSTEM(p) {
 			if (p->p_sysent == &ibcs2_svr3_sysvec) {
 				rval = EBUSY;
 				break;
 			}
 		}
-		sx_sunlock(&allproc_lock);
+		sx_sunlock(&V_allproc_lock);
 		break;
 	default:
 	        rval = EOPNOTSUPP;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/i386/include/vps_md.h head/sys/i386/include/vps_md.h
--- clean-head/sys/i386/include/vps_md.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/i386/include/vps_md.h	2013-06-24 14:21:38.000000000 +0200
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifndef _VPS_MD_H
+#define _VPS_MD_H
+
+#define VPS_ARCH_I386
+
+#define VPS_MD_SNAPCTX_NPAGES		10240 /* 40 MB */
+
+#define VPS_MD_DUMPHDR_PTRSIZE		VPS_DUMPH_32BIT
+
+#define VPS_MD_DUMPHDR_BYTEORDER	VPS_DUMPH_LSB
+
+extern struct sysentvec elf32_freebsd_sysvec; 
+
+#ifdef _VPS_MD_FUNCTIONS
+
+inline
+static void
+vps_md_syscallret(struct thread *td, struct syscall_args *sa)
+{
+
+	/* re-setting tf_eax */
+	td->td_frame->tf_eax = sa->code;
+	DBGCORE("%s: td=%p tf_eax=%p\n",
+	    __func__, td, (void*)td->td_frame->tf_eax);
+}
+
+#endif /* _VPS_MD_FUNCTIONS */
+
+#endif /* _VPS_MD_H */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/i386/linux/linux_machdep.c head/sys/i386/linux/linux_machdep.c
--- clean-head/sys/i386/linux/linux_machdep.c	2013-06-26 09:35:16.000000000 +0200
+++ head/sys/i386/linux/linux_machdep.c	2013-06-24 14:21:37.000000000 +0200
@@ -52,6 +52,8 @@ __FBSDID("$FreeBSD: head/sys/i386/linux/
 #include <sys/wait.h>
 #include <sys/sched.h>
 
+#include <vps/vps.h>
+
 #include <machine/frame.h>
 #include <machine/psl.h>
 #include <machine/segments.h>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/imgact_elf.c head/sys/kern/imgact_elf.c
--- clean-head/sys/kern/imgact_elf.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/imgact_elf.c	2013-06-24 14:20:31.000000000 +0200
@@ -78,6 +78,8 @@ __FBSDID("$FreeBSD: head/sys/kern/imgact
 #include <vm/vm_object.h>
 #include <vm/vm_extern.h>
 
+#include <vps/vps.h>
+
 #include <machine/elf.h>
 #include <machine/md_var.h>
 
@@ -243,14 +245,14 @@ __elfN(brand_inuse)(Elf_Brandinfo *entry
 	struct proc *p;
 	int rval = FALSE;
 
-	sx_slock(&allproc_lock);
+	sx_slock(&V_allproc_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		if (p->p_sysent == entry->sysvec) {
 			rval = TRUE;
 			break;
 		}
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
 
 	return (rval);
 }
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/init_main.c head/sys/kern/init_main.c
--- clean-head/sys/kern/init_main.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/init_main.c	2013-06-24 14:20:31.000000000 +0200
@@ -77,6 +77,9 @@ __FBSDID("$FreeBSD: head/sys/kern/init_m
 #include <sys/conf.h>
 #include <sys/cpuset.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <machine/cpu.h>
 
 #include <security/audit/audit.h>
@@ -99,7 +102,11 @@ static struct pgrp pgrp0;
 struct	proc proc0;
 struct	thread thread0 __aligned(16);
 struct	vmspace vmspace0;
+/*
+#ifndef VPS
 struct	proc *initproc;
+#endif
+*/
 
 #ifndef BOOTHOWTO
 #define	BOOTHOWTO	0
@@ -441,6 +448,9 @@ proc0_init(void *dummy __unused)
 	p->p_magic = P_MAGIC;
 	p->p_osrel = osreldate;
 
+	V_maxproc = maxproc;
+	V_maxprocperuid = maxprocperuid;
+
 	/*
 	 * Initialize thread and process structures.
 	 */
@@ -465,7 +475,7 @@ proc0_init(void *dummy __unused)
 	/*
 	 * Create process 0 (the swapper).
 	 */
-	LIST_INSERT_HEAD(&allproc, p, p_list);
+	LIST_INSERT_HEAD(&V_allproc, p, p_list);
 	LIST_INSERT_HEAD(PIDHASH(0), p, p_hash);
 	mtx_init(&pgrp0.pg_mtx, "process group", NULL, MTX_DEF | MTX_DUPOK);
 	p->p_pgrp = &pgrp0;
@@ -498,7 +508,7 @@ proc0_init(void *dummy __unused)
 	td->td_flags = TDF_INMEM;
 	td->td_pflags = TDP_KTHREAD;
 	td->td_cpuset = cpuset_thread0();
-	prison0.pr_cpuset = cpuset_ref(td->td_cpuset);
+	V_prison0->pr_cpuset = cpuset_ref(td->td_cpuset);
 	p->p_peers = 0;
 	p->p_leader = p;
 
@@ -515,7 +525,7 @@ proc0_init(void *dummy __unused)
 	p->p_ucred->cr_ngroups = 1;	/* group 0 */
 	p->p_ucred->cr_uidinfo = uifind(0);
 	p->p_ucred->cr_ruidinfo = uifind(0);
-	p->p_ucred->cr_prison = &prison0;
+	p->p_ucred->cr_prison = V_prison0;
 	p->p_ucred->cr_loginclass = loginclass_find("default");
 #ifdef AUDIT
 	audit_cred_kproc0(p->p_ucred);
@@ -543,7 +553,7 @@ proc0_init(void *dummy __unused)
 	p->p_limit->pl_rlimit[RLIMIT_NOFILE].rlim_cur =
 	    p->p_limit->pl_rlimit[RLIMIT_NOFILE].rlim_max = maxfiles;
 	p->p_limit->pl_rlimit[RLIMIT_NPROC].rlim_cur =
-	    p->p_limit->pl_rlimit[RLIMIT_NPROC].rlim_max = maxproc;
+	    p->p_limit->pl_rlimit[RLIMIT_NPROC].rlim_max = V_maxproc;
 	p->p_limit->pl_rlimit[RLIMIT_DATA].rlim_cur = dfldsiz;
 	p->p_limit->pl_rlimit[RLIMIT_DATA].rlim_max = maxdsiz;
 	p->p_limit->pl_rlimit[RLIMIT_STACK].rlim_cur = dflssiz;
@@ -589,6 +599,15 @@ proc0_init(void *dummy __unused)
 	PROC_LOCK(p);
 	racct_add_force(p, RACCT_NPROC, 1);
 	PROC_UNLOCK(p);
+
+#ifdef VPS
+	if (bootverbose)
+	    printf("proc0_init: vps0=%p\n", vps0);
+	p->p_ucred->cr_vps = vps0;
+	curthread->td_vps = vps0;
+	vps_ref(vps0, NULL);
+	curthread->td_vps_acc = vps0->vps_acc;
+#endif
 }
 SYSINIT(p0init, SI_SUB_INTRINSIC, SI_ORDER_FIRST, proc0_init, NULL);
 
@@ -605,7 +624,7 @@ proc0_post(void *dummy __unused)
 	 * Now we can look at the time, having had a chance to verify the
 	 * time from the filesystem.  Pretend that proc0 started now.
 	 */
-	sx_slock(&allproc_lock);
+	sx_slock(&V_allproc_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		microuptime(&p->p_stats->p_start);
 		PROC_SLOCK(p);
@@ -619,7 +638,7 @@ proc0_post(void *dummy __unused)
 			td->td_runtime = 0;
 		}
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
 	PCPU_SET(switchtime, cpu_ticks());
 	PCPU_SET(switchticks, ticks);
 
@@ -819,16 +838,16 @@ create_init(const void *udata __unused)
 	struct ucred *newcred, *oldcred;
 	int error;
 
-	error = fork1(&thread0, RFFDG | RFPROC | RFSTOPPED, 0, &initproc,
+	error = fork1(&thread0, RFFDG | RFPROC | RFSTOPPED, 0, &V_initproc,
 	    NULL, 0);
 	if (error)
 		panic("cannot fork init: %d\n", error);
-	KASSERT(initproc->p_pid == 1, ("create_init: initproc->p_pid != 1"));
+	KASSERT(V_initproc->p_pid == 1, ("create_init: initproc->p_pid != 1"));
 	/* divorce init's credentials from the kernel's */
 	newcred = crget();
-	PROC_LOCK(initproc);
-	initproc->p_flag |= P_SYSTEM | P_INMEM;
-	oldcred = initproc->p_ucred;
+	PROC_LOCK(V_initproc);
+	V_initproc->p_flag |= P_SYSTEM | P_INMEM;
+	oldcred = V_initproc->p_ucred;
 	crcopy(newcred, oldcred);
 #ifdef MAC
 	mac_cred_create_init(newcred);
@@ -836,11 +855,11 @@ create_init(const void *udata __unused)
 #ifdef AUDIT
 	audit_cred_proc1(newcred);
 #endif
-	initproc->p_ucred = newcred;
-	PROC_UNLOCK(initproc);
+	V_initproc->p_ucred = newcred;
+	PROC_UNLOCK(V_initproc);
 	crfree(oldcred);
-	cred_update_thread(FIRST_THREAD_IN_PROC(initproc));
-	cpu_set_fork_handler(FIRST_THREAD_IN_PROC(initproc), start_init, NULL);
+	cred_update_thread(FIRST_THREAD_IN_PROC(V_initproc));
+	cpu_set_fork_handler(FIRST_THREAD_IN_PROC(V_initproc), start_init, NULL);
 }
 SYSINIT(init, SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL);
 
@@ -852,7 +871,7 @@ kick_init(const void *udata __unused)
 {
 	struct thread *td;
 
-	td = FIRST_THREAD_IN_PROC(initproc);
+	td = FIRST_THREAD_IN_PROC(V_initproc);
 	thread_lock(td);
 	TD_SET_CAN_RUN(td);
 	sched_add(td, SRQ_BORING);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_acct.c head/sys/kern/kern_acct.c
--- clean-head/sys/kern/kern_acct.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_acct.c	2013-06-24 14:20:31.000000000 +0200
@@ -93,6 +93,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_a
 #include <sys/tty.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+
 #include <security/mac/mac_framework.h>
 
 /*
@@ -364,7 +366,7 @@ acct_process(struct thread *td)
 	 * Get process accounting information.
 	 */
 
-	sx_slock(&proctree_lock);
+	sx_slock(&V_proctree_lock);
 	PROC_LOCK(p);
 
 	/* (1) The terminal from which the process was started */
@@ -372,7 +374,7 @@ acct_process(struct thread *td)
 		acct.ac_tty = tty_udev(p->p_pgrp->pg_session->s_ttyp);
 	else
 		acct.ac_tty = NODEV;
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 
 	/* (2) The name of the command that ran */
 	bcopy(p->p_comm, acct.ac_comm, sizeof acct.ac_comm);
@@ -383,7 +385,7 @@ acct_process(struct thread *td)
 	acct.ac_stime = encode_timeval(st);
 
 	/* (4) The elapsed time the command ran (and its starting time) */
-	tmp = boottime;
+	tmp = V_boottime;
 	timevaladd(&tmp, &p->p_stats->p_start);
 	acct.ac_btime = tmp.tv_sec;
 	microuptime(&tmp);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_clock.c head/sys/kern/kern_clock.c
--- clean-head/sys/kern/kern_clock.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_clock.c	2013-06-24 14:20:31.000000000 +0200
@@ -70,6 +70,9 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_c
 #include <sys/limits.h>
 #include <sys/timetc.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #ifdef GPROF
 #include <sys/gmon.h>
 #endif
@@ -106,6 +109,13 @@ sysctl_kern_cp_time(SYSCTL_HANDLER_ARGS)
 #endif
 
 	read_cpu_time(cp_time);
+
+#ifdef VPS
+	/* XXX calc real per-vps times */
+	if (req->td->td_vps != vps0)
+		memset(&cp_time, 0, sizeof(cp_time));
+#endif
+
 #ifdef SCTL_MASK32
 	if (req->flags & SCTL_MASK32) {
 		if (!req->oldptr)
@@ -123,8 +133,8 @@ sysctl_kern_cp_time(SYSCTL_HANDLER_ARGS)
 	return error;
 }
 
-SYSCTL_PROC(_kern, OID_AUTO, cp_time, CTLTYPE_LONG|CTLFLAG_RD|CTLFLAG_MPSAFE,
-    0,0, sysctl_kern_cp_time, "LU", "CPU time statistics");
+_SYSCTL_PROC(_kern, OID_AUTO, cp_time, CTLTYPE_LONG|CTLFLAG_RD|CTLFLAG_MPSAFE,
+    0,0, sysctl_kern_cp_time, "LU", "CPU time statistics", VPS_PUBLIC);
 
 static long empty[CPUSTATES];
 
@@ -151,7 +161,12 @@ sysctl_kern_cp_times(SYSCTL_HANDLER_ARGS
 	for (error = 0, c = 0; error == 0 && c <= mp_maxid; c++) {
 		if (!CPU_ABSENT(c)) {
 			pcpu = pcpu_find(c);
-			cp_time = pcpu->pc_cp_time;
+#ifdef VPS
+			if (req->td->td_vps != vps0)
+				cp_time = empty;
+			else
+#endif
+				cp_time = pcpu->pc_cp_time;
 		} else {
 			cp_time = empty;
 		}
@@ -167,8 +182,8 @@ sysctl_kern_cp_times(SYSCTL_HANDLER_ARGS
 	return error;
 }
 
-SYSCTL_PROC(_kern, OID_AUTO, cp_times, CTLTYPE_LONG|CTLFLAG_RD|CTLFLAG_MPSAFE,
-    0,0, sysctl_kern_cp_times, "LU", "per-CPU time statistics");
+_SYSCTL_PROC(_kern, OID_AUTO, cp_times, CTLTYPE_LONG|CTLFLAG_RD|CTLFLAG_MPSAFE,
+    0,0, sysctl_kern_cp_times, "LU", "per-CPU time statistics", VPS_PUBLIC);
 
 #ifdef DEADLKRES
 static const char *blessed[] = {
@@ -188,9 +203,21 @@ deadlkres(void)
 	struct thread *td;
 	void *wchan;
 	int blkticks, i, slpticks, slptype, tryl, tticks;
+#ifdef VPS
+        struct vps *vps, *vps_tmp, *save_vps;
+#endif
 
 	tryl = 0;
 	for (;;) {
+
+#ifdef VPS
+		save_vps = curthread->td_vps;
+		sx_slock(&vps_all_lock);
+		LIST_FOREACH_SAFE(vps, &vps_head, vps_all, vps_tmp) {
+		sx_sunlock(&vps_all_lock);
+		curthread->td_vps = vps;
+#endif /* VPS */
+
 		blkticks = blktime_threshold * hz;
 		slpticks = slptime_threshold * hz;
 
@@ -199,7 +226,7 @@ deadlkres(void)
 		 * priority inversion problem leading to starvation.
 		 * If the lock can't be held after 100 tries, panic.
 		 */
-		if (!sx_try_slock(&allproc_lock)) {
+		if (!sx_try_slock(&V_allproc_lock)) {
 			if (tryl > 100)
 		panic("%s: possible deadlock detected on allproc_lock\n",
 				    __func__);
@@ -242,7 +269,7 @@ deadlkres(void)
 						 * turnstile.
 						 */
 						PROC_UNLOCK(p);
-						sx_sunlock(&allproc_lock);
+						sx_sunlock(&V_allproc_lock);
 	panic("%s: possible deadlock detected for %p, blocked for %d ticks\n",
 						    __func__, td, tticks);
 					}
@@ -289,7 +316,7 @@ deadlkres(void)
 							continue;
 						}
 						PROC_UNLOCK(p);
-						sx_sunlock(&allproc_lock);
+						sx_sunlock(&V_allproc_lock);
 	panic("%s: possible deadlock detected for %p, blocked for %d ticks\n",
 						    __func__, td, tticks);
 					}
@@ -298,7 +325,13 @@ deadlkres(void)
 			}
 			PROC_UNLOCK(p);
 		}
-		sx_sunlock(&allproc_lock);
+		sx_sunlock(&V_allproc_lock);
+#ifdef VPS
+		sx_slock(&vps_all_lock);
+		}
+		sx_sunlock(&vps_all_lock);
+		curthread->td_vps = save_vps;
+#endif
 
 		/* Sleep for sleepfreq seconds. */
 		pause("-", sleepfreq * hz);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_conf.c head/sys/kern/kern_conf.c
--- clean-head/sys/kern/kern_conf.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_conf.c	2013-06-24 14:20:31.000000000 +0200
@@ -941,6 +941,69 @@ make_dev_alias_v(int flags, struct cdev 
 	return (0);
 }
 
+#ifdef VPS
+static int
+make_dev_alias_cred_v(int flags, struct cdev **cdev, struct cdev *pdev,
+    struct ucred *cr, const char *fmt, va_list ap)
+{
+	struct cdev *dev;
+	int error;
+
+	KASSERT(pdev != NULL, ("make_dev_alias_v: pdev is NULL"));
+	KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0,
+	    ("make_dev_alias_v: both WAITOK and NOWAIT specified"));
+	KASSERT((flags & ~(MAKEDEV_WAITOK | MAKEDEV_NOWAIT |
+	    MAKEDEV_CHECKNAME)) == 0,
+	    ("make_dev_alias_v: invalid flags specified (flags=%02x)", flags));
+
+	dev = devfs_alloc(flags);
+	if (dev == NULL)
+		return (ENOMEM);
+	dev_lock();
+	dev->si_flags |= SI_ALIAS;
+	if (cr != NULL)
+		dev->si_cred = crhold(cr);
+	error = prep_devname(dev, fmt, ap);
+	if (error != 0) {
+		if ((flags & MAKEDEV_CHECKNAME) == 0) {
+			panic("make_dev_alias_v: bad si_name "
+			    "(error=%d, si_name=%s)", error, dev->si_name);
+		}
+		dev_unlock();
+		devfs_free(dev);
+		return (error);
+	}
+	dev->si_flags |= SI_NAMED;
+	devfs_create(dev);
+	dev_dependsl(pdev, dev);
+	clean_unrhdrl(devfs_inos);
+	dev_unlock();
+
+	notify_create(dev, flags);
+	*cdev = dev;
+
+	return (0);
+}
+
+struct cdev *
+make_dev_alias_cred(struct cdev *pdev, struct ucred *cr, const char *fmt, ...)
+{
+	struct cdev *dev;
+	va_list ap;
+	int res;
+
+	dev = NULL;
+
+	va_start(ap, fmt);
+	res = make_dev_alias_cred_v(MAKEDEV_WAITOK, &dev, pdev, cr, fmt, ap);
+	va_end(ap);
+
+	KASSERT(res == 0 && dev != NULL,
+	    ("make_dev_alias: failed make_dev_alias_v (error=%d)", res));
+	return (dev);
+}
+#endif /* VPS */
+
 struct cdev *
 make_dev_alias(struct cdev *pdev, const char *fmt, ...)
 {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_cpuset.c head/sys/kern/kern_cpuset.c
--- clean-head/sys/kern/kern_cpuset.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_cpuset.c	2013-06-24 14:20:31.000000000 +0200
@@ -57,6 +57,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_c
 
 #include <vm/uma.h>
 
+#include <vps/vps.h>
+
 #ifdef DDB
 #include <ddb/ddb.h>
 #endif /* DDB */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_descrip.c head/sys/kern/kern_descrip.c
--- clean-head/sys/kern/kern_descrip.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_descrip.c	2013-06-24 14:20:31.000000000 +0200
@@ -95,6 +95,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_d
 #include <netinet/in.h>
 #include <netinet/in_pcb.h>
 
+#include <vps/vps.h>
+
 #include <security/audit/audit.h>
 
 #include <vm/uma.h>
@@ -104,7 +106,7 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_d
 
 static MALLOC_DEFINE(M_FILEDESC, "filedesc", "Open file descriptor table");
 static MALLOC_DEFINE(M_FILEDESC_TO_LEADER, "filedesc_to_leader",
-    "file desc to leader structures");
+	"file desc to leader structures");
 static MALLOC_DEFINE(M_SIGIO, "sigio", "sigio structures");
 MALLOC_DEFINE(M_FILECAPS, "filecaps", "descriptor capabilities");
 
@@ -112,18 +114,24 @@ MALLOC_DECLARE(M_FADVISE);
 
 static uma_zone_t file_zone;
 
-void	(*ksem_info)(struct ksem *ks, char *path, size_t size, uint32_t *value);
+void  (*ksem_info)(struct ksem *ks, char *path, size_t size, uint32_t *value);
 
-static int	closefp(struct filedesc *fdp, int fd, struct file *fp,
-		    struct thread *td, int holdleaders);
+static int    closefp(struct filedesc *fdp, int fd, struct file *fp,
+			struct thread *td, int holdleaders);
 static int	fd_first_free(struct filedesc *fdp, int low, int size);
 static int	fd_last_used(struct filedesc *fdp, int size);
+#ifdef VPS
+void		fdgrowtable(struct filedesc *fdp, int nfd);
+void		fdunused(struct filedesc *fdp, int fd);
+void		fdused(struct filedesc *fdp, int fd);
+#else
 static void	fdgrowtable(struct filedesc *fdp, int nfd);
 static void	fdunused(struct filedesc *fdp, int fd);
 static void	fdused(struct filedesc *fdp, int fd);
+#endif /* !VPS */
 static int	fill_pipe_info(struct pipe *pi, struct kinfo_file *kif);
 static int	fill_procdesc_info(struct procdesc *pdp,
-		    struct kinfo_file *kif);
+			struct kinfo_file *kif);
 static int	fill_pts_info(struct tty *tp, struct kinfo_file *kif);
 static int	fill_sem_info(struct file *fp, struct kinfo_file *kif);
 static int	fill_shm_info(struct file *fp, struct kinfo_file *kif);
@@ -256,7 +264,11 @@ fdisused(struct filedesc *fdp, int fd)
 /*
  * Mark a file descriptor as used.
  */
+#ifdef VPS
+void
+#else
 static void
+#endif
 fdused(struct filedesc *fdp, int fd)
 {
 
@@ -274,7 +286,11 @@ fdused(struct filedesc *fdp, int fd)
 /*
  * Mark a file descriptor as unused.
  */
+#ifdef VPS
+void
+#else
 static void
+#endif
 fdunused(struct filedesc *fdp, int fd)
 {
 
@@ -1003,7 +1019,7 @@ fsetown(pid_t pgid, struct sigio **sigio
 	sigio->sio_ucred = crhold(curthread->td_ucred);
 	sigio->sio_myref = sigiop;
 
-	sx_slock(&proctree_lock);
+	sx_slock(&V_proctree_lock);
 	if (pgid > 0) {
 		proc = pfind(pgid);
 		if (proc == NULL) {
@@ -1071,14 +1087,14 @@ fsetown(pid_t pgid, struct sigio **sigio
 		sigio->sio_pgrp = pgrp;
 		PGRP_UNLOCK(pgrp);
 	}
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 	SIGIO_LOCK();
 	*sigiop = sigio;
 	SIGIO_UNLOCK();
 	return (0);
 
 fail:
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 	crfree(sigio->sio_ucred);
 	free(sigio, M_SIGIO);
 	return (ret);
@@ -1457,38 +1473,42 @@ filecaps_validate(const struct filecaps 
 /*
  * Grow the file table to accomodate (at least) nfd descriptors.
  */
+#ifdef VPS
+void
+#else
 static void
+#endif
 fdgrowtable(struct filedesc *fdp, int nfd)
 {
-	struct filedesc0 *fdp0;
+  	struct filedesc0 *fdp0;
 	struct freetable *ft;
 	struct filedescent *ntable;
 	struct filedescent *otable;
-	int nnfiles, onfiles;
+  	int nnfiles, onfiles;
 	NDSLOTTYPE *nmap, *omap;
-
-	FILEDESC_XLOCK_ASSERT(fdp);
-
+  
+  	FILEDESC_XLOCK_ASSERT(fdp);
+  
 	KASSERT(fdp->fd_nfiles > 0, ("zero-length file table"));
-
+  
 	/* save old values */
-	onfiles = fdp->fd_nfiles;
+  	onfiles = fdp->fd_nfiles;
 	otable = fdp->fd_ofiles;
 	omap = fdp->fd_map;
 
 	/* compute the size of the new table */
-	nnfiles = NDSLOTS(nfd) * NDENTRIES; /* round up */
-	if (nnfiles <= onfiles)
-		/* the table is already large enough */
-		return;
-
-	/*
+  	nnfiles = NDSLOTS(nfd) * NDENTRIES; /* round up */
+  	if (nnfiles <= onfiles)
+  		/* the table is already large enough */
+  		return;
+  
+  	/*
 	 * Allocate a new table and map.  We need enough space for the
 	 * file entries themselves and the struct freetable we will use
 	 * when we decommission the table and place it on the freelist.
 	 * We place the struct freetable in the middle so we don't have
 	 * to worry about padding.
-	 */
+  	 */
 	ntable = malloc(nnfiles * sizeof(ntable[0]) + sizeof(struct freetable),
 	    M_FILEDESC, M_ZERO | M_WAITOK);
 	nmap = malloc(NDSLOTS(nnfiles) * NDSLOTSIZE, M_FILEDESC,
@@ -1501,10 +1521,10 @@ fdgrowtable(struct filedesc *fdp, int nf
 	/* update the pointers and counters */
 	fdp->fd_nfiles = nnfiles;
 	memcpy(ntable, otable, onfiles * sizeof(ntable[0]));
-	fdp->fd_ofiles = ntable;
+  	fdp->fd_ofiles = ntable;
 	fdp->fd_map = nmap;
 
-	/*
+  	/*
 	 * Do not free the old file table, as some threads may still
 	 * reference entries within it.  Instead, place it on a freelist
 	 * which will be processed when the struct filedesc is released.
@@ -1514,14 +1534,14 @@ fdgrowtable(struct filedesc *fdp, int nf
 	 * Note that if onfiles == NDFILE, we're dealing with the original
 	 * static allocation contained within (struct filedesc0 *)fdp,
 	 * which must not be freed.
-	 */
-	if (onfiles > NDFILE) {
+  	 */
+  	if (onfiles > NDFILE) {
 		ft = (struct freetable *)&otable[onfiles];
-		fdp0 = (struct filedesc0 *)fdp;
+  		fdp0 = (struct filedesc0 *)fdp;
 		ft->ft_table = otable;
 		SLIST_INSERT_HEAD(&fdp0->fd_free, ft, ft_next);
 		free(omap, M_FILEDESC);
-	}
+  	}
 }
 
 /*
@@ -2754,7 +2774,7 @@ mountcheckdirs(struct vnode *olddp, stru
 	if (vrefcnt(olddp) == 1)
 		return;
 	nrele = 0;
-	sx_slock(&allproc_lock);
+	sx_slock(&V_allproc_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		fdp = fdhold(p);
 		if (fdp == NULL)
@@ -2778,21 +2798,21 @@ mountcheckdirs(struct vnode *olddp, stru
 		FILEDESC_XUNLOCK(fdp);
 		fddrop(fdp);
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
 	if (rootvnode == olddp) {
 		vref(newdp);
 		rootvnode = newdp;
 		nrele++;
 	}
-	mtx_lock(&prison0.pr_mtx);
-	if (prison0.pr_root == olddp) {
+	mtx_lock(&V_prison0->pr_mtx);
+	if (V_prison0->pr_root == olddp) {
 		vref(newdp);
-		prison0.pr_root = newdp;
+		V_prison0->pr_root = newdp;
 		nrele++;
 	}
-	mtx_unlock(&prison0.pr_mtx);
+	mtx_unlock(&V_prison0->pr_mtx);
 	sx_slock(&allprison_lock);
-	TAILQ_FOREACH(pr, &allprison, pr_list) {
+	TAILQ_FOREACH(pr, &V_allprison, pr_list) {
 		mtx_lock(&pr->pr_mtx);
 		if (pr->pr_root == olddp) {
 			vref(newdp);
@@ -2849,7 +2869,7 @@ sysctl_kern_file(SYSCTL_HANDLER_ARGS)
 		return (error);
 	if (req->oldptr == NULL) {
 		n = 0;
-		sx_slock(&allproc_lock);
+		sx_slock(&V_allproc_lock);
 		FOREACH_PROC_IN_SYSTEM(p) {
 			if (p->p_state == PRS_NEW)
 				continue;
@@ -2861,13 +2881,13 @@ sysctl_kern_file(SYSCTL_HANDLER_ARGS)
 				n += fdp->fd_lastfile;
 			fddrop(fdp);
 		}
-		sx_sunlock(&allproc_lock);
+		sx_sunlock(&V_allproc_lock);
 		return (SYSCTL_OUT(req, 0, n * sizeof(xf)));
 	}
 	error = 0;
 	bzero(&xf, sizeof(xf));
 	xf.xf_size = sizeof(xf);
-	sx_slock(&allproc_lock);
+	sx_slock(&V_allproc_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		PROC_LOCK(p);
 		if (p->p_state == PRS_NEW) {
@@ -2906,7 +2926,7 @@ sysctl_kern_file(SYSCTL_HANDLER_ARGS)
 		if (error)
 			break;
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
 	return (error);
 }
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_environment.c head/sys/kern/kern_environment.c
--- clean-head/sys/kern/kern_environment.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_environment.c	2013-06-24 14:20:31.000000000 +0200
@@ -52,6 +52,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_e
 #include <sys/libkern.h>
 #include <sys/kenv.h>
 
+#include <vps/vps.h>
+
 #include <security/mac/mac_framework.h>
 
 static MALLOC_DEFINE(M_KENV, "kenv", "kernel environment");
@@ -92,6 +94,11 @@ sys_kenv(td, uap)
 
 	KASSERT(dynamic_kenv, ("kenv: dynamic_kenv = 0"));
 
+#ifdef VPS
+	if (td->td_vps != vps0)
+		return (ENOSYS);
+#endif
+
 	error = 0;
 	if (uap->what == KENV_DUMP) {
 #ifdef MAC
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_event.c head/sys/kern/kern_event.c
--- clean-head/sys/kern/kern_event.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_event.c	2013-06-24 14:20:31.000000000 +0200
@@ -91,7 +91,7 @@ TASKQUEUE_DEFINE_THREAD(kqueue);
 
 static int	kevent_copyout(void *arg, struct kevent *kevp, int count);
 static int	kevent_copyin(void *arg, struct kevent *kevp, int count);
-static int	kqueue_register(struct kqueue *kq, struct kevent *kev,
+/* XXX static*/ int	kqueue_register(struct kqueue *kq, struct kevent *kev,
 		    struct thread *td, int waitok);
 static int	kqueue_acquire(struct file *fp, struct kqueue **kqp);
 static void	kqueue_release(struct kqueue *kq, int locked);
@@ -949,7 +949,7 @@ kqueue_fo_release(int filt)
  * influence if memory allocation should wait.  Make sure it is 0 if you
  * hold any mutexes.
  */
-static int
+/*static XXX */ int
 kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int waitok)
 {
 	struct filterops *fops;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_exec.c head/sys/kern/kern_exec.c
--- clean-head/sys/kern/kern_exec.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_exec.c	2013-06-24 14:20:31.000000000 +0200
@@ -112,19 +112,19 @@ static int do_execve(struct thread *td, 
     struct mac *mac_p);
 
 /* XXX This should be vm_size_t. */
-SYSCTL_PROC(_kern, KERN_PS_STRINGS, ps_strings, CTLTYPE_ULONG|CTLFLAG_RD,
-    NULL, 0, sysctl_kern_ps_strings, "LU", "");
+_SYSCTL_PROC(_kern, KERN_PS_STRINGS, ps_strings, CTLTYPE_ULONG|CTLFLAG_RD,
+    NULL, 0, sysctl_kern_ps_strings, "LU", "", VPS_PUBLIC);
 
 /* XXX This should be vm_size_t. */
-SYSCTL_PROC(_kern, KERN_USRSTACK, usrstack, CTLTYPE_ULONG|CTLFLAG_RD|
-    CTLFLAG_CAPRD, NULL, 0, sysctl_kern_usrstack, "LU", "");
+_SYSCTL_PROC(_kern, KERN_USRSTACK, usrstack, CTLTYPE_ULONG|CTLFLAG_RD|
+    CTLFLAG_CAPRD, NULL, 0, sysctl_kern_usrstack, "LU", "", VPS_PUBLIC);
 
-SYSCTL_PROC(_kern, OID_AUTO, stackprot, CTLTYPE_INT|CTLFLAG_RD,
-    NULL, 0, sysctl_kern_stackprot, "I", "");
+_SYSCTL_PROC(_kern, OID_AUTO, stackprot, CTLTYPE_INT|CTLFLAG_RD,
+    NULL, 0, sysctl_kern_stackprot, "I", "", VPS_PUBLIC);
 
 u_long ps_arg_cache_limit = PAGE_SIZE / 16;
-SYSCTL_ULONG(_kern, OID_AUTO, ps_arg_cache_limit, CTLFLAG_RW, 
-    &ps_arg_cache_limit, 0, "");
+_SYSCTL_ULONG(_kern, OID_AUTO, ps_arg_cache_limit, CTLFLAG_RW, 
+    &ps_arg_cache_limit, 0, "", VPS_PUBLIC);
 
 static int map_at_zero = 0;
 TUNABLE_INT("security.bsd.map_at_zero", &map_at_zero);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_exit.c head/sys/kern/kern_exit.c
--- clean-head/sys/kern/kern_exit.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_exit.c	2013-06-24 14:20:31.000000000 +0200
@@ -88,6 +88,12 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_e
 #include <vm/vm_page.h>
 #include <vm/uma.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#define _VPS_USER_H__ONLY_FLAGS 1
+#include <vps/vps_user.h>
+#include <vps/vps_account.h>
+
 #ifdef KDTRACE_HOOKS
 #include <sys/dtrace_bsd.h>
 dtrace_execexit_func_t	dtrace_fasttrap_exit;
@@ -144,12 +150,40 @@ exit1(struct thread *td, int rv)
 	 * work around an unsolved stack overflow seen very late during
 	 * shutdown on sparc64 when the gmirror worker process exists.
 	 */
-	if (p == initproc && rebooting == 0) {
+#ifdef VPS
+	if (p == VPS_VPS(vps0, initproc) && rebooting == 0) { /* NOT V_initproc */
+#else
+	if (p == initproc && rebooting == 0) { /* NOT V_initproc */
+#endif
 		printf("init died (signal %d, exit %d)\n",
 		    WTERMSIG(rv), WEXITSTATUS(rv));
 		panic("Going nowhere without my init!");
 	}
 
+#ifdef VPS
+	/*
+	 * If we are the initproc of a vps, we have to wait for all
+	 * other processes to exit before.
+	 */
+	if (p == V_initproc) {
+		struct vps *vps;
+
+		KASSERT( ! (LIST_EMPTY(&p->p_children) && (V_nprocs - V_nprocs_zomb) > 1),
+			("%s: p==V_initproc && LIST_EMPTY(&p->p_children) "
+			"&& (V_nprocs - V_nprocs_zomb) > 1; p=%p",
+			__func__, p));
+
+		/* From this point on we can't do any suspends. */
+		vps = p->p_ucred->cr_vps;
+		//vps->vps_status = VPS_ST_INITISDYING;
+		while ((V_nprocs - V_nprocs_zomb) > 1) {
+			/* Sleep. */
+			pause("vpsxit", hz / 10);
+		}
+
+	}
+#endif /* VPS */
+
 	/*
 	 * MUST abort all other threads before proceeding past here.
 	 */
@@ -239,7 +273,7 @@ exit1(struct thread *td, int rv)
 
 	/* Are we a task leader? */
 	if (p == p->p_leader) {
-		mtx_lock(&ppeers_lock);
+		mtx_lock(&V_ppeers_lock);
 		q = p->p_peers;
 		while (q != NULL) {
 			PROC_LOCK(q);
@@ -248,8 +282,8 @@ exit1(struct thread *td, int rv)
 			q = q->p_peers;
 		}
 		while (p->p_peers != NULL)
-			msleep(p, &ppeers_lock, PWAIT, "exit1", 0);
-		mtx_unlock(&ppeers_lock);
+			msleep(p, &V_ppeers_lock, PWAIT, "exit1", 0);
+		mtx_unlock(&V_ppeers_lock);
 	}
 
 	/*
@@ -309,7 +343,7 @@ exit1(struct thread *td, int rv)
 	/*
 	 * Remove ourself from our leader's peer list and wake our leader.
 	 */
-	mtx_lock(&ppeers_lock);
+	mtx_lock(&V_ppeers_lock);
 	if (p->p_leader->p_peers) {
 		q = p->p_leader;
 		while (q->p_peers != p)
@@ -317,11 +351,11 @@ exit1(struct thread *td, int rv)
 		q->p_peers = p->p_peers;
 		wakeup(p->p_leader);
 	}
-	mtx_unlock(&ppeers_lock);
+	mtx_unlock(&V_ppeers_lock);
 
 	vmspace_exit(td);
 
-	sx_xlock(&proctree_lock);
+	sx_xlock(&V_proctree_lock);
 	if (SESS_LEADER(p)) {
 		struct session *sp = p->p_session;
 		struct tty *tp;
@@ -359,16 +393,16 @@ exit1(struct thread *td, int rv)
 		}
 
 		if (ttyvp != NULL) {
-			sx_xunlock(&proctree_lock);
+			sx_xunlock(&V_proctree_lock);
 			if (vn_lock(ttyvp, LK_EXCLUSIVE) == 0) {
 				VOP_REVOKE(ttyvp, REVOKEALL);
 				VOP_UNLOCK(ttyvp, 0);
 			}
-			sx_xlock(&proctree_lock);
+			sx_xlock(&V_proctree_lock);
 		}
 	}
 	fixjobc(p, p->p_pgrp, 0);
-	sx_xunlock(&proctree_lock);
+	sx_xunlock(&V_proctree_lock);
 	(void)acct_process(td);
 
 	/* Release the TTY now we've unlocked everything. */
@@ -400,11 +434,14 @@ exit1(struct thread *td, int rv)
 	 * Remove proc from allproc queue and pidhash chain.
 	 * Place onto zombproc.  Unlink from parent's child list.
 	 */
-	sx_xlock(&allproc_lock);
+	sx_xlock(&V_allproc_lock);
 	LIST_REMOVE(p, p_list);
-	LIST_INSERT_HEAD(&zombproc, p, p_list);
+	LIST_INSERT_HEAD(&V_zombproc, p, p_list);
 	LIST_REMOVE(p, p_hash);
-	sx_xunlock(&allproc_lock);
+#ifdef VPS
+	V_nprocs_zomb++;
+#endif
+	sx_xunlock(&V_allproc_lock);
 
 	/*
 	 * Call machine-dependent code to release any
@@ -419,14 +456,25 @@ exit1(struct thread *td, int rv)
 	/*
 	 * Reparent all of our children to init.
 	 */
-	sx_xlock(&proctree_lock);
+	sx_xlock(&V_proctree_lock);
 	q = LIST_FIRST(&p->p_children);
 	if (q != NULL)		/* only need this if any child is S_ZOMB */
-		wakeup(initproc);
+#ifdef VPS
+	/* Since we don't allow the initproc to exit as long as there
+	 * are child processes, V_initproc must never be NULL here.
+	 */
+	KASSERT(V_initproc != NULL, ("%s: child procs exists but V_initproc == NULL, p=%p",
+		__func__, p));
+		/* if (V_initproc != NULL) */
+#endif
+		wakeup(V_initproc);
 	for (; q != NULL; q = nq) {
 		nq = LIST_NEXT(q, p_sibling);
 		PROC_LOCK(q);
-		proc_reparent(q, initproc);
+#ifdef VPS
+		/* if ( ! (q == V_initproc || V_initproc == NULL)) */
+#endif
+		proc_reparent(q, V_initproc);
 		q->p_sigparent = SIGCHLD;
 		/*
 		 * Traced processes are killed
@@ -511,6 +559,15 @@ exit1(struct thread *td, int rv)
 		 * notify process 1 instead (and hope it will handle this
 		 * situation).
 		 */
+#ifdef VPS
+		/*
+		 * If we don't have a parent proc at all we must be the init proc.
+		 * Otherwise something went wrong !
+		 */
+		KASSERT( ! (p->p_pptr==NULL && p != V_initproc),
+			("%s: p->p_pptr==NULL && p != V_initproc, p=%p", __func__, p));
+		if (p->p_pptr) {
+#endif
 		PROC_LOCK(p->p_pptr);
 		mtx_lock(&p->p_pptr->p_sigacts->ps_mtx);
 		if (p->p_pptr->p_sigacts->ps_flag &
@@ -520,7 +577,7 @@ exit1(struct thread *td, int rv)
 			mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx);
 			pp = p->p_pptr;
 			PROC_UNLOCK(pp);
-			proc_reparent(p, initproc);
+			proc_reparent(p, V_initproc);
 			p->p_sigparent = SIGCHLD;
 			PROC_LOCK(p->p_pptr);
 
@@ -533,7 +590,7 @@ exit1(struct thread *td, int rv)
 		} else
 			mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx);
 
-		if (p->p_pptr == initproc)
+		if (p->p_pptr == V_initproc)
 			kern_psignal(p->p_pptr, SIGCHLD);
 		else if (p->p_sigparent != 0) {
 			if (p->p_sigparent == SIGCHLD)
@@ -541,11 +598,14 @@ exit1(struct thread *td, int rv)
 			else	/* LINUX thread */
 				kern_psignal(p->p_pptr, p->p_sigparent);
 		}
+#ifdef VPS
+		}
+#endif
 #ifdef PROCDESC
 	} else
 		PROC_LOCK(p->p_pptr);
 #endif
-	sx_xunlock(&proctree_lock);
+	sx_xunlock(&V_proctree_lock);
 
 	/*
 	 * The state PRS_ZOMBIE prevents other proesses from sending
@@ -565,12 +625,22 @@ exit1(struct thread *td, int rv)
 	 * sched lock, update the state, and release the parent process'
 	 * proc lock.
 	 */
+#ifdef VPS
+	if (p->p_pptr) {
+#endif
 	wakeup(p->p_pptr);
 	cv_broadcast(&p->p_pwait);
 	sched_exit(p->p_pptr, td);
 	PROC_SLOCK(p);
 	p->p_state = PRS_ZOMBIE;
 	PROC_UNLOCK(p->p_pptr);
+#ifdef VPS
+	} else {
+	   cv_broadcast(&p->p_pwait);
+	   PROC_SLOCK(p);
+	   p->p_state = PRS_ZOMBIE;
+	}
+#endif
 
 	/*
 	 * Hopefully no one will try to deliver a signal to the process this
@@ -583,6 +653,10 @@ exit1(struct thread *td, int rv)
 	 */
 	ruadd(&p->p_ru, &p->p_rux, &p->p_stats->p_cru, &p->p_crux);
 
+#ifdef VPS
+	vps_proc_exit(td, p);
+#endif
+
 	/*
 	 * Make sure the scheduler takes this thread out of its tables etc.
 	 * This will also release this thread's reference to the ucred.
@@ -754,7 +828,7 @@ proc_reap(struct thread *td, struct proc
 {
 	struct proc *q, *t;
 
-	sx_assert(&proctree_lock, SA_XLOCKED);
+	sx_assert(&V_proctree_lock, SA_XLOCKED);
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 	PROC_SLOCK_ASSERT(p, MA_OWNED);
 	KASSERT(p->p_state == PRS_ZOMBIE, ("proc_reap: !PRS_ZOMBIE"));
@@ -771,7 +845,7 @@ proc_reap(struct thread *td, struct proc
 		 * release the proc struct just yet.
 		 */
 		PROC_UNLOCK(p);
-		sx_xunlock(&proctree_lock);
+		sx_xunlock(&V_proctree_lock);
 		return;
 	}
 
@@ -793,7 +867,7 @@ proc_reap(struct thread *td, struct proc
 		wakeup(t);
 		cv_broadcast(&p->p_pwait);
 		PROC_UNLOCK(t);
-		sx_xunlock(&proctree_lock);
+		sx_xunlock(&V_proctree_lock);
 		return;
 	}
 
@@ -801,9 +875,9 @@ proc_reap(struct thread *td, struct proc
 	 * Remove other references to this process to ensure we have an
 	 * exclusive reference.
 	 */
-	sx_xlock(&allproc_lock);
+	sx_xlock(&V_allproc_lock);
 	LIST_REMOVE(p, p_list);	/* off zombproc */
-	sx_xunlock(&allproc_lock);
+	sx_xunlock(&V_allproc_lock);
 	LIST_REMOVE(p, p_sibling);
 	PROC_LOCK(p);
 	clear_orphan(p);
@@ -813,7 +887,7 @@ proc_reap(struct thread *td, struct proc
 	if (p->p_procdesc != NULL)
 		procdesc_reap(p);
 #endif
-	sx_xunlock(&proctree_lock);
+	sx_xunlock(&V_proctree_lock);
 
 	/*
 	 * As a side effect of this lock, we know that all other writes to
@@ -841,6 +915,10 @@ proc_reap(struct thread *td, struct proc
 #endif
 	racct_proc_exit(p);
 
+#ifdef VPS
+	vps_account(p->p_ucred->cr_vps, VPS_ACC_PROCS, VPS_ACC_FREE, 1);
+#endif
+
 	/*
 	 * Free credentials, arguments, and sigacts.
 	 */
@@ -867,9 +945,12 @@ proc_reap(struct thread *td, struct proc
 	KASSERT(FIRST_THREAD_IN_PROC(p),
 	    ("proc_reap: no residual thread!"));
 	uma_zfree(proc_zone, p);
-	sx_xlock(&allproc_lock);
-	nprocs--;
-	sx_xunlock(&allproc_lock);
+	sx_xlock(&V_allproc_lock);
+	V_nprocs--;
+#ifdef VPS
+	V_nprocs_zomb--;
+#endif
+	sx_xunlock(&V_allproc_lock);
 }
 
 static int
@@ -879,7 +960,7 @@ proc_to_reap(struct thread *td, struct p
 	struct proc *q;
 	struct rusage *rup;
 
-	sx_assert(&proctree_lock, SA_XLOCKED);
+	sx_assert(&V_proctree_lock, SA_XLOCKED);
 
 	q = td->td_proc;
 	PROC_LOCK(p);
@@ -1101,7 +1182,7 @@ loop:
 		PROC_UNLOCK(q);
 	}
 	nfound = 0;
-	sx_xlock(&proctree_lock);
+	sx_xlock(&V_proctree_lock);
 	LIST_FOREACH(p, &q->p_children, p_sibling) {
 		ret = proc_to_reap(td, p, idtype, id, status, options,
 		    wrusage, siginfo);
@@ -1113,7 +1194,7 @@ loop:
 			return (0);
 
 		PROC_LOCK(p);
-		PROC_SLOCK(p);
+                PROC_SLOCK(p);
 
 		if ((options & WTRAPPED) != 0 &&
 		    (p->p_flag & P_TRACED) != 0 &&
@@ -1123,7 +1204,7 @@ loop:
 			PROC_SUNLOCK(p);
 			if ((options & WNOWAIT) == 0)
 				p->p_flag |= P_WAITED;
-			sx_xunlock(&proctree_lock);
+			sx_xunlock(&V_proctree_lock);
 			td->td_retval[0] = p->p_pid;
 
 			if (status != NULL)
@@ -1137,7 +1218,7 @@ loop:
 				sigqueue_take(p->p_ksi);
 				PROC_UNLOCK(q);
 			}
-
+  
 			PROC_UNLOCK(p);
 			return (0);
 		}
@@ -1148,7 +1229,7 @@ loop:
 			PROC_SUNLOCK(p);
 			if ((options & WNOWAIT) == 0)
 				p->p_flag |= P_WAITED;
-			sx_xunlock(&proctree_lock);
+			sx_xunlock(&V_proctree_lock);
 			td->td_retval[0] = p->p_pid;
 
 			if (status != NULL)
@@ -1162,14 +1243,14 @@ loop:
 				sigqueue_take(p->p_ksi);
 				PROC_UNLOCK(q);
 			}
-
+  
 			PROC_UNLOCK(p);
 			return (0);
 		}
 		PROC_SUNLOCK(p);
 		if ((options & WCONTINUED) != 0 &&
 		    (p->p_flag & P_CONTINUED) != 0) {
-			sx_xunlock(&proctree_lock);
+			sx_xunlock(&V_proctree_lock);
 			td->td_retval[0] = p->p_pid;
 			if ((options & WNOWAIT) == 0) {
 				p->p_flag &= ~P_CONTINUED;
@@ -1178,7 +1259,7 @@ loop:
 				PROC_UNLOCK(q);
 			}
 			PROC_UNLOCK(p);
-
+  
 			if (status != NULL)
 				*status = SIGCONT;
 			if (siginfo != NULL) {
@@ -1213,16 +1294,16 @@ loop:
 			return (0);
 	}
 	if (nfound == 0) {
-		sx_xunlock(&proctree_lock);
+		sx_xunlock(&V_proctree_lock);
 		return (ECHILD);
 	}
 	if (options & WNOHANG) {
-		sx_xunlock(&proctree_lock);
+		sx_xunlock(&V_proctree_lock);
 		td->td_retval[0] = 0;
 		return (0);
 	}
 	PROC_LOCK(q);
-	sx_xunlock(&proctree_lock);
+	sx_xunlock(&V_proctree_lock);
 	if (q->p_flag & P_STATCHILD) {
 		q->p_flag &= ~P_STATCHILD;
 		error = 0;
@@ -1242,7 +1323,7 @@ void
 proc_reparent(struct proc *child, struct proc *parent)
 {
 
-	sx_assert(&proctree_lock, SX_XLOCKED);
+	sx_assert(&V_proctree_lock, SX_XLOCKED);
 	PROC_LOCK_ASSERT(child, MA_OWNED);
 	if (child->p_pptr == parent)
 		return;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_fork.c head/sys/kern/kern_fork.c
--- clean-head/sys/kern/kern_fork.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_fork.c	2013-06-24 14:20:31.000000000 +0200
@@ -74,6 +74,10 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_f
 #include <sys/sysent.h>
 #include <sys/signalvar.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#include <vps/vps_account.h>
+
 #include <security/audit/audit.h>
 #include <security/mac/mac_framework.h>
 
@@ -178,10 +182,23 @@ sys_rfork(struct thread *td, struct rfor
 	return (error);
 }
 
-int	nprocs = 1;		/* process 0 */
-int	lastpid = 0;
-SYSCTL_INT(_kern, OID_AUTO, lastpid, CTLFLAG_RD, &lastpid, 0, 
-    "Last used PID");
+VPS_DEFINE(int, lastpid) = 0;
+VPS_DEFINE(int, nprocs) = 1;
+VPS_DEFINE(int, nprocs_zomb) = 0;
+VPS_DEFINE(int, randompid) = 0;
+VPS_DEFINE(int, pidchecked) = 0;
+VPS_DEFINE(struct timeval, lastfail) = { 0, 0 };
+VPS_DEFINE(int, curfail) = 0;
+SYSCTL_VPS_INT(_kern, OID_AUTO, lastpid, CTLFLAG_RD, &VPS_NAME(lastpid),
+      0, "Last used PID");
+static int sysctl_kern_randompid(SYSCTL_HANDLER_ARGS);
+SYSCTL_PROC(_kern, OID_AUTO, randompid, CTLTYPE_INT|CTLFLAG_RW,
+    0, 0, sysctl_kern_randompid, "I", "Random PID modulus");
+#define V_randompid	VPSV(randompid)
+#define V_lastpid 	VPSV(lastpid)
+#define V_pidchecked	VPSV(pidchecked)
+#define V_curfail  	VPSV(curfail)
+#define V_lastfail	VPSV(lastfail)
 
 /*
  * Random component to lastpid generation.  We mix in a random factor to make
@@ -191,7 +208,6 @@ SYSCTL_INT(_kern, OID_AUTO, lastpid, CTL
  * modulus that is too big causes a LOT more process table scans and slows
  * down fork processing as the pidchecked caching is defeated.
  */
-static int randompid = 0;
 
 static int
 sysctl_kern_randompid(SYSCTL_HANDLER_ARGS)
@@ -201,8 +217,8 @@ sysctl_kern_randompid(SYSCTL_HANDLER_ARG
 	error = sysctl_wire_old_buffer(req, sizeof(int));
 	if (error != 0)
 		return(error);
-	sx_xlock(&allproc_lock);
-	pid = randompid;
+	sx_xlock(&V_allproc_lock);
+	pid = V_randompid;
 	error = sysctl_handle_int(oidp, &pid, 0, req);
 	if (error == 0 && req->newptr != NULL) {
 		if (pid < 0 || pid > pid_max - 100)	/* out of range */
@@ -211,28 +227,24 @@ sysctl_kern_randompid(SYSCTL_HANDLER_ARG
 			pid = 0;
 		else if (pid < 100)			/* Make it reasonable */
 			pid = 100;
-		randompid = pid;
+		V_randompid = pid;
 	}
-	sx_xunlock(&allproc_lock);
+	sx_xunlock(&V_allproc_lock);
 	return (error);
 }
 
-SYSCTL_PROC(_kern, OID_AUTO, randompid, CTLTYPE_INT|CTLFLAG_RW,
-    0, 0, sysctl_kern_randompid, "I", "Random PID modulus");
-
 static int
 fork_findpid(int flags)
 {
 	struct proc *p;
 	int trypid;
-	static int pidchecked = 0;
 
 	/*
 	 * Requires allproc_lock in order to iterate over the list
 	 * of processes, and proctree_lock to access p_pgrp.
 	 */
-	sx_assert(&allproc_lock, SX_LOCKED);
-	sx_assert(&proctree_lock, SX_LOCKED);
+	sx_assert(&V_allproc_lock, SX_LOCKED);
+	sx_assert(&V_proctree_lock, SX_LOCKED);
 
 	/*
 	 * Find an unused process ID.  We remember a range of unused IDs
@@ -241,13 +253,13 @@ fork_findpid(int flags)
 	 * If RFHIGHPID is set (used during system boot), do not allocate
 	 * low-numbered pids.
 	 */
-	trypid = lastpid + 1;
+	trypid = V_lastpid + 1;
 	if (flags & RFHIGHPID) {
 		if (trypid < 10)
 			trypid = 10;
 	} else {
-		if (randompid)
-			trypid += arc4random() % randompid;
+		if (V_randompid)
+			trypid += arc4random() % V_randompid;
 	}
 retry:
 	/*
@@ -259,18 +271,18 @@ retry:
 		trypid = trypid % pid_max;
 		if (trypid < 100)
 			trypid += 100;
-		pidchecked = 0;
+		V_pidchecked = 0;
 	}
-	if (trypid >= pidchecked) {
+	if (trypid >= V_pidchecked) {
 		int doingzomb = 0;
 
-		pidchecked = PID_MAX;
+		V_pidchecked = PID_MAX;
 		/*
 		 * Scan the active and zombie procs to check whether this pid
 		 * is in use.  Remember the lowest pid that's greater
 		 * than trypid, so we can avoid checking for a while.
 		 */
-		p = LIST_FIRST(&allproc);
+		p = LIST_FIRST(&V_allproc);
 again:
 		for (; p != NULL; p = LIST_NEXT(p, p_list)) {
 			while (p->p_pid == trypid ||
@@ -279,24 +291,24 @@ again:
 			    (p->p_session != NULL &&
 			    p->p_session->s_sid == trypid)))) {
 				trypid++;
-				if (trypid >= pidchecked)
+				if (trypid >= V_pidchecked)
 					goto retry;
 			}
-			if (p->p_pid > trypid && pidchecked > p->p_pid)
-				pidchecked = p->p_pid;
+			if (p->p_pid > trypid && V_pidchecked > p->p_pid)
+				V_pidchecked = p->p_pid;
 			if (p->p_pgrp != NULL) {
 				if (p->p_pgrp->pg_id > trypid &&
-				    pidchecked > p->p_pgrp->pg_id)
-					pidchecked = p->p_pgrp->pg_id;
+				    V_pidchecked > p->p_pgrp->pg_id)
+					V_pidchecked = p->p_pgrp->pg_id;
 				if (p->p_session != NULL &&
 				    p->p_session->s_sid > trypid &&
-				    pidchecked > p->p_session->s_sid)
-					pidchecked = p->p_session->s_sid;
+				    V_pidchecked > p->p_session->s_sid)
+					V_pidchecked = p->p_session->s_sid;
 			}
 		}
 		if (!doingzomb) {
 			doingzomb = 1;
-			p = LIST_FIRST(&zombproc);
+			p = LIST_FIRST(&V_zombproc);
 			goto again;
 		}
 	}
@@ -305,9 +317,9 @@ again:
 	 * RFHIGHPID does not mess with the lastpid counter during boot.
 	 */
 	if (flags & RFHIGHPID)
-		pidchecked = 0;
+		V_pidchecked = 0;
 	else
-		lastpid = trypid;
+		V_lastpid = trypid;
 
 	return (trypid);
 }
@@ -372,8 +384,8 @@ do_fork(struct thread *td, int flags, st
 	struct filedesc_to_leader *fdtol;
 	struct sigacts *newsigacts;
 
-	sx_assert(&proctree_lock, SX_SLOCKED);
-	sx_assert(&allproc_lock, SX_XLOCKED);
+	sx_assert(&V_proctree_lock, SX_SLOCKED);
+	sx_assert(&V_allproc_lock, SX_XLOCKED);
 
 	p2_held = 0;
 	p1 = td->td_proc;
@@ -382,22 +394,22 @@ do_fork(struct thread *td, int flags, st
 	 * Increment the nprocs resource before blocking can occur.  There
 	 * are hard-limits as to the number of processes that can run.
 	 */
-	nprocs++;
+	V_nprocs++;
 
 	trypid = fork_findpid(flags);
 
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 
 	p2->p_state = PRS_NEW;		/* protect against others */
 	p2->p_pid = trypid;
 	AUDIT_ARG_PID(p2->p_pid);
-	LIST_INSERT_HEAD(&allproc, p2, p_list);
+	LIST_INSERT_HEAD(&V_allproc, p2, p_list);
 	LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
 	tidhash_add(td2);
 	PROC_LOCK(p2);
 	PROC_LOCK(p1);
 
-	sx_xunlock(&allproc_lock);
+	sx_xunlock(&V_allproc_lock);
 
 	bcopy(&p1->p_startcopy, &p2->p_startcopy,
 	    __rangeof(struct proc, p_startcopy, p_endcopy));
@@ -478,6 +490,10 @@ do_fork(struct thread *td, int flags, st
 	td2->td_vnet = NULL;
 	td2->td_vnet_lpush = NULL;
 #endif
+#ifdef VPS
+	td2->td_vps = td->td_vps;
+	td2->td_vps_acc = td->td_vps->vps_acc;
+#endif
 
 	/*
 	 * Allow the scheduler to initialize the child.
@@ -532,11 +548,11 @@ do_fork(struct thread *td, int flags, st
 	 * Set up linkage for kernel based threading.
 	 */
 	if ((flags & RFTHREAD) != 0) {
-		mtx_lock(&ppeers_lock);
+		mtx_lock(&V_ppeers_lock);
 		p2->p_peers = p1->p_peers;
 		p1->p_peers = p2;
 		p2->p_leader = p1->p_leader;
-		mtx_unlock(&ppeers_lock);
+		mtx_unlock(&V_ppeers_lock);
 		PROC_LOCK(p1->p_leader);
 		if ((p1->p_leader->p_flag & P_WEXIT) != 0) {
 			PROC_UNLOCK(p1->p_leader);
@@ -563,7 +579,7 @@ do_fork(struct thread *td, int flags, st
 		p2->p_leader = p2;
 	}
 
-	sx_xlock(&proctree_lock);
+	sx_xlock(&V_proctree_lock);
 	PGRP_LOCK(p1->p_pgrp);
 	PROC_LOCK(p2);
 	PROC_LOCK(p1);
@@ -613,12 +629,12 @@ do_fork(struct thread *td, int flags, st
 	 * parent.
 	 */
 	if (flags & RFNOWAIT)
-		pptr = initproc;
+		pptr = V_initproc;
 	else
 		pptr = p1;
 	p2->p_pptr = pptr;
 	LIST_INSERT_HEAD(&pptr->p_children, p2, p_sibling);
-	sx_xunlock(&proctree_lock);
+	sx_xunlock(&V_proctree_lock);
 
 	/* Inform accounting that we have forked. */
 	p2->p_acflag = AFORK;
@@ -753,8 +769,6 @@ fork1(struct thread *td, int flags, int 
 	struct vmspace *vm2;
 	vm_ooffset_t mem_charged;
 	int error;
-	static int curfail;
-	static struct timeval lastfail;
 #ifdef PROCDESC
 	struct file *fp_procdesc = NULL;
 #endif
@@ -878,7 +892,7 @@ fork1(struct thread *td, int flags, int 
 	STAILQ_INIT(&newproc->p_ktr);
 
 	/* We have to lock the process tree while we look for a pid. */
-	sx_slock(&proctree_lock);
+	sx_slock(&V_proctree_lock);
 
 	/*
 	 * Although process entries are dynamically created, we still keep
@@ -887,13 +901,26 @@ fork1(struct thread *td, int flags, int 
 	 * exceed the limit. The variable nprocs is the current number of
 	 * processes, maxproc is the limit.
 	 */
-	sx_xlock(&allproc_lock);
-	if ((nprocs >= maxproc - 10 && priv_check_cred(td->td_ucred,
-	    PRIV_MAXPROC, 0) != 0) || nprocs >= maxproc) {
+	sx_xlock(&V_allproc_lock);
+	if ((V_nprocs >= V_maxproc - 10 && priv_check_cred(td->td_ucred,
+	    PRIV_MAXPROC, 0) != 0) || V_nprocs >= V_maxproc) {
 		error = EAGAIN;
 		goto fail;
 	}
 
+#ifdef VPS
+	if (vps_account(td->td_ucred->cr_vps, VPS_ACC_PROCS, VPS_ACC_ALLOC, 1)) {
+		error = ENOMEM;
+		goto fail;
+	}
+	/* Assuming there will be only one thread. */
+	if (vps_account(td->td_ucred->cr_vps, VPS_ACC_THREADS, VPS_ACC_ALLOC, 1)) {
+		vps_account(td->td_ucred->cr_vps, VPS_ACC_PROCS, VPS_ACC_FREE, 1);
+		error = ENOMEM;
+		goto fail;
+	}
+#endif
+
 	/*
 	 * Increment the count of procs running with this uid. Don't allow
 	 * a nonprivileged user to exceed their current limit.
@@ -923,16 +950,20 @@ fork1(struct thread *td, int flags, int 
 		}
 #endif
 		racct_proc_fork_done(newproc);
+#ifdef VPS
+		if (td->td_flags & TDF_VPSSUSPEND)
+			return (EINTR);
+#endif
 		return (0);
 	}
 
 	error = EAGAIN;
 fail:
-	sx_sunlock(&proctree_lock);
-	if (ppsratecheck(&lastfail, &curfail, 1))
+	sx_sunlock(&V_proctree_lock);
+	if (ppsratecheck(&V_lastfail, &V_curfail, 1))
 		printf("maxproc limit exceeded by uid %u (pid %d); see tuning(7) and login.conf(5)\n",
 		    td->td_ucred->cr_ruid, p1->p_pid);
-	sx_xunlock(&allproc_lock);
+	sx_xunlock(&V_allproc_lock);
 #ifdef MAC
 	mac_proc_destroy(newproc);
 #endif
@@ -1018,7 +1049,7 @@ fork_return(struct thread *td, struct tr
 
 	if (td->td_dbgflags & TDB_STOPATFORK) {
 		p = td->td_proc;
-		sx_xlock(&proctree_lock);
+		sx_xlock(&V_proctree_lock);
 		PROC_LOCK(p);
 		if ((p->p_pptr->p_flag & (P_TRACED | P_FOLLOWFORK)) ==
 		    (P_TRACED | P_FOLLOWFORK)) {
@@ -1030,7 +1061,7 @@ fork_return(struct thread *td, struct tr
 			p->p_flag |= P_TRACED;
 			p->p_oppid = p->p_pptr->p_pid;
 			proc_reparent(p, dbg);
-			sx_xunlock(&proctree_lock);
+			sx_xunlock(&V_proctree_lock);
 			td->td_dbgflags |= TDB_CHILD;
 			ptracestop(td, SIGSTOP);
 			td->td_dbgflags &= ~TDB_CHILD;
@@ -1038,7 +1069,7 @@ fork_return(struct thread *td, struct tr
 			/*
 			 * ... otherwise clear the request.
 			 */
-			sx_xunlock(&proctree_lock);
+			sx_xunlock(&V_proctree_lock);
 			td->td_dbgflags &= ~TDB_STOPATFORK;
 			cv_broadcast(&p->p_dbgwait);
 		}
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_jail.c head/sys/kern/kern_jail.c
--- clean-head/sys/kern/kern_jail.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_jail.c	2013-06-24 14:20:31.000000000 +0200
@@ -61,6 +61,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_j
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+
 #include <net/if.h>
 #include <net/vnet.h>
 
@@ -95,6 +97,24 @@ static MALLOC_DEFINE(M_PRISON_RACCT, "pr
 #endif
 #endif
 
+#ifdef VPS
+
+VPS_DEFINE(struct prison *, prison0);
+#define V_prison0	VPSV(prison0)
+
+/* list head is initalized in vps_alloc() */
+VPS_DEFINE(struct prisonlist, allprison);
+VPS_DEFINE(int, lastprid) = 0;
+#define V_lastprid	VPSV(lastprid)
+
+#else
+
+struct	prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison);
+int	lastprid = 0;
+#define V_lastprid	lastprid
+
+#endif /* !VPS */
+
 /* prison0 describes what is "real" about the system. */
 struct prison prison0 = {
 	.pr_id		= 0,
@@ -119,9 +139,7 @@ MTX_SYSINIT(prison0, &prison0.pr_mtx, "j
 /* allprison, allprison_racct and lastprid are protected by allprison_lock. */
 struct	sx allprison_lock;
 SX_SYSINIT(allprison_lock, &allprison_lock, "allprison");
-struct	prisonlist allprison = TAILQ_HEAD_INITIALIZER(allprison);
 LIST_HEAD(, prison_racct) allprison_racct;
-int	lastprid = 0;
 
 static int do_jail_attach(struct thread *td, struct prison *pr);
 static void prison_complete(void *context, int pending);
@@ -226,12 +244,26 @@ const size_t pr_allow_nonames_size = siz
 
 #define	JAIL_DEFAULT_ALLOW		PR_ALLOW_SET_HOSTNAME
 #define	JAIL_DEFAULT_ENFORCE_STATFS	2
-#define	JAIL_DEFAULT_DEVFS_RSNUM	0
-static unsigned jail_default_allow = JAIL_DEFAULT_ALLOW;
-static int jail_default_enforce_statfs = JAIL_DEFAULT_ENFORCE_STATFS;
-static int jail_default_devfs_rsnum = JAIL_DEFAULT_DEVFS_RSNUM;
+#define JAIL_DEFAULT_DEVFS_RSNUM	0
+
+//static unsigned jail_default_allow = JAIL_DEFAULT_ALLOW;
+VPS_DEFINE(unsigned, jail_default_allow) = JAIL_DEFAULT_ALLOW;
+#define V_jail_default_allow VPSV(jail_default_allow)
+
+//static int jail_default_enforce_statfs = JAIL_DEFAULT_ENFORCE_STATFS;
+VPS_DEFINE(int, jail_default_enforce_statfs) = JAIL_DEFAULT_ENFORCE_STATFS;
+#define V_jail_default_enforce_statfs VPSV(jail_default_enforce_statfs)
+
+//static int jail_default_devfs_rsnum = JAIL_DEFAULT_DEVFS_RSNUM;
+VPS_DEFINE(int, jail_default_devfs_rsnum) = JAIL_DEFAULT_DEVFS_RSNUM;
+#define V_jail_default_devfs_rsnum VPSV(jail_default_devfs_rsnum)
+
 #if defined(INET) || defined(INET6)
-static unsigned jail_max_af_ips = 255;
+
+//static unsigned jail_max_af_ips = 255;
+VPS_DEFINE(unsigned, jail_max_af_ips) = 255;
+#define V_jail_max_af_ips VPSV(jail_max_af_ips)
+
 #endif
 
 #ifdef INET
@@ -374,7 +406,7 @@ kern_jail(struct thread *td, struct jail
 		for (fi = 0; fi < sizeof(pr_allow_names) /
 		     sizeof(pr_allow_names[0]); fi++) {
 			optiov[opt.uio_iovcnt].iov_base =
-			    (jail_default_allow & (1 << fi))
+			    (V_jail_default_allow & (1 << fi))
 			    ? pr_allow_names[fi] : pr_allow_nonames[fi];
 			optiov[opt.uio_iovcnt].iov_len =
 			    strlen(optiov[opt.uio_iovcnt].iov_base) + 1;
@@ -383,7 +415,7 @@ kern_jail(struct thread *td, struct jail
 		optiov[opt.uio_iovcnt].iov_base = "enforce_statfs";
 		optiov[opt.uio_iovcnt].iov_len = sizeof("enforce_statfs");
 		opt.uio_iovcnt++;
-		enforce_statfs = jail_default_enforce_statfs;
+		enforce_statfs = V_jail_default_enforce_statfs;
 		optiov[opt.uio_iovcnt].iov_base = &enforce_statfs;
 		optiov[opt.uio_iovcnt].iov_len = sizeof(enforce_statfs);
 		opt.uio_iovcnt++;
@@ -392,7 +424,7 @@ kern_jail(struct thread *td, struct jail
 	tmplen = MAXPATHLEN + MAXHOSTNAMELEN + MAXHOSTNAMELEN;
 #ifdef INET
 	ip4s = (j->version == 0) ? 1 : j->ip4s;
-	if (ip4s > jail_max_af_ips)
+	if (ip4s > V_jail_max_af_ips)
 		return (EINVAL);
 	tmplen += ip4s * sizeof(struct in_addr);
 #else
@@ -400,7 +432,7 @@ kern_jail(struct thread *td, struct jail
 		return (EINVAL);
 #endif
 #ifdef INET6
-	if (j->ip6s > jail_max_af_ips)
+	if (j->ip6s > V_jail_max_af_ips)
 		return (EINVAL);
 	tmplen += j->ip6s * sizeof(struct in6_addr);
 #else
@@ -810,7 +842,7 @@ kern_jail_set(struct thread *td, struct 
 		else {
 			pr_flags = (pr_flags & ~PR_IP4_DISABLE) | PR_IP4_USER;
 			ip4s /= sizeof(*ip4);
-			if (ip4s > jail_max_af_ips) {
+			if (ip4s > V_jail_max_af_ips) {
 				error = EINVAL;
 				vfs_opterror(opts, "too many IPv4 addresses");
 				goto done_errmsg;
@@ -868,7 +900,7 @@ kern_jail_set(struct thread *td, struct 
 		else {
 			pr_flags = (pr_flags & ~PR_IP6_DISABLE) | PR_IP6_USER;
 			ip6s /= sizeof(*ip6);
-			if (ip6s > jail_max_af_ips) {
+			if (ip6s > V_jail_max_af_ips) {
 				error = EINVAL;
 				vfs_opterror(opts, "too many IPv6 addresses");
 				goto done_errmsg;
@@ -1094,7 +1126,7 @@ kern_jail_set(struct thread *td, struct 
 		}
 		if (name[0] != '\0') {
 			namelen =
-			    (ppr == &prison0) ? 0 : strlen(ppr->pr_name) + 1;
+			    (ppr == V_prison0) ? 0 : strlen(ppr->pr_name) + 1;
  name_again:
 			deadpr = NULL;
 			FOREACH_PRISON_CHILD(ppr, tpr) {
@@ -1185,18 +1217,18 @@ kern_jail_set(struct thread *td, struct 
 		pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
 		if (jid == 0) {
 			/* Find the next free jid. */
-			jid = lastprid + 1;
+			jid = V_lastprid + 1;
  findnext:
 			if (jid == JAIL_MAX)
 				jid = 1;
-			TAILQ_FOREACH(tpr, &allprison, pr_list) {
+			TAILQ_FOREACH(tpr, &V_allprison, pr_list) {
 				if (tpr->pr_id < jid)
 					continue;
 				if (tpr->pr_id > jid || tpr->pr_ref == 0) {
 					TAILQ_INSERT_BEFORE(tpr, pr, pr_list);
 					break;
 				}
-				if (jid == lastprid) {
+				if (jid == V_lastprid) {
 					error = EAGAIN;
 					vfs_opterror(opts,
 					    "no available jail IDs");
@@ -1208,20 +1240,20 @@ kern_jail_set(struct thread *td, struct 
 				jid++;
 				goto findnext;
 			}
-			lastprid = jid;
+			V_lastprid = jid;
 		} else {
 			/*
 			 * The jail already has a jid (that did not yet exist),
 			 * so just find where to insert it.
 			 */
-			TAILQ_FOREACH(tpr, &allprison, pr_list)
+			TAILQ_FOREACH(tpr, &V_allprison, pr_list)
 				if (tpr->pr_id >= jid) {
 					TAILQ_INSERT_BEFORE(tpr, pr, pr_list);
 					break;
 				}
 		}
 		if (tpr == NULL)
-			TAILQ_INSERT_TAIL(&allprison, pr, pr_list);
+			TAILQ_INSERT_TAIL(&V_allprison, pr, pr_list);
 		LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling);
 		for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent)
 			tpr->pr_childcount++;
@@ -1424,7 +1456,7 @@ kern_jail_set(struct thread *td, struct 
 		 */
 		tppr = ppr;
 #ifdef VIMAGE
-		for (; tppr != &prison0; tppr = tppr->pr_parent)
+		for (; tppr != V_prison0; tppr = tppr->pr_parent)
 			if (tppr->pr_flags & PR_VNET)
 				break;
 #endif
@@ -1490,7 +1522,7 @@ kern_jail_set(struct thread *td, struct 
 		/* Check for conflicting IP addresses. */
 		tppr = ppr;
 #ifdef VIMAGE
-		for (; tppr != &prison0; tppr = tppr->pr_parent)
+		for (; tppr != V_prison0; tppr = tppr->pr_parent)
 			if (tppr->pr_flags & PR_VNET)
 				break;
 #endif
@@ -1629,7 +1661,7 @@ kern_jail_set(struct thread *td, struct 
 			tpr->pr_devfs_rsnum = rsnum;
 	}
 	if (name != NULL) {
-		if (ppr == &prison0)
+		if (ppr == V_prison0)
 			strlcpy(pr->pr_name, name, sizeof(pr->pr_name));
 		else
 			snprintf(pr->pr_name, sizeof(pr->pr_name), "%s.%s",
@@ -1934,7 +1966,7 @@ kern_jail_get(struct thread *td, struct 
 	sx_slock(&allprison_lock);
 	error = vfs_copyopt(opts, "lastjid", &jid, sizeof(jid));
 	if (error == 0) {
-		TAILQ_FOREACH(pr, &allprison, pr_list) {
+		TAILQ_FOREACH(pr, &V_allprison, pr_list) {
 			if (pr->pr_id > jid && prison_ischild(mypr, pr)) {
 				mtx_lock(&pr->pr_mtx);
 				if (pr->pr_ref > 0 &&
@@ -2275,15 +2307,15 @@ prison_remove_one(struct prison *pr)
 	/*
 	 * Kill all processes unfortunate enough to be attached to this prison.
 	 */
-	sx_slock(&allproc_lock);
-	LIST_FOREACH(p, &allproc, p_list) {
+	sx_slock(&V_allproc_lock);
+	LIST_FOREACH(p, &V_allproc, p_list) {
 		PROC_LOCK(p);
 		if (p->p_state != PRS_NEW && p->p_ucred &&
 		    p->p_ucred->cr_prison == pr)
 			kern_psignal(p, SIGKILL);
 		PROC_UNLOCK(p);
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
 	/* Remove the temporary reference added by jail_remove. */
 	prison_deref(pr, deuref | PD_DEREF);
 }
@@ -2405,7 +2437,7 @@ prison_find(int prid)
 	struct prison *pr;
 
 	sx_assert(&allprison_lock, SX_LOCKED);
-	TAILQ_FOREACH(pr, &allprison, pr_list) {
+	TAILQ_FOREACH(pr, &V_allprison, pr_list) {
 		if (pr->pr_id == prid) {
 			mtx_lock(&pr->pr_mtx);
 			if (pr->pr_ref > 0)
@@ -2448,7 +2480,7 @@ prison_find_name(struct prison *mypr, co
 	int descend;
 
 	sx_assert(&allprison_lock, SX_LOCKED);
-	mylen = (mypr == &prison0) ? 0 : strlen(mypr->pr_name) + 1;
+	mylen = (mypr == V_prison0) ? 0 : strlen(mypr->pr_name) + 1;
  again:
 	deadpr = NULL;
 	FOREACH_PRISON_DESCENDANT(mypr, pr, descend) {
@@ -2542,7 +2574,7 @@ prison_deref(struct prison *pr, int flag
 	for (;;) {
 		if (flags & PD_DEUREF) {
 			pr->pr_uref--;
-			KASSERT(prison0.pr_uref != 0, ("prison0 pr_uref=0"));
+			KASSERT(V_prison0->pr_uref != 0, ("prison0 pr_uref=0"));
 		}
 		if (flags & PD_DEREF)
 			pr->pr_ref--;
@@ -2565,7 +2597,7 @@ prison_deref(struct prison *pr, int flag
 		} else if (!(flags & PD_LIST_XLOCKED))
 			sx_xlock(&allprison_lock);
 
-		TAILQ_REMOVE(&allprison, pr, pr_list);
+		TAILQ_REMOVE(&V_allprison, pr, pr_list);
 		LIST_REMOVE(pr, pr_sibling);
 		ppr = pr->pr_parent;
 		for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent)
@@ -2811,13 +2843,13 @@ prison_equal_ip4(struct prison *pr1, str
 	 * No need to lock since the PR_IP4_USER flag can't be altered for
 	 * existing prisons.
 	 */
-	while (pr1 != &prison0 &&
+	while (pr1 != V_prison0 &&
 #ifdef VIMAGE
 	       !(pr1->pr_flags & PR_VNET) &&
 #endif
 	       !(pr1->pr_flags & PR_IP4_USER))
 		pr1 = pr1->pr_parent;
-	while (pr2 != &prison0 &&
+	while (pr2 != V_prison0 &&
 #ifdef VIMAGE
 	       !(pr2->pr_flags & PR_VNET) &&
 #endif
@@ -3147,13 +3179,13 @@ prison_equal_ip6(struct prison *pr1, str
 	if (pr1 == pr2)
 		return (1);
 
-	while (pr1 != &prison0 &&
+	while (pr1 != V_prison0 &&
 #ifdef VIMAGE
 	       !(pr1->pr_flags & PR_VNET) &&
 #endif
 	       !(pr1->pr_flags & PR_IP6_USER))
 		pr1 = pr1->pr_parent;
-	while (pr2 != &prison0 &&
+	while (pr2 != V_prison0 &&
 #ifdef VIMAGE
 	       !(pr2->pr_flags & PR_VNET) &&
 #endif
@@ -3455,8 +3487,13 @@ prison_ischild(struct prison *pr1, struc
 int
 jailed(struct ucred *cred)
 {
+	/*
+	int result = cred->cr_prison != V_prison0;
+	printf("%s: td=%p cred=%p cred->cr_prison=%p V_prison=%p &prison0=%p result=%d\n",
+		__func__, curthread, cred, cred->cr_prison, V_prison0, &prison0, result);
+	*/
 
-	return (cred->cr_prison != &prison0);
+	return (cred->cr_prison != V_prison0);
 }
 
 /*
@@ -3489,7 +3526,7 @@ getcredhostname(struct ucred *cred, char
 	 * A NULL credential can be used to shortcut to the physical
 	 * system's hostname.
 	 */
-	pr = (cred != NULL) ? cred->cr_prison : &prison0;
+	pr = (cred != NULL) ? cred->cr_prison : V_prison0;
 	mtx_lock(&pr->pr_mtx);
 	strlcpy(buf, pr->pr_hostname, size);
 	mtx_unlock(&pr->pr_mtx);
@@ -3976,7 +4013,7 @@ prison_name(struct prison *pr1, struct p
 		 * so its length can't be counted on.  But the number of dots
 		 * can be counted on - and counted.
 		 */
-		for (; pr1 != &prison0; pr1 = pr1->pr_parent)
+		for (; pr1 != V_prison0; pr1 = pr1->pr_parent)
 			name = strchr(name, '.') + 1;
 	}
 	return (name);
@@ -4010,8 +4047,8 @@ prison_path(struct prison *pr1, struct p
 /*
  * Jail-related sysctls.
  */
-static SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
-    "Jails");
+static _SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
+    "Jails", VPS_PUBLIC);
 
 static int
 sysctl_jail_list(SYSCTL_HANDLER_ARGS)
@@ -4113,9 +4150,9 @@ sysctl_jail_list(SYSCTL_HANDLER_ARGS)
 	return (error);
 }
 
-SYSCTL_OID(_security_jail, OID_AUTO, list,
+_SYSCTL_OID(_security_jail, OID_AUTO, list,
     CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
-    sysctl_jail_list, "S", "List of active jails");
+    sysctl_jail_list, "S", "List of active jails", VPS_PUBLIC);
 
 static int
 sysctl_jail_jailed(SYSCTL_HANDLER_ARGS)
@@ -4128,9 +4165,9 @@ sysctl_jail_jailed(SYSCTL_HANDLER_ARGS)
 	return (error);
 }
 
-SYSCTL_PROC(_security_jail, OID_AUTO, jailed,
+_SYSCTL_PROC(_security_jail, OID_AUTO, jailed,
     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
-    sysctl_jail_jailed, "I", "Process in jail?");
+    sysctl_jail_jailed, "I", "Process in jail?", VPS_PUBLIC);
 
 static int
 sysctl_jail_vnet(SYSCTL_HANDLER_ARGS)
@@ -4153,8 +4190,8 @@ SYSCTL_PROC(_security_jail, OID_AUTO, vn
     sysctl_jail_vnet, "I", "Jail owns VNET?");
 
 #if defined(INET) || defined(INET6)
-SYSCTL_UINT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW,
-    &jail_max_af_ips, 0,
+SYSCTL_VPS_UINT(_security_jail, OID_AUTO, jail_max_af_ips, CTLFLAG_RW,
+    &VPS_NAME(jail_max_af_ips), 0,
     "Number of IP addresses a jail may have at most per address family");
 #endif
 
@@ -4170,7 +4207,7 @@ sysctl_jail_default_allow(SYSCTL_HANDLER
 	int allow, error, i;
 
 	pr = req->td->td_ucred->cr_prison;
-	allow = (pr == &prison0) ? jail_default_allow : pr->pr_allow;
+	allow = (pr == V_prison0) ? V_jail_default_allow : pr->pr_allow;
 
 	/* Get the current flag value, and convert it to a boolean. */
 	i = (allow & arg2) ? 1 : 0;
@@ -4186,52 +4223,52 @@ sysctl_jail_default_allow(SYSCTL_HANDLER
 	 * The sysctls don't have CTLFLAGS_PRISON, so assume prison0
 	 * for writing.
 	 */
-	mtx_lock(&prison0.pr_mtx);
-	jail_default_allow = (jail_default_allow & ~arg2) | i;
-	mtx_unlock(&prison0.pr_mtx);
+	mtx_lock(&V_prison0->pr_mtx);
+	V_jail_default_allow = (V_jail_default_allow & ~arg2) | i;
+	mtx_unlock(&V_prison0->pr_mtx);
 	return (0);
 }
 
-SYSCTL_PROC(_security_jail, OID_AUTO, set_hostname_allowed,
+_SYSCTL_PROC(_security_jail, OID_AUTO, set_hostname_allowed,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
     NULL, PR_ALLOW_SET_HOSTNAME, sysctl_jail_default_allow, "I",
-    "Processes in jail can set their hostnames");
-SYSCTL_PROC(_security_jail, OID_AUTO, socket_unixiproute_only,
+    "Processes in jail can set their hostnames", VPS_PUBLIC);
+_SYSCTL_PROC(_security_jail, OID_AUTO, socket_unixiproute_only,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
     (void *)1, PR_ALLOW_SOCKET_AF, sysctl_jail_default_allow, "I",
-    "Processes in jail are limited to creating UNIX/IP/route sockets only");
-SYSCTL_PROC(_security_jail, OID_AUTO, sysvipc_allowed,
+    "Processes in jail are limited to creating UNIX/IP/route sockets only", VPS_PUBLIC);
+_SYSCTL_PROC(_security_jail, OID_AUTO, sysvipc_allowed,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
     NULL, PR_ALLOW_SYSVIPC, sysctl_jail_default_allow, "I",
-    "Processes in jail can use System V IPC primitives");
-SYSCTL_PROC(_security_jail, OID_AUTO, allow_raw_sockets,
+    "Processes in jail can use System V IPC primitives", VPS_PUBLIC);
+_SYSCTL_PROC(_security_jail, OID_AUTO, allow_raw_sockets,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
     NULL, PR_ALLOW_RAW_SOCKETS, sysctl_jail_default_allow, "I",
-    "Prison root can create raw sockets");
-SYSCTL_PROC(_security_jail, OID_AUTO, chflags_allowed,
+    "Prison root can create raw sockets", VPS_PUBLIC);
+_SYSCTL_PROC(_security_jail, OID_AUTO, chflags_allowed,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
     NULL, PR_ALLOW_CHFLAGS, sysctl_jail_default_allow, "I",
-    "Processes in jail can alter system file flags");
-SYSCTL_PROC(_security_jail, OID_AUTO, mount_allowed,
+    "Processes in jail can alter system file flags", VPS_PUBLIC);
+_SYSCTL_PROC(_security_jail, OID_AUTO, mount_allowed,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
     NULL, PR_ALLOW_MOUNT, sysctl_jail_default_allow, "I",
-    "Processes in jail can mount/unmount jail-friendly file systems");
-SYSCTL_PROC(_security_jail, OID_AUTO, mount_devfs_allowed,
+    "Processes in jail can mount/unmount jail-friendly file systems", VPS_PUBLIC);
+_SYSCTL_PROC(_security_jail, OID_AUTO, mount_devfs_allowed,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
     NULL, PR_ALLOW_MOUNT_DEVFS, sysctl_jail_default_allow, "I",
-    "Processes in jail can mount the devfs file system");
-SYSCTL_PROC(_security_jail, OID_AUTO, mount_nullfs_allowed,
+    "Processes in jail can mount the devfs file system", VPS_PUBLIC);
+_SYSCTL_PROC(_security_jail, OID_AUTO, mount_nullfs_allowed,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
     NULL, PR_ALLOW_MOUNT_NULLFS, sysctl_jail_default_allow, "I",
-    "Processes in jail can mount the nullfs file system");
-SYSCTL_PROC(_security_jail, OID_AUTO, mount_procfs_allowed,
+    "Processes in jail can mount the nullfs file system", VPS_PUBLIC);
+_SYSCTL_PROC(_security_jail, OID_AUTO, mount_procfs_allowed,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
     NULL, PR_ALLOW_MOUNT_PROCFS, sysctl_jail_default_allow, "I",
-    "Processes in jail can mount the procfs file system");
-SYSCTL_PROC(_security_jail, OID_AUTO, mount_zfs_allowed,
+    "Processes in jail can mount the procfs file system", VPS_PUBLIC);
+_SYSCTL_PROC(_security_jail, OID_AUTO, mount_zfs_allowed,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
     NULL, PR_ALLOW_MOUNT_ZFS, sysctl_jail_default_allow, "I",
-    "Processes in jail can mount the zfs file system");
+    "Processes in jail can mount the zfs file system", VPS_PUBLIC);
 
 static int
 sysctl_jail_default_level(SYSCTL_HANDLER_ARGS)
@@ -4240,7 +4277,7 @@ sysctl_jail_default_level(SYSCTL_HANDLER
 	int level, error;
 
 	pr = req->td->td_ucred->cr_prison;
-	level = (pr == &prison0) ? *(int *)arg1 : *(int *)((char *)pr + arg2);
+	level = (pr == V_prison0) ? *(int *)arg1 : *(int *)((char *)pr + arg2);
 	error = sysctl_handle_int(oidp, &level, 0, req);
 	if (error || !req->newptr)
 		return (error);
@@ -4248,15 +4285,15 @@ sysctl_jail_default_level(SYSCTL_HANDLER
 	return (0);
 }
 
-SYSCTL_PROC(_security_jail, OID_AUTO, enforce_statfs,
+SYSCTL_VPS_PROC(_security_jail, OID_AUTO, enforce_statfs,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
-    &jail_default_enforce_statfs, offsetof(struct prison, pr_enforce_statfs),
+    &VPS_NAME(jail_default_enforce_statfs), offsetof(struct prison, pr_enforce_statfs),
     sysctl_jail_default_level, "I",
     "Processes in jail cannot see all mounted file systems");
 
-SYSCTL_PROC(_security_jail, OID_AUTO, devfs_ruleset,
+SYSCTL_VPS_PROC(_security_jail, OID_AUTO, devfs_ruleset,
     CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
-    &jail_default_devfs_rsnum, offsetof(struct prison, pr_devfs_rsnum),
+    &VPS_NAME(jail_default_devfs_rsnum), offsetof(struct prison, pr_devfs_rsnum),
     sysctl_jail_default_level, "I",
     "Ruleset for the devfs filesystem in jail");
 
@@ -4265,8 +4302,8 @@ SYSCTL_PROC(_security_jail, OID_AUTO, de
  * is returned in the string itself, and the other parameters exist merely
  * to make themselves and their types known.
  */
-SYSCTL_NODE(_security_jail, OID_AUTO, param, CTLFLAG_RW, 0,
-    "Jail parameters");
+_SYSCTL_NODE(_security_jail, OID_AUTO, param, CTLFLAG_RW, 0,
+    "Jail parameters", VPS_PUBLIC);
 
 int
 sysctl_jail_param(SYSCTL_HANDLER_ARGS)
@@ -4629,9 +4666,9 @@ DB_SHOW_COMMAND(prison, db_show_prison_c
 		 * Show all prisons in the list, and prison0 which is not
 		 * listed.
 		 */
-		db_show_prison(&prison0);
+		db_show_prison(V_prison0);
 		if (!db_pager_quit) {
-			TAILQ_FOREACH(pr, &allprison, pr_list) {
+			TAILQ_FOREACH(pr, &V_allprison, pr_list) {
 				db_show_prison(pr);
 				if (db_pager_quit)
 					break;
@@ -4641,15 +4678,15 @@ DB_SHOW_COMMAND(prison, db_show_prison_c
 	}
 
 	if (addr == 0)
-		pr = &prison0;
+		pr = V_prison0;
 	else {
 		/* Look for a prison with the ID and with references. */
-		TAILQ_FOREACH(pr, &allprison, pr_list)
+		TAILQ_FOREACH(pr, &V_allprison, pr_list)
 			if (pr->pr_id == addr && pr->pr_ref > 0)
 				break;
 		if (pr == NULL)
 			/* Look again, without requiring a reference. */
-			TAILQ_FOREACH(pr, &allprison, pr_list)
+			TAILQ_FOREACH(pr, &V_allprison, pr_list)
 				if (pr->pr_id == addr)
 					break;
 		if (pr == NULL)
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_khelp.c head/sys/kern/kern_khelp.c
--- clean-head/sys/kern/kern_khelp.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_khelp.c	2013-06-24 14:20:31.000000000 +0200
@@ -52,6 +52,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_k
 #include <sys/rwlock.h>
 #include <sys/systm.h>
 
+#include <vps/vps.h>
+
 #include <net/vnet.h>
 
 static struct rwlock khelp_list_lock;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_kthread.c head/sys/kern/kern_kthread.c
--- clean-head/sys/kern/kern_kthread.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_kthread.c	2013-06-24 14:20:31.000000000 +0200
@@ -43,6 +43,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_k
 #include <sys/sched.h>
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
+#include <vps/vps.h>
+#include <vps/vps2.h>
 
 #include <machine/stdarg.h>
 
@@ -150,11 +152,11 @@ kproc_exit(int ecode)
 	 * Reparent curthread from proc0 to init so that the zombie
 	 * is harvested.
 	 */
-	sx_xlock(&proctree_lock);
+	sx_xlock(&V_proctree_lock);
 	PROC_LOCK(p);
-	proc_reparent(p, initproc);
+	proc_reparent(p, V_initproc);
 	PROC_UNLOCK(p);
-	sx_xunlock(&proctree_lock);
+	sx_xunlock(&V_proctree_lock);
 
 	/*
 	 * Wakeup anyone waiting for us to exit.
@@ -290,6 +292,10 @@ kthread_add(void (*func)(void *), void *
 
 	newtd->td_pflags |= TDP_KTHREAD;
 	newtd->td_ucred = crhold(p->p_ucred);
+#ifdef VPS
+	newtd->td_vps = newtd->td_ucred->cr_vps;
+	newtd->td_vps_acc = newtd->td_ucred->cr_vps->vps_acc;
+#endif
 
 	/* this code almost the same as create_thread() in kern_thr.c */
 	PROC_LOCK(p);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_ktrace.c head/sys/kern/kern_ktrace.c
--- clean-head/sys/kern/kern_ktrace.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_ktrace.c	2013-06-24 14:20:31.000000000 +0200
@@ -59,6 +59,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_k
 #include <sys/syslog.h>
 #include <sys/sysproto.h>
 
+#include <vps/vps.h>
+
 #include <security/mac/mac_framework.h>
 
 /*
@@ -154,7 +156,11 @@ static void ktr_freerequest_locked(struc
 static void ktr_writerequest(struct thread *td, struct ktr_request *req);
 static int ktrcanset(struct thread *,struct proc *);
 static int ktrsetchildren(struct thread *,struct proc *,int,int,struct vnode *);
+#ifdef VPS
+int ktrops(struct thread *,struct proc *,int,int,struct vnode *);
+#else
 static int ktrops(struct thread *,struct proc *,int,int,struct vnode *);
+#endif
 static void ktrprocctor_entered(struct thread *, struct proc *);
 
 /*
@@ -896,7 +902,7 @@ sys_ktrace(td, uap)
 		int vrele_count;
 
 		vrele_count = 0;
-		sx_slock(&allproc_lock);
+		sx_slock(&V_allproc_lock);
 		FOREACH_PROC_IN_SYSTEM(p) {
 			PROC_LOCK(p);
 			if (p->p_tracevp == vp) {
@@ -911,7 +917,7 @@ sys_ktrace(td, uap)
 			}
 			PROC_UNLOCK(p);
 		}
-		sx_sunlock(&allproc_lock);
+		sx_sunlock(&V_allproc_lock);
 		if (vrele_count > 0) {
 			while (vrele_count-- > 0)
 				vrele(vp);
@@ -921,14 +927,14 @@ sys_ktrace(td, uap)
 	/*
 	 * do it
 	 */
-	sx_slock(&proctree_lock);
+	sx_slock(&V_proctree_lock);
 	if (uap->pid < 0) {
 		/*
 		 * by process group
 		 */
 		pg = pgfind(-uap->pid);
 		if (pg == NULL) {
-			sx_sunlock(&proctree_lock);
+			sx_sunlock(&V_proctree_lock);
 			error = ESRCH;
 			goto done;
 		}
@@ -952,7 +958,7 @@ sys_ktrace(td, uap)
 				ret |= ktrops(td, p, ops, facs, vp);
 		}
 		if (nfound == 0) {
-			sx_sunlock(&proctree_lock);
+			sx_sunlock(&V_proctree_lock);
 			error = ESRCH;
 			goto done;
 		}
@@ -968,7 +974,7 @@ sys_ktrace(td, uap)
 		if (error) {
 			if (p != NULL)
 				PROC_UNLOCK(p);
-			sx_sunlock(&proctree_lock);
+			sx_sunlock(&V_proctree_lock);
 			goto done;
 		}
 		if (descend)
@@ -976,7 +982,7 @@ sys_ktrace(td, uap)
 		else
 			ret |= ktrops(td, p, ops, facs, vp);
 	}
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 	if (!ret)
 		error = EPERM;
 done:
@@ -1026,7 +1032,11 @@ sys_utrace(td, uap)
 }
 
 #ifdef KTRACE
+#ifdef VPS
+int
+#else
 static int
+#endif
 ktrops(td, p, ops, facs, vp)
 	struct thread *td;
 	struct proc *p;
@@ -1093,7 +1103,7 @@ ktrsetchildren(td, top, ops, facs, vp)
 
 	p = top;
 	PROC_LOCK_ASSERT(p, MA_OWNED);
-	sx_assert(&proctree_lock, SX_LOCKED);
+	sx_assert(&V_proctree_lock, SX_LOCKED);
 	for (;;) {
 		ret |= ktrops(td, p, ops, facs, vp);
 		/*
@@ -1221,7 +1231,7 @@ ktr_writerequest(struct thread *td, stru
 	 * credentials for the operation.
 	 */
 	cred = NULL;
-	sx_slock(&allproc_lock);
+	sx_slock(&V_allproc_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		PROC_LOCK(p);
 		if (p->p_tracevp == vp) {
@@ -1236,7 +1246,7 @@ ktr_writerequest(struct thread *td, stru
 			cred = NULL;
 		}
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
 
 	while (vrele_count-- > 0)
 		vrele(vp);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_linker.c head/sys/kern/kern_linker.c
--- clean-head/sys/kern/kern_linker.c	2013-06-26 09:37:48.000000000 +0200
+++ head/sys/kern/kern_linker.c	2013-06-24 14:20:31.000000000 +0200
@@ -55,6 +55,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_l
 
 #include <net/vnet.h>
 
+#include <vps/vps.h>
+
 #include <security/mac/mac_framework.h>
 
 #include "linker_if.h"
@@ -383,7 +385,7 @@ linker_load_file(const char *filename, l
 	int foundfile, error, modules;
 
 	/* Refuse to load modules if securelevel raised */
-	if (prison0.pr_securelevel > 0)
+	if (V_prison0->pr_securelevel > 0)
 		return (EPERM);
 
 	KLD_LOCK_ASSERT();
@@ -599,7 +601,7 @@ linker_file_unload(linker_file_t file, i
 	int error, i;
 
 	/* Refuse to unload modules if securelevel raised. */
-	if (prison0.pr_securelevel > 0)
+	if (V_prison0->pr_securelevel > 0)
 		return (EPERM);
 
 	KLD_LOCK_ASSERT();
@@ -1166,6 +1168,11 @@ sys_kldfind(struct thread *td, struct kl
 	linker_file_t lf;
 	int error;
 
+#ifdef VPS
+	if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0)
+		return (error);
+#endif
+
 #ifdef MAC
 	error = mac_kld_check_stat(td->td_ucred);
 	if (error)
@@ -1197,6 +1204,11 @@ sys_kldnext(struct thread *td, struct kl
 	linker_file_t lf;
 	int error = 0;
 
+#ifdef VPS
+	if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0)
+		return (error);
+#endif
+
 #ifdef MAC
 	error = mac_kld_check_stat(td->td_ucred);
 	if (error)
@@ -1234,6 +1246,11 @@ sys_kldstat(struct thread *td, struct kl
 	struct kld_file_stat stat;
 	int error, version;
 
+#ifdef VPS
+	if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0)
+		return (error);
+#endif
+
 	/*
 	 * Check the version of the user's structure.
 	 */
@@ -1297,6 +1314,11 @@ sys_kldfirstmod(struct thread *td, struc
 	module_t mp;
 	int error = 0;
 
+#ifdef VPS
+	if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0)
+		return (error);
+#endif
+
 #ifdef MAC
 	error = mac_kld_check_stat(td->td_ucred);
 	if (error)
@@ -1329,6 +1351,11 @@ sys_kldsym(struct thread *td, struct kld
 	struct kld_sym_lookup lookup;
 	int error = 0;
 
+#ifdef VPS
+	if ((error = priv_check(td, PRIV_KLD_LOAD)) != 0)
+		return (error);
+#endif
+
 #ifdef MAC
 	error = mac_kld_check_stat(td->td_ucred);
 	if (error)
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_mib.c head/sys/kern/kern_mib.c
--- clean-head/sys/kern/kern_mib.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_mib.c	2013-06-24 14:20:31.000000000 +0200
@@ -55,22 +55,25 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_m
 #include <sys/sx.h>
 #include <sys/unistd.h>
 
-SYSCTL_NODE(, 0,	  sysctl, CTLFLAG_RW, 0,
-	"Sysctl internal magic");
-SYSCTL_NODE(, CTL_KERN,	  kern,   CTLFLAG_RW|CTLFLAG_CAPRD, 0,
-	"High kernel, proc, limits &c");
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
+_SYSCTL_NODE(, 0,	  sysctl, CTLFLAG_RW, 0,
+	"Sysctl internal magic", VPS_PUBLIC);
+_SYSCTL_NODE(, CTL_KERN,	  kern,   CTLFLAG_RW|CTLFLAG_CAPRD, 0,
+	"High kernel, proc, limits &c", VPS_PUBLIC);
 SYSCTL_NODE(, CTL_VM,	  vm,     CTLFLAG_RW, 0,
 	"Virtual memory");
 SYSCTL_NODE(, CTL_VFS,	  vfs,     CTLFLAG_RW, 0,
 	"File system");
-SYSCTL_NODE(, CTL_NET,	  net,    CTLFLAG_RW, 0,
-	"Network, (see socket.h)");
+_SYSCTL_NODE(, CTL_NET,	  net,    CTLFLAG_RW, 0,
+	"Network, (see socket.h)", VPS_PUBLIC);
 SYSCTL_NODE(, CTL_DEBUG,  debug,  CTLFLAG_RW, 0,
 	"Debugging");
 SYSCTL_NODE(_debug, OID_AUTO,  sizeof,  CTLFLAG_RW, 0,
 	"Sizeof various things");
-SYSCTL_NODE(, CTL_HW,	  hw,     CTLFLAG_RW, 0,
-	"hardware");
+_SYSCTL_NODE(, CTL_HW,	  hw,     CTLFLAG_RW, 0,
+	"hardware", VPS_PUBLIC);
 SYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0,
 	"machine dependent");
 SYSCTL_NODE(, CTL_USER,	  user,   CTLFLAG_RW, 0,
@@ -87,49 +90,51 @@ SYSCTL_NODE(, OID_AUTO, regression, CTLF
      "Regression test MIB");
 #endif
 
-SYSCTL_STRING(_kern, OID_AUTO, ident, CTLFLAG_RD|CTLFLAG_MPSAFE,
-    kern_ident, 0, "Kernel identifier");
+_SYSCTL_STRING(_kern, OID_AUTO, ident, CTLFLAG_RD|CTLFLAG_MPSAFE,
+    kern_ident, 0, "Kernel identifier", VPS_PUBLIC);
 
-SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD|CTLFLAG_MPSAFE|
-    CTLFLAG_CAPRD, osrelease, 0, "Operating system release");
+_SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD|CTLFLAG_MPSAFE|
+    CTLFLAG_CAPRD, osrelease, 0, "Operating system release", VPS_PUBLIC);
 
-SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD|CTLFLAG_CAPRD,
-    0, BSD, "Operating system revision");
+_SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD|CTLFLAG_CAPRD,
+    0, BSD, "Operating system revision", VPS_PUBLIC);
 
-SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD|CTLFLAG_MPSAFE,
-    version, 0, "Kernel version");
+_SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD|CTLFLAG_MPSAFE,
+    version, 0, "Kernel version", VPS_PUBLIC);
 
-SYSCTL_STRING(_kern, OID_AUTO, compiler_version, CTLFLAG_RD|CTLFLAG_MPSAFE,
-    compiler_version, 0, "Version of compiler used to compile kernel");
+_SYSCTL_STRING(_kern, OID_AUTO, compiler_version, CTLFLAG_RD|CTLFLAG_MPSAFE,
+	compiler_version, 0, "Version of compiler used to compile kernel", VPS_PUBLIC);
 
-SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD|CTLFLAG_MPSAFE|
-    CTLFLAG_CAPRD, ostype, 0, "Operating system type");
+_SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD|CTLFLAG_MPSAFE|
+    CTLFLAG_CAPRD, ostype, 0, "Operating system type", VPS_PUBLIC);
 
 /*
  * NOTICE: The *userland* release date is available in
  * /usr/include/osreldate.h
  */
-SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD|CTLFLAG_CAPRD,
-    &osreldate, 0, "Kernel release date");
+_SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD|CTLFLAG_CAPRD,
+    &osreldate, 0, "Kernel release date", VPS_PUBLIC);
 
+#ifndef VPS
 SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RDTUN,
     &maxproc, 0, "Maximum number of processes");
 
 SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, CTLFLAG_RW,
     &maxprocperuid, 0, "Maximum processes allowed per userid");
+#endif
 
 SYSCTL_INT(_kern, OID_AUTO, maxusers, CTLFLAG_RDTUN,
     &maxusers, 0, "Hint for kernel tuning");
 
-SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD|CTLFLAG_CAPRD,
-    0, ARG_MAX, "Maximum bytes of argument to execve(2)");
+_SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD|CTLFLAG_CAPRD,
+    0, ARG_MAX, "Maximum bytes of argument to execve(2)", VPS_PUBLIC);
 
 SYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD|CTLFLAG_CAPRD,
     0, _POSIX_VERSION, "Version of POSIX attempting to comply to");
 
-SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RDTUN|CTLFLAG_CAPRD,
+_SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RDTUN|CTLFLAG_CAPRD,
     &ngroups_max, 0,
-    "Maximum number of supplemental groups a user can belong to");
+    "Maximum number of supplemental groups a user can belong to", VPS_PUBLIC);
 
 SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD|CTLFLAG_CAPRD,
     0, 1, "Whether job control is available");
@@ -144,17 +149,17 @@ SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_
 
 char kernelname[MAXPATHLEN] = "/kernel";	/* XXX bloat */
 
-SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW,
-    kernelname, sizeof kernelname, "Name of kernel file booted");
+_SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW,
+    kernelname, sizeof kernelname, "Name of kernel file booted", VPS_PUBLIC);
 
-SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD|CTLFLAG_CAPRD,
-    &mp_ncpus, 0, "Number of active CPUs");
+_SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD|CTLFLAG_CAPRD,
+    &mp_ncpus, 0, "Number of active CPUs", VPS_PUBLIC);
 
-SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD|CTLFLAG_CAPRD,
-    0, BYTE_ORDER, "System byte order");
+_SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD|CTLFLAG_CAPRD,
+    0, BYTE_ORDER, "System byte order", VPS_PUBLIC);
 
-SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD|CTLFLAG_CAPRD,
-    0, PAGE_SIZE, "System memory page size");
+_SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD|CTLFLAG_CAPRD,
+    0, PAGE_SIZE, "System memory page size", VPS_PUBLIC);
 
 static int
 sysctl_kern_arnd(SYSCTL_HANDLER_ARGS)
@@ -169,9 +174,9 @@ sysctl_kern_arnd(SYSCTL_HANDLER_ARGS)
 	return (SYSCTL_OUT(req, buf, len));
 }
 
-SYSCTL_PROC(_kern, KERN_ARND, arandom,
+_SYSCTL_PROC(_kern, KERN_ARND, arandom,
     CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE | CTLFLAG_CAPRD, NULL, 0,
-    sysctl_kern_arnd, "", "arc4rand");
+    sysctl_kern_arnd, "", "arc4rand", VPS_PUBLIC);
 
 static int
 sysctl_hw_physmem(SYSCTL_HANDLER_ARGS)
@@ -206,7 +211,24 @@ sysctl_hw_usermem(SYSCTL_HANDLER_ARGS)
 SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_ULONG | CTLFLAG_RD,
 	0, 0, sysctl_hw_usermem, "LU", "");
 
+#ifdef VPS
+static int
+sysctl_hw_availpages(SYSCTL_HANDLER_ARGS)
+{
+	u_long val;
+	if (req->td->td_vps == vps0)
+		val = physmem;
+	else
+		/* XXX retrieve phys memory limit of vps instance */
+		val = 1024;
+	return (sysctl_handle_long(oidp, &val, 0, req));
+}
+
+_SYSCTL_PROC(_hw, OID_AUTO, availpages, CTLTYPE_ULONG | CTLFLAG_RD,
+	0, 0, sysctl_hw_availpages, "LU", "", VPS_PUBLIC);
+#else
 SYSCTL_LONG(_hw, OID_AUTO, availpages, CTLFLAG_RD, &physmem, 0, "");
+#endif
 
 u_long pagesizes[MAXPAGESIZES] = { PAGE_SIZE };
 
@@ -228,12 +250,13 @@ sysctl_hw_pagesizes(SYSCTL_HANDLER_ARGS)
 
 		error = SYSCTL_OUT(req, pagesizes32, sizeof(pagesizes32));
 	} else
+
 #endif
 		error = SYSCTL_OUT(req, pagesizes, sizeof(pagesizes));
 	return (error);
 }
-SYSCTL_PROC(_hw, OID_AUTO, pagesizes, CTLTYPE_ULONG | CTLFLAG_RD,
-    NULL, 0, sysctl_hw_pagesizes, "LU", "Supported page sizes");
+_SYSCTL_PROC(_hw, OID_AUTO, pagesizes, CTLTYPE_ULONG | CTLFLAG_RD,
+    NULL, 0, sysctl_hw_pagesizes, "LU", "Supported page sizes", VPS_PUBLIC);
 
 #ifdef SCTL_MASK32
 int adaptive_machine_arch = 1;
@@ -258,9 +281,20 @@ sysctl_hw_machine_arch(SYSCTL_HANDLER_AR
 	return (error);
 
 }
-SYSCTL_PROC(_hw, HW_MACHINE_ARCH, machine_arch, CTLTYPE_STRING | CTLFLAG_RD,
-    NULL, 0, sysctl_hw_machine_arch, "A", "System architecture");
+_SYSCTL_PROC(_hw, HW_MACHINE_ARCH, machine_arch, CTLTYPE_STRING | CTLFLAG_RD,
+    NULL, 0, sysctl_hw_machine_arch, "A", "System architecture", VPS_PUBLIC);
+
+#ifdef VPS
+static int
+sysctl_hostname(SYSCTL_HANDLER_ARGS)
+{
+      int error;
+
+      error = vps_sysctl_handle_string(oidp, arg1, arg2, req);
 
+      return (error);
+}
+#else /* VPS */
 static int
 sysctl_hostname(SYSCTL_HANDLER_ARGS)
 {
@@ -311,7 +345,26 @@ sysctl_hostname(SYSCTL_HANDLER_ARGS)
 	}
 	return (error);
 }
+#endif /* VPS */
+
+#ifdef VPS
+VPS_DEFINE(char, hostname[MAXHOSTNAMELEN]) = "";
+VPS_DEFINE(char, domainname[MAXHOSTNAMELEN]) = "";
+VPS_DEFINE(char, hostuuid[HOSTUUIDLEN]) = "";
 
+SYSCTL_VPS_PROC(_kern, KERN_HOSTNAME, hostname,
+    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
+    &VPS_NAME(hostname), MAXHOSTNAMELEN,
+    sysctl_hostname, "A", "Hostname");
+SYSCTL_VPS_PROC(_kern, KERN_NISDOMAINNAME, domainname,
+    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
+    &VPS_NAME(domainname), MAXHOSTNAMELEN,
+    sysctl_hostname, "A", "Name of the current YP/NIS domain");
+SYSCTL_VPS_PROC(_kern, KERN_HOSTUUID, hostuuid,
+    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
+    &VPS_NAME(hostuuid), HOSTUUIDLEN,
+    sysctl_hostname, "A", "Host UUID");
+#else
 SYSCTL_PROC(_kern, KERN_HOSTNAME, hostname,
     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
     (void *)(offsetof(struct prison, pr_hostname)), MAXHOSTNAMELEN,
@@ -324,6 +377,7 @@ SYSCTL_PROC(_kern, KERN_HOSTUUID, hostuu
     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
     (void *)(offsetof(struct prison, pr_hostuuid)), HOSTUUIDLEN,
     sysctl_hostname, "A", "Host UUID");
+#endif /* VPS */
 
 static int	regression_securelevel_nonmonotonic = 0;
 
@@ -422,7 +476,7 @@ SYSCTL_PROC(_kern, KERN_HOSTID, hostid,
     CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
     NULL, 0, sysctl_hostid, "LU", "Host ID");
 
-SYSCTL_NODE(_kern, OID_AUTO, features, CTLFLAG_RD, 0, "Kernel Features");
+_SYSCTL_NODE(_kern, OID_AUTO, features, CTLFLAG_RD, 0, "Kernel Features", VPS_PUBLIC);
 
 #ifdef COMPAT_FREEBSD4
 FEATURE(compat_freebsd4, "Compatible with FreeBSD 4");
@@ -504,8 +558,8 @@ sysctl_kern_pid_max(SYSCTL_HANDLER_ARGS)
 	error = sysctl_handle_int(oidp, &pm, 0, req);
 	if (error || !req->newptr)
 		return (error);
-	sx_xlock(&proctree_lock);
-	sx_xlock(&allproc_lock);
+	sx_xlock(&V_proctree_lock);
+	sx_xlock(&V_allproc_lock);
 
 	/*
 	 * Only permit the values less then PID_MAX.
@@ -515,8 +569,8 @@ sysctl_kern_pid_max(SYSCTL_HANDLER_ARGS)
 		error = EINVAL;
 	else
 		pid_max = pm;
-	sx_xunlock(&allproc_lock);
-	sx_xunlock(&proctree_lock);
+	sx_xunlock(&V_allproc_lock);
+	sx_xunlock(&V_proctree_lock);
 	return (error);
 }
 SYSCTL_PROC(_kern, OID_AUTO, pid_max, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_TUN |
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_module.c head/sys/kern/kern_module.c
--- clean-head/sys/kern/kern_module.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_module.c	2013-06-24 14:20:31.000000000 +0200
@@ -44,6 +44,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_m
 #include <sys/module.h>
 #include <sys/linker.h>
 
+#include <vps/vps.h>
+
 static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
 
 struct module {
@@ -317,6 +319,11 @@ sys_modnext(struct thread *td, struct mo
 
 	td->td_retval[0] = -1;
 
+#ifdef VPS
+	if (td->td_vps != vps0)
+		return (ENOSYS);
+#endif
+
 	MOD_SLOCK;
 	if (uap->modid == 0) {
 		mod = TAILQ_FIRST(&modules);
@@ -348,6 +355,11 @@ sys_modfnext(struct thread *td, struct m
 
 	td->td_retval[0] = -1;
 
+#ifdef VPS
+	if (td->td_vps != vps0)
+		return (ENOSYS);
+#endif
+
 	MOD_SLOCK;
 	mod = module_lookupbyid(uap->modid);
 	if (mod == NULL) {
@@ -380,6 +392,11 @@ sys_modstat(struct thread *td, struct mo
 	struct module_stat *stat;
 	char *name;
 
+#ifdef VPS
+	if (td->td_vps != vps0)
+		return (ENOSYS);
+#endif
+
 	MOD_SLOCK;
 	mod = module_lookupbyid(uap->modid);
 	if (mod == NULL) {
@@ -430,6 +447,11 @@ sys_modfind(struct thread *td, struct mo
 	char name[MAXMODNAME];
 	module_t mod;
 
+#ifdef VPS
+	if (td->td_vps != vps0)
+		return (ENOSYS);
+#endif
+
 	if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
 		return (error);
 
@@ -477,6 +499,11 @@ freebsd32_modstat(struct thread *td, str
 	struct module_stat32 *stat32;
 	char *name;
 
+#ifdef VPS
+	if (td->td_vps != vps0)
+		return (ENOSYS);
+#endif
+
 	MOD_SLOCK;
 	mod = module_lookupbyid(uap->modid);
 	if (mod == NULL) {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_priv.c head/sys/kern/kern_priv.c
--- clean-head/sys/kern/kern_priv.c	2013-06-26 09:37:48.000000000 +0200
+++ head/sys/kern/kern_priv.c	2013-06-24 14:20:31.000000000 +0200
@@ -42,6 +42,9 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_p
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <security/mac/mac_framework.h>
 
 /*
@@ -90,14 +93,6 @@ priv_check_cred(struct ucred *cred, int 
 		goto out;
 #endif
 
-	/*
-	 * Jail policy will restrict certain privileges that may otherwise be
-	 * be granted.
-	 */
-	error = prison_priv_check(cred, priv);
-	if (error)
-		goto out;
-
 	if (unprivileged_mlock) {
 		/*
 		 * Allow unprivileged users to call mlock(2)/munlock(2) and
@@ -112,6 +107,24 @@ priv_check_cred(struct ucred *cred, int 
 	}
 
 	/*
+	 * Jail policy will restrict certain privileges that may otherwise be
+	 * be granted.
+	 */
+	error = prison_priv_check(cred, priv);
+	if (error)
+		goto out;
+
+#ifdef VPS
+	/*
+	 * VPS instances have a very fine granulated privilege mask.
+	 * In the ''base'' instance altough, usually every privilege is set.
+	 */
+	error = vps_priv_check(cred, priv);
+	if (error)
+		goto out;
+#endif
+
+	/*
 	 * Having determined if privilege is restricted by various policies,
 	 * now determine if privilege is granted.  At this point, any policy
 	 * may grant privilege.  For now, we allow short-circuit boolean
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_proc.c head/sys/kern/kern_proc.c
--- clean-head/sys/kern/kern_proc.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_proc.c	2013-06-24 14:20:31.000000000 +0200
@@ -76,6 +76,7 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_p
 #ifdef DDB
 #include <ddb/ddb.h>
 #endif
+#include <vps/vps.h>
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -143,15 +144,20 @@ static struct proc *zpfind_locked(pid_t 
 /*
  * Other process lists
  */
-struct pidhashhead *pidhashtbl;
-u_long pidhash;
-struct pgrphashhead *pgrphashtbl;
-u_long pgrphash;
-struct proclist allproc;
-struct proclist zombproc;
-struct sx allproc_lock;
-struct sx proctree_lock;
-struct mtx ppeers_lock;
+VPS_DEFINE(struct pidhashhead *, pidhashtbl);
+VPS_DEFINE(u_long, pidhash);
+VPS_DEFINE(struct pgrphashhead *, pgrphashtbl);
+VPS_DEFINE(u_long, pgrphash);
+VPS_DEFINE(struct proclist, allproc);  /* List of all processes. */
+VPS_DEFINE(struct proclist, zombproc); /* List of zombie processes. */
+VPS_DEFINE(struct proc *, initproc);   /* Process slot for init. */
+VPS_DEFINE(struct pgrp *, initpgrp);
+VPS_DEFINE(struct sx, allproc_lock);
+VPS_DEFINE(struct sx, proctree_lock);
+VPS_DEFINE(struct mtx, ppeers_lock);
+VPS_DEFINE(int, vmaxproc);              /* Max number of procs. */
+VPS_DEFINE(int, vmaxprocperuid);        /* Max procs per uid. */
+
 uma_zone_t proc_zone;
 
 int kstack_pages = KSTACK_PAGES;
@@ -163,6 +169,8 @@ CTASSERT(sizeof(struct kinfo_proc) == KI
 CTASSERT(sizeof(struct kinfo_proc32) == KINFO_PROC32_SIZE);
 #endif
 
+VPS_DEFINE(char *, proc_lock_names);
+
 /*
  * Initialize global process hashing structures.
  */
@@ -170,19 +178,87 @@ void
 procinit()
 {
 
-	sx_init(&allproc_lock, "allproc");
-	sx_init(&proctree_lock, "proctree");
-	mtx_init(&ppeers_lock, "p_peers", NULL, MTX_DEF);
-	LIST_INIT(&allproc);
-	LIST_INIT(&zombproc);
-	pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
-	pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
+#ifdef VPS
+	char *str;
+
+	/* This is freed in procuninit(). */
+	str = malloc(0x100 * 3, M_PROC, M_WAITOK);
+	V_proc_lock_names = str;
+
+	snprintf(str + 0x0, 0x100, "allproc_%p", curthread->td_vps);
+	sx_init(&V_allproc_lock, str + 0x0);
+
+	snprintf(str + 0x100, 0x100, "proctree_%p", curthread->td_vps);
+	sx_init(&V_proctree_lock, str + 0x100);
+
+	snprintf(str + 0x200, 0x100, "ppeers_%p", curthread->td_vps);
+	mtx_init(&V_ppeers_lock, str + 0x200, NULL, MTX_DEF);
+
+#else
+	sx_init(&V_allproc_lock, "allproc");
+	sx_init(&V_proctree_lock, "proctree");
+	mtx_init(&V_ppeers_lock, "p_peers", NULL, MTX_DEF);
+#endif
+	LIST_INIT(&V_allproc);
+	LIST_INIT(&V_zombproc);
+	V_pidhashtbl = hashinit(V_maxproc / 4, M_PROC, &V_pidhash);
+	V_pgrphashtbl = hashinit(V_maxproc / 4, M_PROC, &V_pgrphash);
+	uihashinit();
+#ifdef VPS
+	if (curthread->td_vps == vps0) {
+#endif
+	V_nprocs = 1;
 	proc_zone = uma_zcreate("PROC", sched_sizeof_proc(),
 	    proc_ctor, proc_dtor, proc_init, proc_fini,
-	    UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
-	uihashinit();
+	    UMA_ALIGN_PTR, 0 /* VPS // UMA_ZONE_NOFREE */);
+#ifdef VPS
+	}
+#endif
 }
 
+#ifdef VPS
+/*
+ * Reverse of procinit().
+ */
+
+void
+procuninit(void)
+{
+#if 1
+	//LIST_HEAD(generic, generic) *hashtbl, *hp;
+	struct pidhashhead *pidhashtbl, *hp;
+	struct pgrphashhead *pghashtbl, *hpg;
+	struct pgrp *pg;
+	struct proc *p;
+
+	pghashtbl = (void *)V_pgrphashtbl;
+	for (hpg = pghashtbl; hpg <= &pghashtbl[V_pgrphash]; hpg++)
+		LIST_FOREACH(pg, hpg, pg_hash) {
+			printf("%s: pgrphash pg=%p pg->pg_id=%d\n",
+				__func__, pg, pg->pg_id);
+		}
+
+	pidhashtbl = (void *)V_pidhashtbl;
+	for (hp = pidhashtbl; hp <= &pidhashtbl[V_pidhash]; hp++)
+		LIST_FOREACH(p, hp, p_hash) {
+			printf("%s: pidhash p=%p p->p_pid=%d\n",
+				__func__, p, p->p_pid);
+		}
+#endif
+
+	uihashdestroy();
+
+	hashdestroy(V_pgrphashtbl, M_PROC, V_pgrphash);
+	hashdestroy(V_pidhashtbl, M_PROC, V_pidhash);
+
+	mtx_destroy(&V_ppeers_lock);
+	sx_destroy(&V_proctree_lock);
+	sx_destroy(&V_allproc_lock);
+
+	free(V_proc_lock_names, M_PROC);	
+}
+#endif /* VPS */
+
 /*
  * Prepare a proc for use.
  */
@@ -256,13 +332,21 @@ proc_init(void *mem, int size, int flags
 static void
 proc_fini(void *mem, int size)
 {
-#ifdef notnow
+//#ifdef notnow
+#if 1
 	struct proc *p;
+	struct thread *td;
 
 	p = (struct proc *)mem;
 	EVENTHANDLER_INVOKE(process_fini, p);
 	pstats_free(p->p_stats);
-	thread_free(FIRST_THREAD_IN_PROC(p));
+	td = FIRST_THREAD_IN_PROC(p);
+	if (td)
+		thread_free(td);
+	/*
+	else
+		printf("%s: XXXXXXXXXXXXXXXXXXXXX p=%p td==NULL\n", __func__, p);
+	*/
 	mtx_destroy(&p->p_mtx);
 	if (p->p_ksi != NULL)
 		ksiginfo_free(p->p_ksi);
@@ -279,9 +363,13 @@ inferior(p)
 	register struct proc *p;
 {
 
-	sx_assert(&proctree_lock, SX_LOCKED);
+	sx_assert(&V_proctree_lock, SX_LOCKED);
 	for (; p != curproc; p = p->p_pptr)
+#ifdef VPS
+		if (p == V_initproc || p->p_pid == 0)
+#else
 		if (p->p_pid == 0)
+#endif
 			return (0);
 	return (1);
 }
@@ -291,7 +379,7 @@ pfind_locked(pid_t pid)
 {
 	struct proc *p;
 
-	sx_assert(&allproc_lock, SX_LOCKED);
+	sx_assert(&V_allproc_lock, SX_LOCKED);
 	LIST_FOREACH(p, PIDHASH(pid), p_hash) {
 		if (p->p_pid == pid) {
 			PROC_LOCK(p);
@@ -316,9 +404,9 @@ pfind(pid_t pid)
 {
 	struct proc *p;
 
-	sx_slock(&allproc_lock);
+	sx_slock(&V_allproc_lock);
 	p = pfind_locked(pid);
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
 	return (p);
 }
 
@@ -328,7 +416,7 @@ pfind_tid_locked(pid_t tid)
 	struct proc *p;
 	struct thread *td;
 
-	sx_assert(&allproc_lock, SX_LOCKED);
+	sx_assert(&V_allproc_lock, SX_LOCKED);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		PROC_LOCK(p);
 		if (p->p_state == PRS_NEW) {
@@ -355,7 +443,7 @@ pgfind(pgid)
 {
 	register struct pgrp *pgrp;
 
-	sx_assert(&proctree_lock, SX_LOCKED);
+	sx_assert(&V_proctree_lock, SX_LOCKED);
 
 	LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash) {
 		if (pgrp->pg_id == pgid) {
@@ -375,7 +463,7 @@ pget(pid_t pid, int flags, struct proc *
 	struct proc *p;
 	int error;
 
-	sx_slock(&allproc_lock);
+	sx_slock(&V_allproc_lock);
 	if (pid <= PID_MAX) {
 		p = pfind_locked(pid);
 		if (p == NULL && (flags & PGET_NOTWEXIT) == 0)
@@ -385,7 +473,7 @@ pget(pid_t pid, int flags, struct proc *
 	} else {
 		p = NULL;
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
 	if (p == NULL)
 		return (ESRCH);
 	if ((flags & PGET_CANSEE) != 0) {
@@ -438,7 +526,7 @@ enterpgrp(p, pgid, pgrp, sess)
 	struct session *sess;
 {
 
-	sx_assert(&proctree_lock, SX_XLOCKED);
+	sx_assert(&V_proctree_lock, SX_XLOCKED);
 
 	KASSERT(pgrp != NULL, ("enterpgrp: pgrp == NULL"));
 	KASSERT(p->p_pid == pgid,
@@ -501,7 +589,7 @@ enterthispgrp(p, pgrp)
 	struct pgrp *pgrp;
 {
 
-	sx_assert(&proctree_lock, SX_XLOCKED);
+	sx_assert(&V_proctree_lock, SX_XLOCKED);
 	PROC_LOCK_ASSERT(p, MA_NOTOWNED);
 	PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
 	PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED);
@@ -529,7 +617,7 @@ doenterpgrp(p, pgrp)
 {
 	struct pgrp *savepgrp;
 
-	sx_assert(&proctree_lock, SX_XLOCKED);
+	sx_assert(&V_proctree_lock, SX_XLOCKED);
 	PROC_LOCK_ASSERT(p, MA_NOTOWNED);
 	PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
 	PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED);
@@ -567,7 +655,7 @@ leavepgrp(p)
 {
 	struct pgrp *savepgrp;
 
-	sx_assert(&proctree_lock, SX_XLOCKED);
+	sx_assert(&V_proctree_lock, SX_XLOCKED);
 	savepgrp = p->p_pgrp;
 	PGRP_LOCK(savepgrp);
 	PROC_LOCK(p);
@@ -590,7 +678,7 @@ pgdelete(pgrp)
 	struct session *savesess;
 	struct tty *tp;
 
-	sx_assert(&proctree_lock, SX_XLOCKED);
+	sx_assert(&V_proctree_lock, SX_XLOCKED);
 	PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
 	SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED);
 
@@ -653,7 +741,7 @@ fixjobc(p, pgrp, entering)
 	register struct pgrp *hispgrp;
 	register struct session *mysession;
 
-	sx_assert(&proctree_lock, SX_LOCKED);
+	sx_assert(&V_proctree_lock, SX_LOCKED);
 	PROC_LOCK_ASSERT(p, MA_NOTOWNED);
 	PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
 	SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED);
@@ -663,8 +751,14 @@ fixjobc(p, pgrp, entering)
 	 * group; if so, adjust count for p's process group.
 	 */
 	mysession = pgrp->pg_session;
+#ifdef VPS
+	if (p->p_pptr == NULL ||
+	    ( (hispgrp = p->p_pptr->p_pgrp) != pgrp &&
+	    hispgrp->pg_session == mysession) )
+#else 
 	if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
 	    hispgrp->pg_session == mysession)
+#endif
 		pgadjustjobc(pgrp, entering);
 
 	/*
@@ -737,6 +831,13 @@ sess_release(struct session *s)
 	}
 }
 
+void
+proc_zone_reclaim(void)
+{
+
+	uma_zone_reclaim(proc_zone);
+}
+
 #ifdef DDB
 
 DB_SHOW_COMMAND(pgrpdump, pgrpdump)
@@ -745,10 +846,10 @@ DB_SHOW_COMMAND(pgrpdump, pgrpdump)
 	register struct proc *p;
 	register int i;
 
-	for (i = 0; i <= pgrphash; i++) {
-		if (!LIST_EMPTY(&pgrphashtbl[i])) {
+	for (i = 0; i <= V_pgrphash; i++) {
+		if (!LIST_EMPTY(&V_pgrphashtbl[i])) {
 			printf("\tindx %d\n", i);
-			LIST_FOREACH(pgrp, &pgrphashtbl[i], pg_hash) {
+			LIST_FOREACH(pgrp, &V_pgrphashtbl[i], pg_hash) {
 				printf(
 			"\tpgrp %p, pgid %ld, sess %p, sesscnt %d, mem %p\n",
 				    (void *)pgrp, (long)pgrp->pg_id,
@@ -878,7 +979,7 @@ fill_kinfo_proc_only(struct proc *p, str
 	kp->ki_pid = p->p_pid;
 	kp->ki_nice = p->p_nice;
 	kp->ki_start = p->p_stats->p_start;
-	timevaladd(&kp->ki_start, &boottime);
+	timevaladd(&kp->ki_start, &V_boottime);
 	PROC_SLOCK(p);
 	rufetch(p, &kp->ki_rusage);
 	kp->ki_runtime = cputick2usec(p->p_rux.rux_runtime);
@@ -1065,8 +1166,8 @@ zpfind_locked(pid_t pid)
 {
 	struct proc *p;
 
-	sx_assert(&allproc_lock, SX_LOCKED);
-	LIST_FOREACH(p, &zombproc, p_list) {
+	sx_assert(&V_allproc_lock, SX_LOCKED);
+	LIST_FOREACH(p, &V_zombproc, p_list) {
 		if (p->p_pid == pid) {
 			PROC_LOCK(p);
 			break;
@@ -1083,9 +1184,9 @@ zpfind(pid_t pid)
 {
 	struct proc *p;
 
-	sx_slock(&allproc_lock);
+	sx_slock(&V_allproc_lock);
 	p = zpfind_locked(pid);
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
 	return (p);
 }
 
@@ -1325,12 +1426,12 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
 	error = sysctl_wire_old_buffer(req, 0);
 	if (error != 0)
 		return (error);
-	sx_slock(&allproc_lock);
+	sx_slock(&V_allproc_lock);
 	for (doingzomb=0 ; doingzomb < 2 ; doingzomb++) {
 		if (!doingzomb)
-			p = LIST_FIRST(&allproc);
+			p = LIST_FIRST(&V_allproc);
 		else
-			p = LIST_FIRST(&zombproc);
+			p = LIST_FIRST(&V_zombproc);
 		for (; p != 0; p = LIST_NEXT(p, p_list)) {
 			/*
 			 * Skip embryonic processes.
@@ -1428,12 +1529,12 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
 
 			error = sysctl_out_proc(p, req, flags, doingzomb);
 			if (error) {
-				sx_sunlock(&allproc_lock);
+				sx_sunlock(&V_allproc_lock);
 				return (error);
 			}
 		}
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
 	return (0);
 }
 
@@ -2643,42 +2744,42 @@ errout:
 	return (error);
 }
 
-SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD,  0, "Process table");
+_SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD,  0, "Process table", 0);
 
-SYSCTL_PROC(_kern_proc, KERN_PROC_ALL, all, CTLFLAG_RD|CTLTYPE_STRUCT|
+_SYSCTL_PROC(_kern_proc, KERN_PROC_ALL, all, CTLFLAG_RD|CTLTYPE_STRUCT|
 	CTLFLAG_MPSAFE, 0, 0, sysctl_kern_proc, "S,proc",
-	"Return entire process table");
+	"Return entire process table", 0);
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_GID, gid, CTLFLAG_RD | CTLFLAG_MPSAFE,
-	sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_GID, gid, CTLFLAG_RD | CTLFLAG_MPSAFE,
+	sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_PGRP, pgrp, CTLFLAG_RD | CTLFLAG_MPSAFE,
-	sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_PGRP, pgrp, CTLFLAG_RD | CTLFLAG_MPSAFE,
+	sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_RGID, rgid, CTLFLAG_RD | CTLFLAG_MPSAFE,
-	sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_RGID, rgid, CTLFLAG_RD | CTLFLAG_MPSAFE,
+	sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_SESSION, sid, CTLFLAG_RD |
-	CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_SESSION, sid, CTLFLAG_RD |
+	CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_TTY, tty, CTLFLAG_RD | CTLFLAG_MPSAFE,
-	sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_TTY, tty, CTLFLAG_RD | CTLFLAG_MPSAFE, 
+	sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_UID, uid, CTLFLAG_RD | CTLFLAG_MPSAFE,
-	sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_UID, uid, CTLFLAG_RD | CTLFLAG_MPSAFE, 
+	sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_RUID, ruid, CTLFLAG_RD | CTLFLAG_MPSAFE,
-	sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_RUID, ruid, CTLFLAG_RD | CTLFLAG_MPSAFE,
+	sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_PID, pid, CTLFLAG_RD | CTLFLAG_MPSAFE,
-	sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_PID, pid, CTLFLAG_RD | CTLFLAG_MPSAFE,
+	sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_PROC, proc, CTLFLAG_RD | CTLFLAG_MPSAFE,
-	sysctl_kern_proc, "Return process table, no threads");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_PROC, proc, CTLFLAG_RD | CTLFLAG_MPSAFE,
+	sysctl_kern_proc, "Return process table, no threads", 0);
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_ARGS, args,
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_ARGS, args,
 	CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE,
-	sysctl_kern_proc_args, "Process argument list");
+	sysctl_kern_proc_args, "Process argument list", 0);
 
 static SYSCTL_NODE(_kern_proc, KERN_PROC_ENV, env, CTLFLAG_RD | CTLFLAG_MPSAFE,
 	sysctl_kern_proc_env, "Process environment");
@@ -2686,56 +2787,56 @@ static SYSCTL_NODE(_kern_proc, KERN_PROC
 static SYSCTL_NODE(_kern_proc, KERN_PROC_AUXV, auxv, CTLFLAG_RD |
 	CTLFLAG_MPSAFE, sysctl_kern_proc_auxv, "Process ELF auxiliary vector");
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_PATHNAME, pathname, CTLFLAG_RD |
-	CTLFLAG_MPSAFE, sysctl_kern_proc_pathname, "Process executable path");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_PATHNAME, pathname, CTLFLAG_RD |
+	CTLFLAG_MPSAFE, sysctl_kern_proc_pathname, "Process executable path", 0);
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_SV_NAME, sv_name, CTLFLAG_RD |
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_SV_NAME, sv_name, CTLFLAG_RD |
 	CTLFLAG_MPSAFE, sysctl_kern_proc_sv_name,
-	"Process syscall vector name (ABI type)");
+	"Process syscall vector name (ABI type)", 0);
 
-static SYSCTL_NODE(_kern_proc, (KERN_PROC_GID | KERN_PROC_INC_THREAD), gid_td,
-	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, (KERN_PROC_GID | KERN_PROC_INC_THREAD), gid_td,
+	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, (KERN_PROC_PGRP | KERN_PROC_INC_THREAD), pgrp_td,
-	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, (KERN_PROC_PGRP | KERN_PROC_INC_THREAD), pgrp_td,
+	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, (KERN_PROC_RGID | KERN_PROC_INC_THREAD), rgid_td,
-	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, (KERN_PROC_RGID | KERN_PROC_INC_THREAD), rgid_td,
+	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, (KERN_PROC_SESSION | KERN_PROC_INC_THREAD),
-	sid_td, CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, (KERN_PROC_SESSION | KERN_PROC_INC_THREAD),
+	sid_td, CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, (KERN_PROC_TTY | KERN_PROC_INC_THREAD), tty_td,
-	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, (KERN_PROC_TTY | KERN_PROC_INC_THREAD), tty_td,
+	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, (KERN_PROC_UID | KERN_PROC_INC_THREAD), uid_td,
-	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, (KERN_PROC_UID | KERN_PROC_INC_THREAD), uid_td,
+	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, (KERN_PROC_RUID | KERN_PROC_INC_THREAD), ruid_td,
-	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, (KERN_PROC_RUID | KERN_PROC_INC_THREAD), ruid_td,
+	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, (KERN_PROC_PID | KERN_PROC_INC_THREAD), pid_td,
-	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table");
+static _SYSCTL_NODE(_kern_proc, (KERN_PROC_PID | KERN_PROC_INC_THREAD), pid_td,
+	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc, "Process table", 0);
 
-static SYSCTL_NODE(_kern_proc, (KERN_PROC_PROC | KERN_PROC_INC_THREAD), proc_td,
+static _SYSCTL_NODE(_kern_proc, (KERN_PROC_PROC | KERN_PROC_INC_THREAD), proc_td,
 	CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_kern_proc,
-	"Return process table, no threads");
+	"Return process table, no threads", 0);
 
 #ifdef COMPAT_FREEBSD7
-static SYSCTL_NODE(_kern_proc, KERN_PROC_OVMMAP, ovmmap, CTLFLAG_RD |
-	CTLFLAG_MPSAFE, sysctl_kern_proc_ovmmap, "Old Process vm map entries");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_OVMMAP, ovmmap, CTLFLAG_RD |
+	CTLFLAG_MPSAFE, sysctl_kern_proc_ovmmap, "Old Process vm map entries", 0);
 #endif
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_VMMAP, vmmap, CTLFLAG_RD |
-	CTLFLAG_MPSAFE, sysctl_kern_proc_vmmap, "Process vm map entries");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_VMMAP, vmmap, CTLFLAG_RD |
+	CTLFLAG_MPSAFE, sysctl_kern_proc_vmmap, "Process vm map entries", 0);
 
 #if defined(STACK) || defined(DDB)
 static SYSCTL_NODE(_kern_proc, KERN_PROC_KSTACK, kstack, CTLFLAG_RD |
 	CTLFLAG_MPSAFE, sysctl_kern_proc_kstack, "Process kernel stacks");
 #endif
 
-static SYSCTL_NODE(_kern_proc, KERN_PROC_GROUPS, groups, CTLFLAG_RD |
-	CTLFLAG_MPSAFE, sysctl_kern_proc_groups, "Process groups");
+static _SYSCTL_NODE(_kern_proc, KERN_PROC_GROUPS, groups, CTLFLAG_RD |
+	CTLFLAG_MPSAFE, sysctl_kern_proc_groups, "Process groups", 0);
 
 static SYSCTL_NODE(_kern_proc, KERN_PROC_RLIMIT, rlimit, CTLFLAG_RW |
 	CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, sysctl_kern_proc_rlimit,
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_prot.c head/sys/kern/kern_prot.c
--- clean-head/sys/kern/kern_prot.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_prot.c	2013-06-24 14:20:31.000000000 +0200
@@ -84,6 +84,9 @@ FEATURE(regression,
 #include <security/audit/audit.h>
 #include <security/mac/mac_framework.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 static MALLOC_DEFINE(M_CRED, "cred", "credentials");
 
 SYSCTL_NODE(_security, OID_AUTO, bsd, CTLFLAG_RW, 0, "BSD security policy");
@@ -106,7 +109,13 @@ sys_getpid(struct thread *td, struct get
 	td->td_retval[0] = p->p_pid;
 #if defined(COMPAT_43)
 	PROC_LOCK(p);
+#ifdef VPS
+	if (V_initproc == td->td_proc) {
+		td->td_retval[1] = 0;
+	}
+#else
 	td->td_retval[1] = p->p_pptr->p_pid;
+#endif /* VPS */
 	PROC_UNLOCK(p);
 #endif
 	return (0);
@@ -124,6 +133,17 @@ sys_getppid(struct thread *td, struct ge
 	struct proc *p = td->td_proc;
 
 	PROC_LOCK(p);
+#ifdef VPS
+	/*
+	 * In case the initproc of a VPS instance called getppid()
+	 * we return pid 0, which would be true on a non-vps system.
+	 */
+	if (V_initproc == td->td_proc) {
+		td->td_retval[0] = 0;
+		PROC_UNLOCK(p);
+		return (0);
+	}
+#endif
 	td->td_retval[0] = p->p_pptr->p_pid;
 	PROC_UNLOCK(p);
 	return (0);
@@ -348,7 +368,7 @@ sys_setsid(register struct thread *td, s
 	newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
 	newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
 
-	sx_xlock(&proctree_lock);
+	sx_xlock(&V_proctree_lock);
 
 	if (p->p_pgid == p->p_pid || (pgrp = pgfind(p->p_pid)) != NULL) {
 		if (pgrp != NULL)
@@ -361,7 +381,7 @@ sys_setsid(register struct thread *td, s
 		newsess = NULL;
 	}
 
-	sx_xunlock(&proctree_lock);
+	sx_xunlock(&V_proctree_lock);
 
 	if (newpgrp != NULL)
 		free(newpgrp, M_PGRP);
@@ -407,7 +427,7 @@ sys_setpgid(struct thread *td, register 
 
 	newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
 
-	sx_xlock(&proctree_lock);
+	sx_xlock(&V_proctree_lock);
 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
 		if ((targp = pfind(uap->pid)) == NULL) {
 			error = ESRCH;
@@ -465,7 +485,7 @@ sys_setpgid(struct thread *td, register 
 		error = enterthispgrp(targp, pgrp);
 	}
 done:
-	sx_xunlock(&proctree_lock);
+	sx_xunlock(&V_proctree_lock);
 	KASSERT((error == 0) || (newpgrp != NULL),
 	    ("setpgid failed and newpgrp is NULL"));
 	if (newpgrp != NULL)
@@ -1695,7 +1715,7 @@ p_candebug(struct thread *td, struct pro
 	}
 
 	/* Can't trace init when securelevel > 0. */
-	if (p == initproc) {
+	if (p == V_initproc) {
 		error = securelevel_gt(td->td_ucred, 0);
 		if (error)
 			return (error);
@@ -1835,6 +1855,17 @@ crhold(struct ucred *cr)
 void
 crfree(struct ucred *cr)
 {
+#ifdef VPS
+	/*
+	 * For e.g. timed TCP operations this function is called by the
+	 * ''intr'' system process without any VPS context.
+	 */
+	struct vps *vps_save;
+
+	vps_save = curthread->td_vps;
+	KASSERT(cr->cr_vps != NULL, ("%s: cr->cr_vps == NULL", __func__));
+	KASSERT((cr->cr_ref & 0xffff0000) != 0xdead0000, ("dangling reference to ucred 2: cr=%p cr_ref=%08x", cr, cr->cr_ref));
+#endif
 
 	KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref));
 	KASSERT(cr->cr_ref != 0xdeadc0de, ("dangling reference to ucred"));
@@ -1844,10 +1875,16 @@ crfree(struct ucred *cr)
 		 * allocate a temporary credential, but don't
 		 * allocate a uidinfo structure.
 		 */
+#ifdef VPS
+		curthread->td_vps = cr->cr_vps;
+#endif
 		if (cr->cr_uidinfo != NULL)
 			uifree(cr->cr_uidinfo);
 		if (cr->cr_ruidinfo != NULL)
 			uifree(cr->cr_ruidinfo);
+#ifdef VPS
+		curthread->td_vps = vps_save;
+#endif
 		/*
 		 * Free a prison, if any.
 		 */
@@ -1855,6 +1892,11 @@ crfree(struct ucred *cr)
 			prison_free(cr->cr_prison);
 		if (cr->cr_loginclass != NULL)
 			loginclass_free(cr->cr_loginclass);
+#ifdef VPS
+		/* Drop reference to vps. */
+		if (cr->cr_vps != NULL)
+			vps_deref(cr->cr_vps, cr);
+#endif
 #ifdef AUDIT
 		audit_cred_destroy(cr);
 #endif
@@ -1892,6 +1934,10 @@ crcopy(struct ucred *dest, struct ucred 
 	uihold(dest->cr_ruidinfo);
 	prison_hold(dest->cr_prison);
 	loginclass_hold(dest->cr_loginclass);
+#ifdef VPS
+	/* Get reference on vps. */
+	vps_ref(dest->cr_vps, dest);
+#endif
 #ifdef AUDIT
 	audit_cred_copy(src, dest);
 #endif
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_resource.c head/sys/kern/kern_resource.c
--- clean-head/sys/kern/kern_resource.c	2013-06-26 09:37:48.000000000 +0200
+++ head/sys/kern/kern_resource.c	2013-06-24 14:20:31.000000000 +0200
@@ -66,13 +66,26 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_r
 #include <vm/pmap.h>
 #include <vm/vm_map.h>
 
+#include <vps/vps.h>
+
 
 static MALLOC_DEFINE(M_PLIMIT, "plimit", "plimit structures");
 static MALLOC_DEFINE(M_UIDINFO, "uidinfo", "uidinfo structures");
+
+#if 0
 #define	UIHASH(uid)	(&uihashtbl[(uid) & uihash])
 static struct rwlock uihashtbl_lock;
 static LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
 static u_long uihash;		/* size of hash table - 1 */
+#endif
+
+VPS_DEFINE(struct rwlock, uihashtbl_lock);
+VPS_DEFINE(LIST_HEAD(uihashhead, uidinfo) *, uihashtbl);
+VPS_DEFINE(u_long, uihash);
+#define V_uihashtbl_lock	VPSV(uihashtbl_lock)
+#define V_uihashtbl		VPSV(uihashtbl)
+#define V_uihash		VPSV(uihash)
+#define	UIHASH(uid)	(&V_uihashtbl[(uid) & V_uihash])
 
 static void	calcru1(struct proc *p, struct rusage_ext *ruxp,
 		    struct timeval *up, struct timeval *sp);
@@ -116,18 +129,18 @@ sys_getpriority(td, uap)
 		break;
 
 	case PRIO_PGRP:
-		sx_slock(&proctree_lock);
+		sx_slock(&V_proctree_lock);
 		if (uap->who == 0) {
 			pg = td->td_proc->p_pgrp;
 			PGRP_LOCK(pg);
 		} else {
 			pg = pgfind(uap->who);
 			if (pg == NULL) {
-				sx_sunlock(&proctree_lock);
+				sx_sunlock(&V_proctree_lock);
 				break;
 			}
 		}
-		sx_sunlock(&proctree_lock);
+		sx_sunlock(&V_proctree_lock);
 		LIST_FOREACH(p, &pg->pg_members, p_pglist) {
 			PROC_LOCK(p);
 			if (p->p_state == PRS_NORMAL &&
@@ -143,7 +156,7 @@ sys_getpriority(td, uap)
 	case PRIO_USER:
 		if (uap->who == 0)
 			uap->who = td->td_ucred->cr_uid;
-		sx_slock(&allproc_lock);
+		sx_slock(&V_allproc_lock);
 		FOREACH_PROC_IN_SYSTEM(p) {
 			PROC_LOCK(p);
 			if (p->p_state == PRS_NORMAL &&
@@ -154,7 +167,7 @@ sys_getpriority(td, uap)
 			}
 			PROC_UNLOCK(p);
 		}
-		sx_sunlock(&allproc_lock);
+		sx_sunlock(&V_allproc_lock);
 		break;
 
 	default:
@@ -203,18 +216,18 @@ sys_setpriority(td, uap)
 		break;
 
 	case PRIO_PGRP:
-		sx_slock(&proctree_lock);
+		sx_slock(&V_proctree_lock);
 		if (uap->who == 0) {
 			pg = curp->p_pgrp;
 			PGRP_LOCK(pg);
 		} else {
 			pg = pgfind(uap->who);
 			if (pg == NULL) {
-				sx_sunlock(&proctree_lock);
+				sx_sunlock(&V_proctree_lock);
 				break;
 			}
 		}
-		sx_sunlock(&proctree_lock);
+		sx_sunlock(&V_proctree_lock);
 		LIST_FOREACH(p, &pg->pg_members, p_pglist) {
 			PROC_LOCK(p);
 			if (p->p_state == PRS_NORMAL &&
@@ -230,7 +243,7 @@ sys_setpriority(td, uap)
 	case PRIO_USER:
 		if (uap->who == 0)
 			uap->who = td->td_ucred->cr_uid;
-		sx_slock(&allproc_lock);
+		sx_slock(&V_allproc_lock);
 		FOREACH_PROC_IN_SYSTEM(p) {
 			PROC_LOCK(p);
 			if (p->p_state == PRS_NORMAL &&
@@ -241,7 +254,7 @@ sys_setpriority(td, uap)
 			}
 			PROC_UNLOCK(p);
 		}
-		sx_sunlock(&allproc_lock);
+		sx_sunlock(&V_allproc_lock);
 		break;
 
 	default:
@@ -728,10 +741,10 @@ kern_proc_setrlimit(struct thread *td, s
 		break;
 
 	case RLIMIT_NPROC:
-		if (limp->rlim_cur > maxprocperuid)
-			limp->rlim_cur = maxprocperuid;
-		if (limp->rlim_max > maxprocperuid)
-			limp->rlim_max = maxprocperuid;
+		if (limp->rlim_cur > V_maxprocperuid)
+			limp->rlim_cur = V_maxprocperuid;
+		if (limp->rlim_max > V_maxprocperuid)
+			limp->rlim_max = V_maxprocperuid;
 		if (limp->rlim_cur < 1)
 			limp->rlim_cur = 1;
 		if (limp->rlim_max < 1)
@@ -1212,9 +1225,19 @@ void
 uihashinit()
 {
 
-	uihashtbl = hashinit(maxproc / 16, M_UIDINFO, &uihash);
-	rw_init(&uihashtbl_lock, "uidinfo hash");
+	V_uihashtbl = hashinit(V_maxproc / 16, M_UIDINFO, &V_uihash);
+	rw_init(&V_uihashtbl_lock, "uidinfo hash");
+}
+
+#ifdef VPS
+void
+uihashdestroy()
+{
+
+	rw_destroy(&V_uihashtbl_lock);
+	hashdestroy(V_uihashtbl, M_UIDINFO, V_uihash);
 }
+#endif
 
 /*
  * Look up a uidinfo struct for the parameter uid.
@@ -1227,7 +1250,7 @@ uilookup(uid)
 	struct uihashhead *uipp;
 	struct uidinfo *uip;
 
-	rw_assert(&uihashtbl_lock, RA_LOCKED);
+	rw_assert(&V_uihashtbl_lock, RA_LOCKED);
 	uipp = UIHASH(uid);
 	LIST_FOREACH(uip, uipp, ui_hash)
 		if (uip->ui_uid == uid)
@@ -1247,13 +1270,13 @@ uifind(uid)
 {
 	struct uidinfo *old_uip, *uip;
 
-	rw_rlock(&uihashtbl_lock);
+	rw_rlock(&V_uihashtbl_lock);
 	uip = uilookup(uid);
 	if (uip == NULL) {
-		rw_runlock(&uihashtbl_lock);
+		rw_runlock(&V_uihashtbl_lock);
 		uip = malloc(sizeof(*uip), M_UIDINFO, M_WAITOK | M_ZERO);
 		racct_create(&uip->ui_racct);
-		rw_wlock(&uihashtbl_lock);
+		rw_wlock(&V_uihashtbl_lock);
 		/*
 		 * There's a chance someone created our uidinfo while we
 		 * were in malloc and not holding the lock, so we have to
@@ -1273,7 +1296,7 @@ uifind(uid)
 		}
 	}
 	uihold(uip);
-	rw_unlock(&uihashtbl_lock);
+	rw_unlock(&V_uihashtbl_lock);
 	return (uip);
 }
 
@@ -1315,11 +1338,11 @@ uifree(uip)
 		return;
 
 	/* Prepare for suboptimal case. */
-	rw_wlock(&uihashtbl_lock);
+	rw_wlock(&V_uihashtbl_lock);
 	if (refcount_release(&uip->ui_ref)) {
 		racct_destroy(&uip->ui_racct);
 		LIST_REMOVE(uip, ui_hash);
-		rw_wunlock(&uihashtbl_lock);
+		rw_wunlock(&V_uihashtbl_lock);
 		if (uip->ui_sbsize != 0)
 			printf("freeing uidinfo: uid = %d, sbsize = %ld\n",
 			    uip->ui_uid, uip->ui_sbsize);
@@ -1335,9 +1358,9 @@ uifree(uip)
 	}
 	/*
 	 * Someone added a reference between atomic_cmpset_int() and
-	 * rw_wlock(&uihashtbl_lock).
+	 * rw_wlock(&V_uihashtbl_lock).
 	 */
-	rw_wunlock(&uihashtbl_lock);
+	rw_wunlock(&V_uihashtbl_lock);
 }
 
 void
@@ -1347,13 +1370,13 @@ ui_racct_foreach(void (*callback)(struct
 	struct uidinfo *uip;
 	struct uihashhead *uih;
 
-	rw_rlock(&uihashtbl_lock);
-	for (uih = &uihashtbl[uihash]; uih >= uihashtbl; uih--) {
+	rw_rlock(&V_uihashtbl_lock);
+	for (uih = &V_uihashtbl[V_uihash]; uih >= V_uihashtbl; uih--) {
 		LIST_FOREACH(uip, uih, ui_hash) {
 			(callback)(uip->ui_racct, arg2, arg3);
 		}
 	}
-	rw_runlock(&uihashtbl_lock);
+	rw_runlock(&V_uihashtbl_lock);
 }
 
 /*
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_sharedpage.c head/sys/kern/kern_sharedpage.c
--- clean-head/sys/kern/kern_sharedpage.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_sharedpage.c	2013-06-24 14:20:31.000000000 +0200
@@ -50,7 +50,11 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_s
 #include <vm/vm_pager.h>
 
 static struct sx shared_page_alloc_sx;
+#ifdef VPS
+vm_object_t shared_page_obj;
+#else
 static vm_object_t shared_page_obj;
+#endif
 static int shared_page_free;
 char *shared_page_mapping;
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_shutdown.c head/sys/kern/kern_shutdown.c
--- clean-head/sys/kern/kern_shutdown.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_shutdown.c	2013-06-24 14:20:31.000000000 +0200
@@ -70,6 +70,9 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_s
 #include <sys/vnode.h>
 #include <sys/watchdog.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <ddb/ddb.h>
 
 #include <machine/cpu.h>
@@ -186,11 +189,23 @@ sys_reboot(struct thread *td, struct reb
 #endif
 	if (error == 0)
 		error = priv_check(td, PRIV_REBOOT);
+#ifdef VPS
+	if (error == 0 && td->td_vps != vps0) {
+		error = vps_reboot(td, uap->opt);
+
+	} else if (error == 0) {
+		(void)vps_shutdown_all(td);
+		mtx_lock(&Giant);
+		kern_reboot(uap->opt);
+		mtx_unlock(&Giant);
+	}
+#else 
 	if (error == 0) {
 		mtx_lock(&Giant);
 		kern_reboot(uap->opt);
 		mtx_unlock(&Giant);
 	}
+#endif
 	return (error);
 }
 
@@ -206,10 +221,10 @@ shutdown_nice(int howto)
 	shutdown_howto = howto;
 
 	/* Send a signal to init(8) and have it shutdown the world */
-	if (initproc != NULL) {
-		PROC_LOCK(initproc);
-		kern_psignal(initproc, SIGINT);
-		PROC_UNLOCK(initproc);
+	if (V_initproc != NULL) {
+		PROC_LOCK(V_initproc);
+		kern_psignal(V_initproc, SIGINT);
+		PROC_UNLOCK(V_initproc);
 	} else {
 		/* No init(8) running, so simply reboot */
 		kern_reboot(RB_NOSYNC);
@@ -885,7 +900,7 @@ mkdumpheader(struct kerneldumpheader *kd
 	kdh->dumplength = htod64(dumplen);
 	kdh->dumptime = htod64(time_second);
 	kdh->blocksize = htod32(blksz);
-	strncpy(kdh->hostname, prison0.pr_hostname, sizeof(kdh->hostname));
+	strncpy(kdh->hostname, V_prison0->pr_hostname, sizeof(kdh->hostname));
 	strncpy(kdh->versionstring, version, sizeof(kdh->versionstring));
 	if (panicstr != NULL)
 		strncpy(kdh->panicstring, panicstr, sizeof(kdh->panicstring));
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_sig.c head/sys/kern/kern_sig.c
--- clean-head/sys/kern/kern_sig.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_sig.c	2013-06-24 14:20:31.000000000 +0200
@@ -86,6 +86,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_s
 
 #include <sys/jail.h>
 
+#include <vps/vps.h>
+
 #include <machine/cpu.h>
 
 #include <security/audit/audit.h>
@@ -1610,7 +1612,7 @@ killpg1(struct thread *td, int sig, int 
 		/*
 		 * broadcast
 		 */
-		sx_slock(&allproc_lock);
+		sx_slock(&V_allproc_lock);
 		FOREACH_PROC_IN_SYSTEM(p) {
 			PROC_LOCK(p);
 			if (p->p_pid <= 1 || p->p_flag & P_SYSTEM ||
@@ -1628,9 +1630,9 @@ killpg1(struct thread *td, int sig, int 
 				ret = err;
 			PROC_UNLOCK(p);
 		}
-		sx_sunlock(&allproc_lock);
+		sx_sunlock(&V_allproc_lock);
 	} else {
-		sx_slock(&proctree_lock);
+		sx_slock(&V_proctree_lock);
 		if (pgid == 0) {
 			/*
 			 * zero pgid means send to my process group.
@@ -1640,11 +1642,11 @@ killpg1(struct thread *td, int sig, int 
 		} else {
 			pgrp = pgfind(pgid);
 			if (pgrp == NULL) {
-				sx_sunlock(&proctree_lock);
+				sx_sunlock(&V_proctree_lock);
 				return (ESRCH);
 			}
 		}
-		sx_sunlock(&proctree_lock);
+		sx_sunlock(&V_proctree_lock);
 		LIST_FOREACH(p, &pgrp->pg_members, p_pglist) {
 			PROC_LOCK(p);
 			if (p->p_pid <= 1 || p->p_flag & P_SYSTEM ||
@@ -1831,9 +1833,9 @@ gsignal(int pgid, int sig, ksiginfo_t *k
 	struct pgrp *pgrp;
 
 	if (pgid != 0) {
-		sx_slock(&proctree_lock);
+		sx_slock(&V_proctree_lock);
 		pgrp = pgfind(pgid);
-		sx_sunlock(&proctree_lock);
+		sx_sunlock(&V_proctree_lock);
 		if (pgrp != NULL) {
 			pgsignal(pgrp, sig, 0, ksi);
 			PGRP_UNLOCK(pgrp);
@@ -2690,7 +2692,11 @@ issignal(struct thread *td)
 			/*
 			 * Don't take default actions on system processes.
 			 */
+#ifdef VPS
+			if (p->p_flag & P_SYSTEM) {
+#else
 			if (p->p_pid <= 1) {
+#endif
 #ifdef DIAGNOSTIC
 				/*
 				 * Are you sure you want to ignore SIGSEGV
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_switch.c head/sys/kern/kern_switch.c
--- clean-head/sys/kern/kern_switch.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_switch.c	2013-06-24 14:20:31.000000000 +0200
@@ -45,6 +45,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_s
 
 #include <machine/cpu.h>
 
+#include <vps/vps_account.h>
+
 /* Uncomment this to enable logging of critical_enter/exit. */
 #if 0
 #define	KTR_CRITICAL	KTR_SCHED
@@ -169,6 +171,14 @@ retry:
 		goto retry;
 	}
 
+#ifdef VPS
+	if (vps_account_runnable(td) == 0) {
+		/* note that it is no longer on the run queue */
+		vps_account_thread_pause(td);
+		goto retry;
+	}	
+#endif
+
 	TD_SET_RUNNING(td);
 	return (td);
 }
@@ -210,12 +220,14 @@ critical_exit(void)
 			td->td_critnest = 1;
 			thread_lock(td);
 			td->td_critnest--;
+			td->td_flags |= TDF_PREEMPTED;
 			flags = SW_INVOL | SW_PREEMPT;
 			if (TD_IS_IDLETHREAD(td))
 				flags |= SWT_IDLE;
 			else
 				flags |= SWT_OWEPREEMPT;
 			mi_switch(flags, NULL);
+			td->td_flags &= ~TDF_PREEMPTED;
 			thread_unlock(td);
 		}
 	} else
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_synch.c head/sys/kern/kern_synch.c
--- clean-head/sys/kern/kern_synch.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_synch.c	2013-06-24 14:20:31.000000000 +0200
@@ -103,7 +103,7 @@ static fixpt_t cexp[3] = {
 
 /* kernel uses `FSCALE', userland (SHOULD) use kern.fscale */
 static int      fscale __unused = FSCALE;
-SYSCTL_INT(_kern, OID_AUTO, fscale, CTLFLAG_RD, 0, FSCALE, "");
+_SYSCTL_INT(_kern, OID_AUTO, fscale, CTLFLAG_RD, 0, FSCALE, "", VPS_PUBLIC);
 
 static void	loadav(void *arg);
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_sysctl.c head/sys/kern/kern_sysctl.c
--- clean-head/sys/kern/kern_sysctl.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_sysctl.c	2013-06-24 14:20:31.000000000 +0200
@@ -64,6 +64,9 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_s
 
 #include <net/vnet.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <security/mac/mac_framework.h>
 
 #include <vm/vm.h>
@@ -459,7 +462,9 @@ sysctl_remove_oid_locked(struct sysctl_o
 struct sysctl_oid *
 sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
 	int number, const char *name, int kind, void *arg1, intptr_t arg2,
-	int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr)
+	int (*handler)(SYSCTL_HANDLER_ARGS), const char *fmt, const char *descr,
+	u_int8_t vps0
+	)
 {
 	struct sysctl_oid *oidp;
 
@@ -504,6 +509,9 @@ sysctl_add_oid(struct sysctl_ctx_list *c
 	oidp->oid_fmt = fmt;
 	if (descr)
 		oidp->oid_descr = strdup(descr, M_SYSCTLOID);
+#ifdef VPS
+	oidp->vps0 = vps0;
+#endif
 	/* Update the context, if used */
 	if (clist != NULL)
 		sysctl_ctx_entry_add(clist, oidp);
@@ -717,8 +725,8 @@ sysctl_sysctl_name(SYSCTL_HANDLER_ARGS)
  * XXXRW/JA: Shouldn't return name data for nodes that we don't permit in
  * capability mode.
  */
-static SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD | CTLFLAG_CAPRD,
-    sysctl_sysctl_name, "");
+static _SYSCTL_NODE(_sysctl, 1, name, CTLFLAG_RD | CTLFLAG_CAPRD,
+    sysctl_sysctl_name, "", VPS_PUBLIC);
 
 static int
 sysctl_sysctl_next_ls(struct sysctl_oid_list *lsp, int *name, u_int namelen, 
@@ -803,8 +811,8 @@ sysctl_sysctl_next(SYSCTL_HANDLER_ARGS)
  * XXXRW/JA: Shouldn't return next data for nodes that we don't permit in
  * capability mode.
  */
-static SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD | CTLFLAG_CAPRD,
-    sysctl_sysctl_next, "");
+static _SYSCTL_NODE(_sysctl, 2, next, CTLFLAG_RD | CTLFLAG_CAPRD,
+    sysctl_sysctl_next, "", VPS_PUBLIC);
 
 static int
 name2oid(char *name, int *oid, int *len, struct sysctl_oid **oidpp)
@@ -884,9 +892,9 @@ sysctl_sysctl_name2oid(SYSCTL_HANDLER_AR
  * XXXRW/JA: Shouldn't return name2oid data for nodes that we don't permit in
  * capability mode.
  */
-SYSCTL_PROC(_sysctl, 3, name2oid,
+_SYSCTL_PROC(_sysctl, 3, name2oid,
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE
-    | CTLFLAG_CAPRW, 0, 0, sysctl_sysctl_name2oid, "I", "");
+    | CTLFLAG_CAPRW, 0, 0, sysctl_sysctl_name2oid, "I", "", VPS_PUBLIC);
 
 static int
 sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS)
@@ -913,8 +921,8 @@ sysctl_sysctl_oidfmt(SYSCTL_HANDLER_ARGS
 }
 
 
-static SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD|CTLFLAG_MPSAFE|CTLFLAG_CAPRD,
-    sysctl_sysctl_oidfmt, "");
+static _SYSCTL_NODE(_sysctl, 4, oidfmt, CTLFLAG_RD|CTLFLAG_MPSAFE|CTLFLAG_CAPRD,
+    sysctl_sysctl_oidfmt, "", VPS_PUBLIC);
 
 static int
 sysctl_sysctl_oiddescr(SYSCTL_HANDLER_ARGS)
@@ -937,8 +945,8 @@ sysctl_sysctl_oiddescr(SYSCTL_HANDLER_AR
 	return (error);
 }
 
-static SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD|CTLFLAG_CAPRD,
-    sysctl_sysctl_oiddescr, "");
+static _SYSCTL_NODE(_sysctl, 5, oiddescr, CTLFLAG_RD|CTLFLAG_CAPRD,
+    sysctl_sysctl_oiddescr, "", VPS_PUBLIC);
 
 /*
  * Default "handler" functions.
@@ -1414,6 +1422,16 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
 	if (error)
 		return (error);
 
+#ifdef VPS
+	if (req->td->td_vps != vps0 && oid->vps0 != 0) {
+
+		DBGCORE("%s: hiding [%s (%s)]\n",
+			__func__, oid->oid_name, oid->oid_descr);
+
+		return (ENOENT);
+	}
+#endif
+
 	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
 		/*
 		 * You can't call a sysctl when it's a node, but has
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_tc.c head/sys/kern/kern_tc.c
--- clean-head/sys/kern/kern_tc.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_tc.c	2013-06-24 14:20:31.000000000 +0200
@@ -34,8 +34,12 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_t
 #include <sys/timepps.h>
 #include <sys/timetc.h>
 #include <sys/timex.h>
+#include <sys/proc.h>
 #include <sys/vdso.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 /*
  * A large step happens on boot.  This constant detects such steps.
  * It is relatively small so that ntp_update_second gets called enough
@@ -107,11 +111,19 @@ int tc_min_ticktock_freq = 1;
 volatile time_t time_second = 1;
 volatile time_t time_uptime = 1;
 
+VPS_DEFINE(struct bintime, boottimebin);
+VPS_DEFINE(struct timeval, boottime);
+static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS);
+SYSCTL_VPS_PROC(_kern, KERN_BOOTTIME, boottime, CTLTYPE_STRUCT|CTLFLAG_RD,
+	NULL, 0, sysctl_kern_boottime, "S,timeval", "System boottime");
+
+#if 0
 struct bintime boottimebin;
 struct timeval boottime;
 static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS);
 SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime, CTLTYPE_STRUCT|CTLFLAG_RD,
     NULL, 0, sysctl_kern_boottime, "S,timeval", "System boottime");
+#endif
 
 SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
 static SYSCTL_NODE(_kern_timecounter, OID_AUTO, tc, CTLFLAG_RW, 0, "");
@@ -148,13 +160,13 @@ sysctl_kern_boottime(SYSCTL_HANDLER_ARGS
 	int tv[2];
 
 	if (req->flags & SCTL_MASK32) {
-		tv[0] = boottime.tv_sec;
-		tv[1] = boottime.tv_usec;
+		tv[0] = V_boottime.tv_sec;
+		tv[1] = V_boottime.tv_usec;
 		return SYSCTL_OUT(req, tv, sizeof(tv));
 	} else
 #endif
 #endif
-		return SYSCTL_OUT(req, &boottime, sizeof(boottime));
+		return SYSCTL_OUT(req, &V_boottime, sizeof(V_boottime));
 }
 
 static int
@@ -235,7 +247,7 @@ fbclock_bintime(struct bintime *bt)
 {
 
 	fbclock_binuptime(bt);
-	bintime_add(bt, &boottimebin);
+	bintime_add(bt, &V_boottimebin);
 }
 
 void
@@ -306,7 +318,7 @@ fbclock_getbintime(struct bintime *bt)
 		gen = th->th_generation;
 		*bt = th->th_offset;
 	} while (gen == 0 || gen != th->th_generation);
-	bintime_add(bt, &boottimebin);
+	bintime_add(bt, &V_boottimebin);
 }
 
 void
@@ -372,7 +384,7 @@ bintime(struct bintime *bt)
 {
 
 	binuptime(bt);
-	bintime_add(bt, &boottimebin);
+	bintime_add(bt, &G_boottimebin);
 }
 
 void
@@ -443,7 +455,7 @@ getbintime(struct bintime *bt)
 		gen = th->th_generation;
 		*bt = th->th_offset;
 	} while (gen == 0 || gen != th->th_generation);
-	bintime_add(bt, &boottimebin);
+	bintime_add(bt, &V_boottimebin);
 }
 
 void
@@ -1100,7 +1112,7 @@ sysclock_snap2bintime(struct sysclock_sn
 			bintime_addx(bt, cs->fb_info.th_scale * cs->delta);
 
 		if ((flags & FBCLOCK_UPTIME) == 0)
-			bintime_add(bt, &boottimebin);
+			bintime_add(bt, &V_boottimebin);
 		break;
 #ifdef FFCLOCK
 	case SYSCLOCK_FFWD:
@@ -1222,9 +1234,9 @@ tc_setclock(struct timespec *ts)
 	timespec2bintime(ts, &bt);
 	binuptime(&bt2);
 	bintime_sub(&bt, &bt2);
-	bintime_add(&bt2, &boottimebin);
-	boottimebin = bt;
-	bintime2timeval(&bt, &boottime);
+	bintime_add(&bt2, &V_boottimebin);
+	V_boottimebin = bt;
+	bintime2timeval(&bt, &V_boottime);
 
 	/* XXX fiddle all the little crinkly bits around the fiords... */
 	tc_windup();
@@ -1313,7 +1325,7 @@ tc_windup(void)
 	 * case we missed a leap second.
 	 */
 	bt = th->th_offset;
-	bintime_add(&bt, &boottimebin);
+	bintime_add(&bt, &G_boottimebin);
 	i = bt.sec - tho->th_microtime.tv_sec;
 	if (i > LARGE_STEP)
 		i = 2;
@@ -1321,7 +1333,7 @@ tc_windup(void)
 		t = bt.sec;
 		ntp_update_second(&th->th_adjustment, &bt.sec);
 		if (bt.sec != t)
-			boottimebin.sec += bt.sec - t;
+			G_boottimebin.sec += bt.sec - t;
 	}
 	/* Update the UTC timestamps used by the get*() functions. */
 	/* XXX shouldn't do this here.  Should force non-`get' versions. */
@@ -1683,7 +1695,7 @@ pps_event(struct pps_state *pps, int eve
 	tcount &= pps->capth->th_counter->tc_counter_mask;
 	bt = pps->capth->th_offset;
 	bintime_addx(&bt, pps->capth->th_scale * tcount);
-	bintime_add(&bt, &boottimebin);
+	bintime_add(&bt, &V_boottimebin);
 	bintime2timespec(&bt, &ts);
 
 	/* If the timecounter was wound up underneath us, bail out. */
@@ -1999,7 +2011,7 @@ tc_fill_vdso_timehands(struct vdso_timeh
 	vdso_th->th_offset_count = th->th_offset_count;
 	vdso_th->th_counter_mask = th->th_counter->tc_counter_mask;
 	vdso_th->th_offset = th->th_offset;
-	vdso_th->th_boottime = boottimebin;
+	vdso_th->th_boottime = V_boottimebin;
 	enabled = cpu_fill_vdso_timehands(vdso_th);
 	if (!vdso_th_enable)
 		enabled = 0;
@@ -2020,8 +2032,8 @@ tc_fill_vdso_timehands32(struct vdso_tim
 	vdso_th32->th_counter_mask = th->th_counter->tc_counter_mask;
 	vdso_th32->th_offset.sec = th->th_offset.sec;
 	*(uint64_t *)&vdso_th32->th_offset.frac[0] = th->th_offset.frac;
-	vdso_th32->th_boottime.sec = boottimebin.sec;
-	*(uint64_t *)&vdso_th32->th_boottime.frac[0] = boottimebin.frac;
+	vdso_th32->th_boottime.sec = V_boottimebin.sec;
+	*(uint64_t *)&vdso_th32->th_boottime.frac[0] = V_boottimebin.frac;
 	enabled = cpu_fill_vdso_timehands32(vdso_th32);
 	if (!vdso_th_enable)
 		enabled = 0;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_thr.c head/sys/kern/kern_thr.c
--- clean-head/sys/kern/kern_thr.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_thr.c	2013-06-24 14:20:31.000000000 +0200
@@ -56,6 +56,10 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_t
 
 #include <machine/frame.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#include <vps/vps_account.h>
+
 #include <security/audit/audit.h>
 
 static SYSCTL_NODE(_kern, OID_AUTO, threads, CTLFLAG_RW, 0,
@@ -168,6 +172,11 @@ create_thread(struct thread *td, mcontex
 		return (EPROCLIM);
 	}
 
+#ifdef VPS
+	if (vps_account(p->p_ucred->cr_vps, VPS_ACC_THREADS, VPS_ACC_ALLOC, 1))
+		return (ENOMEM);
+#endif
+
 	if (rtp != NULL) {
 		switch(rtp->type) {
 		case RTP_PRIO_REALTIME:
@@ -228,6 +237,11 @@ create_thread(struct thread *td, mcontex
 	newtd->td_proc = td->td_proc;
 	newtd->td_ucred = crhold(td->td_ucred);
 
+#ifdef VPS
+	newtd->td_vps = newtd->td_ucred->cr_vps;
+	newtd->td_vps_acc = newtd->td_ucred->cr_vps->vps_acc;
+#endif
+
 	if (ctx != NULL) { /* old way to set user context */
 		error = set_mcontext(newtd, ctx);
 		if (error != 0) {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_thread.c head/sys/kern/kern_thread.c
--- clean-head/sys/kern/kern_thread.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_thread.c	2013-06-24 14:20:31.000000000 +0200
@@ -55,6 +55,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_t
 #include <sys/pmckern.h>
 #endif
 
+#include <vps/vps_account.h>
+
 #include <security/audit/audit.h>
 
 #include <vm/vm.h>
@@ -279,7 +281,7 @@ threadinit(void)
 	thread_zone = uma_zcreate("THREAD", sched_sizeof_thread(),
 	    thread_ctor, thread_dtor, thread_init, thread_fini,
 	    16 - 1, 0);
-	tidhashtbl = hashinit(maxproc / 2, M_TIDHASH, &tidhash);
+	tidhashtbl = hashinit(V_maxproc / 2, M_TIDHASH, &tidhash);
 	rw_init(&tidhash_lock, "tidhash");
 }
 
@@ -320,6 +322,7 @@ thread_reap(void)
 	if (!TAILQ_EMPTY(&zombie_threads)) {
 		mtx_lock_spin(&zombie_lock);
 		td_first = TAILQ_FIRST(&zombie_threads);
+		/* XXX - KLAUS: ?! */
 		if (td_first)
 			TAILQ_INIT(&zombie_threads);
 		mtx_unlock_spin(&zombie_lock);
@@ -372,6 +375,10 @@ void
 thread_free(struct thread *td)
 {
 
+	/* THREAD_CAN_MIGRATE() check for lock_profile_thread_exit() */
+	KASSERT(td->td_pinned == 0,
+		("%s: td=%p td->td_pinned=%d\n",
+		__func__, td, td->td_pinned));
 	lock_profile_thread_exit(td);
 	if (td->td_cpuset)
 		cpuset_rel(td->td_cpuset);
@@ -412,6 +419,10 @@ thread_exit(void)
 	    (long)p->p_pid, td->td_name);
 	KASSERT(TAILQ_EMPTY(&td->td_sigqueue.sq_list), ("signal pending"));
 
+#ifdef VPS
+	vps_account(p->p_ucred->cr_vps, VPS_ACC_THREADS, VPS_ACC_FREE, 1);
+#endif
+
 #ifdef AUDIT
 	AUDIT_SYSCALL_EXIT(0, td);
 #endif
@@ -1052,3 +1063,11 @@ tidhash_remove(struct thread *td)
 	LIST_REMOVE(td, td_hash);
 	rw_wunlock(&tidhash_lock);
 }
+
+void
+thread_zone_reclaim(void)
+{
+
+	uma_zone_reclaim(thread_zone);
+}
+
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_time.c head/sys/kern/kern_time.c
--- clean-head/sys/kern/kern_time.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_time.c	2013-06-24 14:20:31.000000000 +0200
@@ -55,6 +55,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_t
 #include <sys/timetc.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 
@@ -347,11 +349,35 @@ kern_clock_gettime(struct thread *td, cl
 	case CLOCK_MONOTONIC_PRECISE:
 	case CLOCK_UPTIME:
 	case CLOCK_UPTIME_PRECISE:
+#ifdef VPS
+		if (curthread->td_vps == vps0)
+			nanouptime(ats);
+		else {
+			struct timespec t1;
+
+			nanotime(ats);
+			bintime2timespec(&V_boottimebin, &t1);
+			timespecsub(ats, &t1);
+		}
+#else
 		nanouptime(ats);
+#endif
 		break;
 	case CLOCK_UPTIME_FAST:
 	case CLOCK_MONOTONIC_FAST:
+#ifdef VPS
+		if (curthread->td_vps == vps0)
+			getnanouptime(ats);
+		else {
+			struct timespec t1;
+
+			getnanotime(ats);
+			bintime2timespec(&V_boottimebin, &t1);
+			timespecsub(ats, &t1);
+		}
+#else
 		getnanouptime(ats);
+#endif
 		break;
 	case CLOCK_SECOND:
 		ats->tv_sec = time_second;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_umtx.c head/sys/kern/kern_umtx.c
--- clean-head/sys/kern/kern_umtx.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_umtx.c	2013-06-24 14:20:31.000000000 +0200
@@ -3771,3 +3771,38 @@ umtx_thread_cleanup(struct thread *td)
 	sched_lend_user_prio(td, PRI_MAX);
 	thread_unlock(td);
 }
+
+#ifdef VPS
+
+/*
+ * VPS stuff
+ */
+
+int vps_umtx_snapshot(struct thread *td);
+int
+vps_umtx_snapshot(struct thread *td)
+{
+	struct umtx_q *uq, *uq2;
+	struct umtx_pi *pi;
+
+	uq = td->td_umtxq;
+
+	printf("%s: td->td_umtxq=%p\n", __func__, uq);
+	if (uq == NULL)
+		return (0);
+
+	printf("%s: uq->uq_spare_queue=%p\n", __func__, uq->uq_spare_queue);
+	printf("%s: uq->uq_inherited_pri=%d\n", __func__, uq->uq_inherited_pri);
+
+	if (uq->uq_spare_queue)
+		TAILQ_FOREACH(uq2, &uq->uq_spare_queue->head, uq_link)
+			printf("%s: uq2=%p\n", __func__, uq2);
+
+	TAILQ_FOREACH(pi, &uq->uq_pi_contested, pi_link)
+		printf("%s: pi=%p\n", __func__, pi);
+	
+	return (0);
+}
+
+#endif /* VPS */
+
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/kern_uuid.c head/sys/kern/kern_uuid.c
--- clean-head/sys/kern/kern_uuid.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/kern_uuid.c	2013-06-24 14:20:31.000000000 +0200
@@ -44,6 +44,8 @@ __FBSDID("$FreeBSD: head/sys/kern/kern_u
 #include <net/if_types.h>
 #include <net/vnet.h>
 
+#include <vps/vps.h>
+
 /*
  * See also:
  *	http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/posix4_mib.c head/sys/kern/posix4_mib.c
--- clean-head/sys/kern/posix4_mib.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/posix4_mib.c	2013-06-24 14:20:31.000000000 +0200
@@ -57,22 +57,22 @@ static int p31b_sysctl_proc(SYSCTL_HANDL
 SYSCTL_DECL(_p1003_1b);
 
 #define P1B_SYSCTL(num, name)  \
-	SYSCTL_INT(_p1003_1b, num, name, CTLFLAG_RD | CTLFLAG_CAPRD, \
-	facility + num - 1, 0, "");
+	_SYSCTL_INT(_p1003_1b, num, name, CTLFLAG_RD | CTLFLAG_CAPRD, \
+	facility + num - 1, 0, "", VPS_PUBLIC);
 #define P1B_SYSCTL_RW(num, name)  \
-	SYSCTL_PROC(_p1003_1b, num, name, CTLTYPE_INT | CTLFLAG_RW, NULL, num, \
-	    p31b_sysctl_proc, "I", "");
+	_SYSCTL_PROC(_p1003_1b, num, name, CTLTYPE_INT | CTLFLAG_RW, NULL, num, \
+	    p31b_sysctl_proc, "I", "", VPS_0);
 
 #else
 
 SYSCTL_DECL(_kern_p1003_1b);
 
 #define P1B_SYSCTL(num, name)  \
-	SYSCTL_INT(_kern_p1003_1b, OID_AUTO, name, CTLFLAG_RD | CTLFLAG_CAPRD, \
-	    facility + num - 1, 0, "");
+	_SYSCTL_INT(_kern_p1003_1b, OID_AUTO, name, CTLFLAG_RD | CTLFLAG_CAPRD, \
+	    facility + num - 1, 0, "", VPS_PUBLIC);
 #define P1B_SYSCTL_RW(num, name)  \
-	SYSCTL_PROC(_p1003_1b, OID_AUTO, name, CTLTYPE_INT | CTLFLAG_RW, NULL, \
-	    num, p31b_sysctl_proc, "I", "");
+	_SYSCTL_PROC(_p1003_1b, OID_AUTO, name, CTLTYPE_INT | CTLFLAG_RW, NULL, \
+	    num, p31b_sysctl_proc, "I", "", VPS_0);
 SYSCTL_NODE(_kern, OID_AUTO, p1003_1b, CTLFLAG_RW, 0, "P1003.1B");
 
 #endif
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/sched_ule.c head/sys/kern/sched_ule.c
--- clean-head/sys/kern/sched_ule.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/sched_ule.c	2013-06-24 14:20:31.000000000 +0200
@@ -2180,6 +2180,7 @@ sched_preempt(struct thread *td)
 		else
 			mi_switch(flags | SWT_REMOTEPREEMPT, NULL);
 	}
+	td->td_flags &= ~TDF_PREEMPTED;
 	thread_unlock(td);
 }
 
@@ -2452,6 +2453,29 @@ sched_rem(struct thread *td)
 		tdq_setlowpri(tdq, NULL);
 }
 
+#ifdef VPS
+/*
+ * sched_rem() without tdq_runq_rem() ...
+ */
+void
+sched_rem_norunq(struct thread *td)
+{
+	struct tdq *tdq;
+
+	tdq = TDQ_CPU(td->td_sched->ts_cpu);
+	TDQ_LOCK_ASSERT(tdq, MA_OWNED);
+	MPASS(td->td_lock == TDQ_LOCKPTR(tdq));
+
+	KASSERT(TD_ON_RUNQ(td) == 0,
+	    ("sched_rem: thread on run queue"));
+
+	tdq_load_rem(tdq, td);
+	TD_SET_CAN_RUN(td);
+	if (td->td_priority == tdq->tdq_lowpri)
+		tdq_setlowpri(tdq, NULL);
+}
+#endif
+
 /*
  * Fetch cpu utilization information.  Updates on demand.
  */
@@ -2900,4 +2924,4 @@ SYSCTL_PROC(_kern_sched, OID_AUTO, topol
 
 /* ps compat.  All cpu percentages from ULE are weighted. */
 static int ccpu = 0;
-SYSCTL_INT(_kern, OID_AUTO, ccpu, CTLFLAG_RD, &ccpu, 0, "");
+_SYSCTL_INT(_kern, OID_AUTO, ccpu, CTLFLAG_RD, &ccpu, 0, "", VPS_PUBLIC);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/subr_kdb.c head/sys/kern/subr_kdb.c
--- clean-head/sys/kern/subr_kdb.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/subr_kdb.c	2013-06-24 14:20:31.000000000 +0200
@@ -43,6 +43,8 @@ __FBSDID("$FreeBSD: head/sys/kern/subr_k
 #include <sys/stack.h>
 #include <sys/sysctl.h>
 
+#include <vps/vps.h>
+
 #include <machine/kdb.h>
 #include <machine/pcb.h>
 
@@ -537,7 +539,7 @@ kdb_thr_first(void)
 	struct proc *p;
 	struct thread *thr;
 
-	p = LIST_FIRST(&allproc);
+	p = LIST_FIRST(&V_allproc);
 	while (p != NULL) {
 		if (p->p_flag & P_INMEM) {
 			thr = FIRST_THREAD_IN_PROC(p);
@@ -554,7 +556,7 @@ kdb_thr_from_pid(pid_t pid)
 {
 	struct proc *p;
 
-	p = LIST_FIRST(&allproc);
+	p = LIST_FIRST(&V_allproc);
 	while (p != NULL) {
 		if (p->p_flag & P_INMEM && p->p_pid == pid)
 			return (FIRST_THREAD_IN_PROC(p));
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/subr_prf.c head/sys/kern/subr_prf.c
--- clean-head/sys/kern/subr_prf.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/subr_prf.c	2013-06-24 14:20:31.000000000 +0200
@@ -59,6 +59,8 @@ __FBSDID("$FreeBSD: head/sys/kern/subr_p
 #include <sys/uio.h>
 #include <sys/ctype.h>
 
+#include <vps/vps.h>
+
 #ifdef DDB
 #include <ddb/ddb.h>
 #endif
@@ -146,7 +148,7 @@ uprintf(const char *fmt, ...)
 	if (TD_IS_IDLETHREAD(td))
 		return (0);
 
-	sx_slock(&proctree_lock);
+	sx_slock(&V_proctree_lock);
 	p = td->td_proc;
 	PROC_LOCK(p);
 	if ((p->p_flag & P_CONTROLT) == 0) {
@@ -170,7 +172,7 @@ uprintf(const char *fmt, ...)
 	tty_unlock(pca.tty);
 	va_end(ap);
 out:
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 	return (retval);
 }
 
@@ -187,7 +189,7 @@ tprintf(struct proc *p, int pri, const c
 	struct putchar_arg pca;
 	struct session *sess = NULL;
 
-	sx_slock(&proctree_lock);
+	sx_slock(&V_proctree_lock);
 	if (pri != -1)
 		flags |= TOLOG;
 	if (p != NULL) {
@@ -218,7 +220,7 @@ tprintf(struct proc *p, int pri, const c
 	if (sess != NULL)
 		sess_release(sess);
 	msgbuftrigger = 1;
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 }
 
 /*
@@ -1007,7 +1009,12 @@ sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
 	u_int seq;
 	int error, len;
 
+#ifdef VPS
+	/* Always check for PRIV_MSGBUF. */
+	if (1) {
+#else
 	if (!unprivileged_read_msgbuf) {
+#endif
 		error = priv_check(req->td, PRIV_MSGBUF);
 		if (error)
 			return (error);
@@ -1030,9 +1037,9 @@ sysctl_kern_msgbuf(SYSCTL_HANDLER_ARGS)
 	}
 }
 
-SYSCTL_PROC(_kern, OID_AUTO, msgbuf,
+_SYSCTL_PROC(_kern, OID_AUTO, msgbuf,
     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
-    NULL, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer");
+    NULL, 0, sysctl_kern_msgbuf, "A", "Contents of kernel message buffer", VPS_PUBLIC);
 
 static int msgbuf_clearflag;
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/subr_smp.c head/sys/kern/subr_smp.c
--- clean-head/sys/kern/subr_smp.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/subr_smp.c	2013-06-24 14:20:31.000000000 +0200
@@ -78,21 +78,21 @@ static SYSCTL_NODE(_kern, OID_AUTO, smp,
 SYSCTL_INT(_kern_smp, OID_AUTO, maxid, CTLFLAG_RD|CTLFLAG_CAPRD, &mp_maxid, 0,
     "Max CPU ID.");
 
-SYSCTL_INT(_kern_smp, OID_AUTO, maxcpus, CTLFLAG_RD|CTLFLAG_CAPRD, &mp_maxcpus,
-    0, "Max number of CPUs that the system was compiled for.");
+_SYSCTL_INT(_kern_smp, OID_AUTO, maxcpus, CTLFLAG_RD|CTLFLAG_CAPRD, &mp_maxcpus,
+    0, "Max number of CPUs that the system was compiled for.", VPS_PUBLIC);
 
 int smp_active = 0;	/* are the APs allowed to run? */
-SYSCTL_INT(_kern_smp, OID_AUTO, active, CTLFLAG_RW, &smp_active, 0,
-    "Number of Auxillary Processors (APs) that were successfully started");
+_SYSCTL_INT(_kern_smp, OID_AUTO, active, CTLFLAG_RW, &smp_active, 0,
+    "Number of Auxillary Processors (APs) that were successfully started", VPS_PUBLIC);
 
 int smp_disabled = 0;	/* has smp been disabled? */
-SYSCTL_INT(_kern_smp, OID_AUTO, disabled, CTLFLAG_RDTUN|CTLFLAG_CAPRD,
-    &smp_disabled, 0, "SMP has been disabled from the loader");
+_SYSCTL_INT(_kern_smp, OID_AUTO, disabled, CTLFLAG_RDTUN|CTLFLAG_CAPRD,
+    &smp_disabled, 0, "SMP has been disabled from the loader", VPS_PUBLIC);
 TUNABLE_INT("kern.smp.disabled", &smp_disabled);
 
 int smp_cpus = 1;	/* how many cpu's running */
-SYSCTL_INT(_kern_smp, OID_AUTO, cpus, CTLFLAG_RD|CTLFLAG_CAPRD, &smp_cpus, 0,
-    "Number of CPUs online");
+_SYSCTL_INT(_kern_smp, OID_AUTO, cpus, CTLFLAG_RD|CTLFLAG_CAPRD, &smp_cpus, 0,
+    "Number of CPUs online", VPS_PUBLIC);
 
 int smp_topology = 0;	/* Which topology we're using. */
 SYSCTL_INT(_kern_smp, OID_AUTO, topology, CTLFLAG_RD, &smp_topology, 0,
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/subr_syscall.c head/sys/kern/subr_syscall.c
--- clean-head/sys/kern/subr_syscall.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/subr_syscall.c	2013-06-24 14:20:31.000000000 +0200
@@ -52,6 +52,11 @@ __FBSDID("$FreeBSD: head/sys/kern/subr_s
 #endif
 #include <security/audit/audit.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#define _VPS_MD_FUNCTIONS
+#include <machine/vps_md.h>
+
 static inline int
 syscallenter(struct thread *td, struct syscall_args *sa)
 {
@@ -150,6 +155,31 @@ syscallenter(struct thread *td, struct s
 #endif
 		syscall_thread_exit(td, sa->callp);
 	}
+
+#ifdef VPS
+	/*
+	 * If thread was suspended by VPS vps_suspend, suspend it now
+	 * without any syscall error processing.
+	 *
+	 * XXX error/td_errno hack
+	 */
+	if (td->td_flags & TDF_VPSSUSPEND) {
+		DBGCORE("%s: td=%p suspending\n", __func__, td);
+		td->td_errno = error;
+		if (td->td_flags & TDF_NEEDSUSPCHK) {
+			PROC_LOCK(td->td_proc);
+			thread_suspend_check(0);
+			/*
+			 * Threads created by vps_restore() never
+			 * reach this point.
+			 */
+			PROC_UNLOCK(td->td_proc);
+		}
+		td->td_flags &= ~TDF_VPSSUSPEND;
+		error = td->td_errno;
+	}
+#endif
+
  retval:
 	KTR_STOP4(KTR_SYSC, "syscall", syscallname(p, sa->code),
 	    (uintptr_t)td, "pid:%d", td->td_proc->p_pid, "error:%d", error,
@@ -228,8 +258,52 @@ syscallret(struct thread *td, int error,
 		td->td_pflags &= ~TDP_RFPPWAIT;
 		p2 = td->td_rfppwait_p;
 		PROC_LOCK(p2);
+#ifdef VPS
+		while (p2->p_flag & P_PPWAIT) {
+			cv_wait(&p2->p_pwait, &p2->p_mtx);
+			if (td->td_flags & TDF_VPSSUSPEND)
+				break;
+		}
+#else
 		while (p2->p_flag & P_PPWAIT)
 			cv_wait(&p2->p_pwait, &p2->p_mtx);
+#endif /* !VPS */
 		PROC_UNLOCK(p2);
 	}
+
+#ifdef VPS
+	/*
+	 * Have to duplicate this code block from syscallenter()
+	 * here because of above TDP_RFPPWAIT check.
+	 * 
+	 * syscallenter() calls sv_set_syscall_retval(), which
+	 * overwrites trapframe->tf_rax (the syscall number).
+	 */
+	/*
+	 * If thread was suspended by VPS vps_suspend, suspend it now
+	 * without any syscall error processing.
+	 *
+	 * XXX error/td_errno hack
+	 */
+	if (td->td_flags & TDF_VPSSUSPEND) {
+		DBGCORE("%s: td=%p suspending\n", __func__, td);
+
+		vps_md_syscallret(td, sa);
+
+		td->td_errno = error = EINTR;
+		td->td_errno = error;
+		if (td->td_flags & TDF_NEEDSUSPCHK) {
+			PROC_LOCK(td->td_proc);
+			thread_suspend_check(0);
+			/*
+			 * Threads created by vps_restore() never
+			 * reach this point.
+			 */
+			PROC_UNLOCK(td->td_proc);
+		}
+		td->td_flags &= ~TDF_VPSSUSPEND;
+		error = td->td_errno;
+	}
+#endif
+
 }
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/subr_trap.c head/sys/kern/subr_trap.c
--- clean-head/sys/kern/subr_trap.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/subr_trap.c	2013-06-24 14:20:31.000000000 +0200
@@ -176,6 +176,16 @@ userret(struct thread *td, struct trapfr
 		msleep(p->p_racct, &p->p_mtx, 0, "racct", 0);
 	PROC_UNLOCK(p);
 #endif
+#ifdef VPS
+	/*
+	KASSERT(td->td_vps == NULL || td->td_vps == td->td_ucred->cr_vps,
+		("%s: bad vps ref: td=%p, td->td_vps=%p, td->td_ucred->cr_vps=%p\n",
+		__func__, td, td->td_vps, td->td_ucred->cr_vps));
+	*/
+	KASSERT(td->td_vps != NULL && td->td_vps == td->td_ucred->cr_vps,
+		("%s: bad vps ref: td=%p, td->td_vps=%p, td->td_ucred->cr_vps=%p\n",
+		__func__, td, td->td_vps, td->td_ucred->cr_vps));
+#endif
 }
 
 /*
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/subr_turnstile.c head/sys/kern/subr_turnstile.c
--- clean-head/sys/kern/subr_turnstile.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/subr_turnstile.c	2013-06-24 14:20:31.000000000 +0200
@@ -78,6 +78,8 @@ __FBSDID("$FreeBSD: head/sys/kern/subr_t
 #include <sys/sysctl.h>
 #include <sys/turnstile.h>
 
+#include <vps/vps.h>
+
 #include <vm/uma.h>
 
 #ifdef DDB
@@ -250,6 +252,21 @@ propagate_priority(struct thread *td)
 			thread_unlock(td);
 			return;
 		}
+#ifdef VPS
+		/*
+		 * Td is suspended in order to maintain resource limits.
+		 * Since threads are only suspended if they don't own
+		 * locks, the only possible case is that td _was_
+		 * blocking on a turnstile, was woken up again
+		 * but wasn't scheduled to actually run yet.
+		 */
+		if (td->td_flags & TDF_VPSLIMIT) {
+			MPASS(td->td_blocked == NULL);
+			MPASS(td->td_turnstile != NULL);
+			thread_unlock(td);
+			return;
+		}
+#endif
 
 #ifndef SMP
 		/*
@@ -262,6 +279,11 @@ propagate_priority(struct thread *td)
 		/*
 		 * If we aren't blocked on a lock, we should be.
 		 */
+		if (TD_ON_LOCK(td) == 0) {
+			printf("%s: thread=%p proc=%p pid=%d procname=[%s] td->prio=%d prio=%d\n",
+				__func__, td, td->td_proc, td->td_proc->p_pid,
+				td->td_proc->p_comm, td->td_priority, pri);
+		}
 		KASSERT(TD_ON_LOCK(td), (
 		    "thread %d(%s):%d holds %s but isn't blocked on a lock\n",
 		    td->td_tid, td->td_name, td->td_state,
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/subr_witness.c head/sys/kern/subr_witness.c
--- clean-head/sys/kern/subr_witness.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/subr_witness.c	2013-06-24 14:20:31.000000000 +0200
@@ -108,6 +108,8 @@ __FBSDID("$FreeBSD: head/sys/kern/subr_w
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 
+#include <vps/vps.h>
+
 #ifdef DDB
 #include <ddb/ddb.h>
 #endif
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/sys_generic.c head/sys/kern/sys_generic.c
--- clean-head/sys/kern/sys_generic.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/sys_generic.c	2013-06-24 14:20:31.000000000 +0200
@@ -86,7 +86,11 @@ SYSCTL_INT(_debug, OID_AUTO, iosize_max_
 CTASSERT(sizeof(register_t) >= sizeof(size_t));
 
 static MALLOC_DEFINE(M_IOCTLOPS, "ioctlops", "ioctl data buffer");
+#ifdef VPS
+MALLOC_DEFINE(M_SELECT, "select", "select() buffer");
+#else
 static MALLOC_DEFINE(M_SELECT, "select", "select() buffer");
+#endif
 MALLOC_DEFINE(M_IOV, "iov", "large iov's");
 
 static int	pollout(struct thread *, struct pollfd *, struct pollfd *,
@@ -95,13 +99,16 @@ static int	pollscan(struct thread *, str
 static int	pollrescan(struct thread *);
 static int	selscan(struct thread *, fd_mask **, fd_mask **, int);
 static int	selrescan(struct thread *, fd_mask **, fd_mask **);
+#ifndef VPS
 static void	selfdalloc(struct thread *, void *);
 static void	selfdfree(struct seltd *, struct selfd *);
+#endif
 static int	dofileread(struct thread *, int, struct file *, struct uio *,
 		    off_t, int);
 static int	dofilewrite(struct thread *, int, struct file *, struct uio *,
 		    off_t, int);
 static void	doselwakeup(struct selinfo *, int);
+#ifndef VPS
 static void	seltdinit(struct thread *);
 static int	seltdwait(struct thread *, sbintime_t, sbintime_t);
 static void	seltdclear(struct thread *);
@@ -136,8 +143,13 @@ struct selfd {
 	struct seltd		*sf_td;		/* (k) owning seltd. */
 	void			*sf_cookie;	/* (k) fd or pollfd. */
 };
+#endif
 
+#ifdef VPS
+uma_zone_t selfd_zone;
+#else
 static uma_zone_t selfd_zone;
+#endif
 static struct mtx_pool *mtxpool_select;
 
 #ifndef _SYS_SYSPROTO_H_
@@ -1501,7 +1513,11 @@ sys_openbsd_poll(td, uap)
  * Preallocate two selfds associated with 'cookie'.  Some fo_poll routines
  * have two select sets, one for read and another for write.
  */
+#ifdef VPS
+void
+#else
 static void
+#endif
 selfdalloc(struct thread *td, void *cookie)
 {
 	struct seltd *stp;
@@ -1517,7 +1533,11 @@ selfdalloc(struct thread *td, void *cook
 	stp->st_free2->sf_cookie = cookie;
 }
 
+#ifdef VPS
+void
+#else
 static void
+#endif
 selfdfree(struct seltd *stp, struct selfd *sfp)
 {
 	STAILQ_REMOVE(&stp->st_selq, sfp, selfd, sf_link);
@@ -1649,7 +1669,11 @@ doselwakeup(sip, pri)
 	mtx_unlock(sip->si_mtx);
 }
 
+#ifdef VPS
+void
+#else
 static void
+#endif
 seltdinit(struct thread *td)
 {
 	struct seltd *stp;
@@ -1664,7 +1688,11 @@ out:
 	STAILQ_INIT(&stp->st_selq);
 }
 
+#ifdef VPS
+int
+#else
 static int
+#endif
 seltdwait(struct thread *td, sbintime_t sbt, sbintime_t precision)
 {
 	struct seltd *stp;
@@ -1716,7 +1744,11 @@ seltdfini(struct thread *td)
  * Remove the references to the thread from all of the objects we were
  * polling.
  */
+#ifdef VPS
+void
+#else
 static void
+#endif
 seltdclear(struct thread *td)
 {
 	struct seltd *stp;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/sys_process.c head/sys/kern/sys_process.c
--- clean-head/sys/kern/sys_process.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/sys_process.c	2013-06-24 14:20:31.000000000 +0200
@@ -62,6 +62,8 @@ __FBSDID("$FreeBSD: head/sys/kern/sys_pr
 #include <vm/vm_page.h>
 #include <vm/vm_param.h>
 
+#include <vps/vps.h>
+
 #ifdef COMPAT_FREEBSD32
 #include <sys/procfs.h>
 #include <compat/freebsd32/freebsd32_signal.h>
@@ -659,7 +661,7 @@ kern_ptrace(struct thread *td, int req, 
 	case PT_SYSCALL:
 	case PT_FOLLOW_FORK:
 	case PT_DETACH:
-		sx_xlock(&proctree_lock);
+		sx_xlock(&V_proctree_lock);
 		proctree_locked = 1;
 		break;
 	default:
@@ -674,14 +676,14 @@ kern_ptrace(struct thread *td, int req, 
 		if (pid <= PID_MAX) {
 			if ((p = pfind(pid)) == NULL) {
 				if (proctree_locked)
-					sx_xunlock(&proctree_lock);
+					sx_xunlock(&V_proctree_lock);
 				return (ESRCH);
 			}
 		} else {
 			td2 = tdfind(pid, -1);
 			if (td2 == NULL) {
 				if (proctree_locked)
-					sx_xunlock(&proctree_lock);
+					sx_xunlock(&V_proctree_lock);
 				return (ESRCH);
 			}
 			p = td2->td_proc;
@@ -839,10 +841,23 @@ kern_ptrace(struct thread *td, int req, 
 		 * on a "detach".
 		 */
 		p->p_flag |= P_TRACED;
+#ifdef VPS
+		if (p->p_pptr == NULL) {
+			p->p_oppid = 0;
+			LIST_INSERT_HEAD(&td->td_proc->p_children, p, p_sibling);
+			p->p_pptr = td->td_proc;
+		} else {
+			p->p_oppid = p->p_pptr->p_pid;
+			if (p->p_pptr != td->td_proc) {
+				proc_reparent(p, td->td_proc);
+			}
+		}
+#else
 		p->p_oppid = p->p_pptr->p_pid;
 		if (p->p_pptr != td->td_proc) {
 			proc_reparent(p, td->td_proc);
 		}
+#endif /* !VPS */
 		data = SIGSTOP;
 		goto sendsig;	/* in PT_CONTINUE below */
 
@@ -914,6 +929,16 @@ kern_ptrace(struct thread *td, int req, 
 			break;
 		case PT_DETACH:
 			/* reset process parent */
+#ifdef VPS
+			if (p->p_oppid == 0) {
+				PROC_LOCK(p->p_pptr);
+				sigqueue_take(p->p_ksi);
+				PROC_UNLOCK(p->p_pptr);
+
+				LIST_REMOVE(p, p_sibling);
+				p->p_pptr = NULL;
+			} else 
+#endif /* VPS */
 			if (p->p_oppid != p->p_pptr->p_pid) {
 				struct proc *pp;
 
@@ -924,12 +949,12 @@ kern_ptrace(struct thread *td, int req, 
 				PROC_UNLOCK(p);
 				pp = pfind(p->p_oppid);
 				if (pp == NULL)
-					pp = initproc;
+					pp = V_initproc;
 				else
 					PROC_UNLOCK(pp);
 				PROC_LOCK(p);
 				proc_reparent(p, pp);
-				if (pp == initproc)
+				if (pp == V_initproc)
 					p->p_sigparent = SIGCHLD;
 			}
 			p->p_oppid = 0;
@@ -942,7 +967,7 @@ kern_ptrace(struct thread *td, int req, 
 
 	sendsig:
 		if (proctree_locked) {
-			sx_xunlock(&proctree_lock);
+			sx_xunlock(&V_proctree_lock);
 			proctree_locked = 0;
 		}
 		p->p_xstat = data;
@@ -1215,7 +1240,7 @@ out:
 fail:
 	PROC_UNLOCK(p);
 	if (proctree_locked)
-		sx_xunlock(&proctree_lock);
+		sx_xunlock(&V_proctree_lock);
 	return (error);
 }
 #undef PROC_READ
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/sysv_msg.c head/sys/kern/sysv_msg.c
--- clean-head/sys/kern/sysv_msg.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/sysv_msg.c	2013-06-24 14:20:31.000000000 +0200
@@ -46,6 +46,19 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*-
+ * VPS adaption:
+ *
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * <BSD license>
+ *
+ * $Id: sysv_msg.c 162 2013-06-06 18:17:55Z klaus $
+ */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: head/sys/kern/sysv_msg.c 225617 2011-09-16 13:58:51Z kmacy $");
@@ -62,14 +75,21 @@ __FBSDID("$FreeBSD: head/sys/kern/sysv_m
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/module.h>
+#include <sys/sysctl.h>
 #include <sys/msg.h>
 #include <sys/racct.h>
 #include <sys/syscall.h>
 #include <sys/syscallsubr.h>
 #include <sys/sysent.h>
-#include <sys/sysctl.h>
 #include <sys/malloc.h>
 #include <sys/jail.h>
+#include <sys/eventhandler.h>
+
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#include <vps/vps_int.h>
+#include <vps/vps_libdump.h>
+#include <vps/vps_snapst.h>
 
 #include <security/mac/mac_framework.h>
 
@@ -78,6 +98,7 @@ FEATURE(sysv_msg, "System V message queu
 static MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
 
 static int msginit(void);
+static int msginit2(void);
 static int msgunload(void);
 static int sysvmsg_modload(struct module *, int, void *);
 
@@ -117,6 +138,7 @@ static void msg_freehdr(struct msg *msgh
  * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
  * two between 8 and 1024 inclusive (and panic's if it isn't).
  */
+#if 0
 struct msginfo msginfo = {
                 MSGMAX,         /* max chars in a message */
                 MSGMNI,         /* # of message queue identifiers */
@@ -126,6 +148,7 @@ struct msginfo msginfo = {
                 		/* (must be small power of 2 greater than 4) */
                 MSGSEG          /* number of message segments */
 };
+#endif
 
 /*
  * macros to convert between msqid_ds's and msqid's.
@@ -147,6 +170,7 @@ struct msgmap {
 
 #define MSG_LOCKED	01000	/* Is this msqid_ds locked? */
 
+#if 0
 static int nfree_msgmaps;	/* # of free map entries */
 static short free_msgmaps;	/* head of linked list of free map entries */
 static struct msg *free_msghdrs;/* list of free msg headers */
@@ -155,6 +179,27 @@ static struct msgmap *msgmaps;	/* MSGSEG
 static struct msg *msghdrs;	/* MSGTQL msg headers */
 static struct msqid_kernel *msqids;	/* MSGMNI msqid_kernel struct's */
 static struct mtx msq_mtx;	/* global mutex for message queues. */
+#endif
+
+VPS_DEFINE(int, nfree_msgmaps);
+VPS_DEFINE(short, free_msgmaps);
+VPS_DEFINE(struct msg *, free_msghdrs);
+VPS_DEFINE(char *, msgpool);
+VPS_DEFINE(struct msgmap *, msgmaps);
+VPS_DEFINE(struct msg *, msghdrs);
+VPS_DEFINE(struct msqid_kernel *, msqids);
+VPS_DEFINE(struct mtx, msq_mtx);
+VPS_DEFINE(struct msginfo, msginfo);
+
+#define V_nfree_msgmaps	VPSV(nfree_msgmaps)
+#define V_free_msgmaps	VPSV(free_msgmaps)
+#define V_free_msghdrs	VPSV(free_msghdrs)
+#define V_msgpool	VPSV(msgpool)
+#define V_msgmaps	VPSV(msgmaps)
+#define V_msghdrs	VPSV(msghdrs)
+#define	V_msqids	VPSV(msqids)
+#define V_msq_mtx	VPSV(msq_mtx)
+#define V_msginfo	VPSV(msginfo)
 
 static struct syscall_helper_data msg_syscalls[] = {
 	SYSCALL_INIT_HELPER(msgctl),
@@ -189,25 +234,153 @@ static struct syscall_helper_data msg32_
 #endif
 	SYSCALL_INIT_LAST
 };
+#endif /* COMPAT_FREEBSD32 */
+
+#ifdef VPS
+static u_int nmsgmaps_global;
+static eventhandler_tag msg_vpsalloc_tag;
+static eventhandler_tag msg_vpsfree_tag;
+
+int msg_snapshot_vps(struct vps_snapst_ctx *ctx, struct vps *vps);
+int msg_snapshot_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc* proc);
+int msg_restore_vps(struct vps_snapst_ctx *ctx, struct vps *vps);
+int msg_restore_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc* proc);
+int msg_restore_fixup(struct vps_snapst_ctx *ctx, struct vps *vps);
+
+static void
+msg_vpsalloc_hook(void *arg, struct vps *vps)
+{
+
+	DPRINTF(("%s: vps=%p\n", __func__, vps));
+
+	vps_ref(vps, NULL);
+
+	msginit();
+}
+
+static void
+msg_vpsfree_hook(void *arg, struct vps *vps)
+{
+
+	DPRINTF(("%s: vps=%p\n", __func__, vps));
+
+	if (msgunload())
+		printf("%s: msgunload() error\n", __func__);
+
+	vps_deref(vps, NULL);
+}
+
+static int
+msginit_global(void)
+{
+	struct vps *vps, *save_vps;
+	int error;
+
+	save_vps = curthread->td_vps;
+
+	nmsgmaps_global = 0;
+
+	sx_slock(&vps_all_lock);
+	LIST_FOREACH(vps, &vps_head, vps_all) {
+		curthread->td_vps = vps;
+		msg_vpsalloc_hook(NULL, vps);
+		curthread->td_vps = save_vps;
+	}
+	sx_sunlock(&vps_all_lock);
+
+	msg_vpsalloc_tag = EVENTHANDLER_REGISTER(vps_alloc, msg_vpsalloc_hook, NULL,
+		EVENTHANDLER_PRI_ANY);
+	msg_vpsfree_tag = EVENTHANDLER_REGISTER(vps_free, msg_vpsfree_hook, NULL,
+		EVENTHANDLER_PRI_ANY);
+
+	vps_func->msg_snapshot_vps = msg_snapshot_vps;
+	vps_func->msg_snapshot_proc = msg_snapshot_proc;
+	vps_func->msg_restore_vps = msg_restore_vps;
+	vps_func->msg_restore_proc = msg_restore_proc;
+	vps_func->msg_restore_fixup = msg_restore_fixup;
+
+	error = syscall_helper_register(msg_syscalls);
+	if (error != 0)
+		return (error);
+	#ifdef COMPAT_FREEBSD32
+	error = syscall32_helper_register(msg32_syscalls);
+	if (error != 0)
+		return (error);
+	#endif
+	return (error);
+}
+
+static int
+msgunload_global(void)
+{
+	struct vps *vps, *save_vps;
+
+	save_vps = curthread->td_vps;
+
+	if (nmsgmaps_global > 0)
+		return (EBUSY);
+
+	syscall_helper_unregister(msg_syscalls);
+#ifdef COMPAT_FREEBSD32
+	syscall32_helper_unregister(msg32_syscalls);
 #endif
 
+	vps_func->msg_snapshot_vps = NULL;
+	vps_func->msg_snapshot_proc = NULL;
+	vps_func->msg_restore_vps = NULL;
+	vps_func->msg_restore_proc = NULL;
+	vps_func->msg_restore_fixup = NULL;
+
+	EVENTHANDLER_DEREGISTER(vps_alloc, msg_vpsalloc_tag);
+	EVENTHANDLER_DEREGISTER(vps_free, msg_vpsfree_tag);
+
+	sx_slock(&vps_all_lock);
+	LIST_FOREACH(vps, &vps_head, vps_all) {
+		curthread->td_vps = vps;
+		if (VPS_VPS(vps, msgpool))
+			msg_vpsfree_hook(NULL, vps);
+		curthread->td_vps = save_vps;
+	}
+	sx_sunlock(&vps_all_lock);
+
+	return (0);
+}
+#endif /* VPS */
+
 static int
 msginit()
 {
-	int i, error;
 
-	TUNABLE_INT_FETCH("kern.ipc.msgseg", &msginfo.msgseg);
-	TUNABLE_INT_FETCH("kern.ipc.msgssz", &msginfo.msgssz);
-	msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
-	TUNABLE_INT_FETCH("kern.ipc.msgmni", &msginfo.msgmni);
-	TUNABLE_INT_FETCH("kern.ipc.msgmnb", &msginfo.msgmnb);
-	TUNABLE_INT_FETCH("kern.ipc.msgtql", &msginfo.msgtql);
-
-	msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
-	msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
-	msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
-	msqids = malloc(sizeof(struct msqid_kernel) * msginfo.msgmni, M_MSG,
-	    M_WAITOK);
+	V_msginfo.msgmax = MSGMAX;
+	V_msginfo.msgmni = MSGMNI;
+	V_msginfo.msgmnb = MSGMNB;
+	V_msginfo.msgtql = MSGTQL;
+	V_msginfo.msgssz = MSGSSZ;
+	V_msginfo.msgseg = MSGSEG;
+
+	TUNABLE_INT_FETCH("kern.ipc.msgseg", &V_msginfo.msgseg);
+	TUNABLE_INT_FETCH("kern.ipc.msgssz", &V_msginfo.msgssz);
+	V_msginfo.msgmax = V_msginfo.msgseg * V_msginfo.msgssz;
+	TUNABLE_INT_FETCH("kern.ipc.msgmni", &V_msginfo.msgmni);
+	TUNABLE_INT_FETCH("kern.ipc.msgmnb", &V_msginfo.msgmnb);
+	TUNABLE_INT_FETCH("kern.ipc.msgtql", &V_msginfo.msgtql);
+
+	return (msginit2());
+}
+
+static int
+msginit2()
+{
+	int i;
+#ifndef VPS
+	int error;
+#endif
+
+	V_msgpool = malloc(V_msginfo.msgmax, M_MSG, M_WAITOK);
+	V_msgmaps = malloc(sizeof(struct msgmap) * V_msginfo.msgseg, M_MSG, M_WAITOK);
+	V_msghdrs = malloc(sizeof(struct msg) * V_msginfo.msgtql, M_MSG, M_WAITOK);
+	V_msqids = malloc(sizeof(struct msqid_kernel) * V_msginfo.msgmni, M_MSG,
+		M_WAITOK);
 
 	/*
 	 * msginfo.msgssz should be a power of two for efficiency reasons.
@@ -216,48 +389,50 @@ msginit()
 	 */
 
 	i = 8;
-	while (i < 1024 && i != msginfo.msgssz)
+	while (i < 1024 && i != V_msginfo.msgssz)
 		i <<= 1;
-    	if (i != msginfo.msgssz) {
-		DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
-		    msginfo.msgssz));
+    	if (i != V_msginfo.msgssz) {
+		DPRINTF(("msginfo.msgssz=%d (0x%x)\n", V_msginfo.msgssz,
+		    V_msginfo.msgssz));
 		panic("msginfo.msgssz not a small power of 2");
 	}
 
-	if (msginfo.msgseg > 32767) {
-		DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
+	if (V_msginfo.msgseg > 32767) {
+		DPRINTF(("msginfo.msgseg=%d\n", V_msginfo.msgseg));
 		panic("msginfo.msgseg > 32767");
 	}
 
-	for (i = 0; i < msginfo.msgseg; i++) {
+	for (i = 0; i < V_msginfo.msgseg; i++) {
 		if (i > 0)
-			msgmaps[i-1].next = i;
-		msgmaps[i].next = -1;	/* implies entry is available */
+			V_msgmaps[i-1].next = i;
+		V_msgmaps[i].next = -1;	/* implies entry is available */
 	}
-	free_msgmaps = 0;
-	nfree_msgmaps = msginfo.msgseg;
+	V_free_msgmaps = 0;
+	V_nfree_msgmaps = V_msginfo.msgseg;
 
-	for (i = 0; i < msginfo.msgtql; i++) {
-		msghdrs[i].msg_type = 0;
+	for (i = 0; i < V_msginfo.msgtql; i++) {
+		V_msghdrs[i].msg_type = 0;
 		if (i > 0)
-			msghdrs[i-1].msg_next = &msghdrs[i];
-		msghdrs[i].msg_next = NULL;
+			V_msghdrs[i-1].msg_next = &V_msghdrs[i];
+		V_msghdrs[i].msg_next = NULL;
 #ifdef MAC
-		mac_sysvmsg_init(&msghdrs[i]);
+		mac_sysvmsg_init(&V_msghdrs[i]);
 #endif
     	}
-	free_msghdrs = &msghdrs[0];
+	V_free_msghdrs = &V_msghdrs[0];
 
-	for (i = 0; i < msginfo.msgmni; i++) {
-		msqids[i].u.msg_qbytes = 0;	/* implies entry is available */
-		msqids[i].u.msg_perm.seq = 0;	/* reset to a known value */
-		msqids[i].u.msg_perm.mode = 0;
+	for (i = 0; i < V_msginfo.msgmni; i++) {
+		V_msqids[i].u.msg_qbytes = 0;	/* implies entry is available */
+		V_msqids[i].u.msg_perm.seq = 0;	/* reset to a known value */
+		V_msqids[i].u.msg_perm.mode = 0;
+		V_msqids[i].cred = NULL;
 #ifdef MAC
-		mac_sysvmsq_init(&msqids[i]);
+		mac_sysvmsq_init(&V_msqids[i]);
 #endif
 	}
-	mtx_init(&msq_mtx, "msq", NULL, MTX_DEF);
+	mtx_init(&V_msq_mtx, "msq", NULL, MTX_DEF);
 
+#ifndef VPS
 	error = syscall_helper_register(msg_syscalls);
 	if (error != 0)
 		return (error);
@@ -266,6 +441,7 @@ msginit()
 	if (error != 0)
 		return (error);
 #endif
+#endif /* VPS */
 	return (0);
 }
 
@@ -278,37 +454,47 @@ msgunload()
 	int i;
 #endif
 
+#ifndef VPS
 	syscall_helper_unregister(msg_syscalls);
 #ifdef COMPAT_FREEBSD32
 	syscall32_helper_unregister(msg32_syscalls);
 #endif
+#endif /* VPS */
 
-	for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
+	for (msqid = 0; msqid < V_msginfo.msgmni; msqid++) {
 		/*
 		 * Look for an unallocated and unlocked msqid_ds.
 		 * msqid_ds's can be locked by msgsnd or msgrcv while
 		 * they are copying the message in/out.  We can't
 		 * re-use the entry until they release it.
 		 */
-		msqkptr = &msqids[msqid];
+		msqkptr = &V_msqids[msqid];
 		if (msqkptr->u.msg_qbytes != 0 ||
 		    (msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
 			break;
 	}
-	if (msqid != msginfo.msgmni)
+
+	for (msqid = 0; msqid < V_msginfo.msgmni; msqid++) {
+		if (V_msqids[msqid].cred != NULL)
+			crfree(V_msqids[msqid].cred);
+	}
+#ifndef VPS
+	/* For VPS, just kill everything silently. */
+	if (msqid != V_msginfo.msgmni)
 		return (EBUSY);
+#endif
 
 #ifdef MAC
-	for (i = 0; i < msginfo.msgtql; i++)
-		mac_sysvmsg_destroy(&msghdrs[i]);
-	for (msqid = 0; msqid < msginfo.msgmni; msqid++)
-		mac_sysvmsq_destroy(&msqids[msqid]);
-#endif
-	free(msgpool, M_MSG);
-	free(msgmaps, M_MSG);
-	free(msghdrs, M_MSG);
-	free(msqids, M_MSG);
-	mtx_destroy(&msq_mtx);
+	for (i = 0; i < V_msginfo.msgtql; i++)
+		mac_sysvmsg_destroy(&V_msghdrs[i]);
+	for (msqid = 0; msqid < V_msginfo.msgmni; msqid++)
+		mac_sysvmsq_destroy(&V_msqids[msqid]);
+#endif
+	free(V_msgpool, M_MSG);
+	free(V_msgmaps, M_MSG);
+	free(V_msghdrs, M_MSG);
+	free(V_msqids, M_MSG);
+	mtx_destroy(&V_msq_mtx);
 	return (0);
 }
 
@@ -320,12 +506,22 @@ sysvmsg_modload(struct module *module, i
 
 	switch (cmd) {
 	case MOD_LOAD:
+#ifdef VPS
+		error = msginit_global();
+		if (error != 0)
+			msgunload_global();
+#else
 		error = msginit();
 		if (error != 0)
 			msgunload();
+#endif
 		break;
 	case MOD_UNLOAD:
+#ifdef VPS
+		error = msgunload_global();
+#else
 		error = msgunload();
+#endif
 		break;
 	case MOD_SHUTDOWN:
 		break;
@@ -351,22 +547,25 @@ msg_freehdr(msghdr)
 {
 	while (msghdr->msg_ts > 0) {
 		short next;
-		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
+		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= V_msginfo.msgseg)
 			panic("msghdr->msg_spot out of range");
-		next = msgmaps[msghdr->msg_spot].next;
-		msgmaps[msghdr->msg_spot].next = free_msgmaps;
-		free_msgmaps = msghdr->msg_spot;
-		nfree_msgmaps++;
+		next = V_msgmaps[msghdr->msg_spot].next;
+		V_msgmaps[msghdr->msg_spot].next = V_free_msgmaps;
+		V_free_msgmaps = msghdr->msg_spot;
+		V_nfree_msgmaps++;
+#ifdef VPS
+		atomic_subtract_int(&nmsgmaps_global, 1);
+#endif
 		msghdr->msg_spot = next;
-		if (msghdr->msg_ts >= msginfo.msgssz)
-			msghdr->msg_ts -= msginfo.msgssz;
+		if (msghdr->msg_ts >= V_msginfo.msgssz)
+			msghdr->msg_ts -= V_msginfo.msgssz;
 		else
 			msghdr->msg_ts = 0;
 	}
 	if (msghdr->msg_spot != -1)
 		panic("msghdr->msg_spot != -1");
-	msghdr->msg_next = free_msghdrs;
-	free_msghdrs = msghdr;
+	msghdr->msg_next = V_free_msghdrs;
+	V_free_msghdrs = msghdr;
 #ifdef MAC
 	mac_sysvmsg_cleanup(msghdr);
 #endif
@@ -414,15 +613,15 @@ kern_msgctl(td, msqid, cmd, msqbuf)
 
 	msqix = IPCID_TO_IX(msqid);
 
-	if (msqix < 0 || msqix >= msginfo.msgmni) {
+	if (msqix < 0 || msqix >= V_msginfo.msgmni) {
 		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
-		    msginfo.msgmni));
+		    V_msginfo.msgmni));
 		return (EINVAL);
 	}
 
-	msqkptr = &msqids[msqix];
+	msqkptr = &V_msqids[msqix];
 
-	mtx_lock(&msq_mtx);
+	mtx_lock(&V_msq_mtx);
 	if (msqkptr->u.msg_qbytes == 0) {
 		DPRINTF(("no such msqid\n"));
 		error = EINVAL;
@@ -511,10 +710,10 @@ kern_msgctl(td, msqid, cmd, msqbuf)
 			if (error)
 				goto done2;
 		}
-		if (msqbuf->msg_qbytes > msginfo.msgmnb) {
+		if (msqbuf->msg_qbytes > V_msginfo.msgmnb) {
 			DPRINTF(("can't increase msg_qbytes beyond %d"
-			    "(truncating)\n", msginfo.msgmnb));
-			msqbuf->msg_qbytes = msginfo.msgmnb;	/* silently restrict qbytes to system limit */
+			    "(truncating)\n", V_msginfo.msgmnb));
+			msqbuf->msg_qbytes = V_msginfo.msgmnb;	/* silently restrict qbytes to system limit */
 		}
 		if (msqbuf->msg_qbytes == 0) {
 			DPRINTF(("can't reduce msg_qbytes to 0\n"));
@@ -546,7 +745,7 @@ kern_msgctl(td, msqid, cmd, msqbuf)
 	if (error == 0)
 		td->td_retval[0] = rval;
 done2:
-	mtx_unlock(&msq_mtx);
+	mtx_unlock(&V_msq_mtx);
 	return (error);
 }
 
@@ -573,15 +772,15 @@ sys_msgget(td, uap)
 	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
 		return (ENOSYS);
 
-	mtx_lock(&msq_mtx);
+	mtx_lock(&V_msq_mtx);
 	if (key != IPC_PRIVATE) {
-		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
-			msqkptr = &msqids[msqid];
+		for (msqid = 0; msqid < V_msginfo.msgmni; msqid++) {
+			msqkptr = &V_msqids[msqid];
 			if (msqkptr->u.msg_qbytes != 0 &&
 			    msqkptr->u.msg_perm.key == key)
 				break;
 		}
-		if (msqid < msginfo.msgmni) {
+		if (msqid < V_msginfo.msgmni) {
 			DPRINTF(("found public key\n"));
 			if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
 				DPRINTF(("not exclusive\n"));
@@ -605,19 +804,19 @@ sys_msgget(td, uap)
 
 	DPRINTF(("need to allocate the msqid_ds\n"));
 	if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
-		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
+		for (msqid = 0; msqid < V_msginfo.msgmni; msqid++) {
 			/*
 			 * Look for an unallocated and unlocked msqid_ds.
 			 * msqid_ds's can be locked by msgsnd or msgrcv while
 			 * they are copying the message in/out.  We can't
 			 * re-use the entry until they release it.
 			 */
-			msqkptr = &msqids[msqid];
+			msqkptr = &V_msqids[msqid];
 			if (msqkptr->u.msg_qbytes == 0 &&
 			    (msqkptr->u.msg_perm.mode & MSG_LOCKED) == 0)
 				break;
 		}
-		if (msqid == msginfo.msgmni) {
+		if (msqid == V_msginfo.msgmni) {
 			DPRINTF(("no more msqid_ds's available\n"));
 			error = ENOSPC;
 			goto done2;
@@ -645,7 +844,7 @@ sys_msgget(td, uap)
 		msqkptr->u.msg_last = NULL;
 		msqkptr->u.msg_cbytes = 0;
 		msqkptr->u.msg_qnum = 0;
-		msqkptr->u.msg_qbytes = msginfo.msgmnb;
+		msqkptr->u.msg_qbytes = V_msginfo.msgmnb;
 		msqkptr->u.msg_lspid = 0;
 		msqkptr->u.msg_lrpid = 0;
 		msqkptr->u.msg_stime = 0;
@@ -664,7 +863,7 @@ found:
 	/* Construct the unique msqid */
 	td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqkptr->u.msg_perm);
 done2:
-	mtx_unlock(&msq_mtx);
+	mtx_unlock(&V_msq_mtx);
 	return (error);
 }
 
@@ -696,17 +895,17 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgf
 	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
 		return (ENOSYS);
 
-	mtx_lock(&msq_mtx);
+	mtx_lock(&V_msq_mtx);
 	msqix = IPCID_TO_IX(msqid);
 
-	if (msqix < 0 || msqix >= msginfo.msgmni) {
+	if (msqix < 0 || msqix >= V_msginfo.msgmni) {
 		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
-		    msginfo.msgmni));
+		    V_msginfo.msgmni));
 		error = EINVAL;
 		goto done2;
 	}
 
-	msqkptr = &msqids[msqix];
+	msqkptr = &V_msqids[msqix];
 	if (msqkptr->u.msg_qbytes == 0) {
 		DPRINTF(("no such message queue id\n"));
 		error = EINVAL;
@@ -746,9 +945,9 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgf
 	PROC_UNLOCK(td->td_proc);
 #endif
 
-	segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
+	segs_needed = (msgsz + V_msginfo.msgssz - 1) / V_msginfo.msgssz;
 	DPRINTF(("msgsz=%zu, msgssz=%d, segs_needed=%d\n", msgsz,
-	    msginfo.msgssz, segs_needed));
+	    V_msginfo.msgssz, segs_needed));
 	for (;;) {
 		int need_more_resources = 0;
 
@@ -771,11 +970,11 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgf
 			DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
 			need_more_resources = 1;
 		}
-		if (segs_needed > nfree_msgmaps) {
+		if (segs_needed > V_nfree_msgmaps) {
 			DPRINTF(("segs_needed > nfree_msgmaps\n"));
 			need_more_resources = 1;
 		}
-		if (free_msghdrs == NULL) {
+		if (V_free_msghdrs == NULL) {
 			DPRINTF(("no more msghdrs\n"));
 			need_more_resources = 1;
 		}
@@ -801,7 +1000,7 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgf
 				we_own_it = 1;
 			}
 			DPRINTF(("msgsnd:  goodnight\n"));
-			error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
+			error = msleep(msqkptr, &V_msq_mtx, (PZERO - 4) | PCATCH,
 			    "msgsnd", hz);
 			DPRINTF(("msgsnd:  good morning, error=%d\n", error));
 			if (we_own_it)
@@ -839,11 +1038,11 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgf
 
 	if (msqkptr->u.msg_perm.mode & MSG_LOCKED)
 		panic("msg_perm.mode & MSG_LOCKED");
-	if (segs_needed > nfree_msgmaps)
+	if (segs_needed > V_nfree_msgmaps)
 		panic("segs_needed > nfree_msgmaps");
 	if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes)
 		panic("msgsz + msg_cbytes > msg_qbytes");
-	if (free_msghdrs == NULL)
+	if (V_free_msghdrs == NULL)
 		panic("no more msghdrs");
 
 	/*
@@ -859,8 +1058,8 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgf
 	 * Allocate a message header
 	 */
 
-	msghdr = free_msghdrs;
-	free_msghdrs = msghdr->msg_next;
+	msghdr = V_free_msghdrs;
+	V_free_msghdrs = msghdr->msg_next;
 	msghdr->msg_spot = -1;
 	msghdr->msg_ts = msgsz;
 	msghdr->msg_type = mtype;
@@ -878,19 +1077,22 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgf
 	 */
 
 	while (segs_needed > 0) {
-		if (nfree_msgmaps <= 0)
+		if (V_nfree_msgmaps <= 0)
 			panic("not enough msgmaps");
-		if (free_msgmaps == -1)
+		if (V_free_msgmaps == -1)
 			panic("nil free_msgmaps");
-		next = free_msgmaps;
+		next = V_free_msgmaps;
 		if (next <= -1)
 			panic("next too low #1");
-		if (next >= msginfo.msgseg)
+		if (next >= V_msginfo.msgseg)
 			panic("next out of range #1");
 		DPRINTF(("allocating segment %d to message\n", next));
-		free_msgmaps = msgmaps[next].next;
-		nfree_msgmaps--;
-		msgmaps[next].next = msghdr->msg_spot;
+		V_free_msgmaps = V_msgmaps[next].next;
+		V_nfree_msgmaps--;
+#ifdef VPS
+		atomic_add_int(&nmsgmaps_global, 1);
+#endif 
+		V_msgmaps[next].next = msghdr->msg_spot;
 		msghdr->msg_spot = next;
 		segs_needed--;
 	}
@@ -915,18 +1117,18 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgf
 	next = msghdr->msg_spot;
 	while (msgsz > 0) {
 		size_t tlen;
-		if (msgsz > msginfo.msgssz)
-			tlen = msginfo.msgssz;
+		if (msgsz > V_msginfo.msgssz)
+			tlen = V_msginfo.msgssz;
 		else
 			tlen = msgsz;
 		if (next <= -1)
 			panic("next too low #2");
-		if (next >= msginfo.msgseg)
+		if (next >= V_msginfo.msgseg)
 			panic("next out of range #2");
-		mtx_unlock(&msq_mtx);
-		if ((error = copyin(msgp, &msgpool[next * msginfo.msgssz],
+		mtx_unlock(&V_msq_mtx);
+		if ((error = copyin(msgp, &V_msgpool[next * V_msginfo.msgssz],
 		    tlen)) != 0) {
-			mtx_lock(&msq_mtx);
+			mtx_lock(&V_msq_mtx);
 			DPRINTF(("error %d copying in message segment\n",
 			    error));
 			msg_freehdr(msghdr);
@@ -934,10 +1136,10 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgf
 			wakeup(msqkptr);
 			goto done3;
 		}
-		mtx_lock(&msq_mtx);
+		mtx_lock(&V_msq_mtx);
 		msgsz -= tlen;
 		msgp = (const char *)msgp + tlen;
-		next = msgmaps[next].next;
+		next = V_msgmaps[next].next;
 	}
 	if (next != -1)
 		panic("didn't use all the msg segments");
@@ -1008,7 +1210,7 @@ done3:
 	}
 #endif
 done2:
-	mtx_unlock(&msq_mtx);
+	mtx_unlock(&V_msq_mtx);
 	return (error);
 }
 
@@ -1062,14 +1264,14 @@ kern_msgrcv(td, msqid, msgp, msgsz, msgt
 
 	msqix = IPCID_TO_IX(msqid);
 
-	if (msqix < 0 || msqix >= msginfo.msgmni) {
+	if (msqix < 0 || msqix >= V_msginfo.msgmni) {
 		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
-		    msginfo.msgmni));
+		    V_msginfo.msgmni));
 		return (EINVAL);
 	}
 
-	msqkptr = &msqids[msqix];
-	mtx_lock(&msq_mtx);
+	msqkptr = &V_msqids[msqix];
+	mtx_lock(&V_msq_mtx);
 	if (msqkptr->u.msg_qbytes == 0) {
 		DPRINTF(("no such message queue id\n"));
 		error = EINVAL;
@@ -1207,7 +1409,7 @@ kern_msgrcv(td, msqid, msgp, msgsz, msgt
 		 */
 
 		DPRINTF(("msgrcv:  goodnight\n"));
-		error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
+		error = msleep(msqkptr, &V_msq_mtx, (PZERO - 4) | PCATCH,
 		    "msgrcv", 0);
 		DPRINTF(("msgrcv:  good morning (error=%d)\n", error));
 
@@ -1260,20 +1462,20 @@ kern_msgrcv(td, msqid, msgp, msgsz, msgt
 	 */
 
 	next = msghdr->msg_spot;
-	for (len = 0; len < msgsz; len += msginfo.msgssz) {
+	for (len = 0; len < msgsz; len += V_msginfo.msgssz) {
 		size_t tlen;
 
-		if (msgsz - len > msginfo.msgssz)
-			tlen = msginfo.msgssz;
+		if (msgsz - len > V_msginfo.msgssz)
+			tlen = V_msginfo.msgssz;
 		else
 			tlen = msgsz - len;
 		if (next <= -1)
 			panic("next too low #3");
-		if (next >= msginfo.msgseg)
+		if (next >= V_msginfo.msgseg)
 			panic("next out of range #3");
-		mtx_unlock(&msq_mtx);
-		error = copyout(&msgpool[next * msginfo.msgssz], msgp, tlen);
-		mtx_lock(&msq_mtx);
+		mtx_unlock(&V_msq_mtx);
+		error = copyout(&V_msgpool[next * V_msginfo.msgssz], msgp, tlen);
+		mtx_lock(&V_msq_mtx);
 		if (error != 0) {
 			DPRINTF(("error (%d) copying out message segment\n",
 			    error));
@@ -1282,7 +1484,7 @@ kern_msgrcv(td, msqid, msgp, msgsz, msgt
 			goto done2;
 		}
 		msgp = (char *)msgp + tlen;
-		next = msgmaps[next].next;
+		next = V_msgmaps[next].next;
 	}
 
 	/*
@@ -1293,7 +1495,7 @@ kern_msgrcv(td, msqid, msgp, msgsz, msgt
 	wakeup(msqkptr);
 	td->td_retval[0] = msgsz;
 done2:
-	mtx_unlock(&msq_mtx);
+	mtx_unlock(&V_msq_mtx);
 	return (error);
 }
 
@@ -1321,23 +1523,23 @@ static int
 sysctl_msqids(SYSCTL_HANDLER_ARGS)
 {
 
-	return (SYSCTL_OUT(req, msqids,
-	    sizeof(struct msqid_kernel) * msginfo.msgmni));
+	return (SYSCTL_OUT(req, V_msqids,
+	    sizeof(struct msqid_kernel) * V_msginfo.msgmni));
 }
 
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &VPS_NAME(msginfo.msgmax), 0,
     "Maximum message size");
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &msginfo.msgmni, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &VPS_NAME(msginfo.msgmni), 0,
     "Number of message queue identifiers");
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RDTUN, &msginfo.msgmnb, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RDTUN, &VPS_NAME(msginfo.msgmnb), 0,
     "Maximum number of bytes in a queue");
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RDTUN, &msginfo.msgtql, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RDTUN, &VPS_NAME(msginfo.msgtql), 0,
     "Maximum number of messages in the system");
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &msginfo.msgssz, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &VPS_NAME(msginfo.msgssz), 0,
     "Size of a message segment");
-SYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &msginfo.msgseg, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &VPS_NAME(msginfo.msgseg), 0,
     "Number of message segments");
-SYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLTYPE_OPAQUE | CTLFLAG_RD,
+SYSCTL_VPS_PROC(_kern_ipc, OID_AUTO, msqids, CTLTYPE_OPAQUE | CTLFLAG_RD,
     NULL, 0, sysctl_msqids, "", "Message queue IDs");
 
 #ifdef COMPAT_FREEBSD32
@@ -1590,3 +1792,241 @@ freebsd7_msgctl(td, uap)
 
 #endif	/* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 ||
 	   COMPAT_FREEBSD7 */
+
+#ifdef VPS
+
+__attribute__ ((noinline, unused))
+int msg_snapshot_vps(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_sysvmsg_msginfo *vdmsginfo;
+	uint16 *vdmsgmaps;
+	struct vps_dump_sysvmsg_msg *vdmsghdrs;
+	struct vps_dump_sysvmsg_msqid *vdmsqids;
+	struct msginfo *msginfo;
+	struct msgmap *msgmaps;
+	struct msg *msghdrs;
+	struct msqid_kernel *msqids;
+	int i;
+
+	o1 = vdo_create(ctx, VPS_DUMPOBJT_SYSVMSG_VPS, M_WAITOK);
+	vdmsginfo = vdo_space(ctx, sizeof(*vdmsginfo), M_WAITOK);
+
+	msginfo = &VPS_VPS(vps, msginfo);
+	vdmsginfo->msgmax = msginfo->msgmax;
+	vdmsginfo->msgmni = msginfo->msgmni;
+	vdmsginfo->msgmnb = msginfo->msgmnb;
+	vdmsginfo->msgtql = msginfo->msgtql;
+	vdmsginfo->msgssz = msginfo->msgssz;
+	vdmsginfo->msgseg = msginfo->msgseg;
+	vdmsginfo->nfree_msgmaps = VPS_VPS(vps, nfree_msgmaps);
+	vdmsginfo->free_msgmaps = VPS_VPS(vps, free_msgmaps);
+	vdmsginfo->free_msghdrs_idx = VPS_VPS(vps, free_msghdrs) - VPS_VPS(vps, msghdrs);
+
+	/* msgpool */
+	vdo_append(ctx, VPS_VPS(vps, msgpool), msginfo->msgmax, M_WAITOK);
+
+	/* msgmaps */
+	msgmaps = VPS_VPS(vps, msgmaps);
+	vdmsgmaps = vdo_space(ctx, msginfo->msgseg * sizeof(uint16), M_WAITOK);
+	for (i = 0; i < msginfo->msgseg; i++) {
+		vdmsgmaps[i] = msgmaps[i].next;
+	}
+
+	/* msghdrs */
+	msghdrs = VPS_VPS(vps, msghdrs);
+	vdmsghdrs = vdo_space(ctx, sizeof(struct vps_dump_sysvmsg_msg) *
+		msginfo->msgtql, M_WAITOK);
+	for (i = 0; i < msginfo->msgtql; i++) {
+		vdmsghdrs[i].msg_next = -1;
+		if (msghdrs[i].msg_next != NULL)
+			vdmsghdrs[i].msg_next = msghdrs[i].msg_next - msghdrs;
+		vdmsghdrs[i].msg_type = msghdrs[i].msg_type;
+		vdmsghdrs[i].msg_ts = msghdrs[i].msg_ts;
+		vdmsghdrs[i].msg_spot = msghdrs[i].msg_spot;
+		/* XXX assert label == NULL */
+		vdmsghdrs[i].label = msghdrs[i].label;
+	}
+
+	/* msqids */
+	msqids = VPS_VPS(vps, msqids);
+	vdmsqids = vdo_space(ctx, sizeof(struct vps_dump_sysvmsg_msqid) *
+		msginfo->msgmni, M_WAITOK);
+	for (i = 0; i < msginfo->msgmni; i++) {
+		vdmsqids[i].msg_first = -1;
+		if (msqids[i].u.msg_first != NULL)
+			vdmsqids[i].msg_first = msqids[i].u.msg_first - msghdrs;
+		vdmsqids[i].msg_last = -1;
+		if (msqids[i].u.msg_last != NULL)
+			vdmsqids[i].msg_last = msqids[i].u.msg_last - msghdrs;
+		vdmsqids[i].msg_perm.cuid = msqids[i].u.msg_perm.cuid;
+		vdmsqids[i].msg_perm.cgid = msqids[i].u.msg_perm.cgid;
+		vdmsqids[i].msg_perm.uid = msqids[i].u.msg_perm.uid;
+		vdmsqids[i].msg_perm.gid = msqids[i].u.msg_perm.gid;
+		vdmsqids[i].msg_perm.mode = msqids[i].u.msg_perm.mode;
+		vdmsqids[i].msg_perm.seq = msqids[i].u.msg_perm.seq;
+		vdmsqids[i].msg_perm.key = msqids[i].u.msg_perm.key;
+		vdmsqids[i].msg_cbytes = msqids[i].u.msg_cbytes;
+		vdmsqids[i].msg_qnum = msqids[i].u.msg_qnum;
+		vdmsqids[i].msg_qbytes = msqids[i].u.msg_qbytes;
+		vdmsqids[i].msg_lspid = msqids[i].u.msg_lspid;
+		vdmsqids[i].msg_lrpid = msqids[i].u.msg_lrpid;
+		vdmsqids[i].msg_stime = msqids[i].u.msg_stime;
+		vdmsqids[i].msg_rtime = msqids[i].u.msg_rtime;
+		vdmsqids[i].msg_ctime = msqids[i].u.msg_ctime;
+		/* XXX assert label == NULL */
+		vdmsqids[i].label = msqids[i].label;
+		vdmsqids[i].cred = msqids[i].cred;
+	}
+
+	for (i = 0; i < msginfo->msgmni; i++) {
+		if (vdmsqids[i].cred != NULL)
+			vps_func->vps_snapshot_ucred(ctx, vps, vdmsqids[i].cred, M_WAITOK);
+	}
+
+	vdo_close(ctx);
+
+	return (0);
+}
+
+__attribute__ ((noinline, unused))
+int msg_snapshot_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc *p)
+{
+
+	return (0);
+}
+
+__attribute__ ((noinline, unused))
+int msg_restore_vps(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_sysvmsg_msginfo *vdmsginfo;
+	uint16 *vdmsgmaps;
+	struct vps_dump_sysvmsg_msg *vdmsghdrs;
+	struct vps_dump_sysvmsg_msqid *vdmsqids;
+	struct msginfo *msginfo;
+	struct msgmap *msgmaps;
+	struct msg *msghdrs;
+	struct msqid_kernel *msqids;
+	struct vps *vps_save;
+	struct ucred *ncr;
+	caddr_t cpos;
+	int i;
+
+	o1 = vdo_next(ctx);
+	if (o1->type != VPS_DUMPOBJT_SYSVMSG_VPS) {
+		printf("%s: o1=%p is not VPS_DUMPOBJT_SYSVMSG_VPS\n",
+			__func__, o1);
+		return (EINVAL);
+	}
+	vdmsginfo = (struct vps_dump_sysvmsg_msginfo *)o1->data;
+
+	/* realloc in case msginfo is different */
+	vps_save = curthread->td_vps;
+	curthread->td_vps = vps;
+	msgunload();
+	msginfo = &VPS_VPS(vps, msginfo);
+	msginfo->msgmax = vdmsginfo->msgmax;
+	msginfo->msgmni = vdmsginfo->msgmni;
+	msginfo->msgmnb = vdmsginfo->msgmnb;
+	msginfo->msgtql = vdmsginfo->msgtql;
+	msginfo->msgssz = vdmsginfo->msgssz;
+	msginfo->msgseg = vdmsginfo->msgseg;
+	msginit2();
+	curthread->td_vps = vps_save;
+
+	cpos = (caddr_t)(vdmsginfo + 1);
+
+	/* msgpool */
+	memcpy(VPS_VPS(vps, msgpool), cpos, msginfo->msgmax);
+	cpos += msginfo->msgmax;
+
+	/* msgmaps */
+	msgmaps = VPS_VPS(vps, msgmaps);
+	vdmsgmaps = (uint16 *)cpos;
+	cpos += sizeof(uint16) * msginfo->msgseg;
+	for (i = 0; i < msginfo->msgseg; i++) {
+		msgmaps[i].next = vdmsgmaps[i];
+	}
+
+	/* msghdrs */
+	msghdrs = VPS_VPS(vps, msghdrs);
+	vdmsghdrs = (struct vps_dump_sysvmsg_msg *)cpos;
+	cpos += sizeof(*vdmsghdrs) * msginfo->msgtql;
+	for (i = 0; i < msginfo->msgtql; i++) {
+		msghdrs[i].msg_next = NULL;
+		if (vdmsghdrs[i].msg_next != -1)
+			msghdrs[i].msg_next = msghdrs + vdmsghdrs[i].msg_next;
+		msghdrs[i].msg_type = vdmsghdrs[i].msg_type;
+		msghdrs[i].msg_ts = vdmsghdrs[i].msg_ts;
+		msghdrs[i].msg_spot = vdmsghdrs[i].msg_spot;
+		/* XXX assert label == NULL */
+		//msghdrs[i].label = vdmsghdrs[i].label;
+		msghdrs[i].label = NULL;
+
+	}
+
+	/* msqids */
+	msqids = VPS_VPS(vps, msqids);
+	vdmsqids = (struct vps_dump_sysvmsg_msqid *)cpos;
+	cpos += sizeof(*vdmsqids) * msginfo->msgmni;
+	for (i = 0; i < msginfo->msgmni; i++) {
+		msqids[i].u.msg_first = NULL;
+		if (vdmsqids[i].msg_first != -1)
+			msqids[i].u.msg_first = msghdrs + vdmsqids[i].msg_first;
+		msqids[i].u.msg_last = NULL;
+		if (vdmsqids[i].msg_last != -1)
+			msqids[i].u.msg_last = msghdrs + vdmsqids[i].msg_last;
+		msqids[i].u.msg_perm.cuid = vdmsqids[i].msg_perm.cuid;
+		msqids[i].u.msg_perm.cgid = vdmsqids[i].msg_perm.cgid;
+		msqids[i].u.msg_perm.uid = vdmsqids[i].msg_perm.uid;
+		msqids[i].u.msg_perm.gid = vdmsqids[i].msg_perm.gid;
+		msqids[i].u.msg_perm.mode = vdmsqids[i].msg_perm.mode;
+		msqids[i].u.msg_perm.seq = vdmsqids[i].msg_perm.seq;
+		msqids[i].u.msg_perm.key = vdmsqids[i].msg_perm.key;
+		msqids[i].u.msg_cbytes = vdmsqids[i].msg_cbytes;
+		msqids[i].u.msg_qnum = vdmsqids[i].msg_qnum;
+		msqids[i].u.msg_qbytes = vdmsqids[i].msg_qbytes;
+		msqids[i].u.msg_lspid = vdmsqids[i].msg_lspid;
+		msqids[i].u.msg_lrpid = vdmsqids[i].msg_lrpid;
+		msqids[i].u.msg_stime = vdmsqids[i].msg_stime;
+		msqids[i].u.msg_rtime = vdmsqids[i].msg_rtime;
+		msqids[i].u.msg_ctime = vdmsqids[i].msg_ctime;
+		/* XXX assert label == NULL */
+		msqids[i].label = vdmsqids[i].label;
+		msqids[i].cred = vdmsqids[i].cred;
+	}
+
+	VPS_VPS(vps, nfree_msgmaps) = vdmsginfo->nfree_msgmaps;
+	VPS_VPS(vps, free_msgmaps) = vdmsginfo->free_msgmaps;
+	VPS_VPS(vps, free_msghdrs) = VPS_VPS(vps, msghdrs) + vdmsginfo->free_msghdrs_idx;
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_UCRED)
+		vdo_next(ctx);//vps_func->vps_restore_ucred(ctx, vps);
+
+	for (i = 0; i < msginfo->msgmni; i++)
+		if (msqids[i].cred != NULL) {
+			ncr = vps_func->vps_restore_ucred_lookup(ctx, vps,
+					msqids[i].cred);
+			msqids[i].cred = ncr;
+		}
+
+	return (0);
+}
+
+__attribute__ ((noinline, unused))
+int msg_restore_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc *p)
+{
+
+	return (0);
+}
+
+__attribute__ ((noinline, unused))
+int msg_restore_fixup(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+
+	return (0);
+}
+
+#endif /* VPS */
+
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/sysv_sem.c head/sys/kern/sysv_sem.c
--- clean-head/sys/kern/sysv_sem.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/sysv_sem.c	2013-06-24 14:20:31.000000000 +0200
@@ -35,6 +35,19 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*-
+ * VPS adaption:
+ *
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * <BSD license>
+ *
+ * $Id: sysv_sem.c 162 2013-06-06 18:17:55Z klaus $
+ */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: head/sys/kern/sysv_sem.c 225617 2011-09-16 13:58:51Z kmacy $");
@@ -52,15 +65,21 @@ __FBSDID("$FreeBSD: head/sys/kern/sysv_s
 #include <sys/module.h>
 #include <sys/mutex.h>
 #include <sys/racct.h>
-#include <sys/sem.h>
 #include <sys/syscall.h>
 #include <sys/syscallsubr.h>
 #include <sys/sysent.h>
 #include <sys/sysctl.h>
+#include <sys/sem.h>
 #include <sys/uio.h>
 #include <sys/malloc.h>
 #include <sys/jail.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#include <vps/vps_int.h>
+#include <vps/vps_libdump.h>
+#include <vps/vps_snapst.h>
+
 #include <security/mac/mac_framework.h>
 
 FEATURE(sysv_sem, "System V semaphores support");
@@ -74,6 +93,7 @@ static MALLOC_DEFINE(M_SEM, "sem", "SVID
 #endif
 
 static int seminit(void);
+static int seminit2(void);
 static int sysvsem_modload(struct module *, int, void *);
 static int semunload(void);
 static void semexit_myhook(void *arg, struct proc *p);
@@ -94,6 +114,7 @@ static int semundo_adjust(struct thread 
     int semid, int semseq, int semnum, int adjval);
 static void semundo_clear(int semid, int semnum);
 
+#if 0
 static struct mtx	sem_mtx;	/* semaphore global lock */
 static struct mtx sem_undo_mtx;
 static int	semtot = 0;
@@ -103,9 +124,43 @@ static struct sem *sem;		/* semaphore po
 LIST_HEAD(, sem_undo) semu_list;	/* list of active undo structures */
 LIST_HEAD(, sem_undo) semu_free_list;	/* list of free undo structures */
 static int	*semu;		/* undo structure pool */
+#endif
+
+#ifdef VPS
+static int semtot_global = 0;
+#endif
+
+VPS_DEFINE(struct mtx, sem_mtx);
+VPS_DEFINE(struct mtx, sem_undo_mtx);
+VPS_DEFINE(int, semtot) = 0;
+VPS_DEFINE(struct semid_kernel *, sema);
+VPS_DEFINE(struct mtx *, sema_mtx);
+VPS_DEFINE(struct sem *, sem);
+VPS_DEFINE(LIST_HEAD(, sem_undo), semu_list);
+VPS_DEFINE(LIST_HEAD(, sem_undo), semu_free_list);
+VPS_DEFINE(int *, semu);
+VPS_DEFINE(struct seminfo, seminfo);
+
+#define V_sem_mtx		VPSV(sem_mtx)
+#define V_sem_undo_mtx		VPSV(sem_undo_mtx)
+#define V_semtot		VPSV(semtot)
+#define V_sema			VPSV(sema)
+#define V_sema_mtx		VPSV(sema_mtx)
+#define V_sem			VPSV(sem)
+#define V_semu_list		VPSV(semu_list)
+#define V_semu_free_list	VPSV(semu_free_list)
+#define V_semu			VPSV(semu)
+#define V_seminfo		VPSV(seminfo)
+
 static eventhandler_tag semexit_tag;
 
-#define SEMUNDO_MTX		sem_undo_mtx
+#ifdef VPS
+static eventhandler_tag sem_vpsalloc_tag;
+static eventhandler_tag sem_vpsfree_tag;
+#endif
+
+
+#define SEMUNDO_MTX		V_sem_undo_mtx
 #define SEMUNDO_LOCK()		mtx_lock(&SEMUNDO_MTX);
 #define SEMUNDO_UNLOCK()	mtx_unlock(&SEMUNDO_MTX);
 #define SEMUNDO_LOCKASSERT(how)	mtx_assert(&SEMUNDO_MTX, (how));
@@ -173,8 +228,9 @@ struct sem_undo {
  * Macro to find a particular sem_undo vector
  */
 #define SEMU(ix) \
-	((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
+	((struct sem_undo *)(((intptr_t)V_semu)+ix * V_seminfo.semusz))
 
+#if 0
 /*
  * semaphore info struct
  */
@@ -189,26 +245,27 @@ struct seminfo seminfo = {
                 SEMVMX,         /* semaphore maximum value */
                 SEMAEM          /* adjust on exit max value */
 };
+#endif
 
-SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &VPS_NAME(seminfo.semmni), 0,
     "Number of semaphore identifiers");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &VPS_NAME(seminfo.semmns), 0,
     "Maximum number of semaphores in the system");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &VPS_NAME(seminfo.semmnu), 0,
     "Maximum number of undo structures in the system");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &VPS_NAME(seminfo.semmsl), 0,
     "Max semaphores per id");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &VPS_NAME(seminfo.semopm), 0,
     "Max operations per semop call");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &VPS_NAME(seminfo.semume), 0,
     "Max undo entries per process");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &VPS_NAME(seminfo.semusz), 0,
     "Size in bytes of undo structure");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &VPS_NAME(seminfo.semvmx), 0,
     "Semaphore maximum value");
-SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &VPS_NAME(seminfo.semaem), 0,
     "Adjust on exit max value");
-SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLTYPE_OPAQUE | CTLFLAG_RD,
+SYSCTL_VPS_PROC(_kern_ipc, OID_AUTO, sema, CTLTYPE_OPAQUE | CTLFLAG_RD,
     NULL, 0, sysctl_sema, "", "Semaphore id pool");
 
 static struct syscall_helper_data sem_syscalls[] = {
@@ -247,44 +304,66 @@ static struct syscall_helper_data sem32_
 static int
 seminit(void)
 {
-	int i, error;
 
-	TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni);
-	TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns);
-	TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu);
-	TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl);
-	TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm);
-	TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume);
-	TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz);
-	TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx);
-	TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem);
+	V_seminfo.semmni = SEMMNI;
+	V_seminfo.semmns = SEMMNS;
+	V_seminfo.semmnu = SEMMNU;
+	V_seminfo.semmsl = SEMMSL;
+	V_seminfo.semopm = SEMOPM;
+	V_seminfo.semume = SEMUME;
+	V_seminfo.semusz = SEMUSZ;
+	V_seminfo.semvmx = SEMVMX;
+	V_seminfo.semaem = SEMAEM;
+
+	TUNABLE_INT_FETCH("kern.ipc.semmni", &V_seminfo.semmni);
+	TUNABLE_INT_FETCH("kern.ipc.semmns", &V_seminfo.semmns);
+	TUNABLE_INT_FETCH("kern.ipc.semmnu", &V_seminfo.semmnu);
+	TUNABLE_INT_FETCH("kern.ipc.semmsl", &V_seminfo.semmsl);
+	TUNABLE_INT_FETCH("kern.ipc.semopm", &V_seminfo.semopm);
+	TUNABLE_INT_FETCH("kern.ipc.semume", &V_seminfo.semume);
+	TUNABLE_INT_FETCH("kern.ipc.semusz", &V_seminfo.semusz);
+	TUNABLE_INT_FETCH("kern.ipc.semvmx", &V_seminfo.semvmx);
+	TUNABLE_INT_FETCH("kern.ipc.semaem", &V_seminfo.semaem);
+
+	return (seminit2());
+}
 
-	sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK);
-	sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM,
+static int
+seminit2(void)
+{
+	int i;
+#ifndef VPS
+	int error;
+#endif
+
+	V_sem = malloc(sizeof(struct sem) * V_seminfo.semmns, M_SEM, M_WAITOK);
+	V_sema = malloc(sizeof(struct semid_kernel) * V_seminfo.semmni, M_SEM,
 	    M_WAITOK);
-	sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM,
+	V_sema_mtx = malloc(sizeof(struct mtx) * V_seminfo.semmni, M_SEM,
 	    M_WAITOK | M_ZERO);
-	semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK);
+	V_semu = malloc(V_seminfo.semmnu * V_seminfo.semusz, M_SEM, M_WAITOK);
 
-	for (i = 0; i < seminfo.semmni; i++) {
-		sema[i].u.sem_base = 0;
-		sema[i].u.sem_perm.mode = 0;
-		sema[i].u.sem_perm.seq = 0;
+	for (i = 0; i < V_seminfo.semmni; i++) {
+		V_sema[i].u.sem_base = 0;
+		V_sema[i].u.sem_perm.mode = 0;
+		V_sema[i].u.sem_perm.seq = 0;
+		V_sema[i].cred = NULL;
 #ifdef MAC
-		mac_sysvsem_init(&sema[i]);
+		mac_sysvsem_init(&V_sema[i]);
 #endif
 	}
-	for (i = 0; i < seminfo.semmni; i++)
-		mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF);
-	LIST_INIT(&semu_free_list);
-	for (i = 0; i < seminfo.semmnu; i++) {
+	for (i = 0; i < V_seminfo.semmni; i++)
+		mtx_init(&V_sema_mtx[i], "semid", NULL, MTX_DEF);
+	LIST_INIT(&V_semu_free_list);
+	for (i = 0; i < V_seminfo.semmnu; i++) {
 		struct sem_undo *suptr = SEMU(i);
 		suptr->un_proc = NULL;
-		LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
+		LIST_INSERT_HEAD(&V_semu_free_list, suptr, un_next);
 	}
-	LIST_INIT(&semu_list);
-	mtx_init(&sem_mtx, "sem", NULL, MTX_DEF);
-	mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF);
+	LIST_INIT(&V_semu_list);
+	mtx_init(&V_sem_mtx, "sem", NULL, MTX_DEF);
+	mtx_init(&V_sem_undo_mtx, "semu", NULL, MTX_DEF);
+#ifndef VPS
 	semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL,
 	    EVENTHANDLER_PRI_ANY);
 
@@ -296,6 +375,7 @@ seminit(void)
 	if (error != 0)
 		return (error);
 #endif
+#endif /* VPS */
 	return (0);
 }
 
@@ -304,43 +384,183 @@ semunload(void)
 {
 	int i;
 
+#ifdef VPS
+	semtot_global -= V_semtot;
+#else
 	/* XXXKIB */
-	if (semtot != 0)
+	if (V_semtot != 0)
 		return (EBUSY);
+#endif
 
+#ifndef VPS
 #ifdef COMPAT_FREEBSD32
 	syscall32_helper_unregister(sem32_syscalls);
 #endif
 	syscall_helper_unregister(sem_syscalls);
 	EVENTHANDLER_DEREGISTER(process_exit, semexit_tag);
+#endif /* VPS */
 #ifdef MAC
-	for (i = 0; i < seminfo.semmni; i++)
-		mac_sysvsem_destroy(&sema[i]);
+	for (i = 0; i < V_seminfo.semmni; i++)
+		mac_sysvsem_destroy(&V_sema[i]);
 #endif
-	free(sem, M_SEM);
-	free(sema, M_SEM);
-	free(semu, M_SEM);
-	for (i = 0; i < seminfo.semmni; i++)
-		mtx_destroy(&sema_mtx[i]);
-	free(sema_mtx, M_SEM);
-	mtx_destroy(&sem_mtx);
-	mtx_destroy(&sem_undo_mtx);
+	for (i = 0; i < V_seminfo.semmni; i++) {
+		if (V_sema[i].cred != NULL)
+			crfree(V_sema[i].cred);
+	}
+	free(V_sem, M_SEM);
+	free(V_sema, M_SEM);
+	free(V_semu, M_SEM);
+	for (i = 0; i < V_seminfo.semmni; i++)
+		mtx_destroy(&V_sema_mtx[i]);
+	free(V_sema_mtx, M_SEM);
+	mtx_destroy(&V_sem_mtx);
+	mtx_destroy(&V_sem_undo_mtx);
+	return (0);
+}
+
+#ifdef VPS
+
+int sem_snapshot_vps(struct vps_snapst_ctx *ctx, struct vps *vps);
+int sem_snapshot_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc* proc);
+int sem_restore_vps(struct vps_snapst_ctx *ctx, struct vps *vps);
+int sem_restore_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc* proc);
+int sem_restore_fixup(struct vps_snapst_ctx *ctx, struct vps *vps);
+
+static void
+sem_vpsalloc_hook(void *arg, struct vps *vps)
+{
+        DPRINTF(("%s: vps=%p\n", __func__, vps));
+
+        vps_ref(vps, NULL);
+
+        seminit();
+}
+
+static void
+sem_vpsfree_hook(void *arg, struct vps *vps)
+{
+        DPRINTF(("%s: vps=%p\n", __func__, vps));
+
+        /* 
+         * Since they can be left over after processes vanished,
+         * just kill everything silently.
+         *
+         * KASSERT(V_semtot == 0, ("%s: vps=%p V_semtot=%d\n", __func__, vps, V_semtot));
+         */
+
+        if (semunload())
+                printf("%s: semunload() error\n", __func__);
+
+        vps_deref(vps, NULL);
+}
+
+static int
+seminit_global(void)
+{
+        struct vps *vps, *save_vps;
+	int error;
+
+        save_vps = curthread->td_vps;
+
+        semtot_global = 0;
+
+        sx_slock(&vps_all_lock);
+        LIST_FOREACH(vps, &vps_head, vps_all) {
+                curthread->td_vps = vps;
+                sem_vpsalloc_hook(NULL, vps);
+                curthread->td_vps = save_vps;
+        }
+        sx_sunlock(&vps_all_lock);
+
+        semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL,
+                EVENTHANDLER_PRI_ANY);
+        sem_vpsalloc_tag = EVENTHANDLER_REGISTER(vps_alloc, sem_vpsalloc_hook, NULL,
+                EVENTHANDLER_PRI_ANY);
+        sem_vpsfree_tag = EVENTHANDLER_REGISTER(vps_free, sem_vpsfree_hook, NULL,
+                EVENTHANDLER_PRI_ANY);
+
+        vps_func->sem_snapshot_vps = sem_snapshot_vps;
+        vps_func->sem_snapshot_proc = sem_snapshot_proc;
+        vps_func->sem_restore_vps = sem_restore_vps;
+        vps_func->sem_restore_proc = sem_restore_proc;
+        vps_func->sem_restore_fixup = sem_restore_fixup;
+
+	error = syscall_helper_register(sem_syscalls);
+	if (error != 0)
+		return (error);
+#ifdef COMPAT_FREEBSD32
+	error = syscall32_helper_register(sem32_syscalls);
+	if (error != 0)
+		return (error);
+#endif
+
 	return (0);
 }
 
 static int
+semunload_global(void)
+{
+        struct vps *vps, *save_vps;
+
+        save_vps = curthread->td_vps;
+
+        if (semtot_global != 0)
+                return (EBUSY);
+
+#ifdef COMPAT_FREEBSD32
+	syscall32_helper_unregister(sem32_syscalls);
+#endif
+	syscall_helper_unregister(sem_syscalls);
+
+        vps_func->sem_snapshot_vps = NULL;
+        vps_func->sem_snapshot_proc = NULL;
+        vps_func->sem_restore_vps = NULL;
+        vps_func->sem_restore_proc = NULL;
+        vps_func->sem_restore_fixup = NULL;
+
+        EVENTHANDLER_DEREGISTER(process_exit, semexit_tag);
+
+        EVENTHANDLER_DEREGISTER(vps_alloc, sem_vpsalloc_tag);
+        EVENTHANDLER_DEREGISTER(vps_free, sem_vpsfree_tag);
+
+        sx_slock(&vps_all_lock);
+        LIST_FOREACH(vps, &vps_head, vps_all) {
+                curthread->td_vps = vps;
+                /* Unless semtot_global is fucked up we got no error here. */
+                if (VPS_VPS(vps, sem))
+                        sem_vpsfree_hook(NULL, vps);
+                curthread->td_vps = save_vps;
+        }       
+        sx_sunlock(&vps_all_lock);
+
+        return (0);
+}
+#endif /* VPS */
+
+
+static int
 sysvsem_modload(struct module *module, int cmd, void *arg)
 {
 	int error = 0;
 
 	switch (cmd) {
 	case MOD_LOAD:
+#ifdef VPS
+		error = seminit_global();
+		if (error != 0)
+			semunload_global();
+#else
 		error = seminit();
 		if (error != 0)
 			semunload();
+#endif
 		break;
 	case MOD_UNLOAD:
+#ifdef VPS
+		error = semunload_global();
+#else
 		error = semunload();
+#endif
 		break;
 	case MOD_SHUTDOWN:
 		break;
@@ -371,10 +591,10 @@ semu_alloc(struct thread *td)
 	struct sem_undo *suptr;
 
 	SEMUNDO_LOCKASSERT(MA_OWNED);
-	if ((suptr = LIST_FIRST(&semu_free_list)) == NULL)
+	if ((suptr = LIST_FIRST(&V_semu_free_list)) == NULL)
 		return (NULL);
 	LIST_REMOVE(suptr, un_next);
-	LIST_INSERT_HEAD(&semu_list, suptr, un_next);
+	LIST_INSERT_HEAD(&V_semu_list, suptr, un_next);
 	suptr->un_cnt = 0;
 	suptr->un_proc = td->td_proc;
 	return (suptr);
@@ -389,7 +609,7 @@ semu_try_free(struct sem_undo *suptr)
 	if (suptr->un_cnt != 0)
 		return (0);
 	LIST_REMOVE(suptr, un_next);
-	LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
+	LIST_INSERT_HEAD(&V_semu_free_list, suptr, un_next);
 	return (1);
 }
 
@@ -412,7 +632,7 @@ semundo_adjust(struct thread *td, struct
 
 	suptr = *supptr;
 	if (suptr == NULL) {
-		LIST_FOREACH(suptr, &semu_list, un_next) {
+		LIST_FOREACH(suptr, &V_semu_list, un_next) {
 			if (suptr->un_proc == p) {
 				*supptr = suptr;
 				break;
@@ -438,7 +658,7 @@ semundo_adjust(struct thread *td, struct
 			continue;
 		if (adjval != 0) {
 			adjval += sunptr->un_adjval;
-			if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
+			if (adjval > V_seminfo.semaem || adjval < -V_seminfo.semaem)
 				return (ERANGE);
 		}
 		sunptr->un_adjval = adjval;
@@ -456,9 +676,9 @@ semundo_adjust(struct thread *td, struct
 	/* Didn't find the right entry - create it */
 	if (adjval == 0)
 		return (0);
-	if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
+	if (adjval > V_seminfo.semaem || adjval < -V_seminfo.semaem)
 		return (ERANGE);
-	if (suptr->un_cnt != seminfo.semume) {
+	if (suptr->un_cnt != V_seminfo.semume) {
 		sunptr = &suptr->un_ent[suptr->un_cnt];
 		suptr->un_cnt++;
 		sunptr->un_adjval = adjval;
@@ -478,7 +698,7 @@ semundo_clear(int semid, int semnum)
 	int i;
 
 	SEMUNDO_LOCKASSERT(MA_OWNED);
-	LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) {
+	LIST_FOREACH_SAFE(suptr, &V_semu_list, un_next, suptr1) {
 		sunptr = &suptr->un_ent[0];
 		for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
 			if (sunptr->un_id != semid)
@@ -601,10 +821,10 @@ kern_semctl(struct thread *td, int semid
 		 * For this command we assume semid is an array index
 		 * rather than an IPC id.
 		 */
-		if (semid < 0 || semid >= seminfo.semmni)
+		if (semid < 0 || semid >= V_seminfo.semmni)
 			return (EINVAL);
-		semakptr = &sema[semid];
-		sema_mtxp = &sema_mtx[semid];
+		semakptr = &V_sema[semid];
+		sema_mtxp = &V_sema_mtx[semid];
 		mtx_lock(sema_mtxp);
 		if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
 			error = EINVAL;
@@ -624,13 +844,13 @@ kern_semctl(struct thread *td, int semid
 	}
 
 	semidx = IPCID_TO_IX(semid);
-	if (semidx < 0 || semidx >= seminfo.semmni)
+	if (semidx < 0 || semidx >= V_seminfo.semmni)
 		return (EINVAL);
 
-	semakptr = &sema[semidx];
-	sema_mtxp = &sema_mtx[semidx];
+	semakptr = &V_sema[semidx];
+	sema_mtxp = &V_sema_mtx[semidx];
 	if (cmd == IPC_RMID)
-		mtx_lock(&sem_mtx);
+		mtx_lock(&V_sem_mtx);
 	mtx_lock(sema_mtxp);
 #ifdef MAC
 	error = mac_sysvsem_check_semctl(cred, semakptr, cmd);
@@ -660,21 +880,24 @@ kern_semctl(struct thread *td, int semid
 		mac_sysvsem_cleanup(semakptr);
 #endif
 		wakeup(semakptr);
-		for (i = 0; i < seminfo.semmni; i++) {
-			if ((sema[i].u.sem_perm.mode & SEM_ALLOC) &&
-			    sema[i].u.sem_base > semakptr->u.sem_base)
-				mtx_lock_flags(&sema_mtx[i], LOP_DUPOK);
-		}
-		for (i = semakptr->u.sem_base - sem; i < semtot; i++)
-			sem[i] = sem[i + semakptr->u.sem_nsems];
-		for (i = 0; i < seminfo.semmni; i++) {
-			if ((sema[i].u.sem_perm.mode & SEM_ALLOC) &&
-			    sema[i].u.sem_base > semakptr->u.sem_base) {
-				sema[i].u.sem_base -= semakptr->u.sem_nsems;
-				mtx_unlock(&sema_mtx[i]);
+		for (i = 0; i < V_seminfo.semmni; i++) {
+			if ((V_sema[i].u.sem_perm.mode & SEM_ALLOC) &&
+			    V_sema[i].u.sem_base > semakptr->u.sem_base)
+				mtx_lock_flags(&V_sema_mtx[i], LOP_DUPOK);
+		}
+		for (i = semakptr->u.sem_base - V_sem; i < V_semtot; i++)
+			V_sem[i] = V_sem[i + semakptr->u.sem_nsems];
+		for (i = 0; i < V_seminfo.semmni; i++) {
+			if ((V_sema[i].u.sem_perm.mode & SEM_ALLOC) &&
+			    V_sema[i].u.sem_base > semakptr->u.sem_base) {
+				V_sema[i].u.sem_base -= semakptr->u.sem_nsems;
+				mtx_unlock(&V_sema_mtx[i]);
 			}
 		}
-		semtot -= semakptr->u.sem_nsems;
+		V_semtot -= semakptr->u.sem_nsems;
+#ifdef VPS
+		atomic_subtract_int(&semtot_global, semakptr->u.sem_nsems);
+#endif
 		break;
 
 	case IPC_SET:
@@ -792,7 +1015,7 @@ kern_semctl(struct thread *td, int semid
 			error = EINVAL;
 			goto done2;
 		}
-		if (arg->val < 0 || arg->val > seminfo.semvmx) {
+		if (arg->val < 0 || arg->val > V_seminfo.semvmx) {
 			error = ERANGE;
 			goto done2;
 		}
@@ -822,7 +1045,7 @@ kern_semctl(struct thread *td, int semid
 			goto done2;
 		for (i = 0; i < semakptr->u.sem_nsems; i++) {
 			usval = array[i];
-			if (usval > seminfo.semvmx) {
+			if (usval > V_seminfo.semvmx) {
 				error = ERANGE;
 				break;
 			}
@@ -842,7 +1065,7 @@ kern_semctl(struct thread *td, int semid
 done2:
 	mtx_unlock(sema_mtxp);
 	if (cmd == IPC_RMID)
-		mtx_unlock(&sem_mtx);
+		mtx_unlock(&V_sem_mtx);
 	if (array != NULL)
 		free(array, M_TEMP);
 	return(error);
@@ -868,20 +1091,20 @@ sys_semget(struct thread *td, struct sem
 	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
 		return (ENOSYS);
 
-	mtx_lock(&sem_mtx);
+	mtx_lock(&V_sem_mtx);
 	if (key != IPC_PRIVATE) {
-		for (semid = 0; semid < seminfo.semmni; semid++) {
-			if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) &&
-			    sema[semid].u.sem_perm.key == key)
+		for (semid = 0; semid < V_seminfo.semmni; semid++) {
+			if ((V_sema[semid].u.sem_perm.mode & SEM_ALLOC) &&
+			    V_sema[semid].u.sem_perm.key == key)
 				break;
 		}
-		if (semid < seminfo.semmni) {
+		if (semid < V_seminfo.semmni) {
 			DPRINTF(("found public key\n"));
-			if ((error = ipcperm(td, &sema[semid].u.sem_perm,
+			if ((error = ipcperm(td, &V_sema[semid].u.sem_perm,
 			    semflg & 0700))) {
 				goto done2;
 			}
-			if (nsems > 0 && sema[semid].u.sem_nsems < nsems) {
+			if (nsems > 0 && V_sema[semid].u.sem_nsems < nsems) {
 				DPRINTF(("too small\n"));
 				error = EINVAL;
 				goto done2;
@@ -892,7 +1115,7 @@ sys_semget(struct thread *td, struct sem
 				goto done2;
 			}
 #ifdef MAC
-			error = mac_sysvsem_check_semget(cred, &sema[semid]);
+			error = mac_sysvsem_check_semget(cred, &V_sema[semid]);
 			if (error != 0)
 				goto done2;
 #endif
@@ -902,24 +1125,24 @@ sys_semget(struct thread *td, struct sem
 
 	DPRINTF(("need to allocate the semid_kernel\n"));
 	if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
-		if (nsems <= 0 || nsems > seminfo.semmsl) {
+		if (nsems <= 0 || nsems > V_seminfo.semmsl) {
 			DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
-			    seminfo.semmsl));
+			    V_seminfo.semmsl));
 			error = EINVAL;
 			goto done2;
 		}
-		if (nsems > seminfo.semmns - semtot) {
+		if (nsems > V_seminfo.semmns - V_semtot) {
 			DPRINTF((
 			    "not enough semaphores left (need %d, got %d)\n",
-			    nsems, seminfo.semmns - semtot));
+			    nsems, V_seminfo.semmns - V_semtot));
 			error = ENOSPC;
 			goto done2;
 		}
-		for (semid = 0; semid < seminfo.semmni; semid++) {
-			if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0)
+		for (semid = 0; semid < V_seminfo.semmni; semid++) {
+			if ((V_sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0)
 				break;
 		}
-		if (semid == seminfo.semmni) {
+		if (semid == V_seminfo.semmni) {
 			DPRINTF(("no more semid_kernel's available\n"));
 			error = ENOSPC;
 			goto done2;
@@ -934,31 +1157,34 @@ sys_semget(struct thread *td, struct sem
 		}
 #endif
 		DPRINTF(("semid %d is available\n", semid));
-		mtx_lock(&sema_mtx[semid]);
-		KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0,
+		mtx_lock(&V_sema_mtx[semid]);
+		KASSERT((V_sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0,
 		    ("Lost semaphore %d", semid));
-		sema[semid].u.sem_perm.key = key;
-		sema[semid].u.sem_perm.cuid = cred->cr_uid;
-		sema[semid].u.sem_perm.uid = cred->cr_uid;
-		sema[semid].u.sem_perm.cgid = cred->cr_gid;
-		sema[semid].u.sem_perm.gid = cred->cr_gid;
-		sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
-		sema[semid].cred = crhold(cred);
-		sema[semid].u.sem_perm.seq =
-		    (sema[semid].u.sem_perm.seq + 1) & 0x7fff;
-		sema[semid].u.sem_nsems = nsems;
-		sema[semid].u.sem_otime = 0;
-		sema[semid].u.sem_ctime = time_second;
-		sema[semid].u.sem_base = &sem[semtot];
-		semtot += nsems;
-		bzero(sema[semid].u.sem_base,
-		    sizeof(sema[semid].u.sem_base[0])*nsems);
+		V_sema[semid].u.sem_perm.key = key;
+		V_sema[semid].u.sem_perm.cuid = cred->cr_uid;
+		V_sema[semid].u.sem_perm.uid = cred->cr_uid;
+		V_sema[semid].u.sem_perm.cgid = cred->cr_gid;
+		V_sema[semid].u.sem_perm.gid = cred->cr_gid;
+		V_sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
+		V_sema[semid].cred = crhold(cred);
+		V_sema[semid].u.sem_perm.seq =
+		    (V_sema[semid].u.sem_perm.seq + 1) & 0x7fff;
+		V_sema[semid].u.sem_nsems = nsems;
+		V_sema[semid].u.sem_otime = 0;
+		V_sema[semid].u.sem_ctime = time_second;
+		V_sema[semid].u.sem_base = &V_sem[V_semtot];
+		V_semtot += nsems;
+#ifdef VPS
+		atomic_add_int(&semtot_global, nsems);
+#endif
+		bzero(V_sema[semid].u.sem_base,
+		    sizeof(V_sema[semid].u.sem_base[0])*nsems);
 #ifdef MAC
-		mac_sysvsem_create(cred, &sema[semid]);
+		mac_sysvsem_create(cred, &V_sema[semid]);
 #endif
-		mtx_unlock(&sema_mtx[semid]);
+		mtx_unlock(&V_sema_mtx[semid]);
 		DPRINTF(("sembase = %p, next = %p\n",
-		    sema[semid].u.sem_base, &sem[semtot]));
+		    V_sema[semid].u.sem_base, &V_sem[semtot]));
 	} else {
 		DPRINTF(("didn't find it and wasn't asked to create it\n"));
 		error = ENOENT;
@@ -966,9 +1192,9 @@ sys_semget(struct thread *td, struct sem
 	}
 
 found:
-	td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm);
+	td->td_retval[0] = IXSEQ_TO_IPCID(semid, V_sema[semid].u.sem_perm);
 done2:
-	mtx_unlock(&sem_mtx);
+	mtx_unlock(&V_sem_mtx);
 	return (error);
 }
 
@@ -1007,14 +1233,14 @@ sys_semop(struct thread *td, struct semo
 
 	semid = IPCID_TO_IX(semid);	/* Convert back to zero origin */
 
-	if (semid < 0 || semid >= seminfo.semmni)
+	if (semid < 0 || semid >= V_seminfo.semmni)
 		return (EINVAL);
 
 	/* Allocate memory for sem_ops */
 	if (nsops <= SMALL_SOPS)
 		sops = small_sops;
-	else if (nsops > seminfo.semopm) {
-		DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm,
+	else if (nsops > V_seminfo.semopm) {
+		DPRINTF(("too many sops (max=%d, nsops=%d)\n", V_seminfo.semopm,
 		    nsops));
 		return (E2BIG);
 	} else {
@@ -1037,8 +1263,8 @@ sys_semop(struct thread *td, struct semo
 		return (error);
 	}
 
-	semakptr = &sema[semid];
-	sema_mtxp = &sema_mtx[semid];
+	semakptr = &V_sema[semid];
+	sema_mtxp = &V_sema_mtx[semid];
 	mtx_lock(sema_mtxp);
 	if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
 		error = EINVAL;
@@ -1118,7 +1344,7 @@ sys_semop(struct thread *td, struct semo
 					break;
 				}
 			} else if (semptr->semval + sopptr->sem_op >
-			    seminfo.semvmx) {
+			    V_seminfo.semvmx) {
 				error = ERANGE;
 				break;
 			} else {
@@ -1304,7 +1530,7 @@ semexit_myhook(void *arg, struct proc *p
 	 * associated with this process.
 	 */
 	SEMUNDO_LOCK();
-	LIST_FOREACH(suptr, &semu_list, un_next) {
+	LIST_FOREACH(suptr, &V_semu_list, un_next) {
 		if (suptr->un_proc == p)
 			break;
 	}
@@ -1327,8 +1553,8 @@ semexit_myhook(void *arg, struct proc *p
 			semnum = suptr->un_ent[ix].un_num;
 			adjval = suptr->un_ent[ix].un_adjval;
 			seq = suptr->un_ent[ix].un_seq;
-			semakptr = &sema[semid];
-			sema_mtxp = &sema_mtx[semid];
+			semakptr = &V_sema[semid];
+			sema_mtxp = &V_sema_mtx[semid];
 
 			mtx_lock(sema_mtxp);
 			if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
@@ -1365,7 +1591,7 @@ semexit_myhook(void *arg, struct proc *p
 	DPRINTF(("removing vector\n"));
 	suptr->un_proc = NULL;
 	suptr->un_cnt = 0;
-	LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
+	LIST_INSERT_HEAD(&V_semu_free_list, suptr, un_next);
 	SEMUNDO_UNLOCK();
 }
 
@@ -1373,9 +1599,256 @@ static int
 sysctl_sema(SYSCTL_HANDLER_ARGS)
 {
 
-	return (SYSCTL_OUT(req, sema,
-	    sizeof(struct semid_kernel) * seminfo.semmni));
+	return (SYSCTL_OUT(req, V_sema,
+	    sizeof(struct semid_kernel) * V_seminfo.semmni));
+}
+
+
+
+#ifdef VPS
+
+__attribute__ ((noinline, unused))
+int
+sem_snapshot_vps(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_sysvsem_seminfo *vdseminfo;
+	struct vps_dump_sysvsem_semid *vdsema;
+	struct vps_dump_sysvsem_sem *vdsem;
+	struct vps_dump_sysvsem_sem_undo *vdsemu;
+	struct semid_kernel *sema;
+	struct seminfo *seminfo;
+	struct sem *sem;
+	struct sem_undo *semu;
+	int vdsemu_size;
+	int i;
+
+	o1 = vdo_create(ctx, VPS_DUMPOBJT_SYSVSEM_VPS, M_WAITOK);
+
+	seminfo = &VPS_VPS(vps, seminfo);
+	vdseminfo = vdo_space(ctx, sizeof(*vdseminfo), M_WAITOK);
+	vdseminfo->semmni = seminfo->semmni;
+	vdseminfo->semmns = seminfo->semmns;
+	vdseminfo->semmnu = seminfo->semmnu;
+	vdseminfo->semmsl = seminfo->semmsl;
+	vdseminfo->semopm = seminfo->semopm;
+	vdseminfo->semume = seminfo->semume;
+	vdseminfo->semusz = seminfo->semusz;
+	vdseminfo->semvmx = seminfo->semvmx;
+	vdseminfo->semaem = seminfo->semaem;
+	vdseminfo->semtot = VPS_VPS(vps, semtot);
+
+	/* sema */
+	sema = VPS_VPS(vps, sema);
+	vdsema = vdo_space(ctx, sizeof(struct vps_dump_sysvsem_semid) *
+		seminfo->semmni, M_WAITOK);
+	for (i = 0; i < seminfo->semmni; i++) {
+		vdsema[i].sem_base = -1;
+		if (sema[i].u.sem_base != NULL)
+			vdsema[i].sem_base = sema[i].u.sem_base - VPS_VPS(vps, sem);
+		vdsema[i].sem_nsems = sema[i].u.sem_nsems;
+		vdsema[i].sem_otime = sema[i].u.sem_otime;
+		vdsema[i].sem_ctime = sema[i].u.sem_ctime;
+		/* XXX assert label == NULL */
+		vdsema[i].label = sema[i].label;
+		vdsema[i].cred = sema[i].cred;
+		vdsema[i].sem_perm.cuid = sema[i].u.sem_perm.cuid;
+		vdsema[i].sem_perm.cgid = sema[i].u.sem_perm.cgid;
+		vdsema[i].sem_perm.uid = sema[i].u.sem_perm.uid;
+		vdsema[i].sem_perm.gid = sema[i].u.sem_perm.gid;
+		vdsema[i].sem_perm.mode = sema[i].u.sem_perm.mode;
+		vdsema[i].sem_perm.seq = sema[i].u.sem_perm.seq;
+		vdsema[i].sem_perm.key = sema[i].u.sem_perm.key;
+	}
+
+	/* sem */
+	sem = VPS_VPS(vps, sem);
+	vdsem = vdo_space(ctx, sizeof(struct vps_dump_sysvsem_sem) *
+		seminfo->semmns, M_WAITOK);
+	for (i = 0; i < seminfo->semmns; i++) {
+		vdsem[i].semval = sem[i].semval;
+		vdsem[i].sempid = sem[i].sempid;
+		vdsem[i].semncnt = sem[i].semncnt;
+		vdsem[i].semzcnt = sem[i].semzcnt;
+	}
+
+	/* semu */
+	vdsemu_size = sizeof(*vdsemu) + (sizeof(vdsemu->un_ent[0]) * seminfo->semume);
+	vdseminfo->semundo_active = 0;
+	vdsemu = vdo_space(ctx, vdsemu_size * seminfo->semmnu, M_WAITOK);
+
+	LIST_FOREACH(semu, &VPS_VPS(vps, semu_list), un_next) {
+		vdsemu->un_cnt = semu->un_cnt;
+		for (i = 0; i < semu->un_cnt; i++) {
+			vdsemu->un_ent[i].un_adjval = semu->un_ent[i].un_adjval;
+			vdsemu->un_ent[i].un_num = semu->un_ent[i].un_num;
+			vdsemu->un_ent[i].un_id = semu->un_ent[i].un_id;
+			vdsemu->un_ent[i].un_seq = semu->un_ent[i].un_seq;
+		}
+		if (semu->un_proc != NULL)
+			vdsemu->un_proc = semu->un_proc->p_pid;
+
+		/* Next */
+		vdsemu = (struct vps_dump_sysvsem_sem_undo *)((caddr_t)vdsemu + vdsemu_size);
+		vdseminfo->semundo_active++;
+	}
+
+	for (i = 0; i < seminfo->semmni; i++) {
+		if (vdsema[i].cred != NULL)
+			vps_func->vps_snapshot_ucred(ctx, vps, vdsema[i].cred, M_WAITOK);
+	}
+
+	vdo_close(ctx);
+
+	return (0);
+}
+
+__attribute__ ((noinline, unused))
+int
+sem_snapshot_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc *p)
+{
+
+	return (0);
+}
+
+
+__attribute__ ((noinline, unused))
+int
+sem_restore_vps(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dump_sysvsem_seminfo *vdseminfo;
+	struct vps_dump_sysvsem_semid *vdsema;
+	struct vps_dump_sysvsem_sem *vdsem;
+	struct vps_dump_sysvsem_sem_undo *vdsemu;
+	struct vps_dumpobj *o1;
+	struct vps *vps_save;
+	struct seminfo *seminfo;
+	struct semid_kernel *sema;
+	struct sem_undo *semu;
+	struct sem *sem;
+	caddr_t cpos;
+	int vdsemu_size;
+	int i;
+	int j;
+
+	o1 = vdo_next(ctx);
+	if (o1->type != VPS_DUMPOBJT_SYSVSEM_VPS) {
+		printf("%s: o1=%p is not VPS_DUMPOBJT_SYSVSEM_VPS\n",
+			__func__, o1);
+		return (EINVAL);
+	}
+	vdseminfo = (struct vps_dump_sysvsem_seminfo *)o1->data;
+
+	/* realloc in case seminfo is different */
+	vps_save = curthread->td_vps;
+	curthread->td_vps = vps;
+	semunload();
+	seminfo = &VPS_VPS(vps, seminfo);
+	seminfo->semmni = vdseminfo->semmni;
+	seminfo->semmns = vdseminfo->semmns;
+	seminfo->semmnu = vdseminfo->semmnu;
+	seminfo->semmsl = vdseminfo->semmsl;
+	seminfo->semopm = vdseminfo->semopm;
+	seminfo->semume = vdseminfo->semume;
+	seminfo->semusz = vdseminfo->semusz;
+	seminfo->semvmx = vdseminfo->semvmx;
+	seminfo->semaem = vdseminfo->semaem;
+	seminit2();
+	curthread->td_vps = vps_save;
+
+	VPS_VPS(vps, semtot) = vdseminfo->semtot;
+	cpos = (caddr_t)(vdseminfo + 1);
+
+	/* sema */
+	sema = VPS_VPS(vps, sema);
+	vdsema = (struct vps_dump_sysvsem_semid *)cpos;
+	cpos += sizeof(*vdsema) * seminfo->semmni;
+	for (i = 0; i < seminfo->semmni; i++) {
+		sema[i].u.sem_base = NULL;
+		if (vdsema[i].sem_base != -1)
+			sema[i].u.sem_base = VPS_VPS(vps, sem) + vdsema[i].sem_base;
+		sema[i].u.sem_nsems = vdsema[i].sem_nsems;
+		sema[i].u.sem_otime = vdsema[i].sem_otime;
+		sema[i].u.sem_ctime = vdsema[i].sem_ctime;
+		/* XXX assert label == NULL */
+		//sema[i].label = vdsema[i].label;
+		sema[i].label = NULL;
+		sema[i].cred = vdsema[i].cred;
+		sema[i].u.sem_perm.cuid = vdsema[i].sem_perm.cuid;
+		sema[i].u.sem_perm.cgid = vdsema[i].sem_perm.cgid;
+		sema[i].u.sem_perm.uid = vdsema[i].sem_perm.uid;
+		sema[i].u.sem_perm.gid = vdsema[i].sem_perm.gid;
+		sema[i].u.sem_perm.mode = vdsema[i].sem_perm.mode;
+		sema[i].u.sem_perm.seq = vdsema[i].sem_perm.seq;
+		sema[i].u.sem_perm.key = vdsema[i].sem_perm.key;
+	}
+
+	/* sem */
+	sem = VPS_VPS(vps, sem);
+	vdsem = (struct vps_dump_sysvsem_sem *)cpos;
+	cpos += sizeof(*vdsem) * seminfo->semmns;
+	for (i = 0; i < seminfo->semmns; i++) {
+		sem[i].semval = vdsem[i].semval;
+		sem[i].sempid = vdsem[i].sempid;
+		sem[i].semncnt = vdsem[i].semncnt;
+		sem[i].semzcnt = vdsem[i].semzcnt;
+	}
+
+	/* sem undo */
+	vdsemu_size = sizeof(*vdsemu) + (sizeof(vdsemu->un_ent[0]) * seminfo->semume);
+	vdsemu = (struct vps_dump_sysvsem_sem_undo *)cpos;
+	for (i = 0; i < vdseminfo->semundo_active; i++) {
+		if ((semu = LIST_FIRST(&VPS_VPS(vps, semu_free_list))) == NULL)
+			panic("nothing on semu_free_list\n");
+		LIST_REMOVE(semu, un_next);
+		LIST_INSERT_HEAD(&VPS_VPS(vps, semu_list), semu, un_next);
+		semu->un_cnt = vdsemu->un_cnt;
+		/* proc pointers fixup happens later */
+		semu->un_proc = (void *)(size_t)vdsemu->un_proc;
+		for (j = 0; j < semu->un_cnt; j++) {
+			semu->un_ent[j].un_adjval = vdsemu->un_ent[j].un_adjval;
+			semu->un_ent[j].un_num = vdsemu->un_ent[j].un_num;
+			semu->un_ent[j].un_id = vdsemu->un_ent[j].un_id;
+			semu->un_ent[j].un_seq = vdsemu->un_ent[j].un_seq;
+		}
+	}
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_UCRED)
+		vdo_next(ctx);//vps_func->vps_restore_ucred(ctx, vps);
+
+	for (i = 0; i < seminfo->semmni; i++) {
+		if (sema[i].cred != NULL)
+			sema[i].cred = vps_func->vps_restore_ucred_lookup(ctx,
+					vps, sema[i].cred);
+	}
+
+	return (0);
+}
+
+__attribute__ ((noinline, unused))
+int
+sem_restore_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc *p)
+{
+
+	return (0);
+}
+
+__attribute__ ((noinline, unused))
+int
+sem_restore_fixup(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct sem_undo *suptr;
+
+	/* Fixup sem undo proc pointers. */
+	LIST_FOREACH(suptr, &VPS_VPS(vps, semu_list), un_next) {
+		suptr->un_proc = pfind((pid_t)(size_t)suptr->un_proc);
+		KASSERT(suptr->un_proc != NULL,
+			("%s: suptr->un_proc == NULL\n", __func__));
+	}
+
+	return (0);
 }
+#endif
 
 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
@@ -1498,7 +1971,6 @@ freebsd7___semctl(struct thread *td, str
 #endif /* COMPAT_FREEBSD{4,5,6,7} */
 
 #ifdef COMPAT_FREEBSD32
-
 int
 freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap)
 {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/sysv_shm.c head/sys/kern/sysv_shm.c
--- clean-head/sys/kern/sysv_shm.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/sysv_shm.c	2013-06-24 14:20:31.000000000 +0200
@@ -58,6 +58,19 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+/*-
+ * VPS adaption:
+ *
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * <BSD license>
+ *
+ * $Id: sysv_shm.c 162 2013-06-06 18:17:55Z klaus $
+ */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: head/sys/kern/sysv_shm.c 248084 2013-03-09 02:32:23Z attilio $");
@@ -68,6 +81,7 @@ __FBSDID("$FreeBSD: head/sys/kern/sysv_s
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/eventhandler.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/sysctl.h>
@@ -87,6 +101,13 @@ __FBSDID("$FreeBSD: head/sys/kern/sysv_s
 #include <sys/sysproto.h>
 #include <sys/jail.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#include <vps/vps_int.h>
+#include <vps/vps_libdump.h>
+#define _VPS_SNAPST_H_RESTORE_OBJ
+#include <vps/vps_snapst.h>
+
 #include <security/mac/mac_framework.h>
 
 #include <vm/vm.h>
@@ -111,10 +132,47 @@ static int shmget_existing(struct thread
 #define	SHMSEG_ALLOCATED	0x0800
 #define	SHMSEG_WANTED		0x1000
 
+#if 0
 static int shm_last_free, shm_nused, shmalloced;
 vm_size_t shm_committed;
 static struct shmid_kernel	*shmsegs;
 
+struct	shminfo shminfo = {
+	SHMMAX,
+	SHMMIN,
+	SHMMNI,
+	SHMSEG,
+	SHMALL
+};
+
+static int shm_use_phys;
+static int shm_allow_removed;
+#endif
+
+VPS_DEFINE(int, shm_last_free);
+VPS_DEFINE(int, shm_nused);
+VPS_DEFINE(int, shmalloced);
+VPS_DEFINE(vm_size_t, shm_committed);
+VPS_DEFINE(struct shmid_kernel *, shmsegs);
+VPS_DEFINE(struct shminfo, shminfo);
+VPS_DEFINE(int, shm_use_phys) = 0;
+VPS_DEFINE(int, shm_allow_removed) = 0;
+
+#define V_shm_last_free		VPSV(shm_last_free)
+#define V_shm_nused		VPSV(shm_nused)
+#define V_shmalloced		VPSV(shmalloced)
+#define V_shm_committed		VPSV(shm_committed)
+#define V_shmsegs		VPSV(shmsegs)
+#define V_shminfo		VPSV(shminfo)
+#define V_shm_use_phys		VPSV(shm_use_phys)
+#define V_shm_allow_removed	VPSV(shm_allow_removed)
+
+#ifdef VPS
+static eventhandler_tag shm_vpsalloc_tag;
+static eventhandler_tag shm_vpsfree_tag;
+static int shm_nused_global;
+#endif
+
 struct shmmap_state {
 	vm_offset_t va;
 	int shmid;
@@ -155,6 +213,7 @@ static int sysctl_shmsegs(SYSCTL_HANDLER
 #define	SHMALL	(SHMMAXPGS)
 #endif
 
+#if 0
 struct	shminfo shminfo = {
 	SHMMAX,
 	SHMMIN,
@@ -165,23 +224,24 @@ struct	shminfo shminfo = {
 
 static int shm_use_phys;
 static int shm_allow_removed;
+#endif
 
-SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RW, &shminfo.shmmax, 0,
+SYSCTL_VPS_ULONG(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RW, &VPS_NAME(shminfo.shmmax), 0,
     "Maximum shared memory segment size");
-SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RW, &shminfo.shmmin, 0,
+SYSCTL_VPS_ULONG(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RW, &VPS_NAME(shminfo.shmmin), 0,
     "Minimum shared memory segment size");
-SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RDTUN, &shminfo.shmmni, 0,
+SYSCTL_VPS_ULONG(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RDTUN, &VPS_NAME(shminfo.shmmni), 0,
     "Number of shared memory identifiers");
-SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RDTUN, &shminfo.shmseg, 0,
+SYSCTL_VPS_ULONG(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RDTUN, &VPS_NAME(shminfo.shmseg), 0,
     "Number of segments per process");
-SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RW, &shminfo.shmall, 0,
+SYSCTL_VPS_ULONG(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RW, &VPS_NAME(shminfo.shmall), 0,
     "Maximum number of pages available for shared memory");
-SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW,
-    &shm_use_phys, 0, "Enable/Disable locking of shared memory pages in core");
-SYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RW,
-    &shm_allow_removed, 0,
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW,
+    &VPS_NAME(shm_use_phys), 0, "Enable/Disable locking of shared memory pages in core");
+SYSCTL_VPS_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RW,
+    &VPS_NAME(shm_allow_removed), 0,
     "Enable/Disable attachment to attached segments marked for removal");
-SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLTYPE_OPAQUE | CTLFLAG_RD,
+SYSCTL_VPS_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLTYPE_OPAQUE | CTLFLAG_RD,
     NULL, 0, sysctl_shmsegs, "",
     "Current number of shared memory segments allocated");
 
@@ -191,9 +251,9 @@ shm_find_segment_by_key(key)
 {
 	int i;
 
-	for (i = 0; i < shmalloced; i++)
-		if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) &&
-		    shmsegs[i].u.shm_perm.key == key)
+	for (i = 0; i < V_shmalloced; i++)
+		if ((V_shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) &&
+		    V_shmsegs[i].u.shm_perm.key == key)
 			return (i);
 	return (-1);
 }
@@ -205,11 +265,11 @@ shm_find_segment_by_shmid(int shmid)
 	struct shmid_kernel *shmseg;
 
 	segnum = IPCID_TO_IX(shmid);
-	if (segnum < 0 || segnum >= shmalloced)
+	if (segnum < 0 || segnum >= V_shmalloced)
 		return (NULL);
-	shmseg = &shmsegs[segnum];
+	shmseg = &V_shmsegs[segnum];
 	if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
-	    (!shm_allow_removed &&
+	    (!V_shm_allow_removed &&
 	     (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) ||
 	    shmseg->u.shm_perm.seq != IPCID_TO_SEQ(shmid))
 		return (NULL);
@@ -221,11 +281,11 @@ shm_find_segment_by_shmidx(int segnum)
 {
 	struct shmid_kernel *shmseg;
 
-	if (segnum < 0 || segnum >= shmalloced)
+	if (segnum < 0 || segnum >= V_shmalloced)
 		return (NULL);
-	shmseg = &shmsegs[segnum];
+	shmseg = &V_shmsegs[segnum];
 	if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
-	    (!shm_allow_removed &&
+	    (!V_shm_allow_removed &&
 	     (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0))
 		return (NULL);
 	return (shmseg);
@@ -242,8 +302,11 @@ shm_deallocate_segment(shmseg)
 	vm_object_deallocate(shmseg->object);
 	shmseg->object = NULL;
 	size = round_page(shmseg->u.shm_segsz);
-	shm_committed -= btoc(size);
-	shm_nused--;
+	V_shm_committed -= btoc(size);
+	V_shm_nused--;
+#ifdef VPS
+	atomic_subtract_int(&shm_nused_global, 1);
+#endif
 	shmseg->u.shm_perm.mode = SHMSEG_FREE;
 #ifdef MAC
 	mac_sysvshm_cleanup(shmseg);
@@ -264,7 +327,7 @@ shm_delete_mapping(struct vmspace *vm, s
 	GIANT_REQUIRED;
 
 	segnum = IPCID_TO_IX(shmmap_s->shmid);
-	shmseg = &shmsegs[segnum];
+	shmseg = &V_shmsegs[segnum];
 	size = round_page(shmseg->u.shm_segsz);
 	result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size);
 	if (result != KERN_SUCCESS)
@@ -274,7 +337,7 @@ shm_delete_mapping(struct vmspace *vm, s
 	if ((--shmseg->u.shm_nattch <= 0) &&
 	    (shmseg->u.shm_perm.mode & SHMSEG_REMOVED)) {
 		shm_deallocate_segment(shmseg);
-		shm_last_free = segnum;
+		V_shm_last_free = segnum;
 	}
 	return (0);
 }
@@ -305,18 +368,18 @@ sys_shmdt(td, uap)
 		error = EINVAL;
 		goto done2;
 	}
-	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
+	for (i = 0; i < V_shminfo.shmseg; i++, shmmap_s++) {
 		if (shmmap_s->shmid != -1 &&
 		    shmmap_s->va == (vm_offset_t)uap->shmaddr) {
 			break;
 		}
 	}
-	if (i == shminfo.shmseg) {
+	if (i == V_shminfo.shmseg) {
 		error = EINVAL;
 		goto done2;
 	}
 #ifdef MAC
-	shmsegptr = &shmsegs[IPCID_TO_IX(shmmap_s->shmid)];
+	shmsegptr = &V_shmsegs[IPCID_TO_IX(shmmap_s->shmid)];
 	error = mac_sysvshm_check_shmdt(td->td_ucred, shmsegptr);
 	if (error != 0)
 		goto done2;
@@ -356,9 +419,9 @@ kern_shmat(td, shmid, shmaddr, shmflg)
 	mtx_lock(&Giant);
 	shmmap_s = p->p_vmspace->vm_shm;
 	if (shmmap_s == NULL) {
-		shmmap_s = malloc(shminfo.shmseg * sizeof(struct shmmap_state),
+		shmmap_s = malloc(V_shminfo.shmseg * sizeof(struct shmmap_state),
 		    M_SHM, M_WAITOK);
-		for (i = 0; i < shminfo.shmseg; i++)
+		for (i = 0; i < V_shminfo.shmseg; i++)
 			shmmap_s[i].shmid = -1;
 		p->p_vmspace->vm_shm = shmmap_s;
 	}
@@ -376,12 +439,12 @@ kern_shmat(td, shmid, shmaddr, shmflg)
 	if (error != 0)
 		goto done2;
 #endif
-	for (i = 0; i < shminfo.shmseg; i++) {
+	for (i = 0; i < V_shminfo.shmseg; i++) {
 		if (shmmap_s->shmid == -1)
 			break;
 		shmmap_s++;
 	}
-	if (i >= shminfo.shmseg) {
+	if (i >= V_shminfo.shmseg) {
 		error = EMFILE;
 		goto done2;
 	}
@@ -466,14 +529,14 @@ kern_shmctl(td, shmid, cmd, buf, bufsz)
 	 * consistent with the Linux ABI.
 	 */
 	case IPC_INFO:
-		memcpy(buf, &shminfo, sizeof(shminfo));
+		memcpy(buf, &V_shminfo, sizeof(V_shminfo));
 		if (bufsz)
-			*bufsz = sizeof(shminfo);
-		td->td_retval[0] = shmalloced;
+			*bufsz = sizeof(V_shminfo);
+		td->td_retval[0] = V_shmalloced;
 		goto done2;
 	case SHM_INFO: {
 		struct shm_info shm_info;
-		shm_info.used_ids = shm_nused;
+		shm_info.used_ids = V_shm_nused;
 		shm_info.shm_rss = 0;	/*XXX where to get from ? */
 		shm_info.shm_tot = 0;	/*XXX where to get from ? */
 		shm_info.shm_swp = 0;	/*XXX where to get from ? */
@@ -482,7 +545,7 @@ kern_shmctl(td, shmid, cmd, buf, bufsz)
 		memcpy(buf, &shm_info, sizeof(shm_info));
 		if (bufsz)
 			*bufsz = sizeof(shm_info);
-		td->td_retval[0] = shmalloced;
+		td->td_retval[0] = V_shmalloced;
 		goto done2;
 	}
 	}
@@ -534,7 +597,7 @@ kern_shmctl(td, shmid, cmd, buf, bufsz)
 		shmseg->u.shm_perm.mode |= SHMSEG_REMOVED;
 		if (shmseg->u.shm_nattch <= 0) {
 			shm_deallocate_segment(shmseg);
-			shm_last_free = IPCID_TO_IX(shmid);
+			V_shm_last_free = IPCID_TO_IX(shmid);
 		}
 		break;
 #if 0
@@ -611,7 +674,7 @@ shmget_existing(td, uap, mode, segnum)
 	struct shmid_kernel *shmseg;
 	int error;
 
-	shmseg = &shmsegs[segnum];
+	shmseg = &V_shmsegs[segnum];
 	if (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) {
 		/*
 		 * This segment is in the process of being allocated.  Wait
@@ -651,26 +714,26 @@ shmget_allocate_segment(td, uap, mode)
 
 	GIANT_REQUIRED;
 
-	if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
+	if (uap->size < V_shminfo.shmmin || uap->size > V_shminfo.shmmax)
 		return (EINVAL);
-	if (shm_nused >= shminfo.shmmni) /* Any shmids left? */
+	if (V_shm_nused >= V_shminfo.shmmni) /* Any shmids left? */
 		return (ENOSPC);
 	size = round_page(uap->size);
-	if (shm_committed + btoc(size) > shminfo.shmall)
+	if (V_shm_committed + btoc(size) > V_shminfo.shmall)
 		return (ENOMEM);
-	if (shm_last_free < 0) {
+	if (V_shm_last_free < 0) {
 		shmrealloc();	/* Maybe expand the shmsegs[] array. */
-		for (i = 0; i < shmalloced; i++)
-			if (shmsegs[i].u.shm_perm.mode & SHMSEG_FREE)
+		for (i = 0; i < V_shmalloced; i++)
+			if (V_shmsegs[i].u.shm_perm.mode & SHMSEG_FREE)
 				break;
-		if (i == shmalloced)
+		if (i == V_shmalloced)
 			return (ENOSPC);
 		segnum = i;
 	} else  {
-		segnum = shm_last_free;
-		shm_last_free = -1;
+		segnum = V_shm_last_free;
+		V_shm_last_free = -1;
 	}
-	shmseg = &shmsegs[segnum];
+	shmseg = &V_shmsegs[segnum];
 #ifdef RACCT
 	PROC_LOCK(td->td_proc);
 	if (racct_add(td->td_proc, RACCT_NSHM, 1)) {
@@ -697,7 +760,7 @@ shmget_allocate_segment(td, uap, mode)
 	 * We make sure that we have allocated a pager before we need
 	 * to.
 	 */
-	shm_object = vm_pager_allocate(shm_use_phys ? OBJT_PHYS : OBJT_SWAP,
+	shm_object = vm_pager_allocate(V_shm_use_phys ? OBJT_PHYS : OBJT_SWAP,
 	    0, size, VM_PROT_DEFAULT, 0, cred);
 	if (shm_object == NULL) {
 #ifdef RACCT
@@ -727,8 +790,11 @@ shmget_allocate_segment(td, uap, mode)
 	mac_sysvshm_create(cred, shmseg);
 #endif
 	shmseg->u.shm_ctime = time_second;
-	shm_committed += btoc(size);
-	shm_nused++;
+	V_shm_committed += btoc(size);
+	V_shm_nused++;
+#ifdef VPS
+	atomic_add_int(&shm_nused_global, 1);
+#endif
 	if (shmseg->u.shm_perm.mode & SHMSEG_WANTED) {
 		/*
 		 * Somebody else wanted this key while we were asleep.  Wake
@@ -789,13 +855,13 @@ shmfork_myhook(p1, p2)
 	int i;
 
 	mtx_lock(&Giant);
-	size = shminfo.shmseg * sizeof(struct shmmap_state);
+	size = V_shminfo.shmseg * sizeof(struct shmmap_state);
 	shmmap_s = malloc(size, M_SHM, M_WAITOK);
 	bcopy(p1->p_vmspace->vm_shm, shmmap_s, size);
 	p2->p_vmspace->vm_shm = shmmap_s;
-	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
+	for (i = 0; i < V_shminfo.shmseg; i++, shmmap_s++)
 		if (shmmap_s->shmid != -1)
-			shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++;
+			V_shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++;
 	mtx_unlock(&Giant);
 }
 
@@ -808,7 +874,7 @@ shmexit_myhook(struct vmspace *vm)
 	if ((base = vm->vm_shm) != NULL) {
 		vm->vm_shm = NULL;
 		mtx_lock(&Giant);
-		for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) {
+		for (i = 0, shm = base; i < V_shminfo.shmseg; i++, shm++) {
 			if (shm->shmid != -1)
 				shm_delete_mapping(vm, shm);
 		}
@@ -823,24 +889,24 @@ shmrealloc(void)
 	int i;
 	struct shmid_kernel *newsegs;
 
-	if (shmalloced >= shminfo.shmmni)
+	if (V_shmalloced >= V_shminfo.shmmni)
 		return;
 
-	newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK);
+	newsegs = malloc(V_shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK);
 	if (newsegs == NULL)
 		return;
-	for (i = 0; i < shmalloced; i++)
-		bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
-	for (; i < shminfo.shmmni; i++) {
-		shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
-		shmsegs[i].u.shm_perm.seq = 0;
+	for (i = 0; i < V_shmalloced; i++)
+		bcopy(&V_shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
+	for (; i < V_shminfo.shmmni; i++) {
+		V_shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
+		V_shmsegs[i].u.shm_perm.seq = 0;
 #ifdef MAC
-		mac_sysvshm_init(&shmsegs[i]);
+		mac_sysvshm_init(&V_shmsegs[i]);
 #endif
 	}
-	free(shmsegs, M_SHM);
-	shmsegs = newsegs;
-	shmalloced = shminfo.shmmni;
+	free(V_shmsegs, M_SHM);
+	V_shmsegs = newsegs;
+	V_shmalloced = V_shminfo.shmmni;
 }
 
 static struct syscall_helper_data shm_syscalls[] = {
@@ -880,41 +946,168 @@ static struct syscall_helper_data shm32_
 };
 #endif
 
+#ifdef VPS
+
+int shm_snapshot_vps(struct vps_snapst_ctx *ctx, struct vps *vps);
+int shm_snapshot_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc* proc);
+int shm_restore_vps(struct vps_snapst_ctx *ctx, struct vps *vps);
+int shm_restore_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc* proc);
+int shm_restore_fixup(struct vps_snapst_ctx *ctx, struct vps *vps);
+
+static void
+shm_vpsalloc_hook(void *arg, struct vps *vps)
+{
+	/*
+	DPRINTF(("%s: vps=%p\n", __func__, vps));
+	*/
+
+	vps_ref(vps, NULL);
+
+	shminit();
+}
+
+static void
+shm_vpsfree_hook(void *arg, struct vps *vps)
+{
+	/*
+	DPRINTF(("%s: vps=%p\n", __func__, vps));
+	*/
+
+	if (shmunload())
+		printf("%s: shmunload() error\n", __func__);
+
+	vps_deref(vps, NULL);
+}
+
+static int
+shminit_global(void)
+{
+	struct vps *vps, *save_vps;
+	int error;
+
+	save_vps = curthread->td_vps;
+
+	shm_nused_global = 0;
+
+	sx_slock(&vps_all_lock);
+	LIST_FOREACH(vps, &vps_head, vps_all) {
+		curthread->td_vps = vps;
+		shminit();
+		curthread->td_vps = save_vps;
+	}
+	sx_sunlock(&vps_all_lock);
+
+	shmexit_hook = &shmexit_myhook;
+	shmfork_hook = &shmfork_myhook;
+
+	shm_vpsalloc_tag = EVENTHANDLER_REGISTER(vps_alloc, shm_vpsalloc_hook, NULL,
+		EVENTHANDLER_PRI_ANY);
+	shm_vpsfree_tag = EVENTHANDLER_REGISTER(vps_free, shm_vpsfree_hook, NULL,
+		EVENTHANDLER_PRI_ANY);
+
+	vps_func->shm_snapshot_vps = shm_snapshot_vps;
+	vps_func->shm_snapshot_proc = shm_snapshot_proc;
+	vps_func->shm_restore_vps = shm_restore_vps;
+	vps_func->shm_restore_proc = shm_restore_proc;
+	vps_func->shm_restore_fixup = shm_restore_fixup;
+
+	error = syscall_helper_register(shm_syscalls);
+	if (error != 0)
+		return (error);
+#ifdef COMPAT_FREEBSD32
+	error = syscall32_helper_register(shm32_syscalls);
+	if (error != 0)
+		return (error);
+#endif
+	return (error);
+}
+
+static int
+shmunload_global(void)
+{
+	struct vps *vps, *save_vps;
+
+	save_vps = curthread->td_vps;
+ 
+	if (shm_nused_global != 0)
+		return (EBUSY);
+
+#ifdef COMPAT_FREEBSD32
+	syscall32_helper_unregister(shm32_syscalls);
+#endif
+	syscall_helper_unregister(shm_syscalls);
+
+	vps_func->shm_snapshot_vps = NULL;
+	vps_func->shm_snapshot_proc = NULL;
+	vps_func->shm_restore_vps = NULL;
+	vps_func->shm_restore_proc = NULL;
+	vps_func->shm_restore_fixup = NULL;
+
+	EVENTHANDLER_DEREGISTER(vps_alloc, shm_vpsalloc_tag);
+	EVENTHANDLER_DEREGISTER(vps_free, shm_vpsfree_tag);
+
+	shmexit_hook = NULL;
+	shmfork_hook = NULL;
+
+	sx_slock(&vps_all_lock);
+	LIST_FOREACH(vps, &vps_head, vps_all) {
+		curthread->td_vps = vps;
+		if (VPS_VPS(vps, shmsegs))
+			shmunload();
+		curthread->td_vps = save_vps;
+	}
+	sx_sunlock(&vps_all_lock);
+
+	return (0);
+}
+#endif /* VPS */
+
 static int
 shminit()
 {
-	int i, error;
+	int i;
+#ifndef VPS
+	int error;
+#endif
+
+	V_shminfo.shmmax = SHMMAX;
+	V_shminfo.shmmin = SHMMIN;
+	V_shminfo.shmmni = SHMMNI;
+	V_shminfo.shmseg = SHMSEG;
+	V_shminfo.shmall = SHMALL;
 
 #ifndef BURN_BRIDGES
-	if (TUNABLE_ULONG_FETCH("kern.ipc.shmmaxpgs", &shminfo.shmall) != 0)
+	if (TUNABLE_ULONG_FETCH("kern.ipc.shmmaxpgs", &V_shminfo.shmall) != 0)
 		printf("kern.ipc.shmmaxpgs is now called kern.ipc.shmall!\n");
 #endif
-	TUNABLE_ULONG_FETCH("kern.ipc.shmall", &shminfo.shmall);
-	if (!TUNABLE_ULONG_FETCH("kern.ipc.shmmax", &shminfo.shmmax)) {
+	TUNABLE_ULONG_FETCH("kern.ipc.shmall", &V_shminfo.shmall);
+		if (!TUNABLE_ULONG_FETCH("kern.ipc.shmmax", &V_shminfo.shmmax)) {
 		/* Initialize shmmax dealing with possible overflow. */
 		for (i = PAGE_SIZE; i > 0; i--) {
-			shminfo.shmmax = shminfo.shmall * i;
-			if (shminfo.shmmax >= shminfo.shmall)
+			V_shminfo.shmmax = V_shminfo.shmall * i;
+			if (V_shminfo.shmmax >= V_shminfo.shmall)
 				break;
 		}
 	}
-	TUNABLE_ULONG_FETCH("kern.ipc.shmmin", &shminfo.shmmin);
-	TUNABLE_ULONG_FETCH("kern.ipc.shmmni", &shminfo.shmmni);
-	TUNABLE_ULONG_FETCH("kern.ipc.shmseg", &shminfo.shmseg);
-	TUNABLE_INT_FETCH("kern.ipc.shm_use_phys", &shm_use_phys);
-
-	shmalloced = shminfo.shmmni;
-	shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK);
-	for (i = 0; i < shmalloced; i++) {
-		shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
-		shmsegs[i].u.shm_perm.seq = 0;
+	TUNABLE_ULONG_FETCH("kern.ipc.shmmin", &V_shminfo.shmmin);
+	TUNABLE_ULONG_FETCH("kern.ipc.shmmni", &V_shminfo.shmmni);
+	TUNABLE_ULONG_FETCH("kern.ipc.shmseg", &V_shminfo.shmseg);
+	TUNABLE_INT_FETCH("kern.ipc.shm_use_phys", &V_shm_use_phys);
+
+	V_shmalloced = V_shminfo.shmmni;
+	V_shmsegs = malloc(V_shmalloced * sizeof(V_shmsegs[0]), M_SHM, M_WAITOK);
+	for (i = 0; i < V_shmalloced; i++) {
+		V_shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
+		V_shmsegs[i].u.shm_perm.seq = 0;
+		V_shmsegs[i].cred = NULL;
 #ifdef MAC
-		mac_sysvshm_init(&shmsegs[i]);
+		mac_sysvshm_init(&V_shmsegs[i]);
 #endif
 	}
-	shm_last_free = 0;
-	shm_nused = 0;
-	shm_committed = 0;
+	V_shm_last_free = 0;
+	V_shm_nused = 0;
+	V_shm_committed = 0;
+#ifndef VPS
 	shmexit_hook = &shmexit_myhook;
 	shmfork_hook = &shmfork_myhook;
 
@@ -926,6 +1119,7 @@ shminit()
 	if (error != 0)
 		return (error);
 #endif
+#endif /* !VPS */
 	return (0);
 }
 
@@ -934,29 +1128,42 @@ shmunload()
 {
 	int i;	
 
-	if (shm_nused > 0)
+#ifdef VPS
+	/* Cleaning up */
+	mtx_lock(&Giant);
+	for (i = 0; i < V_shmalloced; i++)
+		if ((V_shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED)
+			&& V_shmsegs[i].object != NULL)
+			shm_deallocate_segment(&V_shmsegs[i]);
+	mtx_unlock(&Giant);
+#endif
+	if (V_shm_nused > 0)
 		return (EBUSY);
 
+#ifndef VPS
 #ifdef COMPAT_FREEBSD32
 	syscall32_helper_unregister(shm32_syscalls);
 #endif
 	syscall_helper_unregister(shm_syscalls);
+#endif /* !VPS */
 
-	for (i = 0; i < shmalloced; i++) {
+	for (i = 0; i < V_shmalloced; i++) {
 #ifdef MAC
-		mac_sysvshm_destroy(&shmsegs[i]);
+		mac_sysvshm_destroy(&V_shmsegs[i]);
 #endif
 		/*
 		 * Objects might be still mapped into the processes
 		 * address spaces.  Actual free would happen on the
 		 * last mapping destruction.
 		 */
-		if (shmsegs[i].u.shm_perm.mode != SHMSEG_FREE)
-			vm_object_deallocate(shmsegs[i].object);
+		if (V_shmsegs[i].u.shm_perm.mode != SHMSEG_FREE)
+			vm_object_deallocate(V_shmsegs[i].object);
 	}
-	free(shmsegs, M_SHM);
+	free(V_shmsegs, M_SHM);
+#ifndef VPS
 	shmexit_hook = NULL;
 	shmfork_hook = NULL;
+#endif
 	return (0);
 }
 
@@ -964,7 +1171,7 @@ static int
 sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
 {
 
-	return (SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0])));
+	return (SYSCTL_OUT(req, V_shmsegs, V_shmalloced * sizeof(V_shmsegs[0])));
 }
 
 #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
@@ -1381,12 +1588,22 @@ sysvshm_modload(struct module *module, i
 
 	switch (cmd) {
 	case MOD_LOAD:
+#ifdef VPS
+		error = shminit_global();
+		if (error != 0)
+			shmunload();
+#else
 		error = shminit();
 		if (error != 0)
 			shmunload();
+#endif
 		break;
 	case MOD_UNLOAD:
+#ifdef VPS
+		error = shmunload_global();
+#else
 		error = shmunload();
+#endif
 		break;
 	case MOD_SHUTDOWN:
 		break;
@@ -1405,3 +1622,226 @@ static moduledata_t sysvshm_mod = {
 
 DECLARE_MODULE(sysvshm, sysvshm_mod, SI_SUB_SYSV_SHM, SI_ORDER_FIRST);
 MODULE_VERSION(sysvshm, 1);
+
+#ifdef VPS
+
+__attribute__ ((noinline, unused))
+int
+shm_snapshot_vps(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dump_sysvshm_shminfo *vdshminfo;
+	struct vps_dump_sysvshm_shmid *vdshmsegs;
+	struct vps_dumpobj *o1;
+	struct shminfo *shminfo;
+	struct shmid_kernel *shmsegs;
+	int i;
+
+	o1 = vdo_create(ctx, VPS_DUMPOBJT_SYSVSHM_VPS, M_WAITOK);
+
+	shminfo = &VPS_VPS(vps, shminfo);
+	vdshminfo = vdo_space(ctx, sizeof(*vdshminfo), M_WAITOK);
+
+	vdshminfo->shmmax = shminfo->shmmax;
+	vdshminfo->shmmin = shminfo->shmmin;
+	vdshminfo->shmmni = shminfo->shmmni;
+	vdshminfo->shmseg = shminfo->shmseg;
+	vdshminfo->shmall = shminfo->shmall;
+	vdshminfo->shm_last_free = VPS_VPS(vps, shm_last_free);
+	vdshminfo->shm_nused = VPS_VPS(vps, shm_nused);
+	vdshminfo->shmalloced = VPS_VPS(vps, shmalloced);
+	vdshminfo->shm_committed = VPS_VPS(vps, shm_committed);
+
+	shmsegs = VPS_VPS(vps, shmsegs);
+	vdshmsegs = vdo_space(ctx, sizeof(*vdshmsegs) * shminfo->shmmni, M_WAITOK);
+	for (i = 0; i < shminfo->shmmni; i++) {
+		vdshmsegs[i].shm_perm.cuid = shmsegs[i].u.shm_perm.cuid;
+		vdshmsegs[i].shm_perm.cgid = shmsegs[i].u.shm_perm.cgid;
+		vdshmsegs[i].shm_perm.uid = shmsegs[i].u.shm_perm.uid;
+		vdshmsegs[i].shm_perm.gid = shmsegs[i].u.shm_perm.gid;
+		vdshmsegs[i].shm_perm.mode = shmsegs[i].u.shm_perm.mode;
+		vdshmsegs[i].shm_perm.seq = shmsegs[i].u.shm_perm.seq;
+		vdshmsegs[i].shm_perm.key = shmsegs[i].u.shm_perm.key;
+		vdshmsegs[i].shm_segsz = shmsegs[i].u.shm_segsz;
+		vdshmsegs[i].shm_lpid = shmsegs[i].u.shm_lpid;
+		vdshmsegs[i].shm_cpid = shmsegs[i].u.shm_cpid;
+		vdshmsegs[i].shm_nattch = shmsegs[i].u.shm_nattch;
+		vdshmsegs[i].shm_atime = shmsegs[i].u.shm_atime;
+		vdshmsegs[i].shm_ctime = shmsegs[i].u.shm_ctime;
+		vdshmsegs[i].shm_dtime = shmsegs[i].u.shm_dtime;
+		vdshmsegs[i].object = shmsegs[i].object;
+		/* XXX assert label == NULL */
+		vdshmsegs[i].label = shmsegs[i].label;
+		vdshmsegs[i].cred = shmsegs[i].cred;
+		if (shmsegs[i].cred != NULL)
+			vps_func->vps_snapshot_ucred(ctx, vps, shmsegs[i].cred, M_WAITOK);
+	}
+
+	vdo_close(ctx);
+
+	return (0);
+}
+
+__attribute__ ((noinline, unused))
+int
+shm_snapshot_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc* proc)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_sysvshm_shmmap_state *vdbase;
+	struct shmmap_state *base;
+	int i;
+
+	if (proc->p_vmspace->vm_shm == NULL)
+		return (0);
+
+	o1 = vdo_create(ctx, VPS_DUMPOBJT_SYSVSHM_PROC, M_WAITOK);
+
+	base = proc->p_vmspace->vm_shm;
+	vdbase = vdo_space(ctx, sizeof(*vdbase) *
+		VPS_VPS(vps, shminfo).shmseg, M_WAITOK);
+	for (i = 0; i < VPS_VPS(vps, shminfo).shmseg; i++) {
+		vdbase[i].va = base[i].va;
+		vdbase[i].shmid = base[i].shmid;
+	}
+
+	vdo_close(ctx);
+
+	return (0);
+}
+
+__attribute__ ((noinline, unused))
+int
+shm_restore_vps(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dump_sysvshm_shminfo *vdshminfo;
+	struct vps_dump_sysvshm_shmid *vdshmsegs;
+	struct vps_dumpobj *o1;
+	struct shminfo *shminfo;
+	struct shmid_kernel *shmsegs;
+	int i;
+
+	o1 = vdo_next(ctx);
+        if (o1->type != VPS_DUMPOBJT_SYSVSHM_VPS) {
+		printf("%s: o1=%p is not VPS_DUMPOBJT_SYSVSHM_VPS\n",
+			__func__, o1);
+		return (EINVAL);
+	}
+	shminfo = &VPS_VPS(vps, shminfo);
+	vdshminfo = (struct vps_dump_sysvshm_shminfo *)o1->data;
+
+        shminfo->shmmax = vdshminfo->shmmax;
+	shminfo->shmmin = vdshminfo->shmmin;
+	shminfo->shmmni = vdshminfo->shmmni;
+	shminfo->shmseg = vdshminfo->shmseg;
+	shminfo->shmall = vdshminfo->shmall;
+
+	free(VPS_VPS(vps, shmsegs), M_SHM);
+	VPS_VPS(vps, shmsegs) = malloc(VPS_VPS(vps, shmalloced) *
+		sizeof(VPS_VPS(vps, shmsegs[0])), M_SHM, M_WAITOK);
+
+	VPS_VPS(vps, shm_last_free) = vdshminfo->shm_last_free;
+	VPS_VPS(vps, shm_nused) = vdshminfo->shm_nused;
+	VPS_VPS(vps, shmalloced) = vdshminfo->shmalloced;
+	VPS_VPS(vps, shm_committed) = vdshminfo->shm_committed;
+
+	shmsegs = VPS_VPS(vps, shmsegs);
+	vdshmsegs = (struct vps_dump_sysvshm_shmid *)(vdshminfo + 1);
+	for (i = 0; i < shminfo->shmmni; i++) {
+		shmsegs[i].u.shm_perm.cuid = vdshmsegs[i].shm_perm.cuid;
+		shmsegs[i].u.shm_perm.cgid = vdshmsegs[i].shm_perm.cgid;
+		shmsegs[i].u.shm_perm.uid = vdshmsegs[i].shm_perm.uid;
+		shmsegs[i].u.shm_perm.gid = vdshmsegs[i].shm_perm.gid;
+		shmsegs[i].u.shm_perm.mode = vdshmsegs[i].shm_perm.mode;
+		shmsegs[i].u.shm_perm.seq = vdshmsegs[i].shm_perm.seq;
+		shmsegs[i].u.shm_perm.key = vdshmsegs[i].shm_perm.key;
+		shmsegs[i].u.shm_segsz = vdshmsegs[i].shm_segsz;
+		shmsegs[i].u.shm_lpid = vdshmsegs[i].shm_lpid;
+		shmsegs[i].u.shm_cpid = vdshmsegs[i].shm_cpid;
+		shmsegs[i].u.shm_nattch = vdshmsegs[i].shm_nattch;
+		shmsegs[i].u.shm_atime = vdshmsegs[i].shm_atime;
+		shmsegs[i].u.shm_ctime = vdshmsegs[i].shm_ctime;
+		shmsegs[i].u.shm_dtime = vdshmsegs[i].shm_dtime;
+		/* object fixed up later */
+		shmsegs[i].object = vdshmsegs[i].object;
+		/* XXX assert label == NULL */
+		//shmsegs[i].label = vdshmsegs[i].label;
+		shmsegs[i].label = NULL;
+		shmsegs[i].cred = vdshmsegs[i].cred;
+	}
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_UCRED)
+		vdo_next(ctx);//vps_func->vps_restore_ucred(ctx, vps);
+
+	for (i = 0; i < shminfo->shmmni; i++) {
+		if (shmsegs[i].cred != NULL)
+			shmsegs[i].cred = vps_func->vps_restore_ucred_lookup(ctx, vps,
+				shmsegs[i].cred);
+	}
+
+	return (0);
+}
+
+__attribute__ ((noinline, unused))
+int
+shm_restore_proc(struct vps_snapst_ctx *ctx, struct vps *vps, struct proc *proc)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_sysvshm_shmmap_state *vdbase;
+	struct shmmap_state *base;
+	int i;
+
+	o1 = vdo_next(ctx);
+        if (o1->type != VPS_DUMPOBJT_SYSVSHM_PROC) {
+		printf("%s: o1=%p is not VPS_DUMPOBJT_SYSVSHM_PROC\n",
+			__func__, o1);
+		return (EINVAL);
+	}
+
+	proc->p_vmspace->vm_shm = malloc(sizeof(*base) * VPS_VPS(vps, shminfo).shmseg,
+			M_SHM, M_WAITOK);
+	base = proc->p_vmspace->vm_shm;
+	vdbase = (struct vps_dump_sysvshm_shmmap_state *)o1->data;
+
+	for (i = 0; i < VPS_VPS(vps, shminfo).shmseg; i++) {
+		base[i].va = vdbase[i].va;
+		base[i].shmid = vdbase[i].shmid;
+	}
+
+	return (0);
+}
+
+__attribute__ ((noinline, unused))
+int
+shm_restore_fixup(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_restore_obj *vbo;
+	struct shmid_kernel *shmseg;
+	int found;
+	int i;
+
+	for (i = 0; i < VPS_VPS(vps, shminfo).shmmni; i++) {
+		shmseg = &VPS_VPS(vps, shmsegs)[i];
+
+		if ( ! (shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) )
+			continue;
+
+		/* Look up vm object. */
+		found = 0;
+		SLIST_FOREACH(vbo, &ctx->obj_list, list)
+			if (vbo->type == VPS_DUMPOBJT_VMOBJECT &&
+			    vbo->orig_ptr == shmseg->object) {
+				vm_object_reference(vbo->new_ptr);
+				shmseg->object = vbo->new_ptr;
+				found = 1;
+				break;
+			}
+		KASSERT((found != 0), ("%s: object not found !\n", __func__));
+
+		printf("%s: shmseg=%p i=%d object=%p, mode=%08x seq=%08x shm_nattch=%d\n",
+			__func__, shmseg, i, shmseg->object, shmseg->u.shm_perm.mode,
+			shmseg->u.shm_perm.seq, shmseg->u.shm_nattch);
+
+	}
+
+	return (0);
+}
+#endif
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/tty.c head/sys/kern/tty.c
--- clean-head/sys/kern/tty.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/tty.c	2013-06-24 14:20:31.000000000 +0200
@@ -65,6 +65,9 @@ __FBSDID("$FreeBSD: head/sys/kern/tty.c 
 #include <sys/ucred.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <machine/stdarg.h>
 
 static MALLOC_DEFINE(M_TTY, "tty", "tty device");
@@ -77,7 +80,11 @@ SX_SYSINIT(tty_list, &tty_list_sx, "tty 
 static unsigned int tty_list_count = 0;
 
 /* Character device of /dev/console. */
+#ifdef VPS
+struct cdev		*dev_console;
+#else
 static struct cdev	*dev_console;
+#endif
 static const char	*dev_console_filename;
 
 /*
@@ -393,6 +400,28 @@ tty_wait_background(struct tty *tp, stru
 		    SIGISMEMBER(td->td_sigmask, sig)) {
 			/* Only allow them in write()/ioctl(). */
 			PROC_UNLOCK(p);
+			if (sig != SIGTTOU) {
+				printf("%s: EIO #01 PID=%d\n", __func__, p->p_pid);
+				printf("%s: td->td_sigmask:\n"
+					"   0=%08x\n"
+					"   1=%08x\n"
+					"   2=%08x\n"
+					"   3=%08x\n"
+					, __func__
+					, td->td_sigmask.__bits[0]
+					, td->td_sigmask.__bits[1]
+					, td->td_sigmask.__bits[2]
+					, td->td_sigmask.__bits[3]
+					);
+				if (SIGISMEMBER(p->p_sigacts->ps_sigignore, sig))
+					printf (" --> p->p_sigacts->ps_sigignore\n");
+				if (SIGISMEMBER(td->td_sigmask, sig))
+					printf (" --> td->td_sigmask\n");
+				if (tty_is_ctty(tp, p))
+					printf ("tty_is_ctty(tp, p)\n");
+				if (p->p_pgrp == tp->t_pgrp)
+					printf ("p->p_pgrp == tp->t_pgrp\n");
+			}
 			return (sig == SIGTTOU ? 0 : EIO);
 		}
 
@@ -400,6 +429,7 @@ tty_wait_background(struct tty *tp, stru
 		if (p->p_flag & P_PPWAIT || pg->pg_jobc == 0) {
 			/* Don't allow the action to happen. */
 			PROC_UNLOCK(p);
+			printf("%s: EIO #02\n", __func__);
 			return (EIO);
 		}
 		PROC_UNLOCK(p);
@@ -1574,18 +1604,18 @@ tty_generic_ioctl(struct tty *tp, u_long
 
 		/* XXX: This looks awful. */
 		tty_unlock(tp);
-		sx_xlock(&proctree_lock);
+		sx_xlock(&V_proctree_lock);
 		tty_lock(tp);
 
 		if (!SESS_LEADER(p)) {
 			/* Only the session leader may do this. */
-			sx_xunlock(&proctree_lock);
+			sx_xunlock(&V_proctree_lock);
 			return (EPERM);
 		}
 
 		if (tp->t_session != NULL && tp->t_session == p->p_session) {
 			/* This is already our controlling TTY. */
-			sx_xunlock(&proctree_lock);
+			sx_xunlock(&V_proctree_lock);
 			return (0);
 		}
 
@@ -1603,7 +1633,7 @@ tty_generic_ioctl(struct tty *tp, u_long
 			 * TTYs of which the session leader has been
 			 * killed or the TTY revoked.
 			 */
-			sx_xunlock(&proctree_lock);
+			sx_xunlock(&V_proctree_lock);
 			return (EPERM);
 		}
 
@@ -1611,7 +1641,7 @@ tty_generic_ioctl(struct tty *tp, u_long
 		tp->t_session = p->p_session;
 		tp->t_session->s_ttyp = tp;
 		tp->t_sessioncnt++;
-		sx_xunlock(&proctree_lock);
+		sx_xunlock(&V_proctree_lock);
 
 		/* Assign foreground process group. */
 		tp->t_pgrp = p->p_pgrp;
@@ -1630,12 +1660,12 @@ tty_generic_ioctl(struct tty *tp, u_long
 		 * decompose proctree_lock.
 		 */
 		tty_unlock(tp);
-		sx_slock(&proctree_lock);
+		sx_slock(&V_proctree_lock);
 		pg = pgfind(*(int *)data);
 		if (pg != NULL)
 			PGRP_UNLOCK(pg);
 		if (pg == NULL || pg->pg_session != td->td_proc->p_session) {
-			sx_sunlock(&proctree_lock);
+			sx_sunlock(&V_proctree_lock);
 			tty_lock(tp);
 			return (EPERM);
 		}
@@ -1646,11 +1676,11 @@ tty_generic_ioctl(struct tty *tp, u_long
 		 * relocking the TTY.
 		 */
 		if (!tty_is_ctty(tp, td->td_proc)) {
-			sx_sunlock(&proctree_lock);
+			sx_sunlock(&V_proctree_lock);
 			return (ENOTTY);
 		}
 		tp->t_pgrp = pg;
-		sx_sunlock(&proctree_lock);
+		sx_sunlock(&V_proctree_lock);
 
 		/* Wake up the background process groups. */
 		cv_broadcast(&tp->t_bgwait);
@@ -1982,8 +2012,13 @@ static void
 ttyconsdev_init(void *unused)
 {
 
+#ifdef VPS
+	dev_console = make_dev_credf(MAKEDEV_ETERNAL, &ttyconsdev_cdevsw, 0,
+	    vps0->vps_ucred, UID_ROOT, GID_WHEEL, 0600, "console");
+#else
 	dev_console = make_dev_credf(MAKEDEV_ETERNAL, &ttyconsdev_cdevsw, 0,
 	    NULL, UID_ROOT, GID_WHEEL, 0600, "console");
+#endif
 }
 
 SYSINIT(tty, SI_SUB_DRIVERS, SI_ORDER_FIRST, ttyconsdev_init, NULL);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/tty_pts.c head/sys/kern/tty_pts.c
--- clean-head/sys/kern/tty_pts.c	2013-06-26 09:37:48.000000000 +0200
+++ head/sys/kern/tty_pts.c	2013-06-24 14:20:31.000000000 +0200
@@ -63,6 +63,8 @@ __FBSDID("$FreeBSD: head/sys/kern/tty_pt
 #include <sys/tty.h>
 #include <sys/ttycom.h>
 
+#include <vps/vps.h>
+
 #include <machine/stdarg.h>
 
 /*
@@ -71,7 +73,8 @@ __FBSDID("$FreeBSD: head/sys/kern/tty_pt
  * users to increase this number, assuming they have manually increased
  * UT_LINESIZE.
  */
-static struct unrhdr *pts_pool;
+VPS_DEFINE(struct unrhdr *, pts_pool) = NULL;
+#define V_pts_pool    VPSV(pts_pool)
 
 static MALLOC_DEFINE(M_PTS, "pts", "pseudo tty device");
 
@@ -679,10 +682,23 @@ static void
 ptsdrv_free(void *softc)
 {
 	struct pts_softc *psc = softc;
+#ifdef VPS
+	struct vps *save_vps;
+
+	/*
+	 * Since we come in here from the giant taskqueue thread,
+	 * we have to to restore the proper vps reference.
+	 */
+	if (psc->pts_cred) {
+		save_vps = curthread->td_vps;
+		curthread->td_vps = psc->pts_cred->cr_vps;
+	} else
+		save_vps = NULL;
+#endif
 
 	/* Make device number available again. */
 	if (psc->pts_unit >= 0)
-		free_unr(pts_pool, psc->pts_unit);
+		free_unr(V_pts_pool, psc->pts_unit);
 
 	chgptscnt(psc->pts_cred->cr_ruidinfo, -1, 0);
 	racct_sub_cred(psc->pts_cred, RACCT_NPTS, 1);
@@ -700,6 +716,11 @@ ptsdrv_free(void *softc)
 #endif /* PTS_EXTERNAL */
 
 	free(psc, M_PTS);
+
+#ifdef VPS
+	if (save_vps)
+		curthread->td_vps = save_vps;
+#endif
 }
 
 static struct ttydevsw pts_class = {
@@ -715,9 +736,21 @@ static struct ttydevsw pts_class = {
 #ifndef PTS_EXTERNAL
 static
 #endif /* !PTS_EXTERNAL */
+#ifdef VPS
 int
 pts_alloc(int fflags, struct thread *td, struct file *fp)
 {
+
+	return (pts_alloc2(fflags, td, fp, -1));
+}
+
+int
+pts_alloc2(int fflags, struct thread *td, struct file *fp, int want_unit)
+#else
+int
+pts_alloc(int fflags, struct thread *td, struct file *fp)
+#endif /* !VPS */
+{
 	int unit, ok, error;
 	struct tty *tp;
 	struct pts_softc *psc;
@@ -739,8 +772,20 @@ pts_alloc(int fflags, struct thread *td,
 	}
 	PROC_UNLOCK(p);
 
-	/* Try to allocate a new pts unit number. */
-	unit = alloc_unr(pts_pool);
+#ifdef VPS
+	if (want_unit > -1) {
+		//unit = alloc_unr_unit(V_pts_pool, want_unit);                   
+		unit = alloc_unr_specific(V_pts_pool, want_unit);
+		if (unit == -1) {
+			printf("%s: vps=%p could not allocate unit=%d from pool=%p\n",
+			    __func__, curthread->td_vps, want_unit, V_pts_pool);
+			return (EEXIST);
+		}
+	} else
+#endif
+		/* Try to allocate a new pts unit number. */
+		unit = alloc_unr(V_pts_pool);
+
 	if (unit < 0) {
 		racct_sub(p, RACCT_NPTS, 1);
 		chgptscnt(cred->cr_ruidinfo, -1, 0);
@@ -815,8 +860,21 @@ pts_alloc_external(int fflags, struct th
 }
 #endif /* PTS_EXTERNAL */
 
+#ifdef VPS
+int sys_posix_openpt_unit(struct thread *, struct posix_openpt_args *, int);
+
+int
+sys_posix_openpt(struct thread *td, struct posix_openpt_args *uap)
+{
+      return (sys_posix_openpt_unit(td, uap, -1));
+}
+
+int
+sys_posix_openpt_unit(struct thread *td, struct posix_openpt_args *uap, int unit)
+#else
 int
 sys_posix_openpt(struct thread *td, struct posix_openpt_args *uap)
+#endif /* !VPS */
 {
 	int error, fd;
 	struct file *fp;
@@ -833,7 +891,11 @@ sys_posix_openpt(struct thread *td, stru
 		return (error);
 
 	/* Allocate the actual pseudo-TTY. */
+#ifdef VPS
+	error = pts_alloc2(FFLAGS(uap->flags & O_ACCMODE), td, fp, unit);
+#else
 	error = pts_alloc(FFLAGS(uap->flags & O_ACCMODE), td, fp);
+#endif
 	if (error != 0) {
 		fdclose(td->td_proc->p_fd, fp, fd, td);
 		fdrop(fp, td);
@@ -851,7 +913,9 @@ static void
 pts_init(void *unused)
 {
 
-	pts_pool = new_unrhdr(0, INT_MAX, NULL);
+#ifndef VPS
+	V_pts_pool = new_unrhdr(0, INT_MAX, NULL);
+#endif
 }
 
 SYSINIT(pts, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, pts_init, NULL);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/tty_tty.c head/sys/kern/tty_tty.c
--- clean-head/sys/kern/tty_tty.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/tty_tty.c	2013-06-24 14:20:31.000000000 +0200
@@ -34,6 +34,8 @@ __FBSDID("$FreeBSD: head/sys/kern/tty_tt
 #include <sys/sx.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+
 #include <fs/devfs/devfs.h>
 #include <fs/devfs/devfs_int.h>
 
@@ -64,7 +66,7 @@ ctty_clone(void *arg, struct ucred *cred
 	if (strcmp(name, "tty"))
 		return;
 	sx_sunlock(&clone_drain_lock);
-	sx_slock(&proctree_lock);
+	sx_slock(&V_proctree_lock);
 	sx_slock(&clone_drain_lock);
 	dev_lock();
 	if (!(curthread->td_proc->p_flag & P_CONTROLT))
@@ -79,7 +81,7 @@ ctty_clone(void *arg, struct ucred *cred
 		*dev = curthread->td_proc->p_session->s_ttyvp->v_rdev;
 	dev_refl(*dev);
 	dev_unlock();
-	sx_sunlock(&proctree_lock);
+	sx_sunlock(&V_proctree_lock);
 }
 
 static void
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/uipc_socket.c head/sys/kern/uipc_socket.c
--- clean-head/sys/kern/uipc_socket.c	2013-06-26 09:37:48.000000000 +0200
+++ head/sys/kern/uipc_socket.c	2013-06-24 14:20:31.000000000 +0200
@@ -140,6 +140,8 @@ __FBSDID("$FreeBSD: head/sys/kern/uipc_s
 
 #include <net/vnet.h>
 
+#include <vps/vps.h>
+
 #include <security/mac/mac_framework.h>
 
 #include <vm/uma.h>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/uipc_syscalls.c head/sys/kern/uipc_syscalls.c
--- clean-head/sys/kern/uipc_syscalls.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/uipc_syscalls.c	2013-06-24 14:20:31.000000000 +0200
@@ -97,6 +97,10 @@ __FBSDID("$FreeBSD: head/sys/kern/uipc_s
 #endif /* SCTP */
 #endif /* INET || INET6 */
 
+#ifdef VPS
+int getsock(struct filedesc *fdp, int fd, struct file **fpp, u_int *fflagp);
+#endif
+
 /*
  * Flags for accept1() and kern_accept4(), in addition to SOCK_CLOEXEC
  * and SOCK_NONBLOCK.
@@ -154,6 +158,16 @@ getsock_cap(struct filedesc *fdp, int fd
 	return (0);
 }
 
+#ifdef VPS
+int
+getsock(struct filedesc *fdp, int fd, struct file **fpp, u_int *fflagp)
+{
+
+	/* XXX cap_rights_t rights --> 0 */
+	return (getsock_cap(fdp, fd, 0, fpp, fflagp));
+}
+#endif
+
 /*
  * System call interface to the socket abstraction.
  */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/vfs_bio.c head/sys/kern/vfs_bio.c
--- clean-head/sys/kern/vfs_bio.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/vfs_bio.c	2013-06-24 14:20:31.000000000 +0200
@@ -79,6 +79,9 @@ __FBSDID("$FreeBSD: head/sys/kern/vfs_bi
 #include "opt_directio.h"
 #include "opt_swap.h"
 
+#include <vps/vps.h>
+#include <vps/vps_account.h>
+
 static MALLOC_DEFINE(M_BIOBUF, "biobuf", "BIO buffer");
 
 struct	bio_ops bioops;		/* I/O operation notification */
@@ -132,11 +135,12 @@ SYSCTL_LONG(_vfs, OID_AUTO, runningbufsp
 static long bufspace;
 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
     defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
-SYSCTL_PROC(_vfs, OID_AUTO, bufspace, CTLTYPE_LONG|CTLFLAG_MPSAFE|CTLFLAG_RD,
-    &bufspace, 0, sysctl_bufspace, "L", "Virtual memory used for buffers");
+_SYSCTL_PROC(_vfs, OID_AUTO, bufspace, CTLTYPE_LONG|CTLFLAG_MPSAFE|CTLFLAG_RD,
+    &bufspace, 0, sysctl_bufspace, "L", "Virtual memory used for buffers", VPS_PUBLIC);
 #else
-SYSCTL_LONG(_vfs, OID_AUTO, bufspace, CTLFLAG_RD, &bufspace, 0,
-    "Virtual memory used for buffers");
+/* XXX */
+_SYSCTL_LONG(_vfs, OID_AUTO, bufspace, CTLFLAG_RD, &bufspace, 0,
+    "Virtual memory used for buffers", VPS_0);
 #endif
 static long unmapped_bufspace;
 SYSCTL_LONG(_vfs, OID_AUTO, unmapped_bufspace, CTLFLAG_RD,
@@ -340,6 +344,14 @@ sysctl_bufspace(SYSCTL_HANDLER_ARGS)
 	long lvalue;
 	int ivalue;
 
+#ifdef VPS
+	/* XXX value */
+	if (req->td->td_vps != vps0) {
+		lvalue = 0;
+		return (sysctl_handle_long(oidp, &lvalue, 0, req));
+	}
+#endif
+
 	if (sizeof(int) == sizeof(long) || req->oldlen >= sizeof(long))
 		return (sysctl_handle_long(oidp, arg1, arg2, req));
 	lvalue = *(long *)arg1;
@@ -566,6 +578,18 @@ waitrunningbufspace(void)
 	mtx_unlock(&rbreqlock);
 }
 
+#ifdef VPS
+int vps_bio_runningbufspace_high(void);
+int
+vps_bio_runningbufspace_high(void)
+{
+	if (runningbufspace > hirunningspace / 2)
+		return (1);
+	else
+		return (0);
+}
+#endif
+
 
 /*
  *	vfs_buf_test_cache:
@@ -1072,8 +1096,12 @@ breada(struct vnode * vp, daddr_t * rabl
 		rabp = getblk(vp, *rablkno, *rabsize, 0, 0, 0);
 
 		if ((rabp->b_flags & B_CACHE) == 0) {
-			if (!TD_IS_IDLETHREAD(curthread))
+			if (!TD_IS_IDLETHREAD(curthread)) {
 				curthread->td_ru.ru_inblock++;
+#ifdef VPS
+				vps_account_bio(curthread);
+#endif
+			}
 			rabp->b_flags |= B_ASYNC;
 			rabp->b_flags &= ~B_INVAL;
 			rabp->b_ioflags &= ~BIO_ERROR;
@@ -1115,8 +1143,12 @@ breadn_flags(struct vnode *vp, daddr_t b
 
 	/* if not found in cache, do some I/O */
 	if ((bp->b_flags & B_CACHE) == 0) {
-		if (!TD_IS_IDLETHREAD(curthread))
+		if (!TD_IS_IDLETHREAD(curthread)) {
 			curthread->td_ru.ru_inblock++;
+#ifdef VPS
+			vps_account_bio(curthread);
+#endif
+		}
 		bp->b_iocmd = BIO_READ;
 		bp->b_flags &= ~B_INVAL;
 		bp->b_ioflags &= ~BIO_ERROR;
@@ -1171,6 +1203,11 @@ bufwrite(struct buf *bp)
 	if (bp->b_pin_count > 0)
 		bunpin_wait(bp);
 
+#ifdef VPS
+	if (!TD_IS_IDLETHREAD(curthread))
+		vps_account_bio(curthread);
+#endif
+
 	KASSERT(!(bp->b_vflags & BV_BKGRDINPROG),
 	    ("FFS background buffer should not get here %p", bp));
 
@@ -1202,8 +1239,10 @@ bufwrite(struct buf *bp)
 	bp->b_runningbufspace = bp->b_bufsize;
 	space = atomic_fetchadd_long(&runningbufspace, bp->b_runningbufspace);
 
-	if (!TD_IS_IDLETHREAD(curthread))
+	if (!TD_IS_IDLETHREAD(curthread)) {
 		curthread->td_ru.ru_oublock++;
+		//vps_account_bio(curthread);
+	}
 	if (oldflags & B_ASYNC)
 		BUF_KERNPROC(bp);
 	bp->b_iooffset = dbtob(bp->b_blkno);
@@ -2462,7 +2501,7 @@ restart:
 				bp->b_flags |= B_INVAL;
 				brelse(bp);
 				goto restart;
-			}
+                        }
 			atomic_add_int(&bufreusecnt, 1);
 		} else if ((bp->b_flags & B_KVAALLOC) != 0 &&
 		    (gbflags & (GB_UNMAPPED | GB_KVAALLOC)) == 0) {
@@ -2496,6 +2535,16 @@ restart:
 			bp->b_flags &= ~B_UNMAPPED;
 			BUF_CHECK_MAPPED(bp);
 		}
+
+#if 0
+	/* XXX 9.1 -> current: was not used anymore, check if can be deleted */
+#ifdef VPS
+				vps_account(curthread->td_vps, VPS_ACC_BUFCNT,
+					VPS_ACC_ALLOC, 1);
+				vps_account(curthread->td_vps, VPS_ACC_BUFSPACE,
+					VPS_ACC_ALLOC, bp->b_kvasize);
+#endif
+#endif
 	}
 	return (bp);
 }
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/vfs_cache.c head/sys/kern/vfs_cache.c
--- clean-head/sys/kern/vfs_cache.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/vfs_cache.c	2013-06-24 14:20:31.000000000 +0200
@@ -309,8 +309,13 @@ SYSCTL_OPAQUE(_vfs_cache, OID_AUTO, nchs
 static void cache_zap(struct namecache *ncp);
 static int vn_vptocnp_locked(struct vnode **vp, struct ucred *cred, char *buf,
     u_int *buflen);
+#ifdef VPS
+int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
+    char *buf, char **retbuf, u_int buflen);
+#else
 static int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
     char *buf, char **retbuf, u_int buflen);
+#endif
 
 static MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
 
@@ -1264,7 +1269,11 @@ vn_vptocnp_locked(struct vnode **vp, str
 /*
  * The magic behind kern___getcwd() and vn_fullpath().
  */
+#ifdef VPS
+int
+#else
 static int
+#endif
 vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
     char *buf, char **retbuf, u_int buflen)
 {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/vfs_cluster.c head/sys/kern/vfs_cluster.c
--- clean-head/sys/kern/vfs_cluster.c	2013-06-26 09:37:48.000000000 +0200
+++ head/sys/kern/vfs_cluster.c	2013-06-24 14:20:31.000000000 +0200
@@ -53,6 +53,8 @@ __FBSDID("$FreeBSD: head/sys/kern/vfs_cl
 #include <vm/vm_page.h>
 #include <sys/sysctl.h>
 
+#include <vps/vps_account.h>
+
 #if defined(CLUSTERDEBUG)
 static int	rcluster= 0;
 SYSCTL_INT(_debug, OID_AUTO, rcluster, CTLFLAG_RW, &rcluster, 0,
@@ -240,6 +242,9 @@ cluster_read(struct vnode *vp, u_quad_t 
 		bp->b_iooffset = dbtob(bp->b_blkno);
 		bstrategy(bp);
 		curthread->td_ru.ru_inblock++;
+#ifdef VPS
+		vps_account_bio(curthread);
+#endif
 	}
 
 	/*
@@ -293,6 +298,9 @@ cluster_read(struct vnode *vp, u_quad_t 
 		rbp->b_iooffset = dbtob(rbp->b_blkno);
 		bstrategy(rbp);
 		curthread->td_ru.ru_inblock++;
+#ifdef VPS
+		vps_account_bio(curthread);
+#endif
 	}
 
 	if (reqbp)
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/vfs_export.c head/sys/kern/vfs_export.c
--- clean-head/sys/kern/vfs_export.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/vfs_export.c	2013-06-24 14:20:31.000000000 +0200
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD: head/sys/kern/vfs_ex
 #include <sys/mbuf.h>
 #include <sys/mount.h>
 #include <sys/mutex.h>
+#include <sys/proc.h>
 #include <sys/rwlock.h>
 #include <sys/refcount.h>
 #include <sys/signalvar.h>
@@ -54,6 +55,8 @@ __FBSDID("$FreeBSD: head/sys/kern/vfs_ex
 #include <sys/systm.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+
 #include <net/radix.h>
 
 static MALLOC_DEFINE(M_NETADDR, "export_host", "Export host address structure");
@@ -124,7 +127,7 @@ vfs_hang_addrlist(struct mount *mp, stru
 		np->netc_anon->cr_uid = argp->ex_anon.cr_uid;
 		crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups,
 		    argp->ex_anon.cr_groups);
-		np->netc_anon->cr_prison = &prison0;
+		np->netc_anon->cr_prison = V_prison0;
 		prison_hold(np->netc_anon->cr_prison);
 		np->netc_numsecflavors = argp->ex_numsecflavors;
 		bcopy(argp->ex_secflavors, np->netc_secflavors,
@@ -210,7 +213,7 @@ vfs_hang_addrlist(struct mount *mp, stru
 	np->netc_anon->cr_uid = argp->ex_anon.cr_uid;
 	crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups,
 	    argp->ex_anon.cr_groups);
-	np->netc_anon->cr_prison = &prison0;
+	np->netc_anon->cr_prison = V_prison0;
 	prison_hold(np->netc_anon->cr_prison);
 	np->netc_numsecflavors = argp->ex_numsecflavors;
 	bcopy(argp->ex_secflavors, np->netc_secflavors,
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/vfs_mount.c head/sys/kern/vfs_mount.c
--- clean-head/sys/kern/vfs_mount.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/vfs_mount.c	2013-06-24 14:20:31.000000000 +0200
@@ -59,8 +59,12 @@ __FBSDID("$FreeBSD: head/sys/kern/vfs_mo
 #include <sys/sysent.h>
 #include <sys/systm.h>
 #include <sys/vnode.h>
+
 #include <vm/uma.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <geom/geom.h>
 
 #include <machine/stdarg.h>
@@ -472,7 +476,32 @@ vfs_mount_alloc(struct vnode *vp, struct
 	mp->mnt_vnodecovered = vp;
 	mp->mnt_cred = crdup(cred);
 	mp->mnt_stat.f_owner = cred->cr_uid;
-	strlcpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN);
+#if 0
+	/* Deprecated as of 9.1-RELEASE. */
+#ifdef VPS
+	/*
+	//debug
+	if (rootvnode != NULL && cred->cr_vps->_rootvnode != rootvnode)
+		printf("%s: cred->cr_vps->_rootpath=[%s] fspath=[%s]\n",
+			__func__, cred->cr_vps->_rootpath, fspath);
+	*/
+	/*
+	 * If the function is called from any VPS other than vps0;
+	 * the vfs root is likely to be different from the actual root.
+	 * But the entry in the global mount list can't contain an relative
+	 * fspath.
+	 *
+	 * Length check is done in vfs_domount().
+	 */
+	if (rootvnode != NULL && cred->cr_vps->_rootvnode != rootvnode)
+		snprintf(mp->mnt_stat.f_mntonname, MNAMELEN, "%s%s",
+			cred->cr_vps->_rootpath, fspath);
+	else
+#endif /* VPS */
+#else
+#endif /* 0 */
+		strlcpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN);
+
 	mp->mnt_iosize_max = DFLTPHYS;
 #ifdef MAC
 	mac_mount_init(mp);
@@ -651,6 +680,20 @@ vfs_donmount(struct thread *td, uint64_t
 			fsflags |= MNT_UNION;
 	}
 
+#ifdef VPS
+	/*
+	 * If the function is called from any VPS other than vps0;
+	 * the vfs root is likely to be different from the actual root.
+	 * The entry in the global mount list can't contain an relative
+	 * fspath tough.
+	 *
+	 * Only do length check here, the absolute path gets put together
+	 * in vfs_mount_alloc().
+	 */
+	if (rootvnode != NULL && td->td_ucred->cr_vps->_rootvnode != rootvnode)
+		if (strlen(fspath) + strlen(td->td_ucred->cr_vps->_rootpath) >= MNAMELEN)
+			return (ENAMETOOLONG);
+#endif
 	/*
 	 * Be ultra-paranoid about making sure the type and fspath
 	 * variables will fit in our mp buffers, including the
@@ -846,6 +889,10 @@ vfs_domount_first(
 		mp->mnt_kern_flag |= MNTK_ASYNC;
 	else
 		mp->mnt_kern_flag &= ~MNTK_ASYNC;
+#ifdef VPS
+	mp->mnt_vps = curthread->td_vps;
+	vps_ref(mp->mnt_vps, (void*)0xdead0010);
+#endif
 	MNT_IUNLOCK(mp);
 
 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
@@ -987,6 +1034,10 @@ vfs_domount_update(
 		mp->mnt_kern_flag |= MNTK_ASYNC;
 	else
 		mp->mnt_kern_flag &= ~MNTK_ASYNC;
+#ifdef VPS
+	mp->mnt_vps = curthread->td_vps;
+	vps_ref(mp->mnt_vps, (void*)0xdead0010);
+#endif
 	MNT_IUNLOCK(mp);
 
 	if (error != 0)
@@ -1034,6 +1085,20 @@ vfs_domount(
 	char *pathbuf;
 	int error;
 
+#ifdef VPS
+	/*
+	 * If the function is called from any VPS other than vps0;
+	 * the vfs root is likely to be different from the actual root.
+	 * The entry in the global mount list can't contain an relative
+	 * fspath tough.
+	 *
+	 * Only do length check here, the absolute path gets put together
+	 * in vfs_mount_alloc().
+	 */
+	if (rootvnode != NULL && td->td_ucred->cr_vps->_rootvnode != rootvnode)
+		if (strlen(fspath) + strlen(td->td_ucred->cr_vps->_rootpath) >= MNAMELEN)
+			return (ENAMETOOLONG);
+#endif
 	/*
 	 * Be ultra-paranoid about making sure the type and fspath
 	 * variables will fit in our mp buffers, including the
@@ -1201,6 +1266,16 @@ sys_unmount(td, uap)
 		return ((uap->flags & MNT_BYFSID) ? ENOENT : EINVAL);
 	}
 
+#ifdef VPS
+	/* Only allow unmount for vps0 or if mount is owned by vps. */
+	if (td->td_ucred->cr_vps != vps0) {
+		if (mp->mnt_vps != td->td_ucred->cr_vps) {
+			mtx_unlock(&Giant);
+			return (EPERM);
+		}
+	}
+#endif /* VPS */
+
 	/*
 	 * Don't allow unmounting the root filesystem.
 	 */
@@ -1292,6 +1367,12 @@ dounmount(mp, flags, td)
 	async_flag = mp->mnt_flag & MNT_ASYNC;
 	mp->mnt_flag &= ~MNT_ASYNC;
 	mp->mnt_kern_flag &= ~MNTK_ASYNC;
+#ifdef VPS
+	if (mp->mnt_vps) {
+		vps_deref(mp->mnt_vps, (void*)0xdead0010);
+		mp->mnt_vps = NULL;
+	}
+#endif
 	MNT_IUNLOCK(mp);
 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
 	vfs_deallocate_syncvnode(mp);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/vfs_mountroot.c head/sys/kern/vfs_mountroot.c
--- clean-head/sys/kern/vfs_mountroot.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/vfs_mountroot.c	2013-06-24 14:20:31.000000000 +0200
@@ -65,6 +65,9 @@ __FBSDID("$FreeBSD: head/sys/kern/vfs_mo
 #include <sys/systm.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <geom/geom.h>
 
 /*
@@ -980,10 +983,14 @@ vfs_mountroot(void)
 	inittodr(timebase);
 
 	/* Keep prison0's root in sync with the global rootvnode. */
-	mtx_lock(&prison0.pr_mtx);
-	prison0.pr_root = rootvnode;
-	vref(prison0.pr_root);
-	mtx_unlock(&prison0.pr_mtx);
+	mtx_lock(&V_prison0->pr_mtx);
+	V_prison0->pr_root = rootvnode;
+	vref(V_prison0->pr_root);
+	mtx_unlock(&V_prison0->pr_mtx);
+#ifdef VPS
+	/* XXX locking */
+	vps0->_rootvnode = rootvnode;
+#endif
 
 	mtx_lock(&mountlist_mtx);
 	atomic_store_rel_int(&root_mount_complete, 1);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/vfs_subr.c head/sys/kern/vfs_subr.c
--- clean-head/sys/kern/vfs_subr.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/vfs_subr.c	2013-06-24 14:20:31.000000000 +0200
@@ -92,6 +92,8 @@ __FBSDID("$FreeBSD: head/sys/kern/vfs_su
 #include <vm/vm_kern.h>
 #include <vm/uma.h>
 
+#include <vps/vps.h>
+
 #ifdef DDB
 #include <ddb/ddb.h>
 #endif
@@ -330,7 +332,7 @@ vntblinit(void *dummy __unused)
 	 * size.  The memory required by desiredvnodes vnodes and vm objects
 	 * may not exceed one seventh of the kernel's heap size.
 	 */
-	physvnodes = maxproc + cnt.v_page_count / 16 + 3 * min(98304 * 4,
+	physvnodes = V_maxproc + cnt.v_page_count / 16 + 3 * min(98304 * 4,
 	    cnt.v_page_count) / 16;
 	virtvnodes = vm_kmem_size / (7 * (sizeof(struct vm_object) +
 	    sizeof(struct vnode)));
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/kern/vfs_syscalls.c head/sys/kern/vfs_syscalls.c
--- clean-head/sys/kern/vfs_syscalls.c	2013-06-26 09:37:49.000000000 +0200
+++ head/sys/kern/vfs_syscalls.c	2013-06-24 14:20:31.000000000 +0200
@@ -77,6 +77,9 @@ __FBSDID("$FreeBSD: head/sys/kern/vfs_sy
 #include <sys/ktrace.h>
 #endif
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <machine/stdarg.h>
 
 #include <security/audit/audit.h>
@@ -148,7 +151,11 @@ sys_sync(td, uap)
 			continue;
 		}
 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
-		    vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
+#ifdef VPS
+		    vps_canseemount(td->td_ucred, mp) == 0 &&
+#endif /*VPS*/
+		    vn_start_write(NULL, &mp, V_NOWAIT) == 0
+		    ) {
 			save = curthread_pflags_set(TDP_SYNCIO);
 			vfs_msync(mp, MNT_NOWAIT);
 			VFS_SYNC(mp, MNT_NOWAIT);
@@ -200,6 +207,12 @@ sys_quotactl(td, uap)
 	mp = nd.ni_vp->v_mount;
 	vfs_ref(mp);
 	vput(nd.ni_vp);
+#ifdef VPS
+	if (td->td_vps != vps0 && td->td_vps != mp->mnt_vps) {
+		vfs_rel(mp);
+		return (EPERM);
+	}
+#endif
 	error = vfs_busy(mp, 0);
 	vfs_rel(mp);
 	if (error)
@@ -485,6 +498,12 @@ kern_getfsstat(struct thread *td, struct
 			nmp = TAILQ_NEXT(mp, mnt_list);
 			continue;
 		}
+#ifdef VPS
+		if (vps_canseemount(td->td_ucred, mp) != 0) {
+			nmp = TAILQ_NEXT(mp, mnt_list);
+			continue;
+		}
+#endif
 #ifdef MAC
 		if (mac_mount_check_stat(td->td_ucred, mp) != 0) {
 			nmp = TAILQ_NEXT(mp, mnt_list);
@@ -4506,6 +4525,11 @@ kern_fhstatfs(struct thread *td, fhandle
 	error = prison_canseemount(td->td_ucred, mp);
 	if (error)
 		goto out;
+#ifdef VPS
+	error = vps_canseemount(td->td_ucred, mp);
+	if (error)
+		goto out;
+#endif
 #ifdef MAC
 	error = mac_mount_check_stat(td->td_ucred, mp);
 	if (error)
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/mips/conf/EDGEROUTER_VPS head/sys/mips/conf/EDGEROUTER_VPS
--- clean-head/sys/mips/conf/EDGEROUTER_VPS	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/mips/conf/EDGEROUTER_VPS	2013-06-24 14:20:43.000000000 +0200
@@ -0,0 +1,330 @@
+#
+# OCTEON1 -- Generic kernel configuration file for FreeBSD/MIPS on Cavium Octeon
+#
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
+#
+#    http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD: head/sys/mips/conf/OCTEON1 250429 2013-05-10 03:05:44Z imp $
+
+ident		EDGEROUTER_VPS
+
+options		VPS
+options		VPS_STATIC
+options		VIMAGE
+
+#options	MD_ROOT_SIZE=8192		# Reserve 8 MB for MD root image
+#makeoptions	MFS_IMAGE=/usr/src/edgerouter/mdroot.img
+
+options 	ROOTDEVNAME=\"ufs:da0s2a\"	# Default root filesystem.
+
+makeoptions	ARCH_FLAGS="-march=octeon -mabi=64"
+makeoptions	LDSCRIPT_NAME=ldscript.mips.octeon1
+
+# Don't build any modules yet.
+makeoptions	MODULES_OVERRIDE=""
+makeoptions	KERNLOADADDR=0xffffffff80100000
+
+# We don't need to build a trampolined version of the kernel.
+makeoptions	WITHOUT_KERNEL_TRAMPOLINE=1
+
+include		"../cavium/std.octeon1"
+
+hints		"OCTEON1.hints"		#Default places to look for devices.
+
+makeoptions	DEBUG=-g		#Build kernel with gdb(1) debug symbols
+
+# Board-specific support that cannot be auto-detected at runtime.
+#options 	OCTEON_VENDOR_LANNER		# Support for Lanner boards.
+#options 	OCTEON_VENDOR_RADISYS		# Support for Radisys boards.
+options 	OCTEON_VENDOR_UBIQUITI		# Support for Ubiquiti boards.
+#options	OCTEON_VENDOR_GEFES		# Support for GE LANIC boards
+#options 	OCTEON_BOARD_CAPK_0100ND	# Support for CAPK-0100nd.
+
+# Compile for a specified Octeon model.  If not specified, support for
+# detection at runtime will be used instead, which may give inferior
+# performance.
+#
+# See sys/contrib/octeon-sdk/octeon-model.h for possible values.
+#options 	OCTEON_MODEL=OCTEON_CN58XX_PASS1_1
+
+options 	SCHED_ULE		# ULE scheduler
+options 	PREEMPTION		# Enable kernel thread preemption
+options 	INET			# InterNETworking
+options 	INET6			# IPv6 communications protocols
+options 	SCTP			# Stream Control Transmission Protocol
+options 	FFS			# Berkeley Fast Filesystem
+options 	SOFTUPDATES		# Enable FFS soft updates support
+options 	UFS_ACL			# Support for access control lists
+options 	UFS_DIRHASH		# Improve performance on big directories
+options 	UFS_GJOURNAL		# Enable gjournal-based UFS journaling
+options 	MD_ROOT			# MD is a potential root device
+options 	NFSCL			# Network Filesystem Client
+options 	NFSD			# Network Filesystem Server
+options 	NFSLOCKD		# Network Lock Manager
+options 	NFS_ROOT		# NFS usable as /, requires NFSCL
+options 	MSDOSFS			# MSDOS Filesystem
+options 	CD9660			# ISO 9660 Filesystem
+options 	PROCFS			# Process filesystem (requires PSEUDOFS)
+options 	PSEUDOFS		# Pseudo-filesystem framework
+options 	GEOM_PART_GPT		# GUID Partition Tables.
+options 	GEOM_LABEL		# Provides labelization
+#options 	COMPAT_FREEBSD32	# Compatible with o32 binaries
+options 	SCSI_DELAY=5000		# Delay (in ms) before probing SCSI
+options 	KTRACE			# ktrace(1) support
+options 	STACK			# stack(9) support
+options 	SYSVSHM			# SYSV-style shared memory
+options 	SYSVMSG			# SYSV-style message queues
+options 	SYSVSEM			# SYSV-style semaphores
+options 	_KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions
+options 	PRINTF_BUFR_SIZE=128	# Prevent printf output being interspersed.
+options 	HWPMC_HOOKS		# Necessary kernel hooks for hwpmc(4)
+options 	AUDIT			# Security event auditing
+options 	MAC			# TrustedBSD MAC Framework
+#options 	KDTRACE_FRAME		# Ensure frames are compiled in
+#options 	KDTRACE_HOOKS		# Kernel DTrace hooks
+options 	INCLUDE_CONFIG_FILE     # Include this file in kernel
+options 	NO_SWAPPING		# Disable support for paging
+
+# Debugging for use in -current
+options 	KDB			# Enable kernel debugger support.
+options 	DDB			# Support DDB.
+options 	GDB			# Support remote GDB.
+options 	DEADLKRES		# Enable the deadlock resolver
+options 	INVARIANTS		# Enable calls of extra sanity checking
+options 	INVARIANT_SUPPORT	# Extra sanity checks of internal structures, required by INVARIANTS
+options 	WITNESS			# Enable checks to detect deadlocks and cycles
+options 	WITNESS_SKIPSPIN	# Don't run witness on spinlocks for speed
+options 	MALLOC_DEBUG_MAXZONES=8	# Separate malloc(9) zones
+
+# Make an SMP-capable kernel by default
+options 	SMP			# Symmetric MultiProcessor Kernel
+
+# Bus support.
+device		pci
+
+# ATA controllers
+device		ahci		# AHCI-compatible SATA controllers
+device		ata		# Legacy ATA/SATA controllers
+options 	ATA_STATIC_ID	# Static device numbering
+device		mvs		# Marvell 88SX50XX/88SX60XX/88SX70XX/SoC SATA
+device		siis		# SiliconImage SiI3124/SiI3132/SiI3531 SATA
+
+# On-board Compact Flash driver.
+device		cf
+#options 	ROOTDEVNAME=\"ufs:cf0s2a\"	# Default root filesystem.
+
+# SCSI Controllers
+device		ahc		# AHA2940 and onboard AIC7xxx devices
+options 	AHC_REG_PRETTY_PRINT	# Print register bitfields in debug
+					# output.  Adds ~128k to driver.
+device		ahd		# AHA39320/29320 and onboard AIC79xx devices
+options 	AHD_REG_PRETTY_PRINT	# Print register bitfields in debug
+					# output.  Adds ~215k to driver.
+device		esp		# AMD Am53C974 (Tekram DC-390(T))
+device		hptiop		# Highpoint RocketRaid 3xxx series
+device		isp		# Qlogic family
+#device		ispfw		# Firmware for QLogic HBAs- normally a module
+device		mpt		# LSI-Logic MPT-Fusion
+device		mps		# LSI-Logic MPT-Fusion 2
+#device		ncr		# NCR/Symbios Logic
+device		trm		# Tekram DC395U/UW/F DC315U adapters
+
+device		adv		# Advansys SCSI adapters
+device		adw		# Advansys wide SCSI adapters
+device		aic		# Adaptec 15[012]x SCSI adapters, AIC-6[23]60.
+device		bt		# Buslogic/Mylex MultiMaster SCSI adapters
+
+# ATA/SCSI peripherals
+device		scbus		# SCSI bus (required for ATA/SCSI)
+device		ch		# SCSI media changers
+device		da		# Direct Access (disks)
+device		sa		# Sequential Access (tape etc)
+device		cd		# CD
+device		pass		# Passthrough device (direct ATA/SCSI access)
+device		ses		# Enclosure Services (SES and SAF-TE)
+
+# RAID controllers interfaced to the SCSI subsystem
+device		amr		# AMI MegaRAID
+#XXX it is not 64-bit clean, -scottl
+#device		asr		# DPT SmartRAID V, VI and Adaptec SCSI RAID
+device		ciss		# Compaq Smart RAID 5*
+device		dpt		# DPT Smartcache III, IV - See NOTES for options
+device		iir		# Intel Integrated RAID
+device		ips		# IBM (Adaptec) ServeRAID
+device		mly		# Mylex AcceleRAID/eXtremeRAID
+
+# RAID controllers
+device		aac		# Adaptec FSA RAID
+device		aacp		# SCSI passthrough for aac (requires CAM)
+device		ida		# Compaq Smart RAID
+device		mfi		# LSI MegaRAID SAS
+device		mlx		# Mylex DAC960 family
+#XXX pointer/int warnings
+#device		pst		# Promise Supertrak SX6000
+device		twe		# 3ware ATA RAID
+
+# PCCARD (PCMCIA) support
+# PCMCIA and cardbus bridge support
+device		cbb		# cardbus (yenta) bridge
+device		pccard		# PC Card (16-bit) bus
+device		cardbus		# CardBus (32-bit) bus
+
+# Serial (COM) ports
+device		uart		# Generic UART driver
+
+# If you've got a "dumb" serial or parallel PCI card that is
+# supported by the puc(4) glue driver, uncomment the following
+# line to enable it (connects to sio, uart and/or ppc drivers):
+#device		puc
+
+# On-board Cavium Octeon Ethernet.
+# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
+device		octe
+
+# Cavium Octeon management Ethernet.
+device		octm
+
+# Switch PHY support for the octe driver.  These currently present a VLAN per
+# physical port, but may eventually provide support for DSA or similar instead.
+#device		mv88e61xxphy	# Marvell 88E61XX
+
+# PCI Ethernet NICs.
+device		de		# DEC/Intel DC21x4x (``Tulip'')
+device		em		# Intel PRO/1000 Gigabit Ethernet Family
+device		igb		# Intel PRO/1000 PCIE Server Gigabit Family
+device		ixgbe		# Intel PRO/10GbE PCIE Ethernet Family
+device		le		# AMD Am7900 LANCE and Am79C9xx PCnet
+device		ti		# Alteon Networks Tigon I/II gigabit Ethernet
+device		txp		# 3Com 3cR990 (``Typhoon'')
+device		vx		# 3Com 3c590, 3c595 (``Vortex'')
+
+# PCI Ethernet NICs that use the common MII bus controller code.
+# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs!
+device		miibus		# MII bus support
+device		ae		# Attansic/Atheros L2 FastEthernet
+device		age		# Attansic/Atheros L1 Gigabit Ethernet
+device		alc		# Atheros AR8131/AR8132 Ethernet
+device		ale		# Atheros AR8121/AR8113/AR8114 Ethernet
+device		bce		# Broadcom BCM5706/BCM5708 Gigabit Ethernet
+device		bfe		# Broadcom BCM440x 10/100 Ethernet
+device		bge		# Broadcom BCM570xx Gigabit Ethernet
+device		dc		# DEC/Intel 21143 and various workalikes
+device		et		# Agere ET1310 10/100/Gigabit Ethernet
+device		fxp		# Intel EtherExpress PRO/100B (82557, 82558)
+device		jme		# JMicron JMC250 Gigabit/JMC260 Fast Ethernet
+device		lge		# Level 1 LXT1001 gigabit Ethernet
+device		msk		# Marvell/SysKonnect Yukon II Gigabit Ethernet
+device		nge		# NatSemi DP83820 gigabit Ethernet
+#device		nve		# nVidia nForce MCP on-board Ethernet Networking
+device		pcn		# AMD Am79C97x PCI 10/100 (precedence over 'le')
+device		re		# RealTek 8139C+/8169/8169S/8110S
+device		rl		# RealTek 8129/8139
+device		sf		# Adaptec AIC-6915 (``Starfire'')
+device		sge		# Silicon Integrated Systems SiS190/191
+device		sis		# Silicon Integrated Systems SiS 900/SiS 7016
+device		sk		# SysKonnect SK-984x & SK-982x gigabit Ethernet
+device		ste		# Sundance ST201 (D-Link DFE-550TX)
+device		stge		# Sundance/Tamarack TC9021 gigabit Ethernet
+device		tl		# Texas Instruments ThunderLAN
+device		tx		# SMC EtherPower II (83c170 ``EPIC'')
+device		vge		# VIA VT612x gigabit Ethernet
+device		vr		# VIA Rhine, Rhine II
+device		wb		# Winbond W89C840F
+device		xl		# 3Com 3c90x (``Boomerang'', ``Cyclone'')
+
+# Wireless NIC cards
+device		wlan		# 802.11 support
+options 	IEEE80211_DEBUG	# enable debug msgs
+options 	IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's
+options 	IEEE80211_SUPPORT_MESH	# enable 802.11s draft support
+device		wlan_wep	# 802.11 WEP support
+device		wlan_ccmp	# 802.11 CCMP support
+device		wlan_tkip	# 802.11 TKIP support
+device		wlan_amrr	# AMRR transmit rate control algorithm
+device		an		# Aironet 4500/4800 802.11 wireless NICs.
+device		ath		# Atheros NIC's
+device		ath_pci		# Atheros pci/cardbus glue
+device		ath_hal		# pci/cardbus chip support
+options 	AH_SUPPORT_AR5416	# enable AR5416 tx/rx descriptors
+device		ath_rate_sample	# SampleRate tx rate control for ath
+device		ral		# Ralink Technology RT2500 wireless NICs.
+device		wi		# WaveLAN/Intersil/Symbol 802.11 wireless NICs.
+
+# Pseudo devices.
+device		loop		# Network loopback
+device		random		# Entropy device
+device		ether		# Ethernet support
+device		vlan		# 802.1Q VLAN support
+device		tun		# Packet tunnel.
+device		md		# Memory "disks"
+device		gif		# IPv6 and IPv4 tunneling
+device		faith		# IPv6-to-IPv4 relaying (translation)
+device		firmware	# firmware assist module
+
+# The `bpf' device enables the Berkeley Packet Filter.
+# Be aware of the administrative consequences of enabling this!
+# Note that 'bpf' is required for DHCP.
+device		bpf		# Berkeley packet filter
+
+# Hardware watchdog support.
+#device		octeon_wdog	# Octeon hardware watchdog
+
+# USB support
+options 	USB_DEBUG	# enable debug msgs
+device		octusb		# Cavium Octeon on-board USB interface (USB 2.0)
+device		uhci		# UHCI PCI->USB interface
+device		ohci		# OHCI PCI->USB interface
+device		ehci		# EHCI PCI->USB interface (USB 2.0)
+device		usb		# USB Bus (required)
+#device		udbp		# USB Double Bulk Pipe devices
+device		uhid		# "Human Interface Devices"
+device		ulpt		# Printer
+device		umass		# Disks/Mass storage - Requires scbus and da
+device		ums		# Mouse
+device		urio		# Diamond Rio 500 MP3 player
+# USB Serial devices
+device		u3g		# USB-based 3G modems (Option, Huawei, Sierra)
+device		uark		# Technologies ARK3116 based serial adapters
+device		ubsa		# Belkin F5U103 and compatible serial adapters
+device		uftdi		# For FTDI usb serial adapters
+device		uipaq		# Some WinCE based devices
+device		uplcom		# Prolific PL-2303 serial adapters
+device		uslcom		# SI Labs CP2101/CP2102 serial adapters
+device		uvisor		# Visor and Palm devices
+device		uvscom		# USB serial support for DDI pocket's PHS
+# USB Ethernet, requires miibus
+device		aue		# ADMtek USB Ethernet
+device		axe		# ASIX Electronics USB Ethernet
+device		cdce		# Generic USB over Ethernet
+device		cue		# CATC USB Ethernet
+device		kue		# Kawasaki LSI USB Ethernet
+device		rue		# RealTek RTL8150 USB Ethernet
+device		udav		# Davicom DM9601E USB
+# USB Wireless
+device		rum		# Ralink Technology RT2501USB wireless NICs
+device		uath		# Atheros AR5523 wireless NICs
+device		ural		# Ralink Technology RT2500USB wireless NICs
+device		zyd		# ZyDAS zd1211/zd1211b wireless NICs
+
+# crypto subsystem
+device		crypto		# core crypto support
+device		cryptodev	# /dev/crypto for access to h/w
+device		cryptocteon	# Octeon coprocessor 2 crypto offload
+
+# GPIO support
+#device		gpio
+
+# PMC support
+#device		hwpmc
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/mips/include/vps_md.h head/sys/mips/include/vps_md.h
--- clean-head/sys/mips/include/vps_md.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/mips/include/vps_md.h	2013-06-24 14:20:42.000000000 +0200
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id$ */
+
+#ifndef _VPS_MD_H
+#define _VPS_MD_H
+
+#define VPS_ARCH_MIPSEB64
+
+#define VPS_MD_SNAPCTX_NPAGES		131072 /* 512 MB */
+
+#define VPS_MD_DUMPHDR_PTRSIZE		VPS_DUMPH_64BIT
+
+#define VPS_MD_DUMPHDR_BYTEORDER	VPS_DUMPH_MSB
+
+extern struct sysentvec elf64_freebsd_sysvec;
+#ifdef COMPAT_FREEBSD32
+extern struct sysentvec ia32_freebsd_sysvec;   
+#endif
+
+#ifdef _VPS_MD_FUNCTIONS
+
+inline
+static void
+vps_md_syscallret(struct thread *td, struct syscall_args *sa)
+{
+
+	/* re-setting v0 */
+	td->td_frame->v0 = sa->code;
+	DBGCORE("%s: td=%p v0=%p\n",
+	    __func__, td, (void*)td->td_frame->v0);
+}
+
+#endif /* _VPS_MD_FUNCTIONS */
+
+#endif /* _VPS_MD_H */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/mips/mips/vps_machdep.c head/sys/mips/mips/vps_machdep.c
--- clean-head/sys/mips/mips/vps_machdep.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/mips/mips/vps_machdep.c	2013-06-24 14:20:45.000000000 +0200
@@ -0,0 +1,577 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id$";
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/libkern.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+#include <machine/frame.h>
+#include <machine/vmparam.h>
+#include <machine/md_var.h>
+#include <machine/asm.h>
+#include <machine/trap.h>
+#include <machine/vps_md.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_map.h>
+
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#include <vps/vps_int.h>
+#include <vps/vps_libdump.h>
+#include <vps/vps_snapst.h>
+
+#undef v0
+#undef a0
+#undef a1
+#undef a2
+#undef a3
+#undef a4
+#undef a5
+#undef a6
+#undef a7
+
+#ifdef VPS
+
+/*__attribute__((inline))*/
+void
+vps_md_print_thread(struct thread *td)
+{
+
+	DBGCORE("%s: thread %p/%d kernel stack:\n"
+		/*
+		"td->td_pcb->rsp=%016lx\n"
+		"td->td_frame->tf_rax=%016lx\n"
+		"td->td_frame->tf_rsp=%016lx\n"
+		"td->td_frame->tf_rbp=%016lx\n"
+		"td->td_frame->tf_rip=%016lx\n"
+		"trace:\n",
+		*/
+		,
+		__func__,
+		td,
+		td->td_tid
+		/*
+		td->td_pcb->pcb_rsp,
+		td->td_frame->tf_rax,
+		td->td_frame->tf_rsp,
+		td->td_frame->tf_rbp,
+		td->td_frame->tf_rip
+		*/
+		);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_thread(struct vps_dump_thread *vdtd, struct thread *ntd,
+    struct proc *p)
+{
+
+	if (vps_func->vps_restore_return == NULL) {
+		printf("%s: vps_restore module not loaded ? "
+		    "vps_func->vps_restore_return == NULL",
+		    __func__);
+		return (EOPNOTSUPP);
+	}
+
+	/*
+	ntd->td_pcb->pcb_cr3 =
+	    DMAP_TO_PHYS((vm_offset_t)vmspace_pmap(p->p_vmspace)->pm_pml4);
+	ntd->td_pcb->pcb_r12 = (uint64_t)vps_func->vps_restore_return;
+	ntd->td_pcb->pcb_rbp = 0;
+	ntd->td_pcb->pcb_rsp = (uint64_t)ntd->td_frame - sizeof(void *);
+	ntd->td_pcb->pcb_rbx = (uint64_t)ntd;
+	ntd->td_pcb->pcb_rip = (uint64_t)fork_trampoline;
+	ntd->td_md.md_spinlock_count = 1;
+	ntd->td_md.md_saved_flags = PSL_KERNEL | PSL_I;
+	*/
+	ntd->td_pcb->pcb_context[PCB_REG_RA] = (register_t)(intptr_t)
+	    fork_trampoline;
+	/* Make sp 64-bit aligned */
+	ntd->td_pcb->pcb_context[PCB_REG_SP] = (register_t)(((vm_offset_t)
+	    ntd->td_pcb & ~(sizeof(__int64_t) - 1)) - CALLFRAME_SIZ);
+	ntd->td_pcb->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)
+	    vps_func->vps_restore_return;
+	ntd->td_pcb->pcb_context[PCB_REG_S1] = (register_t)(intptr_t)ntd;
+	ntd->td_pcb->pcb_context[PCB_REG_S2] = (register_t)(intptr_t)
+	    ntd->td_frame;
+	ntd->td_pcb->pcb_context[PCB_REG_SR] = mips_rd_status() &
+	    (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_INT_MASK);
+	ntd->td_md.md_tls = curthread->td_md.md_tls;
+	ntd->td_md.md_saved_intr = MIPS_SR_INT_IE;
+	ntd->td_md.md_spinlock_count = 1;
+
+	/* XXX CPU_CNMIPS stuff ?! */
+
+	ntd->td_errno = vdtd->td_errno;
+	ntd->td_retval[0] = vdtd->td_retval[0];
+	ntd->td_retval[1] = vdtd->td_retval[1];
+
+	/*
+	//db_trace_thread(ntd, 10);
+	DBGCORE("%s: td_pcb = %p; td_frame = %p; pcb_rsp = %016lx\n",
+		__func__, ntd->td_pcb, ntd->td_frame, ntd->td_pcb->pcb_rsp);
+	*/
+
+	return (0);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_snapshot_sysentvec(struct sysentvec *sv, long *svtype)
+{
+	int error = 0;
+
+	if (sv == &elf64_freebsd_sysvec) {
+		DBGCORE("%s: elf64_freebsd_sysvec\n", __func__);
+		*svtype = VPS_SYSENTVEC_ELF64;
+#ifdef COMPAT_FREEBSD32
+	} else if (sv == &ia32_freebsd_sysvec) {
+		DBGCORE("%s: ia32_freebsd_sysvec\n", __func__);
+		*svtype = VPS_SYSENTVEC_ELF32;
+#endif
+	} else if (sv == &null_sysvec) {
+		DBGCORE("%s: null_sysvec\n", __func__);
+		*svtype = VPS_SYSENTVEC_NULL;
+        } else {
+		DBGCORE("%s: nknown sysentvec %p\n", __func__, sv);
+		error = EINVAL;
+        }
+
+	return (error);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_sysentvec(long svtype, struct sysentvec **sv)
+{
+	int error = 0;
+
+	if (svtype == VPS_SYSENTVEC_ELF64)
+		*sv = &elf64_freebsd_sysvec;
+#ifdef COMPAT_FREEBSD32
+	else if (svtype == VPS_SYSENTVEC_ELF32)
+		*sv = &ia32_freebsd_sysvec;
+#endif
+	else if (svtype == VPS_SYSENTVEC_NULL)
+		*sv = &null_sysvec;
+	else {
+		DBGCORE("%s: unknown sysentvec type: %ld\n",
+			__func__, svtype);
+		error = EINVAL;
+	}
+
+	return (error);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_checkarch(uint8 ptrsize, uint8 byteorder)
+{
+	int error;
+
+	if (ptrsize == VPS_DUMPH_64BIT && byteorder == VPS_DUMPH_MSB)
+		error = 0;
+	else
+		error = EINVAL;
+
+	return (error);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_snapshot_thread_savefpu(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct thread *td)
+{
+#if 0
+XXX
+        struct vps_dumpobj *o1;
+        struct vps_dump_savefpu *vdsf;
+
+	KASSERT(td->td_pcb != NULL && td->td_pcb->pcb_save != NULL,
+		("%s: td->td_pcb == NULL || td->td_pcb->pcb_save == NULL\n",
+		__func__));
+
+	if ((o1 = vdo_create(ctx, VPS_DUMPOBJT_SAVEFPU, M_NOWAIT)) ==
+	    NULL) {
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+
+	if ((vdsf = vdo_space(ctx, sizeof(*vdsf), M_NOWAIT)) == NULL) {
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+	vdsf->sf_length = sizeof(struct savefpu);
+
+	if (vdo_append(ctx, (void *)td->td_pcb->pcb_save, vdsf->sf_length,
+	    M_NOWAIT)) {
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+
+	vdo_close(ctx);
+#endif
+
+	return (0);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_restore_thread_savefpu(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct thread *td)
+{
+#if 0
+XXX
+	struct vps_dumpobj *o1;
+	struct vps_dump_savefpu *vdsf;
+
+	/* caller verified type. */
+	o1 = vdo_next(ctx);
+
+	vdsf = (struct vps_dump_savefpu *)o1->data;
+
+	/*
+	 * XXX Verify that we can't harm the system (kernel space)
+	 *     by restoring an invalid savefpu context.
+	 */
+	if (vdsf->sf_length != sizeof(struct savefpu)) {
+		DBGCORE("%s: vdsf->sf_length != sizeof(struct savefpu) "
+		    (%u != %lu)\n", __func__, vdsf->sf_length,
+		    sizeof(struct savefpu));
+		return (EINVAL);
+	}
+
+	KASSERT(td->td_pcb != NULL && td->td_pcb->pcb_save != NULL,
+		("%s: td->td_pcb == NULL || td->td_pcb->pcb_save == NULL\n",
+		__func__));
+
+	DBGCORE("%s: td->td_pcb->pcb_save=%p\n",
+	    __func__, td->td_pcb->pcb_save);
+	memcpy(td->td_pcb->pcb_save, vdsf->sf_data, vdsf->sf_length);
+
+#endif
+	return (0);
+}
+
+/*__attribute__((inline))*/
+int
+vps_md_reboot_copyout(struct thread *td, struct execve_args *args)
+{
+	vm_offset_t addr;
+	struct proc *p;
+	int error = 0;
+
+	/*
+	 * We push the arguments to execve() onto the
+	 * userspace stack of our process.
+	 */
+	p = td->td_proc;
+	addr = p->p_sysent->sv_usrstack - PAGE_SIZE;
+	if (p->p_vmspace->vm_ssize < 1 /* page */) {
+		/* Should not ever happen in theory ! */
+		return (ENOSPC);
+	}
+
+	if (p->p_sysent == &elf64_freebsd_sysvec) {
+		copyout("/sbin/init", (void *)(addr + 0x40), 11);
+		suword64((void *)(addr + 0x0), (addr + 0x40));
+		suword64((void *)(addr + 0x8), (vm_offset_t)NULL);
+#ifdef COMPAT_FREEBSD32
+	} else if (p->p_sysent == &ia32_freebsd_sysvec) {
+		copyout("/sbin/init", (void *)(addr + 0x40), 11);
+		suword32((void *)(addr + 0x0), (addr + 0x40));
+		suword32((void *)(addr + 0x4), (vm_offset_t)NULL);
+#endif
+	} else {
+		error = EINVAL;
+	}
+
+	args->fname = (char *)(addr + 0x40);
+	args->argv = (char **)addr;
+	args->envv = NULL;
+
+#if 0
+// notyet
+        KASSERT(pargs != NULL,
+            ("%s: vps=%p, lost pargs somewhere, don't know what to boot\n",
+            __func__, vps));
+        arglen = pargs->ar_length;
+        /*
+        if (arglen > PAGE_SIZE)
+                arglen = PAGE_SIZE - 1;
+        copyout(pargs->ar_args, (void *)addr, arglen);
+        subyte((char *)(addr + PAGE_SIZE - 1), 0x0);
+        */
+        if (exec_alloc_args(&imgargs)) {
+                DBGCORE("%s: exec_alloc_args() returned error\n", __func__);
+                pargs_drop(pargs);
+                goto fail;
+        }  
+        if (arglen > PATH_MAX + ARG_MAX)
+                arglen = PATH_MAX + ARG_MAX - 1;
+        memcpy(imgargs.buf, pargs->ar_args, arglen);
+        addr = (vm_offset_t)imgargs.buf;
+        // ---
+        imgargs.fname = (char *)addr;
+        imgargs.begin_argv = (char *)(addr + 0x0);
+        imgargs.begin_envv = (char *)(addr + arglen);
+        imgargs.endp = (char *)(addr + arglen);
+        imgargs.envc = 0;
+        imgargs.argc = 1; /* XXX */
+        imgargs.stringspace = 0;
+#endif
+
+	return (error);
+}
+
+/*__attribute__((noinline))*/
+int
+vps_md_syscall_fixup(struct vps *vps, struct thread *td,
+    register_t *ret_code, register_t **ret_args, int *ret_narg)
+{
+	struct trapframe *frame;
+	struct sysentvec *sv;
+	struct proc *p;
+	register_t code;
+	register_t args[8];
+	int narg;
+	int error = 0;
+	int i;
+	int ia32_emul = 0;
+	int traptype;
+	struct ucred *save_ucred = curthread->td_ucred;
+
+	if (vps_func->vps_access_vmspace == NULL)
+		return (EOPNOTSUPP);
+
+	p = td->td_proc;
+	frame = td->td_frame;
+	sv = p->p_sysent;
+
+	traptype = (frame->cause & MIPS_CR_EXC_CODE) >>
+	    MIPS_CR_EXC_CODE_SHIFT;
+	if (! (traptype == T_SYSCALL && TRAPF_USERMODE(frame))) {
+		DBGCORE("%s: thread %p was not in syscall: "
+		    "traptype=%d\n", __func__, td,
+		    traptype);
+
+		/* nothing to do ? */
+		error = 0;
+		goto out;
+	}
+
+	if (sv == &elf64_freebsd_sysvec) {
+		DBGCORE("%s: proc=%p/%u elf64_freebsd_sysvec\n",
+		    __func__, p, p->p_pid);
+#ifdef COMPAT_FREEBSD32
+	} else if (sv == &ia32_freebsd_sysvec) {
+		DBGCORE("%s: proc=%p/%u ia32_freebsd_sysvec\n",
+		    __func__, p, p->p_pid);
+		ia32_emul = 1;
+#endif
+	} else {
+		DBGCORE("%s: proc=%p/%u unknown sysentvec %p\n",
+		    __func__, p, p->p_pid, sv);
+		panic("%s: proc=%p/%u unknown sysentvec %p\n",
+		    __func__, p, p->p_pid, sv);
+	}
+
+	/* Just in case vm objects are split/copied/... */
+	curthread->td_ucred = td->td_ucred;
+
+	/*
+	 * XXX: special handling for
+	 *      sa->code == SYS_syscall || sa->code == SYS___syscall
+	 */
+
+	memset((caddr_t)args, 0, sizeof(args));
+
+	code = frame->v0;
+
+	if (sv->sv_mask)
+		code &= sv->sv_mask;
+	if (code >= sv->sv_size)
+		code = 0;
+
+	narg = (&sv->sv_table[code])->sy_narg;
+
+	KASSERT(narg * sizeof(register_t) <= sizeof(args),
+	    ("%s: argument space on stack too small, narg=%d\n",
+	    __func__, narg));
+
+	if (ia32_emul) {
+		uint32_t args32[8];
+
+		memset(args32, 0, sizeof(args32));
+
+		for (i = 0; i < narg; i++)
+			args[i] = (uint64_t)args32[i];
+
+	} else {
+
+		args[0] = frame->a0;
+		args[1] = frame->a1;
+		args[2] = frame->a2;
+		args[3] = frame->a3;
+		args[4] = frame->a4;
+		args[5] = frame->a5;
+		args[6] = frame->a6;
+		args[7] = frame->a7;
+
+		for (i = 0; i < 8; i++)
+			if (i >= narg)
+				args[i] = 0;
+
+	}
+
+	DBGCORE("%s: code=%lu/0x%lx narg=%u args: %016lx %016lx %016lx "
+	    "%016lx %016lx %016lx\n", __func__, code, code, narg,
+	    args[0], args[1], args[2], args[3], args[4], args[5]);
+
+	DBGCORE("SYSCALL: tid=%d pid=%d syscall=%ld retval[0]=%zx "
+	    "retval[1]=%zx errno=%d\n",
+	    td->td_tid, td->td_proc->p_pid, code, td->td_retval[0],
+	    td->td_retval[1], td->td_errno);
+
+	KASSERT(*ret_narg >= narg,
+	    ("%s: supplied args array too small (narg=%d *ret_narg=%d)\n",
+	    __func__, narg, *ret_narg));
+	*ret_code = code;
+	*ret_narg= narg;
+	memcpy(ret_args, &args, narg * sizeof(args[0]));
+
+ out:
+	curthread->td_ucred = save_ucred;
+
+	return (error);
+}
+
+int
+vps_md_syscall_fixup_setup_inthread(struct vps *vps, struct thread *td,
+    register_t code)
+{
+
+	DBGCORE("%s\n", __func__);
+
+	if (vps_func->vps_syscall_fixup_inthread == NULL)
+		return (EOPNOTSUPP);
+
+	/*
+	td->td_pcb->pcb_r12 =
+	    (uint64_t)vps_func->vps_syscall_fixup_inthread;
+	td->td_pcb->pcb_rip = (uint64_t)fork_trampoline;
+	td->td_pcb->pcb_rsp = (uint64_t)td->td_frame -
+	    sizeof(void *);
+	td->td_pcb->pcb_rbx = (uint64_t)code;
+	td->td_pcb->pcb_rbp = 0;
+	*/
+	td->td_pcb->pcb_context[PCB_REG_RA] = (register_t)(intptr_t)
+	    fork_trampoline;
+	/* Make sp 64-bit aligned */
+	td->td_pcb->pcb_context[PCB_REG_SP] = (register_t)(((vm_offset_t)
+	    td->td_pcb & ~(sizeof(__int64_t) - 1)) - CALLFRAME_SIZ);
+	td->td_pcb->pcb_context[PCB_REG_S0] = (register_t)(intptr_t)
+	    vps_func->vps_syscall_fixup_inthread;
+	td->td_pcb->pcb_context[PCB_REG_S1] = (register_t)code;
+
+	return (0);
+}
+
+__attribute__((noinline))
+void
+vps_md_print_pcb(struct thread *td)
+{
+        struct pcb *p;
+
+        p = td->td_pcb;
+
+#if 0
+// XXX
+        DBGCORE("%s: td=%p\n"
+                "pcb_cr3: 0x%08x\n"
+                "pcb_edi: 0x%08x\n"
+                "pcb_esi: 0x%08x\n"
+                "pcb_ebp: 0x%08x\n"
+                "pcb_esp: 0x%08x\n"
+                "pcb_ebx: 0x%08x\n"
+                "pcb_eip: 0x%08x\n"
+                "pcb_psl: 0x%08x\n"
+                "pcb_ext: 0x%08x\n"
+                , __func__, td
+                , p->pcb_cr3
+                , p->pcb_edi
+                , p->pcb_esi
+                , p->pcb_ebp
+                , p->pcb_esp
+                , p->pcb_ebx
+                , p->pcb_eip
+                , p->pcb_psl
+                , (int)p->pcb_ext
+                );
+#endif
+}
+
+#if 0
+/* --------------------------- 8< --------------------------- */
+
+// vps_suspend():
+#if defined(CPU_X86)
+              DBGCORE("td->td_frame=%p tf_rax=%p tf_rsp=%p\n", td->td_frame,
+                 (void*)td->td_frame->tf_rax, (void*)td->td_frame->tf_rsp);
+#elif defined(CPU_386)
+              DBGCORE("td->td_frame=%p tf_eax=%p tf_esp=%p\n", td->td_frame,
+                 (void*)td->td_frame->tf_eax, (void*)td->td_frame->tf_esp);
+#else
+#error "unsupported architecture"
+#endif
+
+// 
+/* --------------------------- 8< --------------------------- */
+#endif /* 0 */
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/modules/Makefile head/sys/modules/Makefile
--- clean-head/sys/modules/Makefile	2013-06-26 09:35:55.000000000 +0200
+++ head/sys/modules/Makefile	2013-06-24 14:20:48.000000000 +0200
@@ -341,6 +341,15 @@ SUBDIR=	\
 	vkbd \
 	${_vmm} \
 	${_vpo} \
+	vps_dev \
+	vps_suspend \
+	vps_account \
+	vps_snapst \
+	vps_restore \
+	vps_libdump \
+	if_vps \
+	vps_ddb \
+	vpsfs \
 	vr \
 	vte \
 	vx \
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/modules/if_vps/Makefile head/sys/modules/if_vps/Makefile
--- clean-head/sys/modules/if_vps/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/modules/if_vps/Makefile	2013-06-24 14:20:45.000000000 +0200
@@ -0,0 +1,19 @@
+
+.PATH: ${.CURDIR}/../../vps
+
+KMOD=	if_vps
+SRCS=	if_vps.c opt_ddb.h opt_vps.h opt_inet.h opt_inet6.h vps.h vps_user.h
+
+.if !defined(KERNBUILDDIR)
+opt_ddb.h:
+	echo "#define DDB 1" > ${.TARGET}
+
+opt_inet.h:
+        echo "#define INET 1" > ${.TARGET}
+
+opt_inet6.h:
+        echo "#define INET6 1" > ${.TARGET}
+
+.endif
+
+.include <bsd.kmod.mk>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/modules/vps_account/Makefile head/sys/modules/vps_account/Makefile
--- clean-head/sys/modules/vps_account/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/modules/vps_account/Makefile	2013-06-24 14:20:49.000000000 +0200
@@ -0,0 +1,13 @@
+
+.PATH: ${.CURDIR}/../../vps
+
+KMOD=	vps_account
+SRCS=	vps_account.c opt_ddb.h opt_global.h opt_vps.h \
+	vnode_if.h vps.h vps_account.h
+
+.if !defined(KERNBUILDDIR)
+opt_ddb.h:
+	echo "#define DDB 1" > ${.TARGET}
+.endif
+
+.include <bsd.kmod.mk>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/modules/vps_ddb/Makefile head/sys/modules/vps_ddb/Makefile
--- clean-head/sys/modules/vps_ddb/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/modules/vps_ddb/Makefile	2013-06-24 14:20:45.000000000 +0200
@@ -0,0 +1,19 @@
+
+.PATH: ${.CURDIR}/../../vps
+
+KMOD=	vps_ddb
+SRCS=	vps_ddb.c opt_ddb.h opt_inet.h opt_inet6.h vps.h vps_user.h vps_snapst.h
+
+.if !defined(KERNBUILDDIR)
+opt_ddb.h:
+	echo "#define DDB 1" > ${.TARGET}
+
+opt_inet.h:
+        echo "#define INET 1" > ${.TARGET}
+
+opt_inet6.h:
+        echo "#define INET6 1" > ${.TARGET}
+
+.endif
+
+.include <bsd.kmod.mk>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/modules/vps_dev/Makefile head/sys/modules/vps_dev/Makefile
--- clean-head/sys/modules/vps_dev/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/modules/vps_dev/Makefile	2013-06-24 14:20:45.000000000 +0200
@@ -0,0 +1,12 @@
+
+.PATH: ${.CURDIR}/../../vps
+
+KMOD=	vps_dev
+SRCS=	vps_dev.c vps_user.c opt_ddb.h opt_global.h opt_vps.h vps.h vps_user.h
+
+.if !defined(KERNBUILDDIR)
+opt_ddb.h:
+	echo "#define DDB 1" > ${.TARGET}
+.endif
+
+.include <bsd.kmod.mk>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/modules/vps_libdump/Makefile head/sys/modules/vps_libdump/Makefile
--- clean-head/sys/modules/vps_libdump/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/modules/vps_libdump/Makefile	2013-06-24 14:20:45.000000000 +0200
@@ -0,0 +1,14 @@
+
+.PATH: ${.CURDIR}/../../vps
+
+KMOD=	vps_libdump
+SRCS=	vps_libdump.c \
+	vps_libdump.h \
+	opt_ddb.h opt_vps.h opt_inet.h opt_inet6.h \
+	vnode_if.h
+
+.if !defined(KERNBUILDDIR)
+
+.endif
+
+.include <bsd.kmod.mk>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/modules/vps_restore/Makefile head/sys/modules/vps_restore/Makefile
--- clean-head/sys/modules/vps_restore/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/modules/vps_restore/Makefile	2013-06-24 14:20:53.000000000 +0200
@@ -0,0 +1,25 @@
+
+.PATH: ${.CURDIR}/../../vps
+
+KMOD=	vps_restore
+SRCS=	vps_restore.c \
+	vps.h vps_user.h vps_snapst.h vps_libdump.h \
+	opt_ddb.h opt_vps.h opt_inet.h opt_inet6.h \
+	vnode_if.h
+
+.if !defined(KERNBUILDDIR)
+opt_vps.h:
+	echo "#define VPS 1" > ${.TARGET}
+
+opt_ddb.h:
+	echo "#define DDB 1" > ${.TARGET}
+
+opt_inet.h:
+        echo "#define INET 1" > ${.TARGET}
+
+opt_inet6.h:
+        echo "#define INET6 1" > ${.TARGET}
+
+.endif
+
+.include <bsd.kmod.mk>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/modules/vps_snapst/Makefile head/sys/modules/vps_snapst/Makefile
--- clean-head/sys/modules/vps_snapst/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/modules/vps_snapst/Makefile	2013-06-24 14:20:48.000000000 +0200
@@ -0,0 +1,25 @@
+
+.PATH: ${.CURDIR}/../../vps
+
+KMOD=	vps_snapst
+SRCS=	vps_snapst.c \
+	vps.h vps_user.h vps_snapst.h vps_libdump.h \
+	opt_ddb.h opt_vps.h opt_inet.h opt_inet6.h \
+	vnode_if.h
+
+.if !defined(KERNBUILDDIR)
+opt_vps.h:
+	echo "#define VPS 1" > ${.TARGET}
+
+opt_ddb.h:
+	echo "#define DDB 1" > ${.TARGET}
+
+opt_inet.h:
+        echo "#define INET 1" > ${.TARGET}
+
+opt_inet6.h:
+        echo "#define INET6 1" > ${.TARGET}
+
+.endif
+
+.include <bsd.kmod.mk>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/modules/vps_suspend/Makefile head/sys/modules/vps_suspend/Makefile
--- clean-head/sys/modules/vps_suspend/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/modules/vps_suspend/Makefile	2013-06-24 14:20:45.000000000 +0200
@@ -0,0 +1,8 @@
+
+.PATH: ${.CURDIR}/../../vps
+
+KMOD=	vps_suspend
+SRCS=	vps_suspend.c opt_ddb.h opt_vps.h opt_inet.h opt_inet6.h opt_compat.h \
+	vnode_if.h vps.h vps_user.h vps_snapst.h
+
+.include <bsd.kmod.mk>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/modules/vpsfs/Makefile head/sys/modules/vpsfs/Makefile
--- clean-head/sys/modules/vpsfs/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/modules/vpsfs/Makefile	2013-06-24 14:20:48.000000000 +0200
@@ -0,0 +1,8 @@
+
+.PATH: ${.CURDIR}/../../fs/vpsfs
+
+KMOD=	vpsfs
+SRCS=	vnode_if.h \
+	vpsfs_subr.c vpsfs_vfsops.c vpsfs_vnops.c vpsfs_quota.c
+
+.include <bsd.kmod.mk>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/net/bpf.c head/sys/net/bpf.c
--- clean-head/sys/net/bpf.c	2013-06-26 09:37:38.000000000 +0200
+++ head/sys/net/bpf.c	2013-06-24 14:21:35.000000000 +0200
@@ -78,6 +78,8 @@ __FBSDID("$FreeBSD: head/sys/net/bpf.c 2
 #include <net/bpfdesc.h>
 #include <net/vnet.h>
 
+#include <vps/vps.h>
+
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
 #include <sys/kernel.h>
@@ -2245,7 +2247,7 @@ bpf_bintime2ts(struct bintime *bt, struc
 
 	if ((tstype & BPF_T_MONOTONIC) == 0) {
 		bt2 = *bt;
-		bintime_add(&bt2, &boottimebin);
+		bintime_add(&bt2, &V_boottimebin);
 		bt = &bt2;
 	}
 	switch (BPF_T_FORMAT(tstype)) {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/net/flowtable.c head/sys/net/flowtable.c
--- clean-head/sys/net/flowtable.c	2013-06-26 09:37:38.000000000 +0200
+++ head/sys/net/flowtable.c	2013-06-24 14:21:35.000000000 +0200
@@ -272,6 +272,7 @@ SYSCTL_VNET_INT(_net_inet_flowtable, OID
     &VNET_NAME(flowtable_tcp_expire), 0,
     "seconds after which to remove flow allocated to a TCP connection.");
 
+MALLOC_DEFINE(M_FLOWTBL, "flowtbl", "flowtable");
 
 /*
  * Maximum number of flows that can be allocated of a given type.
@@ -1308,7 +1309,7 @@ flowtable_alloc(char *name, int nentry, 
 	KASSERT(nentry > 0, ("nentry must be > 0, is %d\n", nentry));
 
 	ft = malloc(sizeof(struct flowtable),
-	    M_RTABLE, M_WAITOK | M_ZERO);
+	    M_FLOWTBL, M_WAITOK | M_ZERO);
 
 	ft->ft_name = name;
 	ft->ft_flags = flags;
@@ -1325,7 +1326,7 @@ flowtable_alloc(char *name, int nentry, 
 		for (i = 0; i <= mp_maxid; i++) {
 			ft->ft_table.pcpu[i] =
 			    malloc(nentry*sizeof(struct flentry *),
-				M_RTABLE, M_WAITOK | M_ZERO);
+				M_FLOWTBL, M_WAITOK | M_ZERO);
 			ft->ft_masks[i] = bit_alloc(nentry);
 		}
 	} else {
@@ -1336,9 +1337,9 @@ flowtable_alloc(char *name, int nentry, 
 		ft->ft_unlock = flowtable_global_unlock;
 		ft->ft_table.global =
 			    malloc(nentry*sizeof(struct flentry *),
-				M_RTABLE, M_WAITOK | M_ZERO);
+				M_FLOWTBL, M_WAITOK | M_ZERO);
 		ft->ft_locks = malloc(ft->ft_lock_count*sizeof(struct mtx),
-				M_RTABLE, M_WAITOK | M_ZERO);
+				M_FLOWTBL, M_WAITOK | M_ZERO);
 		for (i = 0; i < ft->ft_lock_count; i++)
 			mtx_init(&ft->ft_locks[i], "flow", NULL, MTX_DEF|MTX_DUPOK);
 
@@ -1378,6 +1379,82 @@ flowtable_alloc(char *name, int nentry, 
 }
 
 /*
+ * Since this is called from ip_destroy it is assumed
+ * that there will be no more access and thus no locking
+ * required.
+ */
+static bitstr_t * flowtable_mask_pcpu(struct flowtable *ft, int cpuid);
+static struct flentry ** flowtable_entry_pcpu(struct flowtable *ft, uint32_t hash, int cpuid);
+static void fle_free(struct flentry *fle, struct flowtable *ft);
+void
+flowtable_destroy(struct flowtable *ft)
+{
+	struct flowtable *ft2;
+	struct flentry *fle, **flehead;
+	bitstr_t *mask, *tmpmask;
+	int curbit = 0;
+	int cpuid;
+	int i;
+
+	/* Free all entries. */
+	/* XXX not sure if this code actually works because
+	       in my tests there were never entries left at this
+	       point so the code didn't do anything.
+	 */
+
+	for (cpuid = 0; cpuid <= mp_maxid; cpuid++) {
+		
+		mask = flowtable_mask_pcpu(ft, cpuid);
+		tmpmask = ft->ft_tmpmask;
+		memcpy(tmpmask, mask, ft->ft_size/8);
+		bit_ffs(tmpmask, ft->ft_size, &curbit);
+
+		while (curbit != -1) {
+			flehead = flowtable_entry_pcpu(ft, curbit, cpuid);
+			fle = *flehead;
+
+			while (fle != NULL) {
+				fle = fle->f_next;
+				fle_free(fle, ft);
+			}
+			bit_clear(tmpmask, curbit);
+			bit_ffs(tmpmask, ft->ft_size, &curbit);
+		}
+	}
+
+	KASSERT(ft->ft_count == 0, ("%s: ft=%p ft->ft_count=%d\n",
+		__func__, ft, ft->ft_count));
+
+	/* Remove from the cleaner list */
+	if (V_flow_list_head) {
+		ft2 = V_flow_list_head;
+		while (ft2 && ft != ft2 && ft2->ft_next != ft)
+			ft2 = ft2->ft_next;
+		if (ft == V_flow_list_head)
+			V_flow_list_head = ft2;
+		if (ft2 != NULL)
+			ft2->ft_next = ft->ft_next;
+	}
+
+	free(ft->ft_tmpmask, M_DEVBUF);
+
+	if (ft->ft_flags & FL_PCPU) {
+		for (i = 0; i <= mp_maxid; i++) {
+			free(ft->ft_masks[i], M_DEVBUF);
+			free(ft->ft_table.pcpu[i], M_FLOWTBL);
+		}
+	} else {
+		free(ft->ft_masks[0], M_DEVBUF);
+		for (i = 0; i < ft->ft_lock_count; i++)
+			mtx_destroy(&ft->ft_locks[i]);
+		free(ft->ft_locks, M_FLOWTBL);
+		free(ft->ft_table.global, M_FLOWTBL);
+	}
+
+	free(ft, M_FLOWTBL);
+}
+
+/*
  * The rest of the code is devoted to garbage collection of expired entries.
  * It is a new additon made necessary by the switch to dynamically allocating
  * flow tables.
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/net/flowtable.h head/sys/net/flowtable.h
--- clean-head/sys/net/flowtable.h	2013-06-26 09:37:38.000000000 +0200
+++ head/sys/net/flowtable.h	2013-06-24 14:21:35.000000000 +0200
@@ -57,6 +57,7 @@ VNET_DECLARE(struct flowtable *, ip6_ft)
 #define	V_ip6_ft		VNET(ip6_ft)
 
 struct flowtable *flowtable_alloc(char *name, int nentry, int flags);
+void flowtable_destroy(struct flowtable *);
 
 /*
  * Given a flow table, look up the L3 and L2 information and
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/net/if.c head/sys/net/if.c
--- clean-head/sys/net/if.c	2013-06-26 09:37:39.000000000 +0200
+++ head/sys/net/if.c	2013-06-24 14:21:35.000000000 +0200
@@ -73,6 +73,9 @@
 #include <net/route.h>
 #include <net/vnet.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #if defined(INET) || defined(INET6)
 #include <netinet/in.h>
 #include <netinet/in_var.h>
@@ -674,6 +677,12 @@ if_attach_internal(struct ifnet *ifp, in
 			if (ifa->ifa_addr->sa_family == AF_LINK) {
 				sdl = (struct sockaddr_dl *)ifa->ifa_addr;
 				sdl->sdl_index = ifp->if_index;
+#ifdef VPS
+				namelen = strlen(ifp->if_xname);
+				sdl->sdl_nlen = namelen;
+				bcopy(ifp->if_xname, sdl->sdl_data, namelen);
+				/* XXX --> netmask ... */
+#endif
 			}
 		}
 	}
@@ -1072,6 +1081,46 @@ if_vmove_reclaim(struct thread *td, char
 	prison_free(pr);
 	return (0);
 }
+
+#ifdef VPS
+int
+if_vmove_vps(struct thread *td, char *ifname, size_t ifname_size, struct vps *vps, char *newifname)
+{
+	struct ifnet *ifp;
+	struct ifnet *difp;
+
+	ifp = ifunit(ifname);
+	if (ifp == NULL)
+		return (ESRCH);
+
+	/* Do not try to move the iface from and to the same vnet. */
+	if (vps->vnet == ifp->if_vnet)
+		return (EEXIST);
+
+	/* Make sure the named iface does not exists in the dst. vnet. */
+	/* XXX Lock interfaces to avoid races. */
+	CURVNET_SET_QUIET(vps->vnet);
+	difp = ifunit(newifname != NULL ? newifname : ifname);
+	CURVNET_RESTORE();
+	if (difp != NULL)
+		return (EEXIST);
+
+	/* XXX Make sure there are no unwanted side effects. */
+	DBGCORE("%s: newifname=%p\n", __func__, newifname);
+	if (newifname != NULL) {
+		DBGCORE("%s: newifname=[%s]\n", __func__, newifname);
+		snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s", newifname);	
+	}
+
+	/* Move the interface into the child vnet. */
+	if_vmove(ifp, vps->vnet);
+
+	/* Report the new if_xname back to the userland. */
+	snprintf(ifname, ifname_size, "%s", ifp->if_xname);
+
+	return (0);
+}
+#endif /* VPS */
 #endif /* VIMAGE */
 
 /*
@@ -2617,7 +2666,16 @@ ifioctl(struct socket *so, u_long cmd, c
 		if (ifp->if_flags & IFF_UP)
 			in6_if_up(ifp);
 #endif
+
 	}
+
+#ifdef VPS
+	if (ifp->if_pspare[2] != NULL)
+		((void (*) (u_long cmd, caddr_t data,
+			struct ifnet *ifp, struct thread *td))
+			ifp->if_pspare[2])(cmd, data, ifp, td);
+#endif
+
 	if_rele(ifp);
 	CURVNET_RESTORE();
 	return (error);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/net/if_llatbl.h head/sys/net/if_llatbl.h
--- clean-head/sys/net/if_llatbl.h	2013-06-26 09:37:38.000000000 +0200
+++ head/sys/net/if_llatbl.h	2013-06-24 14:21:35.000000000 +0200
@@ -172,6 +172,7 @@ MALLOC_DECLARE(M_LLTABLE);
 #define	LLE_STATIC	0x0002	/* entry is static */
 #define	LLE_IFADDR	0x0004	/* entry is interface addr */
 #define	LLE_VALID	0x0008	/* ll_addr is valid */
+#define LLE_PROXY       0x0010  /* proxy entry ??? */
 #define	LLE_PUB		0x0020	/* publish entry ??? */
 #define	LLE_LINKED	0x0040	/* linked to lookup structure */
 #define	LLE_EXCLUSIVE	0x2000	/* return lle xlocked  */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/net/if_tun.c head/sys/net/if_tun.c
--- clean-head/sys/net/if_tun.c	2013-06-26 09:37:39.000000000 +0200
+++ head/sys/net/if_tun.c	2013-06-24 14:21:35.000000000 +0200
@@ -56,6 +56,8 @@
 #include <net/bpf.h>
 #include <net/if_tun.h>
 
+#include <vps/vps.h>
+
 #include <sys/queue.h>
 #include <sys/condvar.h>
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/net/if_var.h head/sys/net/if_var.h
--- clean-head/sys/net/if_var.h	2013-06-26 09:37:39.000000000 +0200
+++ head/sys/net/if_var.h	2013-06-24 14:21:35.000000000 +0200
@@ -216,7 +216,7 @@ struct ifnet {
 	 */
 	char	if_cspare[3];
 	int	if_ispare[4];
-	void	*if_pspare[8];		/* 1 netmap, 7 TDB */
+	void	*if_pspare[8];		/* 1 netmap, 7 TDB, 2 VPS */
 };
 
 typedef void if_init_f_t(void *);
@@ -965,6 +965,10 @@ int    ether_poll_register(poll_handler_
 int    ether_poll_deregister(struct ifnet *ifp);
 #endif /* DEVICE_POLLING */
 
+#ifdef VPS
+int if_vmove_vps(struct thread *td, char *ifname, size_t ifname_size, struct vps *vps, char *);
+#endif
+
 #endif /* _KERNEL */
 
 #endif /* !_NET_IF_VAR_H_ */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/net/route.c head/sys/net/route.c
--- clean-head/sys/net/route.c	2013-06-26 09:37:39.000000000 +0200
+++ head/sys/net/route.c	2013-06-24 14:21:35.000000000 +0200
@@ -68,6 +68,11 @@
 
 #include <vm/uma.h>
 
+#ifdef VPS
+void vnet_route_init(const void *);
+void vnet_route_uninit(const void *);
+#endif
+
 #define	RT_MAXFIBS	UINT16_MAX
 
 /* Kernel config default option. */
@@ -163,6 +168,8 @@ rt_tables_get_rnh_ptr(int table, int fam
 
 	/* rnh is [fib=0][af=0]. */
 	rnh = (struct radix_node_head **)V_rt_tables;
+	if (rnh == NULL)
+		return (NULL);
 	/* Get the offset to the requested table and fam. */
 	rnh += table * (AF_MAX+1) + fam;
 
@@ -200,7 +207,11 @@ route_init(void)
 }
 SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0);
 
+#ifdef VPS
+void
+#else
 static void
+#endif
 vnet_route_init(const void *unused __unused)
 {
 	struct domain *dom;
@@ -238,7 +249,35 @@ VNET_SYSINIT(vnet_route_init, SI_SUB_PRO
     vnet_route_init, 0);
 
 #ifdef VIMAGE
+#ifdef VPS
+__unused
+static int
+vnet_route_uninit_rtdel(struct radix_node *rn, void *arg)
+{
+	struct rtentry  *rt = (struct rtentry *)rn;
+	int             err;
+
+	/*
+	 * Protect (sorta) against walktree recursion problems
+	 * with cloned routes
+	 */
+	if ((rt->rt_flags & RTF_UP) == 0)
+		return (0);
+
+	err = rtrequest_fib(RTM_DELETE, rt_key(rt), rt->rt_gateway,
+			rt_mask(rt), rt->rt_flags|RTF_RNH_LOCKED,
+			(struct rtentry **) NULL, rt->rt_fibnum);
+	if (err) {
+		log(LOG_WARNING, "%s: error %d\n", __func__, err);
+	}
+
+	return (0);
+}
+
+void
+#else
 static void
+#endif
 vnet_route_uninit(const void *unused __unused)
 {
 	int table;
@@ -247,6 +286,31 @@ vnet_route_uninit(const void *unused __u
 	struct radix_node_head **rnh;
 
 	for (dom = domains; dom; dom = dom->dom_next) {
+#if 0
+// old ...
+		if (dom->dom_rtdetach) {
+			for (table = 0; table < rt_numfibs; table++) {
+				if ( (fam = dom->dom_family) == AF_INET ||
+				    table == 0) {
+					/* For now only AF_INET has > 1 tbl. */
+					rnh = rt_tables_get_rnh_ptr(table, fam);
+					if (rnh == NULL)
+						panic("%s: rnh NULL", __func__);
+
+					/* XXX doesn't improve anything */
+					RADIX_NODE_HEAD_LOCK(*rnh);
+					(void) (*rnh)->rnh_walktree(*rnh,
+						vnet_route_uninit_rtdel, NULL);
+					RADIX_NODE_HEAD_UNLOCK(*rnh);
+
+					dom->dom_rtdetach((void **)rnh,
+					    dom->dom_rtoffset);
+				} else {
+					break;
+				}
+			}
+		}
+#else
 		if (dom->dom_rtdetach == NULL)
 			continue;
 
@@ -261,7 +325,12 @@ vnet_route_uninit(const void *unused __u
 				panic("%s: rnh NULL", __func__);
 			dom->dom_rtdetach((void **)rnh, dom->dom_rtoffset);
 		}
+#endif
 	}
+
+	uma_zdestroy(V_rtzone);
+	free(V_rt_tables, M_RTABLE);
+	V_rt_tables = NULL;
 }
 VNET_SYSUNINIT(vnet_route_uninit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
     vnet_route_uninit, 0);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/net/rtsock.c head/sys/net/rtsock.c
--- clean-head/sys/net/rtsock.c	2013-06-26 09:37:39.000000000 +0200
+++ head/sys/net/rtsock.c	2013-06-24 14:21:35.000000000 +0200
@@ -175,7 +175,7 @@ MTX_SYSINIT(rtsock, &rtsock_mtx, "rtsock
 #define	RTSOCK_UNLOCK()	mtx_unlock(&rtsock_mtx)
 #define	RTSOCK_LOCK_ASSERT()	mtx_assert(&rtsock_mtx, MA_OWNED)
 
-static SYSCTL_NODE(_net, OID_AUTO, route, CTLFLAG_RD, 0, "");
+static _SYSCTL_NODE(_net, OID_AUTO, route, CTLFLAG_RD, 0, "", VPS_PUBLIC);
 
 struct walkarg {
 	int	w_tmemsize;
@@ -220,9 +220,9 @@ sysctl_route_netisr_maxqlen(SYSCTL_HANDL
 		return (EINVAL);
 	return (netisr_setqlimit(&rtsock_nh, qlimit));
 }
-SYSCTL_PROC(_net_route, OID_AUTO, netisr_maxqlen, CTLTYPE_INT|CTLFLAG_RW,
+_SYSCTL_PROC(_net_route, OID_AUTO, netisr_maxqlen, CTLTYPE_INT|CTLFLAG_RW,
     0, 0, sysctl_route_netisr_maxqlen, "I",
-    "maximum routing socket dispatch queue length");
+    "maximum routing socket dispatch queue length", VPS_PUBLIC);
 
 static void
 rts_init(void)
@@ -1965,7 +1965,7 @@ sysctl_rtsock(SYSCTL_HANDLER_ARGS)
 	return (error);
 }
 
-static SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, "");
+static _SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, "", VPS_PUBLIC);
 
 /*
  * Definitions of protocols supported in the ROUTE domain.
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/net/vnet.c head/sys/net/vnet.c
--- clean-head/sys/net/vnet.c	2013-06-26 09:37:38.000000000 +0200
+++ head/sys/net/vnet.c	2013-06-24 14:21:35.000000000 +0200
@@ -66,6 +66,8 @@ __FBSDID("$FreeBSD: head/sys/net/vnet.c 
 #include <net/if_var.h>
 #include <net/vnet.h>
 
+extern struct prison prison0;
+
 /*-
  * This file implements core functions for virtual network stacks:
  *
@@ -505,6 +507,17 @@ vnet_sysctl_handle_uint(SYSCTL_HANDLER_A
 	return (sysctl_handle_int(oidp, arg1, arg2, req));
 }
 
+#ifdef VPS
+int
+vnet_sysctl_handle_long(SYSCTL_HANDLER_ARGS)
+{
+
+	if (arg1 != NULL)
+		arg1 = (void *)(curvnet->vnet_data_base + (uintptr_t)arg1);
+	return (sysctl_handle_long(oidp, arg1, arg2, req));
+}
+#endif
+
 /*
  * Support for special SYSINIT handlers registered via VNET_SYSINIT()
  * and VNET_SYSUNINIT().
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/net/vnet.h head/sys/net/vnet.h
--- clean-head/sys/net/vnet.h	2013-06-26 09:37:38.000000000 +0200
+++ head/sys/net/vnet.h	2013-06-24 14:21:35.000000000 +0200
@@ -64,16 +64,8 @@
  */
 #if defined(_KERNEL) || defined(_WANT_VNET)
 #include <sys/queue.h>
-
-struct vnet {
-	LIST_ENTRY(vnet)	 vnet_le;	/* all vnets list */
-	u_int			 vnet_magic_n;
-	u_int			 vnet_ifcnt;
-	u_int			 vnet_sockcnt;
-	void			*vnet_data_mem;
-	uintptr_t		 vnet_data_base;
-};
-#define	VNET_MAGIC_N	0x3e0d8f29
+#include <sys/sysctl.h>
+#include <sys/vnet2.h>
 
 /*
  * These two virtual network stack allocator definitions are also required
@@ -92,17 +84,6 @@ struct vnet {
 #include <sys/sx.h>
 
 /*
- * Location of the kernel's 'set_vnet' linker set.
- */
-extern uintptr_t	*__start_set_vnet;
-__GLOBL(__start_set_vnet);
-extern uintptr_t	*__stop_set_vnet;
-__GLOBL(__stop_set_vnet);
-
-#define	VNET_START	(uintptr_t)&__start_set_vnet
-#define	VNET_STOP	(uintptr_t)&__stop_set_vnet
-
-/*
  * Functions to allocate and destroy virtual network stacks.
  */
 struct vnet *vnet_alloc(void);
@@ -180,6 +161,7 @@ extern struct vnet *vnet0;
 #define	IS_DEFAULT_VNET(arg)	((arg) == vnet0)
 
 #define	CRED_TO_VNET(cr)	(cr)->cr_prison->pr_vnet
+
 #define	TD_TO_VNET(td)		CRED_TO_VNET((td)->td_ucred)
 #define	P_TO_VNET(p)		CRED_TO_VNET((p)->p_ucred)
 
@@ -205,27 +187,6 @@ extern struct sx vnet_sxlock;
 #define	VNET_FOREACH(arg)	LIST_FOREACH((arg), &vnet_head, vnet_le)
 
 /*
- * Virtual network stack memory allocator, which allows global variables to
- * be automatically instantiated for each network stack instance.
- */
-#define	VNET_NAME(n)		vnet_entry_##n
-#define	VNET_DECLARE(t, n)	extern t VNET_NAME(n)
-#define	VNET_DEFINE(t, n)	t VNET_NAME(n) __section(VNET_SETNAME) __used
-#define	_VNET_PTR(b, n)		(__typeof(VNET_NAME(n))*)		\
-				    ((b) + (uintptr_t)&VNET_NAME(n))
-
-#define	_VNET(b, n)		(*_VNET_PTR(b, n))
-
-/*
- * Virtualized global variable accessor macros.
- */
-#define	VNET_VNET_PTR(vnet, n)		_VNET_PTR((vnet)->vnet_data_base, n)
-#define	VNET_VNET(vnet, n)		(*VNET_VNET_PTR((vnet), n))
-
-#define	VNET_PTR(n)		VNET_VNET_PTR(curvnet, n)
-#define	VNET(n)			VNET_VNET(curvnet, n)
-
-/*
  * Virtual network stack allocator interfaces from the kernel linker.
  */
 void	*vnet_data_alloc(int size);
@@ -239,11 +200,68 @@ void	 vnet_data_free(void *start_arg, in
  * Note: SYSCTL_PROC() handler functions will need to resolve pointer
  * arguments themselves, if required.
  */
-#ifdef SYSCTL_OID
+//#ifdef SYSCTL_OID
 int	vnet_sysctl_handle_int(SYSCTL_HANDLER_ARGS);
 int	vnet_sysctl_handle_opaque(SYSCTL_HANDLER_ARGS);
 int	vnet_sysctl_handle_string(SYSCTL_HANDLER_ARGS);
 int	vnet_sysctl_handle_uint(SYSCTL_HANDLER_ARGS);
+int	vnet_sysctl_handle_long(SYSCTL_HANDLER_ARGS);
+int	vnet_sysctl_handle_ulong(SYSCTL_HANDLER_ARGS);
+
+#ifdef VPS
+
+#define	_SYSCTL_VNET_INT(parent, nbr, name, access, ptr, val, descr, vps0)	\
+	_SYSCTL_OID(parent, nbr, name,					\
+	    CTLTYPE_INT|CTLFLAG_MPSAFE|CTLFLAG_VNET|(access),		\
+	    ptr, val, vnet_sysctl_handle_int, "I", descr, vps0)
+#define	_SYSCTL_VNET_PROC(parent, nbr, name, access, ptr, arg, handler,	\
+	    fmt, descr, vps0)							\
+	_SYSCTL_OID(parent, nbr, name, CTLFLAG_VNET|(access), ptr, arg, 	\
+	    handler, fmt, descr, vps0)
+#define	_SYSCTL_VNET_OPAQUE(parent, nbr, name, access, ptr, len, fmt,	\
+	    descr, vps0)						\
+	_SYSCTL_OID(parent, nbr, name,					\
+	    CTLTYPE_OPAQUE|CTLFLAG_VNET|(access), ptr, len, 		\
+	    vnet_sysctl_handle_opaque, fmt, descr, vps0)
+#define	_SYSCTL_VNET_STRING(parent, nbr, name, access, arg, len, descr, vps0)	\
+	_SYSCTL_OID(parent, nbr, name,					\
+	    CTLTYPE_STRING|CTLFLAG_VNET|(access),			\
+	    arg, len, vnet_sysctl_handle_string, "A", descr, vps0)
+#define	_SYSCTL_VNET_STRUCT(parent, nbr, name, access, ptr, type, descr, vps0)	\
+	_SYSCTL_OID(parent, nbr, name,					\
+	    CTLTYPE_OPAQUE|CTLFLAG_VNET|(access), ptr,			\
+	    sizeof(struct type), vnet_sysctl_handle_opaque, "S," #type,	\
+	    descr, vps0)
+#define	_SYSCTL_VNET_UINT(parent, nbr, name, access, ptr, val, descr, vps0)	\
+	_SYSCTL_OID(parent, nbr, name,					\
+	    CTLTYPE_UINT|CTLFLAG_MPSAFE|CTLFLAG_VNET|(access),		\
+	    ptr, val, vnet_sysctl_handle_uint, "IU", descr, vps0)
+#define	_SYSCTL_VNET_ULONG(parent, nbr, name, access, ptr, val, descr, vps0)	\
+	_SYSCTL_OID(parent, nbr, name,					\
+	    CTLTYPE_ULONG|CTLFLAG_MPSAFE|CTLFLAG_VNET|(access),		\
+	    ptr, val, vnet_sysctl_handle_long, "LU", descr, vps0)
+#define	VNET_SYSCTL_ARG(req, arg1) do {					\
+	if (arg1 != NULL)						\
+		arg1 = (void *)(TD_TO_VNET((req)->td)->vnet_data_base +	\
+		    (uintptr_t)(arg1));					\
+} while (0)
+
+#define SYSCTL_VNET_INT(parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_VNET_INT(parent, nbr, name, access, ptr, val, descr, VPS_PUBLIC)
+#define SYSCTL_VNET_PROC(parent, nbr, name, access, ptr, arg, handler, fmt, descr) \
+	_SYSCTL_VNET_PROC(parent, nbr, name, access, ptr, arg, handler, fmt, descr, VPS_PUBLIC)
+#define SYSCTL_VNET_OPAQUE(parent, nbr, name, access, ptr, len, fmt, descr) \
+	_SYSCTL_VNET_OPAQUE(parent, nbr, name, access, ptr, len, fmt, descr, VPS_PUBLIC)
+#define SYSCTL_VNET_STRING(parent, nbr, name, access, arg, len, descr) \
+	_SYSCTL_VNET_STRING(parent, nbr, name, access, arg, len, descr, VPS_PUBLIC)
+#define SYSCTL_VNET_STRUCT(parent, nbr, name, access, ptr, type, descr) \
+	_SYSCTL_VNET_STRUCT(parent, nbr, name, access, ptr, type, descr, VPS_PUBLIC)
+#define SYSCTL_VNET_UINT(parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_VNET_UINT(parent, nbr, name, access, ptr, val, descr, VPS_PUBLIC)
+#define SYSCTL_VNET_ULONG(parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_VNET_ULONG(parent, nbr, name, access, ptr, val, descr, VPS_PUBLIC)
+
+#else /* VPS */
 
 #define	SYSCTL_VNET_INT(parent, nbr, name, access, ptr, val, descr)	\
 	SYSCTL_OID(parent, nbr, name,					\
@@ -272,12 +290,19 @@ int	vnet_sysctl_handle_uint(SYSCTL_HANDL
 	SYSCTL_OID(parent, nbr, name,					\
 	    CTLTYPE_UINT|CTLFLAG_MPSAFE|CTLFLAG_VNET|(access),		\
 	    ptr, val, vnet_sysctl_handle_uint, "IU", descr)
+#define	SYSCTL_VNET_ULONG(parent, nbr, name, access, ptr, val, descr)	\
+	SYSCTL_OID(parent, nbr, name,					\
+	    CTLTYPE_ULONG|CTLFLAG_MPSAFE|CTLFLAG_VNET|(access),		\
+	    ptr, val, vnet_sysctl_handle_ulong, "LU", descr)
 #define	VNET_SYSCTL_ARG(req, arg1) do {					\
 	if (arg1 != NULL)						\
 		arg1 = (void *)(TD_TO_VNET((req)->td)->vnet_data_base +	\
 		    (uintptr_t)(arg1));					\
 } while (0)
-#endif /* SYSCTL_OID */
+
+#endif /* !VPS */
+
+//#endif /* SYSCTL_OID */
 
 /*
  * Virtual sysinit mechanism, allowing network stack components to declare
@@ -384,28 +409,10 @@ do {									\
 #define	P_TO_VNET(p)		NULL
 
 /*
- * Versions of the VNET macros that compile to normal global variables and
- * standard sysctl definitions.
- */
-#define	VNET_NAME(n)		n
-#define	VNET_DECLARE(t, n)	extern t n
-#define	VNET_DEFINE(t, n)	t n
-#define	_VNET_PTR(b, n)		&VNET_NAME(n)
-
-/*
- * Virtualized global variable accessor macros.
- */
-#define	VNET_VNET_PTR(vnet, n)		(&(n))
-#define	VNET_VNET(vnet, n)		(n)
-
-#define	VNET_PTR(n)		(&(n))
-#define	VNET(n)			(n)
-
-/*
  * When VIMAGE isn't compiled into the kernel, virtaulized SYSCTLs simply
  * become normal SYSCTLs.
  */
-#ifdef SYSCTL_OID
+//#ifdef SYSCTL_OID
 #define	SYSCTL_VNET_INT(parent, nbr, name, access, ptr, val, descr)	\
 	SYSCTL_INT(parent, nbr, name, access, ptr, val, descr)
 #define	SYSCTL_VNET_PROC(parent, nbr, name, access, ptr, arg, handler,	\
@@ -421,8 +428,10 @@ do {									\
 	SYSCTL_STRUCT(parent, nbr, name, access, ptr, type, descr)
 #define	SYSCTL_VNET_UINT(parent, nbr, name, access, ptr, val, descr)	\
 	SYSCTL_UINT(parent, nbr, name, access, ptr, val, descr)
+#define	SYSCTL_VNET_ULONG(parent, nbr, name, access, ptr, val, descr)	\
+	SYSCTL_ULONG(parent, nbr, name, access, ptr, val, descr)
 #define	VNET_SYSCTL_ARG(req, arg1)
-#endif /* SYSCTL_OID */
+//#endif /* SYSCTL_OID */
 
 /*
  * When VIMAGE isn't compiled into the kernel, VNET_SYSINIT/VNET_SYSUNINIT
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/in_proto.c head/sys/netinet/in_proto.c
--- clean-head/sys/netinet/in_proto.c	2013-06-26 09:35:37.000000000 +0200
+++ head/sys/netinet/in_proto.c	2013-06-24 14:20:40.000000000 +0200
@@ -100,7 +100,7 @@ static struct pr_usrreqs nousrreqs;
 #include <netinet/sctp_var.h>
 #endif /* SCTP */
 
-FEATURE(inet, "Internet Protocol version 4");
+_FEATURE(inet, "Internet Protocol version 4", VPS_PUBLIC);
 
 extern	struct domain inetdomain;
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/in_rmx.c head/sys/netinet/in_rmx.c
--- clean-head/sys/netinet/in_rmx.c	2013-06-26 09:35:36.000000000 +0200
+++ head/sys/netinet/in_rmx.c	2013-06-24 14:20:39.000000000 +0200
@@ -315,6 +315,8 @@ in_rtqdrain(void)
 
 		for ( fibnum = 0; fibnum < rt_numfibs; fibnum++) {
 			rnh = rt_tables_get_rnh(fibnum, AF_INET);
+			if (rnh == NULL)
+				continue;
 			arg.found = arg.killed = 0;
 			arg.rnh = rnh;
 			arg.nextstop = 0;
@@ -372,11 +374,67 @@ in_inithead(void **head, int off)
 }
 
 #ifdef VIMAGE
+__attribute__ ((unused))
+static int
+in_rtqkill_hard(struct radix_node *rn, void *rock)
+{
+	struct rtqk_arg *ap = rock;
+	struct rtentry *rt = (struct rtentry *)rn;
+	int err;
+
+	RADIX_NODE_HEAD_WLOCK_ASSERT(ap->rnh);
+
+	if (1) {
+		ap->found++;
+
+		if (1) {
+			if (0 && rt->rt_refcnt > 0)
+				panic("rtqkill route really not free");
+
+			err = in_rtrequest(RTM_DELETE,
+					(struct sockaddr *)rt_key(rt),
+					rt->rt_gateway, rt_mask(rt),
+					rt->rt_flags | RTF_RNH_LOCKED, 0,
+					rt->rt_fibnum);
+			if (err) {
+				log(LOG_WARNING, "in_rtqkill: error %d\n", err);
+			} else {
+				ap->killed++;
+			}
+		}
+	}
+
+	return 0;
+}
+
 int
 in_detachhead(void **head, int off)
 {
+	struct radix_node_head *rnh;
+	struct rtqk_arg arg;
 
 	callout_drain(&V_rtq_timer);
+
+	rnh = *head;
+
+	arg.found = arg.killed = 0;
+	arg.rnh = rnh;
+	arg.nextstop = 0;
+	arg.draining = 1;
+	arg.updating = 0;
+	RADIX_NODE_HEAD_LOCK(rnh);
+	//rnh->rnh_walktree(rnh, in_rtqkill_hard, &arg);
+	rnh->rnh_walktree(rnh, in_rtqkill, &arg);
+	RADIX_NODE_HEAD_UNLOCK(rnh);
+
+	/*
+	printf("%s: found=%d killed=%d\n",
+		__func__, arg.found, arg.killed);
+	*/
+
+	/* XXX determine if tree is actually as empty as it can be. */
+	rn_detachhead(head);
+
 	return (1);
 }
 #endif
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/ip_divert.c head/sys/netinet/ip_divert.c
--- clean-head/sys/netinet/ip_divert.c	2013-06-26 09:35:37.000000000 +0200
+++ head/sys/netinet/ip_divert.c	2013-06-24 14:20:40.000000000 +0200
@@ -156,7 +156,11 @@ div_init(void)
 	 * place for hashbase == NULL.
 	 */
 	in_pcbinfo_init(&V_divcbinfo, "div", &V_divcb, 1, 1, "divcb",
+#ifdef VIMAGE
+	    div_inpcb_init, div_inpcb_fini, 0,
+#else
 	    div_inpcb_init, div_inpcb_fini, UMA_ZONE_NOFREE,
+#endif
 	    IPI_HASHFIELDS_NONE);
 }
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/ip_input.c head/sys/netinet/ip_input.c
--- clean-head/sys/netinet/ip_input.c	2013-06-26 09:35:38.000000000 +0200
+++ head/sys/netinet/ip_input.c	2013-06-24 14:20:39.000000000 +0200
@@ -425,6 +425,10 @@ ip_destroy(void)
 	IPQ_UNLOCK();
 
 	uma_zdestroy(V_ipq_zone);
+
+#ifdef FLOWTABLE
+	flowtable_destroy(V_ip_ft);
+#endif /* FLOWTABLE */
 }
 #endif
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/raw_ip.c head/sys/netinet/raw_ip.c
--- clean-head/sys/netinet/raw_ip.c	2013-06-26 09:35:36.000000000 +0200
+++ head/sys/netinet/raw_ip.c	2013-06-24 14:20:40.000000000 +0200
@@ -205,7 +205,11 @@ rip_init(void)
 {
 
 	in_pcbinfo_init(&V_ripcbinfo, "rip", &V_ripcb, INP_PCBHASH_RAW_SIZE,
+#ifdef VIMAGE
+	    1, "ripcb", rip_inpcb_init, NULL, 0,
+#else
 	    1, "ripcb", rip_inpcb_init, NULL, UMA_ZONE_NOFREE,
+#endif
 	    IPI_HASHFIELDS_NONE);
 	EVENTHANDLER_REGISTER(maxsockets_change, rip_zone_change, NULL,
 	    EVENTHANDLER_PRI_ANY);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/tcp_input.c head/sys/netinet/tcp_input.c
--- clean-head/sys/netinet/tcp_input.c	2013-06-26 09:35:38.000000000 +0200
+++ head/sys/netinet/tcp_input.c	2013-06-24 14:20:39.000000000 +0200
@@ -70,6 +70,9 @@ __FBSDID("$FreeBSD: head/sys/netinet/tcp
 #include <sys/syslog.h>
 #include <sys/systm.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <machine/cpu.h>	/* before tcp_seq.h, for tcp_random18() */
 
 #include <vm/uma.h>
@@ -646,6 +649,14 @@ tcp_input(struct mbuf *m, int off0)
 	short ostate = 0;
 #endif
 
+#ifdef VPS
+	int vnet_vps_flags = curthread->td_vnet->vnet_vps_flags;
+
+	if (vnet_vps_flags & VPS_VNET_ABORT ||
+	    vnet_vps_flags & VPS_VNET_SUSPENDED)
+		goto drop;
+#endif
+
 #ifdef INET6
 	isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0;
 #endif
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/tcp_output.c head/sys/netinet/tcp_output.c
--- clean-head/sys/netinet/tcp_output.c	2013-06-26 09:35:37.000000000 +0200
+++ head/sys/netinet/tcp_output.c	2013-06-24 14:20:39.000000000 +0200
@@ -50,6 +50,10 @@ __FBSDID("$FreeBSD: head/sys/netinet/tcp
 #include <sys/socketvar.h>
 #include <sys/sysctl.h>
 
+#include <sys/proc.h>
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <net/if.h>
 #include <net/route.h>
 #include <net/vnet.h>
@@ -194,6 +198,29 @@ tcp_output(struct tcpcb *tp)
 
 	INP_WLOCK_ASSERT(tp->t_inpcb);
 
+#ifdef VPS
+	if (so->so_vnet->vnet_vps_flags & VPS_VNET_ABORT) {
+		printf("%s: VPS_VNET_ABORT --> returning 0, so=%p\n",
+			__func__, so);
+		return (0);
+	}
+	
+	/*
+	 * This can actually happen because we set the suspended flag
+	 * first and then suspend thread by thread ...
+	 * Better don't panic but return with EAGAIN.
+	 * XXX But make sure common user programs can deal with it.
+	 *
+	KASSERT( ! (so->so_vnet->vnet_vps_flags & VPS_VNET_SUSPENDED),
+		("%s: SUSPENDED vnet %p\n", __func__, so->so_vnet));
+	 */
+	if (so->so_vnet->vnet_vps_flags & VPS_VNET_SUSPENDED) {
+		printf("%s: VPS_VNET_SUSPENDED --> returning EINTR, so=%p\n",
+			__func__, so);
+		return (EINTR);
+	}
+#endif
+
 #ifdef TCP_OFFLOAD
 	if (tp->t_flags & TF_TOE)
 		return (tcp_offload_output(tp));
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/tcp_reass.c head/sys/netinet/tcp_reass.c
--- clean-head/sys/netinet/tcp_reass.c	2013-06-26 09:35:37.000000000 +0200
+++ head/sys/netinet/tcp_reass.c	2013-06-24 14:20:40.000000000 +0200
@@ -118,7 +118,11 @@ tcp_reass_init(void)
 	TUNABLE_INT_FETCH("net.inet.tcp.reass.maxsegments",
 	    &V_tcp_reass_maxseg);
 	V_tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent),
+#ifdef VIMAGE
+	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+#else
 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+#endif
 	/* Set the zone limit and read back the effective value. */
 	V_tcp_reass_maxseg = uma_zone_set_max(V_tcp_reass_zone,
 	    V_tcp_reass_maxseg);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/tcp_subr.c head/sys/netinet/tcp_subr.c
--- clean-head/sys/netinet/tcp_subr.c	2013-06-26 09:35:37.000000000 +0200
+++ head/sys/netinet/tcp_subr.c	2013-06-24 14:20:39.000000000 +0200
@@ -58,6 +58,8 @@ __FBSDID("$FreeBSD: head/sys/netinet/tcp
 #include <sys/protosw.h>
 #include <sys/random.h>
 
+#include <vps/vps.h>
+
 #include <vm/uma.h>
 
 #include <net/route.h>
@@ -357,15 +359,31 @@ tcp_init(void)
 		    "clipped from %d to %d.\n", __func__, oldhashsize,
 		    hashsize);
 	}
+	/*
+	 * Until UMA supports draining a UMA_ZONE_NOFREE zone on destroy,
+	 * UMA_ZONE_NOFREE can't be specified here.
+	 */
 	in_pcbinfo_init(&V_tcbinfo, "tcp", &V_tcb, hashsize, hashsize,
+#ifdef VIMAGE
+	    "tcp_inpcb", tcp_inpcb_init, NULL, 0,
+#else
 	    "tcp_inpcb", tcp_inpcb_init, NULL, UMA_ZONE_NOFREE,
+#endif
 	    IPI_HASHFIELDS_4TUPLE);
 
 	/*
 	 * These have to be type stable for the benefit of the timers.
 	 */
+	/*
+	 * Until UMA supports draining a UMA_ZONE_NOFREE zone on destroy,
+	 * UMA_ZONE_NOFREE can't be specified here.
+	 */
 	V_tcpcb_zone = uma_zcreate("tcpcb", sizeof(struct tcpcb_mem),
-	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+#ifdef VIMAGE
+		NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+#else
+		NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+#endif
 	uma_zone_set_max(V_tcpcb_zone, maxsockets);
 	uma_zone_set_warning(V_tcpcb_zone, "kern.ipc.maxsockets limit reached");
 
@@ -376,7 +394,11 @@ tcp_init(void)
 
 	TUNABLE_INT_FETCH("net.inet.tcp.sack.enable", &V_tcp_do_sack);
 	V_sack_hole_zone = uma_zcreate("sackhole", sizeof(struct sackhole),
+#ifdef VIMAGE
+	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+#else
 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+#endif
 
 	/* Skip initialization of globals for non-default instances. */
 	if (!IS_DEFAULT_VNET(curvnet))
@@ -436,6 +458,10 @@ tcp_destroy(void)
 	in_pcbinfo_destroy(&V_tcbinfo);
 	uma_zdestroy(V_sack_hole_zone);
 	uma_zdestroy(V_tcpcb_zone);
+
+	/* VPS */
+	hhook_head_deregister(V_tcp_hhh[HHOOK_TCP_EST_OUT]);
+	hhook_head_deregister(V_tcp_hhh[HHOOK_TCP_EST_IN]);
 }
 #endif
 
@@ -1275,7 +1301,7 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS)
 	return (error);
 }
 
-SYSCTL_PROC(_net_inet_tcp, TCPCTL_PCBLIST, pcblist,
+SYSCTL_VNET_PROC(_net_inet_tcp, TCPCTL_PCBLIST, pcblist,
     CTLTYPE_OPAQUE | CTLFLAG_RD, NULL, 0,
     tcp_pcblist, "S,xtcpcb", "List of active TCP connections");
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/tcp_timewait.c head/sys/netinet/tcp_timewait.c
--- clean-head/sys/netinet/tcp_timewait.c	2013-06-26 09:35:39.000000000 +0200
+++ head/sys/netinet/tcp_timewait.c	2013-06-24 14:20:40.000000000 +0200
@@ -164,7 +164,11 @@ tcp_tw_init(void)
 {
 
 	V_tcptw_zone = uma_zcreate("tcptw", sizeof(struct tcptw),
+#ifdef VIMAGE
+	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+#else
 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+#endif
 	TUNABLE_INT_FETCH("net.inet.tcp.maxtcptw", &maxtcptw);
 	if (maxtcptw == 0)
 		uma_zone_set_max(V_tcptw_zone, tcptw_auto_size());
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/tcp_usrreq.c head/sys/netinet/tcp_usrreq.c
--- clean-head/sys/netinet/tcp_usrreq.c	2013-06-26 09:35:36.000000000 +0200
+++ head/sys/netinet/tcp_usrreq.c	2013-06-24 14:20:40.000000000 +0200
@@ -59,6 +59,9 @@ __FBSDID("$FreeBSD: head/sys/netinet/tcp
 #include <sys/proc.h>
 #include <sys/jail.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #ifdef DDB
 #include <ddb/ddb.h>
 #endif
@@ -91,6 +94,10 @@ __FBSDID("$FreeBSD: head/sys/netinet/tcp
 #include <netinet/tcp_offload.h>
 #endif
 
+#ifdef VPS
+static void tcp_usr_abort(struct socket *so);
+#endif
+
 /*
  * TCP protocol interface to socket abstraction.
  */
@@ -587,6 +594,14 @@ tcp_usr_disconnect(struct socket *so)
 	int error = 0;
 
 	TCPDEBUG0;
+#ifdef VPS
+	if (so->so_vnet->vnet_vps_flags & VPS_VNET_ABORT) {
+		DBGCORE("%s: VPS_VNET_ABORT --> tcp_usr_abort(so=%p)\n",
+			__func__, so);
+		tcp_usr_abort(so);
+		return (0);
+	}
+#endif
 	INP_INFO_WLOCK(&V_tcbinfo);
 	inp = sotoinpcb(so);
 	KASSERT(inp != NULL, ("tcp_usr_disconnect: inp == NULL"));
@@ -978,6 +993,15 @@ tcp_usr_close(struct socket *so)
 	struct tcpcb *tp = NULL;
 	TCPDEBUG0;
 
+#ifdef VPS
+	if (so->so_vnet->vnet_vps_flags & VPS_VNET_ABORT) {
+		DBGCORE("%s: VPS_VNET_ABORT --> tcp_usr_abort(so=%p)\n",
+			__func__, so);
+		tcp_usr_abort(so);
+		return;
+	}
+#endif
+
 	inp = sotoinpcb(so);
 	KASSERT(inp != NULL, ("tcp_usr_close: inp == NULL"));
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet/udp_usrreq.c head/sys/netinet/udp_usrreq.c
--- clean-head/sys/netinet/udp_usrreq.c	2013-06-26 09:35:38.000000000 +0200
+++ head/sys/netinet/udp_usrreq.c	2013-06-24 14:20:39.000000000 +0200
@@ -185,11 +185,27 @@ void
 udp_init(void)
 {
 
+	/*
+	 * Until UMA supports draining a UMA_ZONE_NOFREE zone on destroy,
+	 * UMA_ZONE_NOFREE can't be specified here.
+	 */
 	in_pcbinfo_init(&V_udbinfo, "udp", &V_udb, UDBHASHSIZE, UDBHASHSIZE,
+#ifdef VIMAGE
+	    "udp_inpcb", udp_inpcb_init, NULL, 0,
+#else
 	    "udp_inpcb", udp_inpcb_init, NULL, UMA_ZONE_NOFREE,
+#endif
 	    IPI_HASHFIELDS_2TUPLE);
+	/*
+	 * Until UMA supports draining a UMA_ZONE_NOFREE zone on destroy,
+	 * UMA_ZONE_NOFREE can't be specified here.
+	 */
 	V_udpcb_zone = uma_zcreate("udpcb", sizeof(struct udpcb),
+#ifdef VIMAGE
+	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+#else
 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+#endif
 	uma_zone_set_max(V_udpcb_zone, maxsockets);
 	uma_zone_set_warning(V_udpcb_zone, "kern.ipc.maxsockets limit reached");
 	EVENTHANDLER_REGISTER(maxsockets_change, udp_zone_change, NULL,
@@ -797,7 +813,7 @@ udp_pcblist(SYSCTL_HANDLER_ARGS)
 	return (error);
 }
 
-SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist,
+SYSCTL_VNET_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist,
     CTLTYPE_OPAQUE | CTLFLAG_RD, NULL, 0,
     udp_pcblist, "S,xinpcb", "List of active UDP sockets");
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet6/in6.c head/sys/netinet6/in6.c
--- clean-head/sys/netinet6/in6.c	2013-06-26 09:35:29.000000000 +0200
+++ head/sys/netinet6/in6.c	2013-06-24 14:21:41.000000000 +0200
@@ -2694,6 +2694,10 @@ in6_lltable_dump(struct lltable *llt, st
 			if (lle->la_flags & LLE_PUB)
 				ndpc.rtm.rtm_flags |= RTF_ANNOUNCE;
 
+			/* proxy */
+			if (lle->la_flags & LLE_PROXY)
+				ndpc.rtm.rtm_flags |= RTF_PROTO1;
+
 			sdl = &ndpc.sdl;
 			sdl->sdl_family = AF_LINK;
 			sdl->sdl_len = sizeof(*sdl);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet6/in6_ifattach.c head/sys/netinet6/in6_ifattach.c
--- clean-head/sys/netinet6/in6_ifattach.c	2013-06-26 09:35:29.000000000 +0200
+++ head/sys/netinet6/in6_ifattach.c	2013-06-24 14:21:41.000000000 +0200
@@ -275,6 +275,9 @@ found:
 #ifdef IFT_IEEE80211
 	case IFT_IEEE80211:
 #endif
+#ifdef VPS
+	case IFT_PROPVIRTUAL:
+#endif
 		/* IEEE802/EUI64 cases - what others? */
 		/* IEEE1394 uses 16byte length address starting with EUI64 */
 		if (addrlen > 8)
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet6/in6_proto.c head/sys/netinet6/in6_proto.c
--- clean-head/sys/netinet6/in6_proto.c	2013-06-26 09:35:29.000000000 +0200
+++ head/sys/netinet6/in6_proto.c	2013-06-24 14:21:41.000000000 +0200
@@ -83,6 +83,8 @@ __FBSDID("$FreeBSD: head/sys/netinet6/in
 #include <sys/systm.h>
 #include <sys/sysctl.h>
 
+#include <vps/vps.h>
+
 #include <net/if.h>
 #include <net/radix.h>
 #include <net/route.h>
@@ -133,7 +135,7 @@ __FBSDID("$FreeBSD: head/sys/netinet6/in
 /*
  * TCP/IP protocol family: IP6, ICMP6, UDP, TCP.
  */
-FEATURE(inet6, "Internet Protocol version 6");
+_FEATURE(inet6, "Internet Protocol version 6", VPS_PUBLIC);
 
 extern	struct domain inet6domain;
 static	struct pr_usrreqs nousrreqs;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet6/in6_rmx.c head/sys/netinet6/in6_rmx.c
--- clean-head/sys/netinet6/in6_rmx.c	2013-06-26 09:35:29.000000000 +0200
+++ head/sys/netinet6/in6_rmx.c	2013-06-24 14:21:41.000000000 +0200
@@ -286,11 +286,75 @@ in6_inithead(void **head, int off)
 }
 
 #ifdef VIMAGE
+#if 0
+__attribute__ ((unused))
+static int
+in6_rtqkill_hard(struct radix_node *rn, void *rock)
+{
+	struct rtqk_arg *ap = rock;
+	struct rtentry *rt = (struct rtentry *)rn;
+	int err;
+
+	RADIX_NODE_HEAD_WLOCK_ASSERT(ap->rnh);
+
+	if (1) {
+		ap->found++;
+
+		if (1) {
+			if (0 && rt->rt_refcnt > 0)
+				panic("rtqkill route really not free");
+
+			err = rtrequest(RTM_DELETE,
+					(struct sockaddr *)rt_key(rt),
+					rt->rt_gateway, rt_mask(rt),
+					rt->rt_flags|RTF_RNH_LOCKED, 0);
+			if (err) {
+				log(LOG_WARNING, "in6_rtqkill: error %d", err);
+			} else {
+				ap->killed++;
+			}
+		}
+	}
+
+	return 0;
+}
+#endif /* 0 */
+
 int
 in6_detachhead(void **head, int off)
 {
+	/*
+	struct radix_node_head *rnh;
+	struct rtqk_arg arg;
+	*/
 
 	callout_drain(&V_rtq_mtutimer);
+
+#if 0
+	/* XXX 9.1.0 -> head: in6_rtqkill() does not exist anymore */
+
+	rnh = *head;
+	KASSERT(rnh == rt_tables_get_rnh(0, AF_INET6), ("rnh?"));
+
+	arg.found = arg.killed = 0;
+	arg.rnh = rnh;
+	arg.nextstop = 0;
+	arg.draining = 1;
+	arg.updating = 0;
+	RADIX_NODE_HEAD_LOCK(rnh);
+	//rnh->rnh_walktree(rnh, in6_rtqkill_hard, &arg);
+	rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
+	RADIX_NODE_HEAD_UNLOCK(rnh);
+
+	/*
+	printf("%s: found=%d killed=%d\n",
+		__func__, arg.found, arg.killed);
+	*/
+
+	/* XXX determine if tree is actually as empty as it can be. */
+	rn_detachhead(head);
+#endif
+
 	return (1);
 }
 #endif
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet6/ip6_input.c head/sys/netinet6/ip6_input.c
--- clean-head/sys/netinet6/ip6_input.c	2013-06-26 09:35:29.000000000 +0200
+++ head/sys/netinet6/ip6_input.c	2013-06-24 14:21:41.000000000 +0200
@@ -304,6 +304,10 @@ ip6_destroy()
 	hashdestroy(V_in6_ifaddrhashtbl, M_IFADDR, V_in6_ifaddrhmask);
 	nd6_destroy();
 	callout_drain(&V_in6_tmpaddrtimer_ch);
+
+#ifdef FLOWTABLE
+        //flowtable_destroy(V_ip6_ft);
+#endif /* FLOWTABLE */
 }
 #endif
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet6/nd6.c head/sys/netinet6/nd6.c
--- clean-head/sys/netinet6/nd6.c	2013-06-26 09:35:29.000000000 +0200
+++ head/sys/netinet6/nd6.c	2013-06-24 14:21:41.000000000 +0200
@@ -1176,6 +1176,11 @@ nd6_rtrequest(int req, struct rtentry *r
 	gateway = (struct sockaddr_in6 *)rt->rt_gateway;
 	ifp = rt->rt_ifp;
 
+#ifdef VPS
+	if (rt->rt_flags & RTF_PROTO1)
+		return(nd6_rtrequest_koh(req, rt, info));
+#endif /* VPS */
+
 	switch (req) {
 	case RTM_ADD:
 		break;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet6/nd6.h head/sys/netinet6/nd6.h
--- clean-head/sys/netinet6/nd6.h	2013-06-26 09:35:29.000000000 +0200
+++ head/sys/netinet6/nd6.h	2013-06-24 14:21:41.000000000 +0200
@@ -395,7 +395,7 @@ int nd6_is_addr_neighbor(struct sockaddr
 void nd6_option_init(void *, int, union nd_opts *);
 struct nd_opt_hdr *nd6_option(union nd_opts *);
 int nd6_options(union nd_opts *);
-struct	llentry *nd6_lookup(struct in6_addr *, int, struct ifnet *);
+struct        llentry *nd6_lookup(struct in6_addr *, int, struct ifnet *);
 void nd6_setmtu(struct ifnet *);
 void nd6_llinfo_settimer(struct llentry *, long);
 void nd6_llinfo_settimer_locked(struct llentry *, long);
@@ -448,6 +448,8 @@ void rt6_flush(struct in6_addr *, struct
 int nd6_setdefaultiface(int);
 int in6_tmpifadd(const struct in6_ifaddr *, int, int);
 
+void nd6_rtrequest_koh(int, struct rtentry *, struct rt_addrinfo *);
+
 #endif /* _KERNEL */
 
 #endif /* _NETINET6_ND6_H_ */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet6/nd6_nbr.c head/sys/netinet6/nd6_nbr.c
--- clean-head/sys/netinet6/nd6_nbr.c	2013-06-26 09:35:29.000000000 +0200
+++ head/sys/netinet6/nd6_nbr.c	2013-06-24 14:21:41.000000000 +0200
@@ -52,6 +52,9 @@ __FBSDID("$FreeBSD: head/sys/netinet6/nd
 #include <sys/queue.h>
 #include <sys/callout.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <net/if.h>
 #include <net/if_types.h>
 #include <net/if_dl.h>
@@ -109,6 +112,7 @@ nd6_ns_input(struct mbuf *m, int off, in
 	struct in6_addr daddr6 = ip6->ip6_dst;
 	struct in6_addr taddr6;
 	struct in6_addr myaddr6;
+	struct rtentry *rt = NULL;
 	char *lladdr = NULL;
 	struct ifaddr *ifa = NULL;
 	int lladdrlen = 0;
@@ -232,7 +236,6 @@ nd6_ns_input(struct mbuf *m, int off, in
 
 	/* (2) check. */
 	if (ifa == NULL) {
-		struct rtentry *rt;
 		struct sockaddr_in6 tsin6;
 		int need_proxy;
 #ifdef RADIX_MPATH
@@ -266,7 +269,6 @@ nd6_ns_input(struct mbuf *m, int off, in
 			 */
 			if (need_proxy)
 				proxydl = *SDL(rt->rt_gateway);
-			RTFREE_LOCKED(rt);
 		}
 		if (need_proxy) {
 			/*
@@ -277,6 +279,19 @@ nd6_ns_input(struct mbuf *m, int off, in
 			if (ifa)
 				proxy = 1;
 		}
+
+#ifdef VPS
+		if (rt && (rt->rt_flags & RTF_PROTO1)) {
+			/* ''Proxy'' ns where we answer with our own lladdr. */
+			DBGCORE("%s: RTF_PROTO1 proxy\n", __func__);
+			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
+				IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
+			proxy = 0;
+			memset(&proxydl, 0, sizeof (proxydl));
+		}
+#endif
+		if (rt != NULL)
+			RTFREE_LOCKED(rt);
 	}
 	if (ifa == NULL) {
 		/*
@@ -363,6 +378,8 @@ nd6_ns_input(struct mbuf *m, int off, in
  freeit:
 	if (ifa != NULL)
 		ifa_free(ifa);
+	if (rt)
+		RTFREE_LOCKED(rt);
 	m_freem(m);
 	return;
 
@@ -376,6 +393,8 @@ nd6_ns_input(struct mbuf *m, int off, in
 	ICMP6STAT_INC(icp6s_badns);
 	if (ifa != NULL)
 		ifa_free(ifa);
+	if (rt)
+		RTFREE_LOCKED(rt);
 	m_freem(m);
 }
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netinet6/nd6_rtr.c head/sys/netinet6/nd6_rtr.c
--- clean-head/sys/netinet6/nd6_rtr.c	2013-06-26 09:35:29.000000000 +0200
+++ head/sys/netinet6/nd6_rtr.c	2013-06-24 14:21:41.000000000 +0200
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD: head/sys/netinet6/nd
 #include <sys/rwlock.h>
 #include <sys/syslog.h>
 #include <sys/queue.h>
+#include <sys/taskqueue.h>
 
 #include <net/if.h>
 #include <net/if_types.h>
@@ -112,6 +113,251 @@ VNET_DEFINE(int, ip6_temp_regen_advance)
 #define RTPREF_INVALID	(-3)	/* internal */
 
 /*
+ * XXX explain PROTO1 route
+ */
+
+struct nd6_rtrequest_koh_sendna_str {
+	struct task sna_task;
+	struct ifnet *sna_ifp;
+	struct rtentry *sna_rt;
+	struct sockaddr_in6 *sna_target;
+#ifdef VIMAGE
+	struct vnet *sna_vnet;
+#endif
+};
+
+void nd6_rtrequest_koh_sendna(void *arg, int pending);
+void
+nd6_rtrequest_koh_sendna(void *arg, int pending)
+{
+	struct nd6_rtrequest_koh_sendna_str *s = (struct nd6_rtrequest_koh_sendna_str *)arg;
+	struct sockaddr_in6 *taddr6;
+	struct in6_addr daddr6;
+	int error;
+
+	CURVNET_SET(s->sna_vnet);
+
+	/* Comes in referenced. */
+	RT_LOCK(s->sna_rt);
+
+	taddr6 = (struct sockaddr_in6 *)rt_key(s->sna_rt);
+	// ff02::1 XXX use the defined values
+	memset(&daddr6, 0, sizeof(daddr6));
+	daddr6.s6_addr8[0] = 0xff;
+	daddr6.s6_addr8[1] = 0x02;
+	daddr6.s6_addr8[15] = 0x01;
+	if ((error = in6_setscope(&daddr6, s->sna_ifp, NULL)) != 0) {
+	        /* XXX: should not happen */
+		printf("%s: in6_setscope failed\n", __func__);
+	        /* XXX cleanup and return */
+	}
+
+	nd6_na_output(s->sna_ifp, &daddr6,
+		&taddr6->sin6_addr,
+		ND_NA_FLAG_OVERRIDE | (V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
+		/* tlladdr */ 1, NULL);
+
+	RTFREE_LOCKED(s->sna_rt);
+	if_rele(s->sna_ifp);
+
+	CURVNET_RESTORE();
+
+	free(s, M_TEMP);
+}
+
+void
+nd6_rtrequest_koh(int req, struct rtentry *rt, struct rt_addrinfo *info)
+{
+	struct sockaddr_in6 *dst6, net6;
+	struct in6_addr llsol;
+	struct in6_multi_mship *imm;
+	struct rtentry *rt2;
+	struct ifnet *srcifp;
+	struct in6_ifaddr *ia;
+	struct nd6_rtrequest_koh_sendna_str *sna;
+	char ip6buf[INET6_ADDRSTRLEN];
+	int error;
+
+	switch (req) {
+	case RTM_ADD:
+		if (rt->rt_flags & RTF_PROTO1 &&
+		    info->rti_addrs & RTA_DST &&
+		    info->rti_addrs & RTA_GATEWAY &&
+		    info->rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) {
+			printf("%s: RTM_ADD; RTF_PROTO1\n", __func__);
+
+			/* info->rti_info[RTAX_DST] ---> sockaddr, the proxied ipv6 address */
+			/* info->rti_info[RTAX_GATEWAY]  ---> sockaddr, the own ll address */
+			/* info->rti_ifp ---> the own _destination_ interface */
+
+			srcifp = NULL;
+			ia = NULL;
+			dst6 = (struct sockaddr_in6 *)info->rti_info[RTAX_DST];
+
+			/* 
+			 * We have to get the interface where the destination address
+			 * would belong to normally.
+			 */
+			/*
+			 * XXX how to get the right route ?!
+			 *     for now use this ugly hack where we assume a prefixlen
+			 *     of 64 for this network on the physical interface.
+			 */
+			/*
+			 * Another (but still ugly and expensive) possibility would be:
+			 *
+			 * Walk through the list of all interfaces and their addresses
+			 * and use the one that has a prefixlen < 128 for and matches
+			 * our destination address.
+			 */
+			memcpy(&net6, dst6, sizeof(net6));
+			net6.sin6_addr.s6_addr32[2] = 0;
+			net6.sin6_addr.s6_addr32[3] = 0;
+			rt2 = rtalloc1((struct sockaddr *)&net6, 0, RTF_RNH_LOCKED);
+			if (rt2) {
+				if_ref(rt2->rt_ifp);
+				srcifp = rt2->rt_ifp;
+				RTFREE_LOCKED(rt2);
+			} else {
+				printf("%s: failed to determine interface for %s\n",
+					__func__, ip6_sprintf(ip6buf, &net6.sin6_addr));
+				goto fail;
+			}
+
+			bzero(&llsol, sizeof(llsol));
+			llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
+			llsol.s6_addr32[1] = 0;
+			llsol.s6_addr32[2] = htonl(1);
+			llsol.s6_addr32[3] = dst6->sin6_addr.s6_addr32[3];
+			llsol.s6_addr8[12] = 0xff;
+			if ((error = in6_setscope(&llsol, srcifp, NULL)) != 0) {
+			        /* XXX: should not happen */
+			        printf("%s: in6_setscope failed\n", __func__);
+			        /* XXX cleanup */
+			        goto fail;
+			}
+			/* XXX causing LOR: rtentry -> in6_multi_mtx */
+			imm = in6_joingroup(srcifp, &llsol, &error, 0 /*delay*/);
+			if (imm == NULL) {
+			        printf("%s: in6_joingroup failed\n", __func__);
+			        /* XXX cleanup */
+			        goto fail;
+			}
+
+			/* XXX not sure if this is alright */
+			ia = in6_ifawithifp(srcifp, &dst6->sin6_addr);
+			if (ia == NULL) {
+				printf("%s: in6_ifawithifp failed\n", __func__);
+				/* XXX cleanup */
+				goto fail;
+			}
+			LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+
+			/* Snd out unsolicited NA immediately */
+			sna = malloc(sizeof(*sna), M_TEMP, M_NOWAIT|M_ZERO);
+			if (sna == NULL) {
+				/* 
+				 * We don't really fail but just omit
+				 * the NA packet, which is only for speeding
+				 * things up, but not necessary.
+				 */
+				goto fail;
+			}
+			sna->sna_ifp = srcifp;
+			if_ref(sna->sna_ifp);
+			sna->sna_rt = rt;
+			RT_ADDREF(sna->sna_rt);
+#ifdef VIMAGE
+			sna->sna_vnet = curvnet;
+#endif
+			TASK_INIT(&sna->sna_task, 0, nd6_rtrequest_koh_sendna, sna);
+			taskqueue_enqueue(taskqueue_thread, &sna->sna_task);
+			
+			fail:
+			if (ia)
+				ifa_free(&ia->ia_ifa);
+			if (srcifp)
+				if_rele(srcifp);
+		}
+		break;
+	case RTM_DELETE:
+		if (rt->rt_flags & RTF_PROTO1 &&
+		    info->rti_addrs & RTA_DST &&
+		    info->rti_addrs & RTA_GATEWAY &&
+		    info->rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) {
+			printf("%s: RTM_DELETE; RTF_PROTO1\n", __func__);
+
+			srcifp = NULL;
+			ia = NULL;
+			dst6 = (struct sockaddr_in6 *)info->rti_info[RTAX_DST];
+
+			/* 
+			 * We have to get the interface where the destination address
+			 * would belong to normally.
+			 *
+			 * XXX - see comments in RTM_ADD section above.
+			 */
+			memcpy(&net6, dst6, sizeof(net6));
+			net6.sin6_addr.s6_addr32[2] = 0;
+			net6.sin6_addr.s6_addr32[3] = 0;
+			rt2 = rtalloc1((struct sockaddr *)&net6, 0, RTF_PROTO1|RTF_RNH_LOCKED);
+			if (rt2) {
+				if_ref(rt2->rt_ifp);
+				srcifp = rt2->rt_ifp;
+				RTFREE_LOCKED(rt2);
+			} else {
+				printf("%s: failed to determine interface for %s\n",
+					__func__, ip6_sprintf(ip6buf, &net6.sin6_addr));
+				goto fail2;
+			}
+
+			bzero(&llsol, sizeof(llsol));
+			llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
+			llsol.s6_addr32[1] = 0;
+			llsol.s6_addr32[2] = htonl(1);
+			llsol.s6_addr32[3] = dst6->sin6_addr.s6_addr32[3];
+			llsol.s6_addr8[12] = 0xff;
+			if ((error = in6_setscope(&llsol, srcifp, NULL)) != 0) {
+			        /* XXX: should not happen */
+			        printf("%s: in6_setscope failed\n", __func__);
+			        /* XXX cleanup */
+			        goto fail2;
+			}
+
+			/* XXX not sure if this is alright */
+			ia = in6_ifawithifp(srcifp, &dst6->sin6_addr);
+			if (ia == NULL) {
+				printf("%s: in6_ifawithifp failed\n", __func__);
+				/* XXX cleanup */
+				goto fail2;
+			}
+			LIST_FOREACH(imm, &ia->ia6_memberships, i6mm_chain)
+				if (IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr, &llsol))
+					break;
+
+			if (imm == NULL) {
+				printf("%s: couldn't find previously created multicast address\n",
+					__func__);
+				/* XXX cleanup */
+				goto fail2;
+			}
+
+			LIST_REMOVE(imm, i6mm_chain);
+			in6_leavegroup(imm);
+
+			fail2:
+			if (ia)
+				ifa_free(&ia->ia_ifa);
+			if (srcifp)
+				if_rele(srcifp);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+/*
  * Receive Router Solicitation Message - just for routers.
  * Router solicitation/advertisement is mostly managed by userland program
  * (rtadvd) so here we have no function like nd6_ra_output().
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/netpfil/ipfw/ip_fw_sockopt.c head/sys/netpfil/ipfw/ip_fw_sockopt.c
--- clean-head/sys/netpfil/ipfw/ip_fw_sockopt.c	2013-06-26 09:38:05.000000000 +0200
+++ head/sys/netpfil/ipfw/ip_fw_sockopt.c	2013-06-24 14:21:51.000000000 +0200
@@ -882,7 +882,7 @@ ipfw_getrules(struct ip_fw_chain *chain,
 	int l, i;
 	time_t	boot_seconds;
 
-        boot_seconds = boottime.tv_sec;
+        boot_seconds = V_boottime.tv_sec;
 	for (i = 0; i < chain->n_rules; i++) {
 		rule = chain->map[i];
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/nfs/nfs_diskless.c head/sys/nfs/nfs_diskless.c
--- clean-head/sys/nfs/nfs_diskless.c	2013-06-26 09:35:10.000000000 +0200
+++ head/sys/nfs/nfs_diskless.c	2013-06-24 14:20:29.000000000 +0200
@@ -45,6 +45,8 @@ __FBSDID("$FreeBSD: head/sys/nfs/nfs_dis
 #include <sys/mount.h>
 #include <sys/socket.h>
 
+#include <vps/vps.h>
+
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <net/if_types.h>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/nfs/nfs_lock.c head/sys/nfs/nfs_lock.c
--- clean-head/sys/nfs/nfs_lock.c	2013-06-26 09:35:10.000000000 +0200
+++ head/sys/nfs/nfs_lock.c	2013-06-24 14:20:29.000000000 +0200
@@ -51,6 +51,8 @@ __FBSDID("$FreeBSD: head/sys/nfs/nfs_loc
 #include <sys/unistd.h>
 #include <sys/vnode.h>
 
+#include <vps/vps.h>
+
 #include <net/if.h>
 
 #include <nfs/nfsproto.h>
@@ -284,7 +286,7 @@ nfs_dolock(struct vop_advlock_args *ap)
 		p->p_nlminfo = malloc(sizeof(struct nlminfo),
 		    M_NLMINFO, M_WAITOK | M_ZERO);
 		p->p_nlminfo->pid_start = p->p_stats->p_start;
-		timevaladd(&p->p_nlminfo->pid_start, &boottime);
+		timevaladd(&p->p_nlminfo->pid_start, &G_boottime);
 	}
 	msg.lm_msg_ident.pid_start = p->p_nlminfo->pid_start;
 	msg.lm_msg_ident.msg_seq = ++(p->p_nlminfo->msg_seq);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/nfsclient/nfs_vfsops.c head/sys/nfsclient/nfs_vfsops.c
--- clean-head/sys/nfsclient/nfs_vfsops.c	2013-06-26 09:39:21.000000000 +0200
+++ head/sys/nfsclient/nfs_vfsops.c	2013-06-24 14:20:29.000000000 +0200
@@ -64,6 +64,8 @@ __FBSDID("$FreeBSD: head/sys/nfsclient/n
 #include <vm/vm_extern.h>
 #include <vm/uma.h>
 
+#include <vps/vps.h>
+
 #include <net/if.h>
 #include <net/route.h>
 #include <net/vnet.h>
@@ -540,10 +542,10 @@ nfs_mountroot(struct mount *mp)
 	 * set hostname here and then let the "/etc/rc.xxx" files
 	 * mount the right /var based upon its preset value.
 	 */
-	mtx_lock(&prison0.pr_mtx);
-	strlcpy(prison0.pr_hostname, nd->my_hostnam,
-	    sizeof (prison0.pr_hostname));
-	mtx_unlock(&prison0.pr_mtx);
+	mtx_lock(&V_prison0->pr_mtx);
+	strlcpy(V_prison0->pr_hostname, nd->my_hostnam,
+	    sizeof (V_prison0->pr_hostname));
+	mtx_unlock(&V_prison0->pr_mtx);
 	inittodr(ntohl(nd->root_time));
 	return (0);
 }
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/nfsclient/nfs_vnops.c head/sys/nfsclient/nfs_vnops.c
--- clean-head/sys/nfsclient/nfs_vnops.c	2013-06-26 09:39:21.000000000 +0200
+++ head/sys/nfsclient/nfs_vnops.c	2013-06-24 14:20:29.000000000 +0200
@@ -63,6 +63,8 @@ __FBSDID("$FreeBSD: head/sys/nfsclient/n
 #include <sys/sysctl.h>
 #include <sys/signalvar.h>
 
+#include <vps/vps.h>
+
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 #include <vm/vm_object.h>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/nfsserver/nfs_serv.c head/sys/nfsserver/nfs_serv.c
--- clean-head/sys/nfsserver/nfs_serv.c	2013-06-26 09:36:12.000000000 +0200
+++ head/sys/nfsserver/nfs_serv.c	2013-06-24 14:20:57.000000000 +0200
@@ -89,6 +89,8 @@ __FBSDID("$FreeBSD: head/sys/nfsserver/n
 #include <sys/buf.h>
 #include <sys/rwlock.h>
 
+#include <vps/vps.h>
+
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 #include <vm/vm_object.h>
@@ -1153,7 +1155,7 @@ ereply:
 		 * for debugging purposes.
 		 */
 		if (nfsver.tv_sec == 0)
-			nfsver = boottime;
+			nfsver = G_boottime;
 		*tl++ = txdr_unsigned(nfsver.tv_sec);
 		*tl = txdr_unsigned(nfsver.tv_usec);
 	} else if (!error) {
@@ -3419,7 +3421,7 @@ ereply:
 	if (!error) {
 		tl = nfsm_build(u_int32_t *, NFSX_V3WRITEVERF);
 		if (nfsver.tv_sec == 0)
-			nfsver = boottime;
+			nfsver = G_boottime;
 		*tl++ = txdr_unsigned(nfsver.tv_sec);
 		*tl = txdr_unsigned(nfsver.tv_usec);
 	} else {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/nlm/nlm_advlock.c head/sys/nlm/nlm_advlock.c
--- clean-head/sys/nlm/nlm_advlock.c	2013-06-26 09:35:10.000000000 +0200
+++ head/sys/nlm/nlm_advlock.c	2013-06-24 14:20:29.000000000 +0200
@@ -1220,7 +1220,7 @@ nlm_init_lock(struct flock *fl, int flag
 	oh_len = strlen(oh_space);
 
 	memset(lock, 0, sizeof(*lock));
-	lock->caller_name = prison0.pr_hostname;
+	lock->caller_name = V_prison0->pr_hostname;
 	lock->fh.n_len = fhlen;
 	lock->fh.n_bytes = fh;
 	lock->oh.n_len = oh_len;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/ofed/include/linux/sysfs.h head/sys/ofed/include/linux/sysfs.h
--- clean-head/sys/ofed/include/linux/sysfs.h	2013-06-26 09:38:42.000000000 +0200
+++ head/sys/ofed/include/linux/sysfs.h	2013-06-24 14:20:55.000000000 +0200
@@ -122,7 +122,7 @@ sysfs_create_file(struct kobject *kobj, 
 
 	sysctl_add_oid(NULL, SYSCTL_CHILDREN(kobj->oidp), OID_AUTO,
 	    attr->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, kobj,
-	    (uintptr_t)attr, sysctl_handle_attr, "A", "");
+	    (uintptr_t)attr, sysctl_handle_attr, "A", "", VPS_0);
 
 	return (0);
 }
@@ -154,7 +154,7 @@ sysfs_create_group(struct kobject *kobj,
 	for (attr = grp->attrs; *attr != NULL; attr++) {
 		sysctl_add_oid(NULL, SYSCTL_CHILDREN(oidp), OID_AUTO,
 		    (*attr)->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE,
-		    kobj, (uintptr_t)*attr, sysctl_handle_attr, "A", "");
+		    kobj, (uintptr_t)*attr, sysctl_handle_attr, "A", "", VPS_0);
 	}
 
 	return (0);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c head/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c
--- clean-head/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c	2013-06-26 09:39:21.000000000 +0200
+++ head/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c	2013-06-24 14:20:28.000000000 +0200
@@ -76,6 +76,8 @@ __FBSDID("$FreeBSD: head/sys/rpc/rpcsec_
 #include <sys/sx.h>
 #include <sys/ucred.h>
 
+#include <vps/vps.h>
+
 #include <rpc/rpc.h>
 #include <rpc/rpcsec_gss.h>
 
@@ -452,7 +454,7 @@ rpc_gss_svc_getcred(struct svc_req *req,
 	cr->cr_uid = cr->cr_ruid = cr->cr_svuid = uc->uid;
 	cr->cr_rgid = cr->cr_svgid = uc->gid;
 	crsetgroups(cr, uc->gidlen, uc->gidlist);
-	cr->cr_prison = &prison0;
+	cr->cr_prison = V_prison0;
 	prison_hold(cr->cr_prison);
 	*crp = crhold(cr);
 
@@ -512,7 +514,7 @@ svc_rpc_gss_find_client(struct svc_rpc_g
 	rpc_gss_log_debug("in svc_rpc_gss_find_client(%d)", id->ci_id);
 
 	getcredhostid(curthread->td_ucred, &hostid);
-	if (id->ci_hostid != hostid || id->ci_boottime != boottime.tv_sec)
+	if (id->ci_hostid != hostid || id->ci_boottime != G_boottime.tv_sec)
 		return (NULL);
 
 	list = &svc_rpc_gss_client_hash[id->ci_id % CLIENT_HASH_SIZE];
@@ -550,7 +552,7 @@ svc_rpc_gss_create_client(void)
 	sx_init(&client->cl_lock, "GSS-client");
 	getcredhostid(curthread->td_ucred, &hostid);
 	client->cl_id.ci_hostid = hostid;
-	client->cl_id.ci_boottime = boottime.tv_sec;
+	client->cl_id.ci_boottime = G_boottime.tv_sec;
 	client->cl_id.ci_id = svc_rpc_gss_next_clientid++;
 	list = &svc_rpc_gss_client_hash[client->cl_id.ci_id % CLIENT_HASH_SIZE];
 	sx_xlock(&svc_rpc_gss_lock);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/rpc/svc_auth.c head/sys/rpc/svc_auth.c
--- clean-head/sys/rpc/svc_auth.c	2013-06-26 09:39:21.000000000 +0200
+++ head/sys/rpc/svc_auth.c	2013-06-24 14:20:28.000000000 +0200
@@ -49,8 +49,11 @@ __FBSDID("$FreeBSD: head/sys/rpc/svc_aut
 #include <sys/mutex.h>
 #include <sys/systm.h>
 #include <sys/jail.h>
+#include <sys/proc.h>
 #include <sys/ucred.h>
 
+#include <vps/vps.h>
+
 #include <rpc/rpc.h>
 
 static enum auth_stat (*_svcauth_rpcsec_gss)(struct svc_req *,
@@ -180,7 +183,7 @@ svc_getcred(struct svc_req *rqst, struct
 		cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xcr->cr_uid;
 		crsetgroups(cr, xcr->cr_ngroups, xcr->cr_groups);
 		cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
-		cr->cr_prison = &prison0;
+		cr->cr_prison = V_prison0;
 		prison_hold(cr->cr_prison);
 		*crp = cr;
 		return (TRUE);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/conf.h head/sys/sys/conf.h
--- clean-head/sys/sys/conf.h	2013-06-26 09:38:52.000000000 +0200
+++ head/sys/sys/conf.h	2013-06-24 14:21:59.000000000 +0200
@@ -276,6 +276,10 @@ int	make_dev_p(int _flags, struct cdev *
 		const char *_fmt, ...) __printflike(8, 9);
 struct cdev *make_dev_alias(struct cdev *_pdev, const char *_fmt, ...)
 		__printflike(2, 3);
+#ifdef VPS
+struct cdev *make_dev_alias_cred(struct cdev *_pdev, struct ucred *_cr,
+		const char *_fmt, ...) __printflike(3, 4);
+#endif
 int	make_dev_alias_p(int _flags, struct cdev **_cdev, struct cdev *_pdev,
 		const char *_fmt, ...) __printflike(4, 5);
 int	make_dev_physpath_alias(int _flags, struct cdev **_cdev,
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/eventhandler.h head/sys/sys/eventhandler.h
--- clean-head/sys/sys/eventhandler.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/eventhandler.h	2013-06-24 14:22:00.000000000 +0200
@@ -239,6 +239,14 @@ typedef void (*app_coredump_error_fn)(vo
 
 EVENTHANDLER_DECLARE(app_coredump_start, app_coredump_start_fn);
 EVENTHANDLER_DECLARE(app_coredump_progress, app_coredump_progress_fn);
+
+#ifdef VPS
+struct vps;
+typedef void (*vps_alloc_fn)(void *, struct vps *);
+typedef void (*vps_free_fn)(void *, struct vps *);
+EVENTHANDLER_DECLARE(vps_alloc, vps_alloc_fn);
+EVENTHANDLER_DECLARE(vps_free, vps_free_fn);
+#endif /* VPS */
 EVENTHANDLER_DECLARE(app_coredump_finish, app_coredump_finish_fn);
 EVENTHANDLER_DECLARE(app_coredump_error, app_coredump_error_fn);
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/jail.h head/sys/sys/jail.h
--- clean-head/sys/sys/jail.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/jail.h	2013-06-24 14:22:00.000000000 +0200
@@ -318,10 +318,17 @@ prison_unlock(struct prison *pr)
 /*
  * Attributes of the physical system, and the root of the jail tree.
  */
-extern struct	prison prison0;
+#ifdef VPS
+VPS_DECLARE(struct prison *, prison0);
+#define V_prison0       VPSV(prison0)
+#else
+extern struct prison prison0;
+#define V_prison0	(&prison0)
+#endif
 
 TAILQ_HEAD(prisonlist, prison);
-extern struct	prisonlist allprison;
+VPS_DECLARE(struct prisonlist, allprison);
+#define V_allprison VPSV(allprison)
 extern struct	sx allprison_lock;
 
 /*
@@ -330,20 +337,20 @@ extern struct	sx allprison_lock;
 SYSCTL_DECL(_security_jail_param);
 
 #define	SYSCTL_JAIL_PARAM(module, param, type, fmt, descr)		\
-    SYSCTL_PROC(_security_jail_param ## module, OID_AUTO, param,	\
-	(type) | CTLFLAG_MPSAFE, NULL, 0, sysctl_jail_param, fmt, descr)
+    _SYSCTL_PROC(_security_jail_param ## module, OID_AUTO, param,	\
+	(type) | CTLFLAG_MPSAFE, NULL, 0, sysctl_jail_param, fmt, descr, VPS_PUBLIC)
 #define	SYSCTL_JAIL_PARAM_STRING(module, param, access, len, descr)	\
-    SYSCTL_PROC(_security_jail_param ## module, OID_AUTO, param,	\
+    _SYSCTL_PROC(_security_jail_param ## module, OID_AUTO, param,	\
 	CTLTYPE_STRING | CTLFLAG_MPSAFE | (access), NULL, len,		\
-	sysctl_jail_param, "A", descr)
+	sysctl_jail_param, "A", descr, VPS_PUBLIC)
 #define	SYSCTL_JAIL_PARAM_STRUCT(module, param, access, len, fmt, descr)\
-    SYSCTL_PROC(_security_jail_param ## module, OID_AUTO, param,	\
+    _SYSCTL_PROC(_security_jail_param ## module, OID_AUTO, param,	\
 	CTLTYPE_STRUCT | CTLFLAG_MPSAFE | (access), NULL, len,		\
-	sysctl_jail_param, fmt, descr)
+	sysctl_jail_param, fmt, descr, VPS_PUBLIC)
 #define	SYSCTL_JAIL_PARAM_NODE(module, descr)				\
-    SYSCTL_NODE(_security_jail_param, OID_AUTO, module, 0, 0, descr)
-#define	SYSCTL_JAIL_PARAM_SUBNODE(parent, module, descr)		\
-    SYSCTL_NODE(_security_jail_param_##parent, OID_AUTO, module, 0, 0, descr)
+    _SYSCTL_NODE(_security_jail_param, OID_AUTO, module, 0, 0, descr, VPS_PUBLIC)
+#define       SYSCTL_JAIL_PARAM_SUBNODE(parent, module, descr)                \
+    _SYSCTL_NODE(_security_jail_param_##parent, OID_AUTO, module, 0, 0, descr, VPS_PUBLIC)
 #define	SYSCTL_JAIL_PARAM_SYS_NODE(module, access, descr)		\
     SYSCTL_JAIL_PARAM_NODE(module, descr);				\
     SYSCTL_JAIL_PARAM(_##module, , CTLTYPE_INT | (access), "E,jailsys",	\
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/kernel.h head/sys/sys/kernel.h
--- clean-head/sys/sys/kernel.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/kernel.h	2013-06-24 14:22:00.000000000 +0200
@@ -110,6 +110,7 @@ enum sysinit_sub_id {
 	SI_SUB_MAC_POLICY	= 0x21C0000,	/* TrustedBSD MAC policies */
 	SI_SUB_MAC_LATE		= 0x21D0000,	/* TrustedBSD MAC subsystem */
 	SI_SUB_VNET		= 0x21E0000,	/* vnet 0 */
+	SI_SUB_VPS		= 0x21E8000,	/* vps setup */
 	SI_SUB_INTRINSIC	= 0x2200000,	/* proc 0*/
 	SI_SUB_VM_CONF		= 0x2300000,	/* config VM, set limits*/
 	SI_SUB_DDB_SERVICES	= 0x2380000,	/* capture, scripting, etc. */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/mount.h head/sys/sys/mount.h
--- clean-head/sys/sys/mount.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/mount.h	2013-06-24 14:22:00.000000000 +0200
@@ -185,6 +185,9 @@ struct mount {
 	int		mnt_secondary_writes;   /* (i) # of secondary writes */
 	int		mnt_secondary_accwrites;/* (i) secondary wr. starts */
 	struct thread	*mnt_susp_owner;	/* (i) thread owning suspension */
+#ifdef VPS
+	struct vps	*mnt_vps;		/* VPS instance reference */
+#endif
 #define	mnt_endzero	mnt_gjprovider
 	char		*mnt_gjprovider;	/* gjournal provider name */
 	struct lock	mnt_explock;		/* vfs_export walkers lock */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/msg.h head/sys/sys/msg.h
--- clean-head/sys/sys/msg.h	2013-06-26 09:38:52.000000000 +0200
+++ head/sys/sys/msg.h	2013-06-24 14:22:00.000000000 +0200
@@ -27,6 +27,10 @@
 #include <sys/_types.h>
 #include <sys/ipc.h>
 
+#if defined(_KERNEL) && defined(VPS)
+#include <vps/vps.h>
+#endif
+
 /*
  * The MSG_NOERROR identifier value, the msqid_ds struct and the msg struct
  * are as defined by the SV API Intel 386 Processor Supplement.
@@ -145,7 +149,12 @@ struct msginfo {
 		msgssz,		/* size of a message segment (see notes above) */
 		msgseg;		/* number of message segments */
 };
+#ifndef VPS
 extern struct msginfo	msginfo;
+#else
+VPS_DECLARE(struct msginfo, msginfo);
+#define V_msginfo VPSV(msginfo)
+#endif
 
 /*
  * Kernel wrapper for the user-level structure.
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/msgbuf.h head/sys/sys/msgbuf.h
--- clean-head/sys/sys/msgbuf.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/msgbuf.h	2013-06-24 14:22:00.000000000 +0200
@@ -78,7 +78,11 @@ int	msgbuf_peekbytes(struct msgbuf *mbp,
 void	msgbuf_reinit(struct msgbuf *mbp, void *ptr, int size);
 
 #ifndef MSGBUF_SIZE
+#if defined(VPS) && defined(DIAGNOSTIC)
+#define	MSGBUF_SIZE	(64 * 32768 * 3)
+#else
 #define	MSGBUF_SIZE	(32768 * 3)
+#endif /* VPS && DIAGNOSTIC */
 #endif
 #endif /* KERNEL */
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/proc.h head/sys/sys/proc.h
--- clean-head/sys/sys/proc.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/proc.h	2013-06-24 14:22:00.000000000 +0200
@@ -65,6 +65,30 @@
 #include <sys/ucred.h>
 #include <machine/proc.h>		/* Machine-dependent proc substruct. */
 
+#ifdef _KERNEL
+#include <vps/vps.h>
+
+#define         V_allproc_lock          VPSV(allproc_lock)
+#define         V_proctree_lock         VPSV(proctree_lock)
+#define         V_ppeers_lock           VPSV(ppeers_lock)
+#define         V_proc_lock_names       VPSV(proc_lock_names)
+#define         V_allproc               VPSV(allproc)
+#define         V_zombproc              VPSV(zombproc)
+#define         V_nprocs                VPSV(nprocs)
+#define         V_nprocs_zomb           VPSV(nprocs_zomb)
+#define         V_maxproc               VPSV(vmaxproc)
+#define         V_maxprocperuid         VPSV(vmaxprocperuid)
+#define         V_lastpid               VPSV(lastpid)
+#define         V_pidhashtbl            VPSV(pidhashtbl)
+#define         V_pidhash               VPSV(pidhash)
+#define         V_pgrphashtbl           VPSV(pgrphashtbl)
+#define         V_pgrphash              VPSV(pgrphash)
+#define         V_initproc              VPSV(initproc)
+#define         V_initpgrp              VPSV(initpgrp)
+
+#define		G_maxproc		maxproc
+#endif /* _KERNEL */
+
 /*
  * One structure allocated per session.
  *
@@ -315,6 +339,10 @@ struct thread {
 	int		td_errno;	/* Error returned by last syscall. */
 	struct vnet	*td_vnet;	/* (k) Effective vnet. */
 	const char	*td_vnet_lpush;	/* (k) Debugging vnet push / pop. */
+#ifdef VPS
+        struct vps      *td_vps;        /* (k) Effective vps. */
+	struct vps_acc	*td_vps_acc;	/* (t) vps accounting info. */
+#endif
 	struct trapframe *td_intr_frame;/* (k) Frame of the current irq */
 	struct proc	*td_rfppwait_p;	/* (k) The vforked child */
 	struct vm_page	**td_ma;	/* (k) uio pages held */
@@ -365,11 +393,14 @@ do {									\
 #define	TDF_NEEDRESCHED	0x00010000 /* Thread needs to yield. */
 #define	TDF_NEEDSIGCHK	0x00020000 /* Thread may need signal delivery. */
 #define	TDF_NOLOAD	0x00040000 /* Ignore during load avg calculations. */
-#define	TDF_UNUSED19	0x00080000 /* --available-- */
+//#define	TDF_UNUSED19	0x00080000 /* --available-- */
+#define TDF_VPSLIMIT  0x00080000 /* Thread is suspended by VPS resource limits. */
 #define	TDF_THRWAKEUP	0x00100000 /* Libthr thread must not suspend itself. */
-#define	TDF_UNUSED21	0x00200000 /* --available-- */
+//#define	TDF_UNUSED21	0x00200000 /* --available-- */
+#define TDF_PREEMPTED 0x0004000  /* Thread was preempted */
 #define	TDF_SWAPINREQ	0x00400000 /* Swapin request due to wakeup. */
-#define	TDF_UNUSED23	0x00800000 /* --available-- */
+//#define	TDF_UNUSED23	0x00800000 /* --available-- */
+#define TDF_VPSSUSPEND        0x00800000 /* VPS suspend pending */
 #define	TDF_SCHED0	0x01000000 /* Reserved for scheduler private use */
 #define	TDF_SCHED1	0x02000000 /* Reserved for scheduler private use */
 #define	TDF_SCHED2	0x04000000 /* Reserved for scheduler private use */
@@ -691,7 +722,7 @@ MALLOC_DECLARE(M_SUBPROC);
 #endif
 
 #define	FOREACH_PROC_IN_SYSTEM(p)					\
-	LIST_FOREACH((p), &allproc, p_list)
+	LIST_FOREACH((p), &V_allproc, p_list)
 #define	FOREACH_THREAD_IN_PROC(p, td)					\
 	TAILQ_FOREACH((td), &(p)->p_threads, td_plist)
 
@@ -793,36 +824,63 @@ extern pid_t pid_max;
 
 #define	THREAD_SLEEPING_OK()		((curthread)->td_no_sleeping--)
 
-#define	PIDHASH(pid)	(&pidhashtbl[(pid) & pidhash])
+#define PIDHASH(pid)    (&V_pidhashtbl[(pid) & V_pidhash])
+#if 0
+//delete
+#ifndef VPS
 extern LIST_HEAD(pidhashhead, proc) *pidhashtbl;
 extern u_long pidhash;
+#endif
+#endif
+LIST_HEAD(pidhashhead, proc);
+VPS_DECLARE(struct pidhashhead *, pidhashtbl);
+VPS_DECLARE(u_long, pidhash);
+
 #define	TIDHASH(tid)	(&tidhashtbl[(tid) & tidhash])
 extern LIST_HEAD(tidhashhead, thread) *tidhashtbl;
 extern u_long tidhash;
 extern struct rwlock tidhash_lock;
 
-#define	PGRPHASH(pgid)	(&pgrphashtbl[(pgid) & pgrphash])
-extern LIST_HEAD(pgrphashhead, pgrp) *pgrphashtbl;
-extern u_long pgrphash;
-
-extern struct sx allproc_lock;
-extern struct sx proctree_lock;
-extern struct mtx ppeers_lock;
+#define PGRPHASH(pgid)  (&V_pgrphashtbl[(pgid) & V_pgrphash])
+
+LIST_HEAD(pgrphashhead, pgrp);
+VPS_DECLARE(struct pgrphashhead *, pgrphashtbl);
+VPS_DECLARE(u_long, pgrphash);
+
+VPS_DECLARE(struct sx, allproc_lock);
+VPS_DECLARE(struct sx, proctree_lock);
+VPS_DECLARE(struct mtx, ppeers_lock);
+
 extern struct proc proc0;		/* Process slot for swapper. */
 extern struct thread thread0;		/* Primary thread in proc0. */
 extern struct vmspace vmspace0;		/* VM space for proc0. */
 extern int hogticks;			/* Limit on kernel cpu hogs. */
-extern int lastpid;
-extern int nprocs, maxproc;		/* Current and max number of procs. */
+
+VPS_DECLARE(int, lastpid);
+VPS_DECLARE(int, randompid);
+VPS_DECLARE(int, nprocs);		/* Current number of procs. */
+VPS_DECLARE(int, nprocs_zomb);
+VPS_DECLARE(int, vmaxproc);		/* Max number of procs. */
+VPS_DECLARE(int, vmaxprocperuid);	/* Max procs per uid. */
+VPS_DECLARE(int, pidchecked);
+VPS_DECLARE(struct timeval, lastfail);
+VPS_DECLARE(int, curfail);
+VPS_DECLARE(char *, proc_lock_names);
+
+extern int maxproc;			/* Max number of procs. */
 extern int maxprocperuid;		/* Max procs per uid. */
+
 extern u_long ps_arg_cache_limit;
 
 LIST_HEAD(proclist, proc);
 TAILQ_HEAD(procqueue, proc);
 TAILQ_HEAD(threadqueue, thread);
-extern struct proclist allproc;		/* List of all processes. */
-extern struct proclist zombproc;	/* List of zombie processes. */
-extern struct proc *initproc, *pageproc; /* Process slots for init, pager. */
+
+VPS_DECLARE(struct proclist, allproc);	/* List of all processes. */
+VPS_DECLARE(struct proclist, zombproc);	/* List of zombie processes. */
+VPS_DECLARE(struct proc *, initproc);	/* Process slot for init. */
+VPS_DECLARE(struct pgrp *, initpgrp);
+extern struct proc *pageproc;		/* Process slots for pager. */
 
 extern struct uma_zone *proc_zone;
 
@@ -877,6 +935,10 @@ int	proc_getargv(struct thread *td, stru
 int	proc_getauxv(struct thread *td, struct proc *p, struct sbuf *sb);
 int	proc_getenvv(struct thread *td, struct proc *p, struct sbuf *sb);
 void	procinit(void);
+#ifdef VPS
+void	procuninit(void);
+#endif
+void	proc_zone_reclaim(void);
 void	proc_linkup0(struct proc *p, struct thread *td);
 void	proc_linkup(struct proc *p, struct thread *td);
 void	proc_reap(struct thread *td, struct proc *p, int *status, int options);
@@ -945,6 +1007,7 @@ int	thread_unsuspend_one(struct thread *
 void	thread_unthread(struct thread *td);
 void	thread_wait(struct proc *p);
 struct thread	*thread_find(struct proc *p, lwpid_t tid);
+void	thread_zone_reclaim(void);
 
 static __inline int
 curthread_pflags_set(int flags)
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/resourcevar.h head/sys/sys/resourcevar.h
--- clean-head/sys/sys/resourcevar.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/resourcevar.h	2013-06-24 14:22:00.000000000 +0200
@@ -145,6 +145,9 @@ struct uidinfo
 	*uifind(uid_t uid);
 void	 uifree(struct uidinfo *uip);
 void	 uihashinit(void);
+#ifdef VPS
+void	 uihashdestroy(void);
+#endif
 void	 uihold(struct uidinfo *uip);
 void	 ui_racct_foreach(void (*callback)(struct racct *racct,
 	    void *arg2, void *arg3), void *arg2, void *arg3);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/sched.h head/sys/sys/sched.h
--- clean-head/sys/sys/sched.h	2013-06-26 09:38:52.000000000 +0200
+++ head/sys/sys/sched.h	2013-06-24 14:22:00.000000000 +0200
@@ -115,6 +115,9 @@ fixpt_t	sched_pctcpu_delta(struct thread
 void	sched_add(struct thread *td, int flags);
 void	sched_clock(struct thread *td);
 void	sched_rem(struct thread *td);
+#ifdef VPS
+void  sched_rem_norunq(struct thread *td);
+#endif
 void	sched_tick(int cnt);
 void	sched_relinquish(struct thread *td);
 struct thread *sched_choose(void);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/selinfo.h head/sys/sys/selinfo.h
--- clean-head/sys/sys/selinfo.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/selinfo.h	2013-06-24 14:22:00.000000000 +0200
@@ -35,6 +35,11 @@
 
 #include <sys/event.h>		/* for struct klist */
 
+#ifdef VPS
+#include <sys/condvar.h>
+#include <vm/uma.h>
+#endif
+
 struct selfd;
 TAILQ_HEAD(selfdlist, selfd);
 
@@ -56,6 +61,49 @@ void	selrecord(struct thread *selector, 
 void	selwakeup(struct selinfo *sip);
 void	selwakeuppri(struct selinfo *sip, int pri);
 void	seltdfini(struct thread *td);
-#endif
+
+#ifdef VPS
+/*
+ * One seltd per-thread allocated on demand as needed.
+ *
+ *      t - protected by st_mtx
+ *      k - Only accessed by curthread or read-only
+ */
+struct seltd {
+        STAILQ_HEAD(, selfd)    st_selq;        /* (k) List of selfds. */
+        struct selfd            *st_free1;      /* (k) free fd for read set. */
+        struct selfd            *st_free2;      /* (k) free fd for write set. */
+        struct mtx              st_mtx;         /* Protects struct seltd */
+        struct cv               st_wait;        /* (t) Wait channel. */
+        int                     st_flags;       /* (t) SELTD_ flags. */
+};
+
+#define SELTD_PENDING   0x0001                  /* We have pending events. */
+#define SELTD_RESCAN    0x0002                  /* Doing a rescan. */
+
+/*
+ * One selfd allocated per-thread per-file-descriptor.
+ *      f - protected by sf_mtx
+ */
+struct selfd {
+        STAILQ_ENTRY(selfd)     sf_link;        /* (k) fds owned by this td. */
+        TAILQ_ENTRY(selfd)      sf_threads;     /* (f) fds on this selinfo. */
+        struct selinfo          *sf_si;         /* (f) selinfo when linked. */
+        struct mtx              *sf_mtx;        /* Pointer to selinfo mtx. */
+        struct seltd            *sf_td;         /* (k) owning seltd. */
+        void                    *sf_cookie;     /* (k) fd or pollfd. */
+};
+
+extern uma_zone_t selfd_zone;
+MALLOC_DECLARE(M_SELECT);
+
+void	selfdalloc(struct thread *td, void *cookie);
+void	selfdfree(struct seltd *stp, struct selfd *sfp);
+int	seltdwait(struct thread *td, sbintime_t sbt, sbintime_t precision);
+void	seltdinit(struct thread *td);
+void	seltdclear(struct thread *td);
+#endif /* VPS */
+
+#endif /* _KERNEL */
 
 #endif /* !_SYS_SELINFO_H_ */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/sem.h head/sys/sys/sem.h
--- clean-head/sys/sys/sem.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/sem.h	2013-06-24 14:22:00.000000000 +0200
@@ -12,6 +12,10 @@
 
 #include <sys/ipc.h>
 
+#if defined(_KERNEL) && defined(VPS)
+#include <vps/vps.h>
+#endif
+
 #ifndef _PID_T_DECLARED
 typedef	__pid_t		pid_t;
 #define	_PID_T_DECLARED
@@ -117,7 +121,12 @@ struct seminfo {
 		semvmx,		/* semaphore maximum value */
 		semaem;		/* adjust on exit max value */
 };
+#ifndef VPS
 extern struct seminfo	seminfo;
+#else
+VPS_DECLARE(struct seminfo, seminfo);
+#define V_seminfo	VPSV(seminfo)
+#endif
 
 /*
  * Kernel wrapper for the user-level structure
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/shm.h head/sys/sys/shm.h
--- clean-head/sys/sys/shm.h	2013-06-26 09:38:52.000000000 +0200
+++ head/sys/sys/shm.h	2013-06-24 14:22:00.000000000 +0200
@@ -127,7 +127,9 @@ struct shmid_kernel {
 	struct ucred *cred;	/* creator's credendials */
 };
 
+#ifndef VPS
 extern struct shminfo	shminfo;
+#endif
 
 struct shm_info {
 	int used_ids;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/sysctl.h head/sys/sys/sysctl.h
--- clean-head/sys/sys/sysctl.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/sysctl.h	2013-06-24 14:22:00.000000000 +0200
@@ -173,6 +173,7 @@ struct sysctl_oid {
 	int		oid_refcnt;
 	u_int		oid_running;
 	const char	*oid_descr;
+	u_int8_t	vps0;	/* Whether oid is supposed to be private to vps0. */
 };
 
 #define SYSCTL_IN(r, p, l) (r->newfunc)(r, p, l)
@@ -274,6 +275,239 @@ SYSCTL_ALLOWED_TYPES(UINT64, uint64_t *a
 #define __DESCR(d) ""
 #endif
 
+#define VPS_PUBLIC	0
+#define VPS_0		1
+
+/* This constructs a "raw" MIB oid. */
+#define _SYSCTL_OID(parent, nbr, name, kind, a1, a2, handler, fmt, descr, vps0) \
+	static struct sysctl_oid sysctl__##parent##_##name = {		 \
+		&sysctl_##parent##_children, { NULL }, nbr, kind,	 \
+		a1, a2, #name, handler, fmt, 0, 0, __DESCR(descr), vps0 };     \
+	DATA_SET(sysctl_set, sysctl__##parent##_##name)
+
+#define _SYSCTL_ADD_OID(ctx, parent, nbr, name, kind, a1, a2, handler, fmt, descr, vps0) \
+	sysctl_add_oid(ctx, parent, nbr, name, kind, a1, a2, handler, fmt, __DESCR(descr), vps0)
+
+/* This constructs a node from which other oids can hang. */
+#define _SYSCTL_NODE(parent, nbr, name, access, handler, descr, vps0)		    \
+	struct sysctl_oid_list SYSCTL_NODE_CHILDREN(parent, name);	    \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_NODE|(access),		    \
+	    (void*)&SYSCTL_NODE_CHILDREN(parent, name), 0, handler, "N", descr, vps0)
+
+#define _SYSCTL_ADD_NODE(ctx, parent, nbr, name, access, handler, descr, vps0)	    \
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_NODE|(access),	    \
+	NULL, 0, handler, "N", __DESCR(descr), vps0)
+
+/* Oid for a string.  len can be 0 to indicate '\0' termination. */
+#define _SYSCTL_STRING(parent, nbr, name, access, arg, len, descr, vps0) \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_STRING|(access), \
+		arg, len, sysctl_handle_string, "A", descr, vps0)
+
+#define _SYSCTL_ADD_STRING(ctx, parent, nbr, name, access, arg, len, descr, vps0)  \
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_STRING|(access),	    \
+	arg, len, sysctl_handle_string, "A", __DESCR(descr), vps0)
+
+/* Oid for an int.  If ptr is NULL, val is returned. */
+#define _SYSCTL_INT(parent, nbr, name, access, ptr, val, descr, vps0) \
+	SYSCTL_ASSERT_TYPE(INT, ptr, parent, name);                   \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|CTLFLAG_MPSAFE|(access), \
+		ptr, val, sysctl_handle_int, "I", descr, vps0)
+
+#define _SYSCTL_ADD_INT(ctx, parent, nbr, name, access, ptr, val, descr, vps0)	    \
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_INT|CTLFLAG_MPSAFE|(access),	    \
+	SYSCTL_ADD_ASSERT_TYPE(INT, ptr), val, sysctl_handle_int, "I", __DESCR(descr), vps0)
+
+/* Oid for an unsigned int.  If ptr is NULL, val is returned. */
+#define _SYSCTL_UINT(parent, nbr, name, access, ptr, val, descr, vps0) \
+	SYSCTL_ASSERT_TYPE(UINT, ptr, parent, name);                   \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_UINT|CTLFLAG_MPSAFE|(access), \
+		ptr, val, sysctl_handle_int, "IU", descr, vps0)
+
+#define _SYSCTL_ADD_UINT(ctx, parent, nbr, name, access, ptr, val, descr, vps0)    \
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_UINT|CTLFLAG_MPSAFE|(access),	    \
+	SYSCTL_ADD_ASSERT_TYPE(UINT, ptr), val, sysctl_handle_int, "IU", __DESCR(descr), vps0)
+
+#define _SYSCTL_XINT(parent, nbr, name, access, ptr, val, descr, vps0) \
+	SYSCTL_ASSERT_TYPE(XINT, ptr, parent, name);                   \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_UINT|CTLFLAG_MPSAFE|(access), \
+		ptr, val, sysctl_handle_int, "IX", descr, vps0)
+
+#define _SYSCTL_ADD_XINT(ctx, parent, nbr, name, access, ptr, val, descr, vps0)    \
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_UINT|CTLFLAG_MPSAFE|(access),	    \
+	SYSCTL_ADD_ASSERT_TYPE(XINT, ptr), val, sysctl_handle_int, "IX", __DESCR(descr), vps0)
+
+/* Oid for a long.  The pointer must be non NULL. */
+#define _SYSCTL_LONG(parent, nbr, name, access, ptr, val, descr, vps0) \
+	SYSCTL_ASSERT_TYPE(LONG, ptr, parent, name);                   \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_LONG|CTLFLAG_MPSAFE|(access), \
+		ptr, val, sysctl_handle_long, "L", descr, vps0)
+
+#define _SYSCTL_ADD_LONG(ctx, parent, nbr, name, access, ptr, descr, vps0)	    \
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_LONG|CTLFLAG_MPSAFE|(access),	    \
+	SYSCTL_ADD_ASSERT_TYPE(LONG, ptr), 0, sysctl_handle_long, "L", __DESCR(descr), vps0)
+
+/* Oid for an unsigned long.  The pointer must be non NULL. */
+#define _SYSCTL_ULONG(parent, nbr, name, access, ptr, val, descr, vps0) \
+	SYSCTL_ASSERT_TYPE(ULONG, ptr, parent, name);                   \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_ULONG|CTLFLAG_MPSAFE|(access), \
+		ptr, val, sysctl_handle_long, "LU", __DESCR(descr), vps0)
+
+#define _SYSCTL_ADD_ULONG(ctx, parent, nbr, name, access, ptr, descr, vps0)	    \
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_ULONG|CTLFLAG_MPSAFE|(access),	    \
+	SYSCTL_ADD_ASSERT_TYPE(ULONG, ptr), 0, sysctl_handle_long, "LU", __DESCR(descr), vps0)
+
+#define _SYSCTL_XLONG(parent, nbr, name, access, ptr, val, descr, vps0) \
+	SYSCTL_ASSERT_TYPE(XLONG, ptr, parent, name);                   \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_ULONG|CTLFLAG_MPSAFE|(access), \
+		ptr, val, sysctl_handle_long, "LX", __DESCR(descr), vps0)
+
+#define _SYSCTL_ADD_XLONG(ctx, parent, nbr, name, access, ptr, descr, vps0)	    \
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_ULONG|CTLFLAG_MPSAFE|(access),	    \
+	SYSCTL_ADD_ASSERT_TYPE(XLONG, ptr), 0, sysctl_handle_long, "LX", __DESCR(descr), vps0)
+
+/* Oid for a quad.  The pointer must be non NULL. */
+#define _SYSCTL_QUAD(parent, nbr, name, access, ptr, val, descr, vps0) \
+	SYSCTL_ASSERT_TYPE(INT64, ptr, parent, name);                   \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_S64|CTLFLAG_MPSAFE|(access), \
+		ptr, val, sysctl_handle_64, "Q", __DESCR(descr), vps0)
+
+#define _SYSCTL_ADD_QUAD(ctx, parent, nbr, name, access, ptr, descr, vps0)	    \
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_S64|CTLFLAG_MPSAFE|(access),	    \
+	SYSCTL_ADD_ASSERT_TYPE(INT64, ptr), 0, sysctl_handle_64, "Q", __DESCR(descr), vps0)
+
+#define _SYSCTL_UQUAD(parent, nbr, name, access, ptr, val, descr, vps0) \
+	SYSCTL_ASSERT_TYPE(UINT64, ptr, parent, name);                   \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_U64|CTLFLAG_MPSAFE|(access), \
+		ptr, val, sysctl_handle_64, "QU", __DESCR(descr), vps0)
+
+#define _SYSCTL_ADD_UQUAD(ctx, parent, nbr, name, access, ptr, descr, vps0)	    \
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_U64|CTLFLAG_MPSAFE|(access),	    \
+	SYSCTL_ADD_ASSERT_TYPE(UINT64, ptr), 0, sysctl_handle_64, "QU", __DESCR(descr), vps0)
+
+/* Oid for an opaque object.  Specified by a pointer and a length. */
+#define _SYSCTL_OPAQUE(parent, nbr, name, access, ptr, len, fmt, descr, vps0) \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_OPAQUE|(access), \
+		ptr, len, sysctl_handle_opaque, fmt, descr, vps0)
+
+#define _SYSCTL_ADD_OPAQUE(ctx, parent, nbr, name, access, ptr, len, fmt, descr, vps0)\
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_OPAQUE|(access),	    \
+	ptr, len, sysctl_handle_opaque, fmt, __DESCR(descr), vps0)
+
+/* Oid for a struct.  Specified by a pointer and a type. */
+#define _SYSCTL_STRUCT(parent, nbr, name, access, ptr, type, descr, vps0) \
+	_SYSCTL_OID(parent, nbr, name, CTLTYPE_OPAQUE|(access), \
+		ptr, sizeof(struct type), sysctl_handle_opaque, \
+		"S," #type, descr, vps0)
+
+#define _SYSCTL_ADD_STRUCT(ctx, parent, nbr, name, access, ptr, type, descr, vps0) \
+	sysctl_add_oid(ctx, parent, nbr, name, CTLTYPE_OPAQUE|(access),	    \
+	ptr, sizeof(struct type), sysctl_handle_opaque, "S," #type, __DESCR(descr), vps0)
+
+/* Oid for a procedure.  Specified by a pointer and an arg. */
+#define _SYSCTL_PROC(parent, nbr, name, access, ptr, arg, handler, fmt, descr, vps0) \
+	_SYSCTL_OID(parent, nbr, name, (access), \
+		ptr, arg, handler, fmt, descr, vps0)
+
+#define _SYSCTL_ADD_PROC(ctx, parent, nbr, name, access, ptr, arg, handler, fmt, descr, vps0) \
+	sysctl_add_oid(ctx, parent, nbr, name, (access),			    \
+	ptr, arg, handler, fmt, __DESCR(descr), vps0)
+
+/*
+ * A macro to generate a read-only sysctl to indicate the presense of optional
+ * kernel features.
+ */
+#define	_FEATURE(name, desc, vps0)						\
+	_SYSCTL_INT(_kern_features, OID_AUTO, name, CTLFLAG_RD, 0, 1, desc, vps0)
+
+#define SYSCTL_OID(parent, nbr, name, kind, a1, a2, handler, fmt, descr) \
+	_SYSCTL_OID(parent, nbr, name, kind, a1, a2, handler, fmt, descr, 1)
+
+#define SYSCTL_ADD_OID(ctx, parent, nbr, name, kind, a1, a2, handler, fmt, descr) \
+	_SYSCTL_ADD_OID(ctx, parent, nbr, name, kind, a1, a2, handler, fmt, descr, 1)
+
+#define SYSCTL_NODE(parent, nbr, name, access, handler, descr) \
+	_SYSCTL_NODE(parent, nbr, name, access, handler, descr, 1)
+
+#define SYSCTL_ADD_NODE(ctx, parent, nbr, name, access, handler, descr) \
+	_SYSCTL_ADD_NODE(ctx, parent, nbr, name, access, handler, descr, 1)
+
+#define SYSCTL_STRING(parent, nbr, name, access, arg, len, descr) \
+	_SYSCTL_STRING(parent, nbr, name, access, arg, len, descr, 1)
+
+#define SYSCTL_ADD_STRING(ctx, parent, nbr, name, access, arg, len, descr) \
+	_SYSCTL_ADD_STRING(ctx, parent, nbr, name, access, arg, len, descr, 1)
+
+#define SYSCTL_INT(parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_INT(parent, nbr, name, access, ptr, val, descr, 1)
+
+#define SYSCTL_ADD_INT(ctx, parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_ADD_INT(ctx, parent, nbr, name, access, ptr, val, descr, 1)
+
+#define SYSCTL_UINT(parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_UINT(parent, nbr, name, access, ptr, val, descr, 1)
+
+#define SYSCTL_ADD_UINT(ctx, parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_ADD_UINT(ctx, parent, nbr, name, access, ptr, val, descr, 1)
+
+#define SYSCTL_XINT(parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_XINT(parent, nbr, name, access, ptr, val, descr, 1)
+
+#define SYSCTL_ADD_XINT(ctx, parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_ADD_XINT(ctx, parent, nbr, name, access, ptr, val, descr, 1)
+
+#define SYSCTL_LONG(parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_LONG(parent, nbr, name, access, ptr, val, descr, 1)
+
+#define SYSCTL_ADD_LONG(ctx, parent, nbr, name, access, ptr, descr) \
+	_SYSCTL_ADD_LONG(ctx, parent, nbr, name, access, ptr, descr, 1)
+
+#define SYSCTL_ULONG(parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_ULONG(parent, nbr, name, access, ptr, val, descr, 1)
+
+#define SYSCTL_ADD_ULONG(ctx, parent, nbr, name, access, ptr, descr) \
+	_SYSCTL_ADD_ULONG(ctx, parent, nbr, name, access, ptr, descr, 1)
+
+#define SYSCTL_XLONG(parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_XLONG(parent, nbr, name, access, ptr, val, descr, 1)
+
+#define SYSCTL_ADD_XLONG(ctx, parent, nbr, name, access, ptr, descr) \
+	_SYSCTL_ADD_XLONG(ctx, parent, nbr, name, access, ptr, descr, 1)
+
+#define SYSCTL_QUAD(parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_QUAD(parent, nbr, name, access, ptr, val, descr, 1)
+
+#define SYSCTL_ADD_QUAD(ctx, parent, nbr, name, access, ptr, descr) \
+	_SYSCTL_ADD_QUAD(ctx, parent, nbr, name, access, ptr, descr, 1)
+
+#define SYSCTL_UQUAD(parent, nbr, name, access, ptr, val, descr) \
+	_SYSCTL_UQUAD(parent, nbr, name, access, ptr, val, descr, 1)
+
+#define SYSCTL_ADD_UQUAD(ctx, parent, nbr, name, access, ptr, descr) \
+	_SYSCTL_ADD_UQUAD(ctx, parent, nbr, name, access, ptr, descr, 1)
+
+#define SYSCTL_OPAQUE(parent, nbr, name, access, ptr, len, fmt, descr) \
+	_SYSCTL_OPAQUE(parent, nbr, name, access, ptr, len, fmt, descr, 1)
+
+#define SYSCTL_ADD_OPAQUE(ctx, parent, nbr, name, access, ptr, len, fmt, descr) \
+	_SYSCTL_ADD_OPAQUE(ctx, parent, nbr, name, access, ptr, len, fmt, descr, 1)
+
+#define SYSCTL_STRUCT(parent, nbr, name, access, ptr, type, descr) \
+	_SYSCTL_STRUCT(parent, nbr, name, access, ptr, type, descr, 1)
+
+#define SYSCTL_ADD_STRUCT(ctx, parent, nbr, name, access, ptr, type, descr) \
+	_SYSCTL_ADD_STRUCT(ctx, parent, nbr, name, access, ptr, type, descr, 1)
+
+#define SYSCTL_PROC(parent, nbr, name, access, ptr, arg, handler, fmt, descr) \
+	_SYSCTL_PROC(parent, nbr, name, access, ptr, arg, handler, fmt, descr, 1)
+
+#define SYSCTL_ADD_PROC(ctx, parent, nbr, name, access, ptr, arg, handler, fmt, descr) \
+	_SYSCTL_ADD_PROC(ctx, parent, nbr, name, access, ptr, arg, handler, fmt, descr, 1)
+
+#define FEATURE(name, desc) \
+	_FEATURE(name, desc, 1)
+
+#if 0
+
 /* This constructs a "raw" MIB oid. */
 #define SYSCTL_OID(parent, nbr, name, kind, a1, a2, handler, fmt, descr) \
 	static struct sysctl_oid sysctl__##parent##_##name = {		 \
@@ -430,6 +664,8 @@ SYSCTL_ALLOWED_TYPES(UINT64, uint64_t *a
 	SYSCTL_INT(_kern_features, OID_AUTO, name, CTLFLAG_RD | CTLFLAG_CAPRD, \
 	    0, 1, desc)
 
+#endif /* 0 */
+
 #endif /* _KERNEL */
 
 /*
@@ -775,7 +1011,9 @@ struct sysctl_oid *sysctl_add_oid(struct
 		struct sysctl_oid_list *parent, int nbr, const char *name,
 		int kind, void *arg1, intptr_t arg2,
 		int (*handler) (SYSCTL_HANDLER_ARGS),
-		const char *fmt, const char *descr);
+                const char *fmt, const char *descr, u_int8_t vps0
+                );
+
 int	sysctl_remove_name(struct sysctl_oid *parent, const char *name, int del,
 		int recurse);
 void	sysctl_rename_oid(struct sysctl_oid *oidp, const char *name);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/systm.h head/sys/sys/systm.h
--- clean-head/sys/sys/systm.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/systm.h	2013-06-24 14:22:00.000000000 +0200
@@ -403,6 +403,9 @@ int alloc_unr(struct unrhdr *uh);
 int alloc_unr_specific(struct unrhdr *uh, u_int item);
 int alloc_unrl(struct unrhdr *uh);
 void free_unr(struct unrhdr *uh, u_int item);
+#ifdef VPS
+int alloc_unr_unit(struct unrhdr *uh, int item);
+#endif
 
 /*
  * Population count algorithm using SWAR approach
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/time.h head/sys/sys/time.h
--- clean-head/sys/sys/time.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/time.h	2013-06-24 14:22:00.000000000 +0200
@@ -37,6 +37,10 @@
 #include <sys/types.h>
 #include <sys/timespec.h>
 
+#ifdef _KERNEL
+#include <vps/vps.h>
+#endif
+
 struct timezone {
 	int	tz_minuteswest;	/* minutes west of Greenwich */
 	int	tz_dsttime;	/* type of dst correction */
@@ -370,8 +374,20 @@ void	resettodr(void);
 
 extern volatile time_t	time_second;
 extern volatile time_t	time_uptime;
+#if 0
 extern struct bintime boottimebin;
+#ifndef VPS
 extern struct timeval boottime;
+#endif
+#endif
+
+VPS_DECLARE(struct bintime, boottimebin);
+VPS_DECLARE(struct timeval, boottime);
+#define V_boottimebin   VPSV(boottimebin)
+#define V_boottime      VPSV(boottime)
+#define G_boottimebin   VPS_VPS(vps0, boottimebin)
+#define G_boottime      VPS_VPS(vps0, boottime)
+
 extern struct bintime tc_tick_bt;
 extern sbintime_t tc_tick_sbt;
 extern struct bintime tick_bt;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/tty.h head/sys/sys/tty.h
--- clean-head/sys/sys/tty.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/tty.h	2013-06-24 14:22:00.000000000 +0200
@@ -213,6 +213,9 @@ void	ttyconsdev_select(const char *name)
 int	pts_alloc(int fflags, struct thread *td, struct file *fp);
 int	pts_alloc_external(int fd, struct thread *td, struct file *fp,
     struct cdev *dev, const char *name);
+#ifdef VPS
+int	pts_alloc2(int fflags, struct thread *td, struct file *fp, int unit);
+#endif
 
 /* Drivers and line disciplines also need to call these. */
 #include <sys/ttydisc.h>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/ucred.h head/sys/sys/ucred.h
--- clean-head/sys/sys/ucred.h	2013-06-26 09:38:53.000000000 +0200
+++ head/sys/sys/ucred.h	2013-06-24 14:22:00.000000000 +0200
@@ -59,6 +59,9 @@ struct ucred {
 	struct loginclass	*cr_loginclass; /* login class */
 	u_int		cr_flags;	/* credential flags */
 	void 		*cr_pspare2[2];	/* general use 2 */
+#ifdef VPS
+	struct vps	*cr_vps;	/* virtual private system */
+#endif
 #define	cr_endcopy	cr_label
 	struct label	*cr_label;	/* MAC label */
 	struct auditinfo_addr	cr_audit;	/* Audit properties. */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/sys/vnet2.h head/sys/sys/vnet2.h
--- clean-head/sys/sys/vnet2.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/sys/vnet2.h	2013-06-24 14:21:59.000000000 +0200
@@ -0,0 +1,88 @@
+
+#ifndef _SYS_VNET2_H_
+#define _SYS_VNET2_H_
+
+/*
+ * These two virtual network stack allocator definitions are also required
+ * for libkvm so that it can evaluate virtualized global variables.
+ */
+#define VNET_SETNAME            "set_vnet"
+#define VNET_SYMPREFIX          "vnet_entry_"
+
+#if defined(_KERNEL) || defined(_WANT_VNET)
+
+#include <sys/queue.h>
+
+struct vnet {
+        LIST_ENTRY(vnet)         vnet_le;       /* all vnets list */
+        u_int                    vnet_magic_n;
+        u_int                    vnet_ifcnt;
+        u_int                    vnet_sockcnt;
+        u_int                    vnet_vps_flags; /* flags used by VPS */
+        void                    *vnet_data_mem;
+        uintptr_t                vnet_data_base;
+};
+#define VNET_MAGIC_N    0x3e0d8f29
+
+#ifdef VIMAGE
+
+/*
+ * Location of the kernel's 'set_vnet' linker set.
+ */
+
+extern uintptr_t        *__start_set_vnet;
+__GLOBL(__start_set_vnet);
+extern uintptr_t        *__stop_set_vnet;
+__GLOBL(__stop_set_vnet);
+
+#define VNET_START      (uintptr_t)&__start_set_vnet
+#define VNET_STOP       (uintptr_t)&__stop_set_vnet
+
+/*
+ * Virtual network stack memory allocator, which allows global variables to
+ * be automatically instantiated for each network stack instance.
+ */
+#define VNET_NAME(n)            vnet_entry_##n
+#define VNET_DECLARE(t, n)      extern t VNET_NAME(n)
+#define VNET_DEFINE(t, n)       t VNET_NAME(n) __section(VNET_SETNAME) __used
+#define _VNET_PTR(b, n)         (__typeof(VNET_NAME(n))*)               \
+                                    ((b) + (uintptr_t)&VNET_NAME(n))
+
+#define _VNET(b, n)             (*_VNET_PTR(b, n))
+
+/*
+ * Virtualized global variable accessor macros.
+ */
+#define VNET_VNET_PTR(vnet, n)          _VNET_PTR((vnet)->vnet_data_base, n)
+#define VNET_VNET(vnet, n)              (*VNET_VNET_PTR((vnet), n))
+
+#define VNET_PTR(n)             VNET_VNET_PTR(curvnet, n)
+#define VNET(n)                 VNET_VNET(curvnet, n)
+
+#else /* !VIMAGE */
+
+
+/*
+ * Versions of the VNET macros that compile to normal global variables and
+ * standard sysctl definitions.
+ */
+#define VNET_NAME(n)            n
+#define VNET_DECLARE(t, n)      extern t n
+#define VNET_DEFINE(t, n)       t n
+#define _VNET_PTR(b, n)         &VNET_NAME(n)
+
+/*
+ * Virtualized global variable accessor macros.
+ */
+#define VNET_VNET_PTR(vnet, n)          (&(n))
+#define VNET_VNET(vnet, n)              (n)
+
+#define VNET_PTR(n)             (&(n))
+#define VNET(n)                 (n)
+
+
+#endif /* VIMAGE */
+#endif /* _KERNEL || _WANT_VNET */
+
+#endif /* !_SYS_VNET2_H_ */
+
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/default_pager.c head/sys/vm/default_pager.c
--- clean-head/sys/vm/default_pager.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/default_pager.c	2013-06-24 14:21:31.000000000 +0200
@@ -47,6 +47,8 @@ __FBSDID("$FreeBSD: head/sys/vm/default_
 #include <sys/resourcevar.h>
 #include <sys/rwlock.h>
 
+#include <vps/vps_account.h>
+
 #include <vm/vm.h>
 #include <vm/vm_object.h>
 #include <vm/vm_page.h>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/phys_pager.c head/sys/vm/phys_pager.c
--- clean-head/sys/vm/phys_pager.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/phys_pager.c	2013-06-24 14:21:31.000000000 +0200
@@ -165,7 +165,8 @@ phys_pager_putpages(vm_object_t object, 
 		    int *rtvals)
 {
 
-	panic("phys_pager_putpage called");
+	panic("phys_pager_putpage called: object=%p m=%p count=%u sync=%u rtvals=%p",
+		object, m, count, sync, rtvals);
 }
 
 /*
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/swap_pager.c head/sys/vm/swap_pager.c
--- clean-head/sys/vm/swap_pager.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/swap_pager.c	2013-06-24 14:21:31.000000000 +0200
@@ -114,6 +114,8 @@ __FBSDID("$FreeBSD: head/sys/vm/swap_pag
 
 #include <geom/geom.h>
 
+#include <vps/vps_account.h>
+
 /*
  * SWB_NPAGES must be a power of 2.  It may be set to 1, 2, 4, 8, 16
  * or 32 pages per allocation.
@@ -245,6 +247,13 @@ swap_reserve_by_cred(vm_ooffset_t incr, 
 	}
 #endif
 
+#ifdef VPS
+	if (res) {
+		if (vps_account(cred->cr_vps, VPS_ACC_VIRT, VPS_ACC_ALLOC, incr) != 0)
+			res = 0;
+	}
+#endif
+
 	return (res);
 }
 
@@ -305,6 +314,10 @@ swap_release_by_cred(vm_ooffset_t decr, 
 	UIDINFO_VMSIZE_UNLOCK(uip);
 
 	racct_sub_cred(cred, RACCT_SWAP, decr);
+
+#ifdef VPS
+	vps_account(cred->cr_vps, VPS_ACC_VIRT, VPS_ACC_FREE, decr);
+#endif
 }
 
 static void swapdev_strategy(struct buf *, struct swdevt *sw);
@@ -1389,6 +1402,10 @@ swap_pager_putpages(vm_object_t object, 
 		for (j = 0; j < n; ++j) {
 			vm_page_t mreq = m[i+j];
 
+			KASSERT(mreq->object == object,
+				("%s: object=%p mreq->object=%p mreq=%p\n",
+				__func__, object, mreq->object, mreq));
+
 			swp_pager_meta_build(
 			    mreq->object,
 			    mreq->pindex,
@@ -1607,6 +1624,9 @@ swp_pager_async_iodone(struct buf *bp)
 			KASSERT(!pmap_page_is_write_mapped(m),
 			    ("swp_pager_async_iodone: page %p is not write"
 			    " protected", m));
+			KASSERT(m->object == object,
+				("%s: object=%p m->object=%p m=%p\n",
+				__func__, object, m->object, m));
 			vm_page_undirty(m);
 			vm_page_io_finish(m);
 			if (vm_page_count_severe()) {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/uma.h head/sys/vm/uma.h
--- clean-head/sys/vm/uma.h	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/uma.h	2013-06-24 14:21:31.000000000 +0200
@@ -647,6 +647,8 @@ struct uma_type_header {
 	uint64_t	_uth_reserved1[2];	/* Reserved. */
 };
 
+void uma_zone_reclaim(uma_zone_t zone);
+
 struct uma_percpu_stat {
 	uint64_t	ups_allocs;	/* Cache: number of allocations. */
 	uint64_t	ups_frees;	/* Cache: number of frees. */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/uma_core.c head/sys/vm/uma_core.c
--- clean-head/sys/vm/uma_core.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/uma_core.c	2013-06-24 14:21:31.000000000 +0200
@@ -1561,9 +1561,12 @@ keg_dtor(void *arg, int size, void *udat
 	keg = (uma_keg_t)arg;
 	KEG_LOCK(keg);
 	if (keg->uk_free != 0) {
+#ifdef DDB
+		db_trace_self();
+#endif
 		printf("Freed UMA keg was not empty (%d items). "
-		    " Lost %d pages of memory.\n",
-		    keg->uk_free, keg->uk_pages);
+		    " Lost %d pages of memory. Zone name [%s].\n",
+		    keg->uk_free, keg->uk_pages, keg->uk_name);
 	}
 	KEG_UNLOCK(keg);
 
@@ -2846,13 +2849,27 @@ zone_free_item(uma_zone_t zone, void *it
 	}
 	MPASS(keg == slab->us_keg);
 
-	/* Do we need to remove from any lists? */
+	/*
+	 * http://lists.freebsd.org/pipermail/freebsd-hackers/2010-August/032800.html
+	 */
+	/* Move to the appropriate list or re-queue further from the head. */
 	if (slab->us_freecount+1 == keg->uk_ipers) {
+		/* Partial -> free. */
 		LIST_REMOVE(slab, us_link);
 		LIST_INSERT_HEAD(&keg->uk_free_slab, slab, us_link);
 	} else if (slab->us_freecount == 0) {
+		/* Full -> partial. */
 		LIST_REMOVE(slab, us_link);
 		LIST_INSERT_HEAD(&keg->uk_part_slab, slab, us_link);
+	} else {
+		/* Partial -> partial. */
+		uma_slab_t tmp;
+
+		tmp = LIST_NEXT(slab, us_link);
+		if (tmp != NULL && slab->us_freecount > tmp->us_freecount) {
+			LIST_REMOVE(slab, us_link);
+			LIST_INSERT_AFTER(tmp, slab, us_link);
+		}
 	}
 
 	/* Slab management stuff */
@@ -3153,6 +3170,16 @@ uma_zone_exhausted(uma_zone_t zone)
 	return (full);	
 }
 
+void
+uma_zone_reclaim(uma_zone_t zone)
+{
+
+	if (zone != NULL)
+		zone_drain_wait(zone, M_WAITOK);
+	else
+		zone_foreach(zone_drain);
+}
+
 int
 uma_zone_exhausted_nolock(uma_zone_t zone)
 {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm.h head/sys/vm/vm.h
--- clean-head/sys/vm/vm.h	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm.h	2013-06-24 14:21:31.000000000 +0200
@@ -83,7 +83,11 @@ typedef u_char vm_prot_t;	/* protection 
 #define	VM_PROT_DEFAULT		VM_PROT_ALL
 
 enum obj_type { OBJT_DEFAULT, OBJT_SWAP, OBJT_VNODE, OBJT_DEVICE, OBJT_PHYS,
-		OBJT_DEAD, OBJT_SG, OBJT_MGTDEVICE };
+		OBJT_DEAD, OBJT_SG, OBJT_MGTDEVICE
+#ifdef VPS
+		, OBJT_VPS
+#endif
+              };
 typedef u_char objtype_t;
 
 union vm_map_object;
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_fault.c head/sys/vm/vm_fault.c
--- clean-head/sys/vm/vm_fault.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_fault.c	2013-06-24 14:21:31.000000000 +0200
@@ -102,6 +102,10 @@ __FBSDID("$FreeBSD: head/sys/vm/vm_fault
 #include <vm/vm_pager.h>
 #include <vm/vm_extern.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#include <vps/vps_account.h>
+
 #define PFBAK 4
 #define PFFOR 4
 #define PAGEORDER_SIZE (PFBAK+PFFOR)
@@ -422,6 +426,38 @@ RetryFault:;
 			 * restart and new reading of the p_flag.
 			 */
 			fs.m = NULL;
+#ifdef VPS
+			if (vps0 == NULL) {
+				/* 
+				 * During very very early system startup we don't
+				 * have vps0.
+				 */
+				;
+			} else {
+				struct vps *vps;
+
+				vps = curthread->td_vps;
+				if (vps->vps_acc->phys.soft != 0 && vps->vps_acc->phys.hard != 0 &&
+				    vps->vps_acc->phys.cur + PAGE_SIZE > vps->vps_acc->phys.hard) {
+					/*
+					printf("%s: vps=%p --> vps_account_waitpfault()\n",
+						__func__, vps);
+					unlock_and_deallocate(&fs);
+					vps_account_waitpfault(vps);
+					goto RetryFault;
+					*/
+					printf("%s: vps=%p --> LIMIT, td=%p\n",
+						__func__, vps, curthread);
+					unlock_and_deallocate(&fs);
+					if (vps_account_waitpfault(vps))
+						/* curproc has been killed */
+						return (KERN_FAILURE);
+					else
+						/* memory is available again */
+						goto RetryFault;
+				}
+			}
+#endif
 			if (!vm_page_count_severe() || P_KILLED(curproc)) {
 #if VM_NRESERVLEVEL > 0
 				if ((fs.object->flags & OBJ_COLORED) == 0) {
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_glue.c head/sys/vm/vm_glue.c
--- clean-head/sys/vm/vm_glue.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_glue.c	2013-06-24 14:21:31.000000000 +0200
@@ -84,6 +84,9 @@ __FBSDID("$FreeBSD: head/sys/vm/vm_glue.
 #include <sys/ktr.h>
 #include <sys/unistd.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <vm/vm.h>
 #include <vm/vm_param.h>
 #include <vm/pmap.h>
@@ -707,6 +710,9 @@ scheduler(dummy)
 	int swtime;
 	int ppri;
 	int pri;
+#ifdef VPS
+	struct vps *vps, *save_vps;
+#endif
 
 	mtx_assert(&Giant, MA_OWNED | MA_NOTRECURSED);
 	mtx_unlock(&Giant);
@@ -719,7 +725,13 @@ loop:
 
 	pp = NULL;
 	ppri = INT_MIN;
-	sx_slock(&allproc_lock);
+#ifdef VPS
+	save_vps = curthread->td_vps;
+	sx_slock(&vps_all_lock);
+	LIST_FOREACH(vps, &vps_head, vps_all) {
+		curthread->td_vps = vps;
+#endif
+	sx_slock(&V_allproc_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		PROC_LOCK(p);
 		if (p->p_state == PRS_NEW ||
@@ -755,7 +767,12 @@ loop:
 		}
 		PROC_UNLOCK(p);
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
+#ifdef VPS
+	}
+	sx_sunlock(&vps_all_lock);
+	curthread->td_vps = save_vps;
+#endif
 
 	/*
 	 * Nothing to do, back to sleep.
@@ -824,9 +841,18 @@ int action;
 	struct proc *p;
 	struct thread *td;
 	int didswap = 0;
+#ifdef VPS
+	struct vps *vps, *save_vps;
+	save_vps = curthread->td_vps;
+#endif
 
+#ifdef VPS
+	sx_slock(&vps_all_lock);
+	LIST_FOREACH(vps, &vps_head, vps_all) {
+		curthread->td_vps = vps;
+#endif
 retry:
-	sx_slock(&allproc_lock);
+	sx_slock(&V_allproc_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		struct vmspace *vm;
 		int minslptime = 100000;
@@ -950,7 +976,7 @@ retry:
 				PROC_UNLOCK(p);
 				vm_map_unlock(&vm->vm_map);
 				vmspace_free(vm);
-				sx_sunlock(&allproc_lock);
+				sx_sunlock(&V_allproc_lock);
 				goto retry;
 			}
 		}
@@ -961,7 +987,12 @@ nextproc1:
 		vmspace_free(vm);
 		continue;
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
+#ifdef VPS
+	}
+	sx_sunlock(&vps_all_lock);
+	curthread->td_vps = save_vps;
+#endif
 	/*
 	 * If we swapped something out, and another process needed memory,
 	 * then wakeup the sched process.
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_kern.c head/sys/vm/vm_kern.c
--- clean-head/sys/vm/vm_kern.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_kern.c	2013-06-24 14:21:31.000000000 +0200
@@ -75,6 +75,8 @@ __FBSDID("$FreeBSD: head/sys/vm/vm_kern.
 #include <sys/rwlock.h>
 #include <sys/sysctl.h>
 
+#include <vps/vps_account.h>
+
 #include <vm/vm.h>
 #include <vm/vm_param.h>
 #include <vm/pmap.h>
@@ -611,6 +613,7 @@ kmem_alloc_wait(map, size)
 	vm_map_insert(map, NULL, 0, addr, addr + size, VM_PROT_ALL,
 	    VM_PROT_ALL, MAP_ACC_CHARGED);
 	vm_map_unlock(map);
+
 	return (addr);
 }
 
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_map.c head/sys/vm/vm_map.c
--- clean-head/sys/vm/vm_map.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_map.c	2013-06-24 14:21:31.000000000 +0200
@@ -83,6 +83,10 @@ __FBSDID("$FreeBSD: head/sys/vm/vm_map.c
 #include <sys/sysent.h>
 #include <sys/shm.h>
 
+#include <vps/vps.h>
+#include <vps/vps_account.h>
+#include <ddb/ddb.h>
+
 #include <vm/vm.h>
 #include <vm/vm_param.h>
 #include <vm/pmap.h>
@@ -305,14 +309,14 @@ vm_init2(void)
 {
 	uma_zone_reserve_kva(kmapentzone, lmin(cnt.v_page_count,
 	    (VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) / PAGE_SIZE) / 8 +
-	     maxproc * 2 + maxfiles);
+	     V_maxproc * 2 + maxfiles);
 	vmspace_zone = uma_zcreate("VMSPACE", sizeof(struct vmspace), NULL,
 #ifdef INVARIANTS
 	    vmspace_zdtor,
 #else
 	    NULL,
 #endif
-	    vmspace_zinit, vmspace_zfini, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+	    vmspace_zinit, vmspace_zfini, UMA_ALIGN_PTR, 0 /* XXX VPS UMA_ZONE_NOFREE*/);
 }
 
 static void
@@ -1168,6 +1172,14 @@ vm_map_insert(vm_map_t map, vm_object_t 
 	    (prev_entry->next->start < end))
 		return (KERN_NO_SPACE);
 
+#ifdef OBSOLETEDVPS
+	if (map != kmem_map && map != kernel_map && map != buffer_map) {
+		if ((vps_account(curthread->td_vps, VPS_ACC_VIRT,
+		   VPS_ACC_ALLOC, end - start)) != 0)
+			return (KERN_RESOURCE_SHORTAGE);
+	}
+#endif
+
 	protoeflags = 0;
 	charge_prev_obj = FALSE;
 
@@ -2713,6 +2725,11 @@ vm_map_entry_delete(vm_map_t map, vm_map
 	size = entry->end - entry->start;
 	map->size -= size;
 
+#ifdef OBSOLETEDVPS
+	if (map != kmem_map && map != kernel_map && map != buffer_map)
+		vps_account(curthread->td_vps, VPS_ACC_VIRT, VPS_ACC_FREE, size);
+#endif
+
 	if (entry->cred != NULL) {
 		swap_release_by_cred(size, entry->cred);
 		crfree(entry->cred);
@@ -3606,6 +3623,13 @@ Retry:
 		}
 
 		grow_amount = addr - stack_entry->end;
+#ifdef OBSOLETEDVPS
+		if (map != kmem_map && map != kernel_map && map != buffer_map) {
+			if ((vps_account(curthread->td_vps, VPS_ACC_VIRT,
+			   VPS_ACC_ALLOC, grow_amount)) != 0)
+				return (KERN_RESOURCE_SHORTAGE);
+		}
+#endif
 		cred = stack_entry->cred;
 		if (cred == NULL && stack_entry->object.vm_object != NULL)
 			cred = stack_entry->object.vm_object->cred;
@@ -4012,6 +4036,13 @@ vm_map_lookup_done(vm_map_t map, vm_map_
 	vm_map_unlock_read(map);
 }
 
+void
+vmspace_zone_reclaim(void)
+{
+
+	uma_zone_reclaim(vmspace_zone);
+}
+
 #include "opt_ddb.h"
 #ifdef DDB
 #include <sys/kernel.h>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_map.h head/sys/vm/vm_map.h
--- clean-head/sys/vm/vm_map.h	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_map.h	2013-06-24 14:21:31.000000000 +0200
@@ -393,5 +393,6 @@ int vm_map_unwire(vm_map_t map, vm_offse
 int vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end,
     int flags);
 long vmspace_swap_count(struct vmspace *vmspace);
+void vmspace_zone_reclaim(void);
 #endif				/* _KERNEL */
 #endif				/* _VM_MAP_ */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_meter.c head/sys/vm/vm_meter.c
--- clean-head/sys/vm/vm_meter.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_meter.c	2013-06-24 14:21:31.000000000 +0200
@@ -53,6 +53,9 @@ __FBSDID("$FreeBSD: head/sys/vm/vm_meter
 #include <vm/vm_object.h>
 #include <sys/sysctl.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 struct vmmeter cnt;
 
 SYSCTL_UINT(_vm, VM_V_FREE_MIN, v_free_min,
@@ -72,6 +75,35 @@ SYSCTL_UINT(_vm, VM_V_PAGEOUT_FREE_MIN, 
 SYSCTL_UINT(_vm, OID_AUTO, v_free_severe,
 	CTLFLAG_RW, &cnt.v_free_severe, 0, "Severe page depletion point");
 
+#ifdef VPS
+/* XXX calculate real per-vps load avg values */
+static int
+sysctl_vm_loadavg(SYSCTL_HANDLER_ARGS)
+{
+	struct loadavg lafake;
+#ifdef SCTL_MASK32
+	u_int32_t la[4];
+
+	if (req->flags & SCTL_MASK32) {
+		if (req->td->td_vps != vps0) {
+			memset(&la, 0, sizeof(la));	
+		} else {
+			la[0] = averunnable.ldavg[0];
+			la[1] = averunnable.ldavg[1];
+			la[2] = averunnable.ldavg[2];
+			la[3] = averunnable.fscale;
+		}
+		return SYSCTL_OUT(req, la, sizeof(la));
+	} else
+#endif
+		if (req->td->td_vps != vps0) {
+			memset(&lafake, 0, sizeof(lafake));
+			return SYSCTL_OUT(req, &lafake, sizeof(lafake));
+		} else {
+			return SYSCTL_OUT(req, &averunnable, sizeof(averunnable));
+		}
+}
+#else
 static int
 sysctl_vm_loadavg(SYSCTL_HANDLER_ARGS)
 {
@@ -89,9 +121,10 @@ sysctl_vm_loadavg(SYSCTL_HANDLER_ARGS)
 #endif
 		return SYSCTL_OUT(req, &averunnable, sizeof(averunnable));
 }
-SYSCTL_PROC(_vm, VM_LOADAVG, loadavg, CTLTYPE_STRUCT | CTLFLAG_RD |
+#endif /* !VPS */
+_SYSCTL_PROC(_vm, VM_LOADAVG, loadavg, CTLTYPE_STRUCT | CTLFLAG_RD |
     CTLFLAG_MPSAFE, NULL, 0, sysctl_vm_loadavg, "S,loadavg",
-    "Machine loadaverage history");
+    "Machine loadaverage history", VPS_PUBLIC);
 
 static int
 vmtotal(SYSCTL_HANDLER_ARGS)
@@ -104,6 +137,9 @@ vmtotal(SYSCTL_HANDLER_ARGS)
 	int paging;
 	struct thread *td;
 	struct vmspace *vm;
+#ifdef VPS
+	struct vps *vps, *save_vps;
+#endif  
 
 	bzero(&total, sizeof(total));
 	/*
@@ -126,7 +162,13 @@ vmtotal(SYSCTL_HANDLER_ARGS)
 	/*
 	 * Calculate process statistics.
 	 */
-	sx_slock(&allproc_lock);
+#ifdef VPS
+	save_vps = curthread->td_vps;
+	sx_slock(&vps_all_lock);
+	LIST_FOREACH(vps, &vps_head, vps_all) {
+		curthread->td_vps = vps;
+#endif
+	sx_slock(&V_allproc_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		if (p->p_flag & P_SYSTEM)
 			continue;
@@ -189,7 +231,12 @@ vmtotal(SYSCTL_HANDLER_ARGS)
 		if (paging)
 			total.t_pw++;
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
+#ifdef VPS
+	}
+	sx_sunlock(&vps_all_lock);
+	curthread->td_vps = save_vps;
+#endif
 	/*
 	 * Calculate object memory usage statistics.
 	 */
@@ -253,11 +300,21 @@ vcnt(SYSCTL_HANDLER_ARGS)
 	int count = *(int *)arg1;
 	int offset = (char *)arg1 - (char *)&cnt;
 	int i;
+#ifdef VPS
+	u_int fakeval;
+#endif
 
 	CPU_FOREACH(i) {
 		struct pcpu *pcpu = pcpu_find(i);
 		count += *(int *)((char *)&pcpu->pc_cnt + offset);
 	}
+#ifdef VPS
+	if (req->td->td_vps != vps0) {
+		/* XXX calc real per-vps values */
+		fakeval = 0;
+		return (SYSCTL_OUT(req, &fakeval, sizeof(int)));
+	}
+#endif
 	return (SYSCTL_OUT(req, &count, sizeof(int)));
 }
 
@@ -271,63 +328,63 @@ static SYSCTL_NODE(_vm_stats, OID_AUTO, 
 	"VM meter vm stats");
 SYSCTL_NODE(_vm_stats, OID_AUTO, misc, CTLFLAG_RW, 0, "VM meter misc stats");
 
-#define	VM_STATS(parent, var, descr) \
-	SYSCTL_PROC(parent, OID_AUTO, var, \
+#define		VM_STATS(parent, var, descr, vps) \
+	_SYSCTL_PROC(parent, OID_AUTO, var, \
 	    CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE, &cnt.var, 0, vcnt, \
-	    "IU", descr)
-#define	VM_STATS_VM(var, descr)		VM_STATS(_vm_stats_vm, var, descr)
-#define	VM_STATS_SYS(var, descr)	VM_STATS(_vm_stats_sys, var, descr)
-
-VM_STATS_SYS(v_swtch, "Context switches");
-VM_STATS_SYS(v_trap, "Traps");
-VM_STATS_SYS(v_syscall, "System calls");
-VM_STATS_SYS(v_intr, "Device interrupts");
-VM_STATS_SYS(v_soft, "Software interrupts");
-VM_STATS_VM(v_vm_faults, "Address memory faults");
-VM_STATS_VM(v_io_faults, "Page faults requiring I/O");
-VM_STATS_VM(v_cow_faults, "Copy-on-write faults");
-VM_STATS_VM(v_cow_optim, "Optimized COW faults");
-VM_STATS_VM(v_zfod, "Pages zero-filled on demand");
-VM_STATS_VM(v_ozfod, "Optimized zero fill pages");
-VM_STATS_VM(v_swapin, "Swap pager pageins");
-VM_STATS_VM(v_swapout, "Swap pager pageouts");
-VM_STATS_VM(v_swappgsin, "Swap pages swapped in");
-VM_STATS_VM(v_swappgsout, "Swap pages swapped out");
-VM_STATS_VM(v_vnodein, "Vnode pager pageins");
-VM_STATS_VM(v_vnodeout, "Vnode pager pageouts");
-VM_STATS_VM(v_vnodepgsin, "Vnode pages paged in");
-VM_STATS_VM(v_vnodepgsout, "Vnode pages paged out");
-VM_STATS_VM(v_intrans, "In transit page faults");
-VM_STATS_VM(v_reactivated, "Pages reactivated from free list");
-VM_STATS_VM(v_pdwakeups, "Pagedaemon wakeups");
-VM_STATS_VM(v_pdpages, "Pages analyzed by pagedaemon");
-VM_STATS_VM(v_tcached, "Total pages cached");
-VM_STATS_VM(v_dfree, "Pages freed by pagedaemon");
-VM_STATS_VM(v_pfree, "Pages freed by exiting processes");
-VM_STATS_VM(v_tfree, "Total pages freed");
-VM_STATS_VM(v_page_size, "Page size in bytes");
-VM_STATS_VM(v_page_count, "Total number of pages in system");
-VM_STATS_VM(v_free_reserved, "Pages reserved for deadlock");
-VM_STATS_VM(v_free_target, "Pages desired free");
-VM_STATS_VM(v_free_min, "Minimum low-free-pages threshold");
-VM_STATS_VM(v_free_count, "Free pages");
-VM_STATS_VM(v_wire_count, "Wired pages");
-VM_STATS_VM(v_active_count, "Active pages");
-VM_STATS_VM(v_inactive_target, "Desired inactive pages");
-VM_STATS_VM(v_inactive_count, "Inactive pages");
-VM_STATS_VM(v_cache_count, "Pages on cache queue");
-VM_STATS_VM(v_cache_min, "Min pages on cache queue");
-VM_STATS_VM(v_cache_max, "Max pages on cached queue");
-VM_STATS_VM(v_pageout_free_min, "Min pages reserved for kernel");
-VM_STATS_VM(v_interrupt_free_min, "Reserved pages for interrupt code");
-VM_STATS_VM(v_forks, "Number of fork() calls");
-VM_STATS_VM(v_vforks, "Number of vfork() calls");
-VM_STATS_VM(v_rforks, "Number of rfork() calls");
-VM_STATS_VM(v_kthreads, "Number of fork() calls by kernel");
-VM_STATS_VM(v_forkpages, "VM pages affected by fork()");
-VM_STATS_VM(v_vforkpages, "VM pages affected by vfork()");
-VM_STATS_VM(v_rforkpages, "VM pages affected by rfork()");
-VM_STATS_VM(v_kthreadpages, "VM pages affected by fork() by kernel");
+	    "IU", descr, vps)
+#define		VM_STATS_VM(var, descr, vps)         VM_STATS(_vm_stats_vm, var, descr, vps)
+#define		VM_STATS_SYS(var, descr, vps)        VM_STATS(_vm_stats_sys, var, descr, vps)
+
+VM_STATS_SYS(v_swtch, "Context switches", VPS_0);
+VM_STATS_SYS(v_trap, "Traps", VPS_0);
+VM_STATS_SYS(v_syscall, "System calls", VPS_0);
+VM_STATS_SYS(v_intr, "Device interrupts", VPS_0);
+VM_STATS_SYS(v_soft, "Software interrupts", VPS_0);
+VM_STATS_VM(v_vm_faults, "Address memory faults", VPS_0);
+VM_STATS_VM(v_io_faults, "Page faults requiring I/O", VPS_0);
+VM_STATS_VM(v_cow_faults, "Copy-on-write faults", VPS_0);
+VM_STATS_VM(v_cow_optim, "Optimized COW faults", VPS_0);
+VM_STATS_VM(v_zfod, "Pages zero-filled on demand", VPS_0);
+VM_STATS_VM(v_ozfod, "Optimized zero fill pages", VPS_0);
+VM_STATS_VM(v_swapin, "Swap pager pageins", VPS_0);
+VM_STATS_VM(v_swapout, "Swap pager pageouts", VPS_0);
+VM_STATS_VM(v_swappgsin, "Swap pages swapped in", VPS_PUBLIC);
+VM_STATS_VM(v_swappgsout, "Swap pages swapped out", VPS_PUBLIC);
+VM_STATS_VM(v_vnodein, "Vnode pager pageins", VPS_0);
+VM_STATS_VM(v_vnodeout, "Vnode pager pageouts", VPS_0);
+VM_STATS_VM(v_vnodepgsin, "Vnode pages paged in", VPS_0);
+VM_STATS_VM(v_vnodepgsout, "Vnode pages paged out", VPS_0);
+VM_STATS_VM(v_intrans, "In transit page faults", VPS_0);
+VM_STATS_VM(v_reactivated, "Pages reactivated from free list", VPS_0);
+VM_STATS_VM(v_pdwakeups, "Pagedaemon wakeups", VPS_0);
+VM_STATS_VM(v_pdpages, "Pages analyzed by pagedaemon", VPS_0);
+VM_STATS_VM(v_tcached, "Total pages cached", VPS_0);
+VM_STATS_VM(v_dfree, "Pages freed by pagedaemon", VPS_0);
+VM_STATS_VM(v_pfree, "Pages freed by exiting processes", VPS_0);
+VM_STATS_VM(v_tfree, "Total pages freed", VPS_0);
+VM_STATS_VM(v_page_size, "Page size in bytes", VPS_0);
+VM_STATS_VM(v_page_count, "Total number of pages in system", VPS_0);
+VM_STATS_VM(v_free_reserved, "Pages reserved for deadlock", VPS_0);
+VM_STATS_VM(v_free_target, "Pages desired free", VPS_0);
+VM_STATS_VM(v_free_min, "Minimum low-free-pages threshold", VPS_0);
+VM_STATS_VM(v_free_count, "Free pages", VPS_PUBLIC);
+VM_STATS_VM(v_wire_count, "Wired pages", VPS_PUBLIC);
+VM_STATS_VM(v_active_count, "Active pages", VPS_PUBLIC);
+VM_STATS_VM(v_inactive_target, "Desired inactive pages", VPS_0);
+VM_STATS_VM(v_inactive_count, "Inactive pages", VPS_PUBLIC);
+VM_STATS_VM(v_cache_count, "Pages on cache queue", VPS_PUBLIC);
+VM_STATS_VM(v_cache_min, "Min pages on cache queue", VPS_0);
+VM_STATS_VM(v_cache_max, "Max pages on cached queue", VPS_0);
+VM_STATS_VM(v_pageout_free_min, "Min pages reserved for kernel", VPS_0);
+VM_STATS_VM(v_interrupt_free_min, "Reserved pages for interrupt code", VPS_0);
+VM_STATS_VM(v_forks, "Number of fork() calls", VPS_0);
+VM_STATS_VM(v_vforks, "Number of vfork() calls", VPS_0);
+VM_STATS_VM(v_rforks, "Number of rfork() calls", VPS_0);
+VM_STATS_VM(v_kthreads, "Number of fork() calls by kernel", VPS_0);
+VM_STATS_VM(v_forkpages, "VM pages affected by fork()", VPS_0);
+VM_STATS_VM(v_vforkpages, "VM pages affected by vfork()", VPS_0);
+VM_STATS_VM(v_rforkpages, "VM pages affected by rfork()", VPS_0);
+VM_STATS_VM(v_kthreadpages, "VM pages affected by fork() by kernel", VPS_0);
 
 SYSCTL_INT(_vm_stats_misc, OID_AUTO, zero_page_count, CTLFLAG_RD,
 	&vm_page_zero_count, 0, "Number of zero-ed free pages");
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_mmap.c head/sys/vm/vm_mmap.c
--- clean-head/sys/vm/vm_mmap.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_mmap.c	2013-06-24 14:21:31.000000000 +0200
@@ -71,6 +71,9 @@ __FBSDID("$FreeBSD: head/sys/vm/vm_mmap.
 #include <sys/sysent.h>
 #include <sys/vmmeter.h>
 
+#include <vps/vps.h>
+#include <vps/vps_account.h>
+
 #include <security/mac/mac_framework.h>
 
 #include <vm/vm.h>
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_object.c head/sys/vm/vm_object.c
--- clean-head/sys/vm/vm_object.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_object.c	2013-06-24 14:21:31.000000000 +0200
@@ -83,6 +83,10 @@ __FBSDID("$FreeBSD: head/sys/vm/vm_objec
 #include <sys/vmmeter.h>
 #include <sys/sx.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#include <vps/vps_account.h>
+
 #include <vm/vm.h>
 #include <vm/vm_param.h>
 #include <vm/pmap.h>
@@ -98,6 +102,45 @@ __FBSDID("$FreeBSD: head/sys/vm/vm_objec
 #include <vm/vm_reserv.h>
 #include <vm/uma.h>
 
+ 
+#include <vps/vps_account.h>
+ 
+#ifdef VPS
+ 
+#define VPS_ACCOUNT_RESIDENT(object, action, charge)      \
+		vps_account_resident(object, action, charge)
+ 
+static __inline void
+vps_account_resident(vm_object_t object, int action, size_t charge)
+{  
+ 
+        if (object->cred == NULL)
+                return;
+   
+        vps_account(object->cred->cr_vps, VPS_ACC_PHYS,
+                action, charge << PAGE_SHIFT);
+}
+
+#define VPS_ACCOUNT_VIRTUAL(object, action, charge)      \
+		vps_account_virtual(object, action, charge)
+ 
+static __inline void
+vps_account_virtual(vm_object_t object, int action, size_t charge)
+{  
+ 
+        if (object->cred == NULL)
+                return;
+   
+        vps_account(object->cred->cr_vps, VPS_ACC_VIRT,
+                action, charge << PAGE_SHIFT);
+}
+
+#else
+
+#define VPS_ACCOUNT_RESIDENT(object, action, charge)
+
+#endif /* !VPS */
+
 static int old_msync;
 SYSCTL_INT(_vm, OID_AUTO, old_msync, CTLFLAG_RW, &old_msync, 0,
     "Use old (insecure) msync behavior");
@@ -236,6 +279,11 @@ _vm_object_allocate(objtype_t type, vm_p
 	case OBJT_VNODE:
 		object->flags = 0;
 		break;
+#ifdef VPS
+	case OBJT_VPS:
+		object->flags = OBJ_ONEMAPPING;
+		break;
+#endif
 	default:
 		panic("_vm_object_allocate: type %d is undefined", type);
 	}
@@ -767,6 +815,7 @@ vm_object_terminate(vm_object_t object)
 	 * modified by the preceding loop.
 	 */
 	if (object->resident_page_count != 0) {
+		VPS_ACCOUNT_RESIDENT(object, VPS_ACC_FREE, object->resident_page_count);
 		vm_radix_reclaim_allnodes(&object->rtree);
 		TAILQ_INIT(&object->memq);
 		object->resident_page_count = 0;
@@ -2406,4 +2455,79 @@ DB_SHOW_COMMAND(vmopag, vm_object_print_
 		}
 	}
 }
+
+DB_SHOW_COMMAND(vmobjlist, vm_object_print_list)
+{
+	vm_object_t obj;
+#ifdef VPS
+	struct vps *vps;
+#endif
+	struct proc *p;
+	char is_in_vmspace;
+	char *mapname;
+	int cnt_nomap_respages = 0;
+	int cnt_nomap = 0;
+
+	TAILQ_FOREACH(obj, &vm_object_list, object_list) {
+
+		is_in_vmspace = 0;
+		mapname = NULL;
+
+		if (_vm_object_in_map(kernel_map, obj, 0))
+			mapname = "kernel_map";
+		if (_vm_object_in_map(kmem_map, obj, 0))
+			mapname = "kmem_map";
+		if (_vm_object_in_map(pager_map, obj, 0))
+			mapname = "pager_map";
+		if (_vm_object_in_map(buffer_map, obj, 0))
+			mapname = "buffer_map";
+
+#ifdef VPS
+		/* sx_slock(&vps_all_lock); */
+        	LIST_FOREACH(vps, &vps_head, vps_all) {
+			/* sx_slock(&allproc_lock); */
+#endif
+			LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list) {
+				if (!p->p_vmspace /* || (p->p_flag & (P_SYSTEM|P_WEXIT)) */)
+					continue;
+				if (_vm_object_in_map(&p->p_vmspace->vm_map, obj, 0)) {
+					/* sx_sunlock(&allproc_lock); */
+					/*
+					db_printf("      is in vmspace %p proc %d/%p\n",
+						p->p_vmspace, p->p_pid, p);
+					*/
+					is_in_vmspace = 1;
+					mapname = "vmspace";
+				}
+			}
+			/* sx_sunlock(&allproc_lock); */
+#ifdef VPS
+		}
+		/* sx_sunlock(&vps_all_lock); */
+#endif
+
+		if (is_in_vmspace)
+			continue;
+
+		if (obj->type == OBJT_VNODE)
+			continue;
+
+		db_printf("obj=%p size=%zu ref_count=%d type=%d resident_page_count=%d\n",
+			obj, (size_t)obj->size, obj->ref_count,
+			obj->type, obj->resident_page_count);
+		if (mapname) {
+			db_printf("      is in %s\n", mapname);
+		} else {
+			db_printf("      IS IN NO MAP !\n");
+			cnt_nomap++;
+			cnt_nomap_respages += obj->resident_page_count;
+
+			if (obj->type == OBJT_VNODE) {
+				db_printf("      OBJT_VNODE; vnode = %p\n", obj->handle);
+			}
+		}
+	}
+	db_printf("total count of objects without mapping: %d\n", cnt_nomap);
+	db_printf("total count of resident pages in such objects: %d\n", cnt_nomap_respages);
+}
 #endif /* DDB */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_page.c head/sys/vm/vm_page.c
--- clean-head/sys/vm/vm_page.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_page.c	2013-06-24 14:21:31.000000000 +0200
@@ -119,6 +119,30 @@ __FBSDID("$FreeBSD: head/sys/vm/vm_page.
 
 #include <machine/md_var.h>
 
+#include <vps/vps_account.h>
+
+#ifdef VPS 
+        
+#define VPS_ACCOUNT_RESIDENT(object, action, charge)      \
+                vps_account_resident(object, action, charge)
+                
+static __inline void
+vps_account_resident(vm_object_t object, int action, size_t charge)
+{
+         
+        if (object->cred == NULL)
+                return;
+        
+        vps_account(object->cred->cr_vps, VPS_ACC_PHYS,
+                action, charge << PAGE_SHIFT);
+}
+
+#else
+
+#define VPS_ACCOUNT_RESIDENT(object, action, charge)
+                
+#endif /* !VPS */
+
 /*
  *	Associated with page of user-allocatable memory is a
  *	page structure.
@@ -866,6 +890,7 @@ vm_page_insert_after(vm_page_t m, vm_obj
 	 */
 	object->resident_page_count++;
 
+	VPS_ACCOUNT_RESIDENT(object, VPS_ACC_ALLOC, 1);
 	/*
 	 * Hold the vnode until the last page is released.
 	 */
@@ -914,6 +939,7 @@ vm_page_remove(vm_page_t m)
 	 * And show that the object has one fewer resident page.
 	 */
 	object->resident_page_count--;
+	VPS_ACCOUNT_RESIDENT(object, VPS_ACC_FREE, 1);
 
 	/*
 	 * The vnode may now be recycled.
@@ -2197,6 +2223,7 @@ vm_page_cache(vm_page_t m)
 	vm_radix_remove(&object->rtree, m->pindex);
 	TAILQ_REMOVE(&object->memq, m, listq);
 	object->resident_page_count--;
+	VPS_ACCOUNT_RESIDENT(object, VPS_ACC_FREE, 1);
 
 	/*
 	 * Restore the default memory attribute to the page.
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_pageout.c head/sys/vm/vm_pageout.c
--- clean-head/sys/vm/vm_pageout.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_pageout.c	2013-06-24 14:21:31.000000000 +0200
@@ -96,6 +96,9 @@ __FBSDID("$FreeBSD: head/sys/vm/vm_pageo
 #include <sys/sx.h>
 #include <sys/sysctl.h>
 
+#include <vps/vps.h>
+#include <vps/vps2.h>
+
 #include <vm/vm.h>
 #include <vm/vm_param.h>
 #include <vm/vm_object.h>
@@ -785,6 +788,10 @@ unlock_return:
 		VM_OBJECT_RUNLOCK(object);
 }
 
+#ifdef VPS
+int vps_pager_put_object(vm_object_t, long);
+#endif
+
 /*
  * deactivate some number of pages in a map, try to do it fairly, but
  * that is really hard to do.
@@ -829,7 +836,12 @@ vm_pageout_map_deactivate_pages(map, des
 	}
 
 	if (bigobj != NULL) {
-		vm_pageout_object_deactivate_pages(map->pmap, bigobj, desired);
+#ifdef VPS
+		if (bigobj->type == OBJT_VPS)
+			vps_pager_put_object(bigobj, desired);
+		else
+#endif
+			vm_pageout_object_deactivate_pages(map->pmap, bigobj, desired);
 		VM_OBJECT_RUNLOCK(bigobj);
 	}
 	/*
@@ -1428,6 +1440,9 @@ vm_pageout_oom(int shortage)
 	vm_offset_t size, bigsize;
 	struct thread *td;
 	struct vmspace *vm;
+#ifdef VPS
+	struct vps *vps, *save_vps;
+#endif  
 
 	/*
 	 * We keep the process bigproc locked once we find it to keep anyone
@@ -1439,7 +1454,13 @@ vm_pageout_oom(int shortage)
 	 */
 	bigproc = NULL;
 	bigsize = 0;
-	sx_slock(&allproc_lock);
+#ifdef VPS
+	save_vps = curthread->td_vps;
+	sx_slock(&vps_all_lock);
+	LIST_FOREACH(vps, &vps_head, vps_all) {
+		curthread->td_vps = vps;
+#endif
+	sx_slock(&V_allproc_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		int breakout;
 
@@ -1506,7 +1527,13 @@ vm_pageout_oom(int shortage)
 		} else
 			PROC_UNLOCK(p);
 	}
-	sx_sunlock(&allproc_lock);
+	sx_sunlock(&V_allproc_lock);
+#ifdef VPS
+	}
+	sx_sunlock(&vps_all_lock);
+	curthread->td_vps = save_vps;
+#endif
+
 	if (bigproc != NULL) {
 		killproc(bigproc, "out of swap space");
 		sched_nice(bigproc, PRIO_MIN);
@@ -1804,6 +1831,10 @@ vm_daemon(void)
 #ifdef RACCT
 	uint64_t rsize, ravailable;
 #endif
+#ifdef VPS
+	struct vps *vps, *save_vps;
+	save_vps = curthread->td_vps;
+#endif  
 
 	while (TRUE) {
 		mtx_lock(&vm_daemon_mtx);
@@ -1826,7 +1857,12 @@ vm_daemon(void)
 		attempts = 0;
 again:
 		attempts++;
-		sx_slock(&allproc_lock);
+#ifdef VPS
+		sx_slock(&vps_all_lock);
+		LIST_FOREACH(vps, &vps_head, vps_all) {
+			curthread->td_vps = vps;
+#endif
+		sx_slock(&V_allproc_lock);
 		FOREACH_PROC_IN_SYSTEM(p) {
 			vm_pindex_t limit, size;
 
@@ -1917,7 +1953,12 @@ again:
 #endif
 			vmspace_free(vm);
 		}
-		sx_sunlock(&allproc_lock);
+		sx_sunlock(&V_allproc_lock);
+#ifdef VPS
+		}
+		sx_sunlock(&vps_all_lock);
+		curthread->td_vps = save_vps;
+#endif
 		if (tryagain != 0 && attempts <= 10)
 			goto again;
 	}
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_pager.c head/sys/vm/vm_pager.c
--- clean-head/sys/vm/vm_pager.c	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_pager.c	2013-06-24 14:21:31.000000000 +0200
@@ -161,7 +161,10 @@ struct pagerops *pagertab[] = {
 	&physpagerops,		/* OBJT_PHYS */
 	&deadpagerops,		/* OBJT_DEAD */
 	&sgpagerops,		/* OBJT_SG */
-	&mgtdevicepagerops,	/* OBJT_MGTDEVICE */
+	&mgtdevicepagerops,     /* OBJT_MGTDEVICE */
+#ifdef VPS
+	&vps_pager_ops,		/* OBJT_VPS */
+#endif
 };
 
 static const int npagers = sizeof(pagertab) / sizeof(pagertab[0]);
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vm/vm_pager.h head/sys/vm/vm_pager.h
--- clean-head/sys/vm/vm_pager.h	2013-06-26 09:39:09.000000000 +0200
+++ head/sys/vm/vm_pager.h	2013-06-24 14:21:31.000000000 +0200
@@ -72,6 +72,7 @@ extern struct pagerops devicepagerops;
 extern struct pagerops physpagerops;
 extern struct pagerops sgpagerops;
 extern struct pagerops mgtdevicepagerops;
+extern struct pagerops vps_pager_ops;
 
 /*
  * get/put return values
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/if_vps.c head/sys/vps/if_vps.c
--- clean-head/sys/vps/if_vps.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/if_vps.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,930 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Based on:
+ *
+ * ''if_epair.c'':
+ *
+ * Copyright (c) 2008 The FreeBSD Foundation
+ * Copyright (c) 2009 Bjoern A. Zeeb <bz@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by CK Software GmbH under sponsorship
+ * from the FreeBSD Foundation.
+
+ * ''if_loop.c'':
+ *
+ * Copyright (c) 1982, 1986, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: if_vps.c 169 2013-06-11 14:10:34Z klaus $";
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_global.h"
+
+#ifdef VPS
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/refcount.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <net/bpf.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_clone.h>
+#include <net/if_var.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <net/vnet.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet6/in6_var.h>
+
+#include "vps_user.h"
+#include "vps.h"
+#include "vps2.h"
+
+#define IFNAME "vps"
+
+static MALLOC_DEFINE(M_VPS_IF, IFNAME,
+    "Virtual Private Systems virtual network interfaces");
+
+#ifdef DIAGNOSTIC
+
+#define DBGIF	if (debug_if) printf
+
+static int debug_if = 0;
+SYSCTL_INT(_debug, OID_AUTO, vps_if_debug, CTLFLAG_RW, &debug_if, 0, "");
+
+#else
+
+#define DBGIF(x, ...)
+
+#endif /* DIAGNOSTIC */
+
+static struct mtx vps_if_mtx;
+
+static int vps_if_refcnt = 0;
+
+struct vps_if_softc {
+        TAILQ_ENTRY(vps_if_softc)  vps_if_list;
+        struct ifnet    *ifp;
+        struct ifnet    *oifp;
+        u_int           refcount;
+        void            (*if_qflush)(struct ifnet *);
+};
+
+static TAILQ_HEAD(,vps_if_softc) vps_if_head =
+    TAILQ_HEAD_INITIALIZER(vps_if_head);
+
+static int vps_if_clone_match(struct if_clone *, const char *);
+static int vps_if_clone_create(struct if_clone *, char *, size_t, caddr_t);
+static int vps_if_clone_destroy(struct if_clone *, struct ifnet *);
+
+/*
+delete
+static struct if_clone vps_if_cloner = IFC_CLONE_INITIALIZER(
+    IFNAME, NULL, IF_MAXUNIT,
+    NULL, vps_if_clone_match, vps_if_clone_create, vps_if_clone_destroy);
+*/
+static struct if_clone *vps_if_cloner;
+#ifdef VIMAGE
+static VNET_DEFINE(struct if_clone *, vps_if_cloner);
+#define V_vps_if_cloner   VNET(vps_if_cloner)
+#endif
+
+struct vps_if_rtentry {
+	struct radix_node rt_nodes[2];	/* tree glue, and other values */
+	struct radix_node_head *rt_rnh;
+	struct ifnet *rt_ifp;
+	struct ifaddr *rt_ifa;
+	union {
+		struct sockaddr u_addr;
+		struct sockaddr_in u_in4addr;
+		struct sockaddr_in6 u_in6addr;
+	} rt_uaddr;
+	union {
+		struct sockaddr u_mask;
+		struct sockaddr_in u_in4mask;
+		struct sockaddr_in6 u_in6mask;
+	} rt_umask;
+	struct vps *rt_vps;
+};
+
+void *vps_if_routehead_ip4;
+void *vps_if_routehead_ip6;
+
+static int
+vps_if_inithead(void)
+{
+
+	rn_inithead(&vps_if_routehead_ip4, 0);
+	rn_inithead(&vps_if_routehead_ip6, 0);
+
+	return (0);
+}
+
+static int
+vps_if_detachhead(void)
+{
+
+	rn_detachhead(&vps_if_routehead_ip6);
+	rn_detachhead(&vps_if_routehead_ip4);
+
+	return (0);
+}
+
+static int
+vps_if_addroute(struct sockaddr *addr, struct sockaddr *mask,
+    struct ifnet *ifp)
+{
+	struct radix_node_head *rnh;
+	struct radix_node *rn;
+	struct vps *vps;
+	struct vps_if_rtentry *vrt;
+	struct in_addr netmask4;
+	struct sockaddr_in *addr4, *mask4;
+	struct sockaddr_in6 *addr6, *mask6;
+
+	vps = curthread->td_vps;
+
+	vrt = malloc(sizeof(*vrt), M_VPS_IF, M_WAITOK | M_ZERO);
+	vrt->rt_ifp = ifp;
+	vrt->rt_ifa = NULL;
+	vrt->rt_vps = vps;
+
+	switch (addr->sa_family) {
+	case AF_INET:
+		rnh = vps_if_routehead_ip4;
+		addr4 = (struct sockaddr_in *)addr;
+		mask4 = (struct sockaddr_in *)mask;
+		vrt->rt_rnh = rnh;
+		vrt->rt_uaddr.u_in4addr = *(struct sockaddr_in *)addr;
+		vrt->rt_umask.u_in4mask = *(struct sockaddr_in *)mask;
+
+		DBGIF("%s: addr=%08x mask=%08x ifp=%p [%s]\n",
+			__func__, addr4->sin_addr.s_addr,
+			mask4->sin_addr.s_addr, ifp, ifp->if_xname);
+
+		netmask4.s_addr = 0xffffffff;
+		if (vps_ip4_check(vps, &addr4->sin_addr, &netmask4) != 0) {
+			DBGIF("%s: vps_ip4_check EPERM\n", __func__);
+			return (EPERM);
+		}
+		break;
+
+	case AF_INET6:
+		rnh = vps_if_routehead_ip6;
+		addr6 = (struct sockaddr_in6 *)addr;
+		mask6 = (struct sockaddr_in6 *)mask;
+		vrt->rt_rnh = rnh;
+		vrt->rt_uaddr.u_in6addr = *(struct sockaddr_in6 *)addr;
+		vrt->rt_umask.u_in6mask = *(struct sockaddr_in6 *)mask;
+
+		/*
+		DBGIF("%s: addr=%16D mask=%16D ifp=%p [%s]\n",
+			__func__, &addr6->sin6_addr, ":",
+			&mask6->sin6_addr, ":",
+			ifp, ifp->if_xname);
+		*/
+
+		if (vps_ip6_check(vps, &addr6->sin6_addr, 128) != 0) {
+			DBGIF("%s: vps_ip6_check EPERM\n", __func__);
+			return (EPERM);
+		}
+		break;
+
+	default:
+		free(vrt, M_VPS_IF);
+		return (EOPNOTSUPP);
+		break;
+	}
+
+	RADIX_NODE_HEAD_LOCK(rnh);
+
+	rn = rnh->rnh_deladdr(&vrt->rt_uaddr.u_addr,
+		&vrt->rt_umask.u_mask,
+		rnh);
+	if (rn != NULL) {
+		DBGIF("%s: warning: old matching route found --> deleted\n",
+			__func__);
+		free(rn, M_VPS_IF);
+	}
+
+	rn = rnh->rnh_addaddr(&vrt->rt_uaddr.u_addr,
+		&vrt->rt_umask.u_mask,
+		rnh, vrt->rt_nodes);
+
+	RADIX_NODE_HEAD_UNLOCK(rnh);
+
+	return (0);
+}
+
+static int
+vps_if_delroute(struct sockaddr *addr, struct sockaddr *mask,
+    struct ifnet *ifp)
+{
+	struct radix_node_head *rnh;
+	struct radix_node *rn;
+	struct vps_if_rtentry *vrt;
+
+	switch (addr->sa_family) {
+	case AF_INET:
+		rnh = vps_if_routehead_ip4;
+		break;
+	case AF_INET6:
+		rnh = vps_if_routehead_ip6;
+		break;
+	default:
+		return (0);
+	}
+
+	RADIX_NODE_HEAD_LOCK(rnh);
+
+	rn = rnh->rnh_deladdr(addr, mask, rnh);
+
+	RADIX_NODE_HEAD_UNLOCK(rnh);
+
+	if (rn == NULL) {
+		DBGIF("%s: rn not found\n", __func__);
+		return (ESRCH);
+	}
+
+	if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
+		panic("%s: rtrequest delete", __func__);
+
+	vrt = (struct vps_if_rtentry *)rn;
+
+	free(vrt, M_VPS_IF);
+
+	return (0);
+}
+
+static int
+vps_if_purgeroute_one(struct radix_node *rn, void *arg)
+{
+	struct vps_if_rtentry *vrt = (struct vps_if_rtentry *)rn;
+	struct ifnet *ifp = arg;
+
+	if (vrt->rt_ifp != ifp)
+		return (0);
+
+	vrt->rt_rnh->rnh_deladdr(&vrt->rt_uaddr.u_addr,
+		&vrt->rt_umask.u_mask, vrt->rt_rnh);
+
+	free(vrt, M_VPS_IF);
+
+	DBGIF("%s: freed one route\n", __func__);
+
+	return (0);
+}
+
+static int
+vps_if_purgeroutes(struct ifnet *ifp)
+{
+	struct radix_node_head *rnh;
+
+	DBGIF("%s: ifp=%p\n", __func__, ifp);
+
+	rnh = vps_if_routehead_ip4;
+	RADIX_NODE_HEAD_LOCK(rnh);
+	(void)(rnh)->rnh_walktree(rnh,
+		vps_if_purgeroute_one, ifp);
+	RADIX_NODE_HEAD_UNLOCK(rnh);
+
+	rnh = vps_if_routehead_ip6;
+	RADIX_NODE_HEAD_LOCK(rnh);
+	(void)(rnh)->rnh_walktree(rnh,
+		vps_if_purgeroute_one, ifp);
+	RADIX_NODE_HEAD_UNLOCK(rnh);
+
+	return (0);
+}
+
+static struct vps_if_rtentry *
+vps_if_lookup(const struct sockaddr *dst2)
+{
+	struct radix_node_head *rnh;
+	struct radix_node *rn;
+	struct vps_if_rtentry *vrt;
+	struct sockaddr *dst;
+	char sockaddr_buf[SOCK_MAXADDRLEN];
+
+	dst = (struct sockaddr *)sockaddr_buf;
+	memcpy(dst, dst2, dst2->sa_len);
+
+	switch (dst->sa_family) {
+	case AF_INET:
+		rnh = vps_if_routehead_ip4;
+		DBGIF("%s: dst: %08x\n",
+			__func__,
+			((struct sockaddr_in *)dst)->sin_addr.s_addr);
+		break;
+	case AF_INET6:
+		rnh = vps_if_routehead_ip6;
+		/*
+		DBGIF("%s: dst: %16D\n",
+			__func__,
+			&((struct sockaddr_in6 *)dst)->sin6_addr, ":");
+		*/
+		break;
+	default:
+		return (NULL);
+	}
+
+	rn = rnh->rnh_matchaddr(dst, rnh);
+	if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) {
+		;//DBGIF("%s: rn=%p\n", __func__, rn);
+	} else {
+		;//DBGIF("%s: RNF_ROOT or rn=%p\n", __func__, rn);
+	}
+
+	vrt = (struct vps_if_rtentry *)rn;
+
+	/*
+	 * If interface and therefore routes still exist somewhere in
+	 * a half dead vps instance, better not use the route.
+	 */
+	if (vrt != NULL && ((vrt->rt_ifp->if_flags & IFF_UP) == 0))
+		return (NULL);
+
+	return (vrt);
+}
+
+static struct ifnet *
+vps_if_get_if_by_addr_v4(const struct sockaddr *dst, struct mbuf *m)
+{
+	struct vps_if_rtentry *vrt;
+
+	vrt = vps_if_lookup(dst);
+	if (vrt == NULL) {
+                /* Nothing found, so use the default (first) interface. */
+                return ((TAILQ_FIRST(&vps_if_head))->ifp);
+	}
+
+	return (vrt->rt_ifp);
+}
+
+static struct ifnet *
+vps_if_get_if_by_addr_v6(const struct sockaddr *dst, struct mbuf *m)
+{
+	struct vps_if_rtentry *vrt;
+
+	vrt = vps_if_lookup(dst);
+	if (vrt == NULL) {
+                /* Nothing found, so use the default (first) interface. */
+                return ((TAILQ_FIRST(&vps_if_head))->ifp);
+	}
+
+	return (vrt->rt_ifp);
+}
+
+static int
+vps_if_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
+    struct route *rt)
+{
+        struct ifnet *oifp;
+        int error;
+        struct vps_if_softc *sc;
+        int isr;
+
+	/* LOCK allvpsif read lock */
+
+        switch (dst->sa_family) {
+        case AF_INET:
+                oifp = vps_if_get_if_by_addr_v4(dst, m);
+                break;
+        case AF_INET6:
+                oifp = vps_if_get_if_by_addr_v6(dst, m);
+                break;
+        default:
+                DBGIF("%s: af=%d unexpected\n", __func__, dst->sa_family);
+                m_freem(m);
+		/* LOCK allvpsif read unlock */
+                return (EAFNOSUPPORT);
+        }
+
+        if (oifp == NULL) {
+                ifp->if_oerrors++;
+                m_freem(m);
+		/* LOCK allvpsif read unlock */
+                return (EHOSTUNREACH);
+        }
+        sc = ifp->if_softc;
+
+        /*
+         * In case the outgoing interface is not usable,
+         * drop the packet.
+         */
+        if ((oifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
+                (oifp->if_flags & IFF_UP) == 0) {
+                ifp->if_oerrors++;
+                m_freem(m);
+		/* LOCK allvpsif read unlock */
+                return (EHOSTUNREACH);
+        }
+
+	/* Loop protection. */
+	if (oifp == ifp) {
+		DBGIF("%s: LOOP ! oifp == ifp == %p\n", __func__, ifp);
+                ifp->if_oerrors++;
+                m_freem(m);
+		/* LOCK allvpsif read unlock */
+		return (EHOSTUNREACH);
+	}
+
+        DBGIF("%s: packet if %p/%s (vnet %p) -> if %p/%s (vnet %p)\n",
+	    __func__, ifp, ifp->if_xname, ifp->if_vnet,
+	    oifp, oifp->if_xname, oifp->if_vnet);
+
+        /* Deliver to upper layer protocol */
+        switch (dst->sa_family) {
+#ifdef INET
+        case AF_INET:
+                isr = NETISR_IP;
+                break;
+#endif
+#ifdef INET6
+        case AF_INET6:
+                m->m_flags |= M_LOOP;
+                isr = NETISR_IPV6;
+                break;
+#endif
+        default:
+                DBGIF("%s: can't handle af=%d\n", __func__, dst->sa_family);
+                m_freem(m);
+                return (EAFNOSUPPORT);
+        }
+
+        refcount_acquire(&sc->refcount);
+	/* LOCK allvpsif read unlock */
+        m->m_pkthdr.rcvif = oifp;
+	KASSERT(m->m_pkthdr.rcvif->if_dname[0] == 'v',
+	    ("%s: m->m_pkthdr.rcvif->if_dname = [%s]\n",
+	    __func__, m->m_pkthdr.rcvif->if_dname));
+        oifp->if_ipackets++;
+        oifp->if_ibytes += m->m_pkthdr.len;
+
+        CURVNET_SET_QUIET(oifp->if_vnet);
+        error = netisr_queue(isr, m);   /* mbuf is free'd on failure. */
+        CURVNET_RESTORE();
+
+        refcount_release(&sc->refcount);
+
+        return (error);
+}
+
+#ifdef DISABLED__VIMAGE
+static void
+vps_if_reassign(struct ifnet *ifp, struct vnet *vnet, char *dname)
+{
+
+        if_detach(ifp);
+        ifp->if_bpf = NULL;
+        if_reassign_common(ifp, vnet, "eth");
+        if (dname)
+                snprintf(ifp->if_xname, IFNAMSIZ, "%s", dname);
+
+        CURVNET_SET_QUIET(vnet);
+        if_attach(ifp);
+        CURVNET_RESTORE();
+}
+#endif
+
+static void
+vps_if_ioctl2(u_long cmd, caddr_t data, struct ifnet *ifp,
+    struct thread *td)
+{
+	struct in_aliasreq *ifra;
+	struct in6_aliasreq *ifra6;
+
+	DBGIF("%s: cmd=%08lx data=%p ifp=%p td=%p\n",
+	    __func__, cmd, data, ifp, td);
+
+        switch (cmd) {
+	case SIOCSIFADDR:
+	case SIOCAIFADDR:
+		ifra = (struct in_aliasreq *)data;
+
+		DBGIF("%s: ADD SIOCAIFADDR/SIOCSIFADDR ifra=%p "
+		    "addr=%08x mask=%08x\n",
+		    __func__, ifra, ifra->ifra_addr.sin_addr.s_addr,
+		    ifra->ifra_mask.sin_addr.s_addr);
+
+		vps_if_addroute((struct sockaddr *)&ifra->ifra_addr,
+			(struct sockaddr *)&ifra->ifra_mask, ifp);
+
+		break;
+
+	case SIOCDIFADDR:
+		ifra = (struct in_aliasreq *)data;
+
+		DBGIF("%s: DEL SIOCDIFADDR ifra=%p addr=%08x mask=%08x\n",
+			__func__, ifra, ifra->ifra_addr.sin_addr.s_addr,
+			ifra->ifra_mask.sin_addr.s_addr);
+
+		vps_if_delroute((struct sockaddr *)&ifra->ifra_addr,
+			(struct sockaddr *)&ifra->ifra_mask, ifp);
+
+		break;
+
+	case SIOCAIFADDR_IN6:
+		ifra6 = (struct in6_aliasreq *)data;
+
+		DBGIF("%s: ADD SIOCAIFADDR_IN6: addr=%16D mask=%16D\n",
+			__func__, (char*)&ifra6->ifra_addr.sin6_addr, ":",
+			(char*)&ifra6->ifra_prefixmask.sin6_addr, ":");
+
+		vps_if_addroute((struct sockaddr *)&ifra6->ifra_addr,
+			(struct sockaddr *)&ifra6->ifra_prefixmask, ifp);
+
+		break;
+
+	case SIOCDIFADDR_IN6:
+		ifra6 = (struct in6_aliasreq *)data;
+
+		DBGIF("%s: DEL SIOCDIFADDR_IN6: addr=%16D mask=%16D\n",
+			__func__, (char*)&ifra6->ifra_addr.sin6_addr, ":",
+			(char*)&ifra6->ifra_prefixmask.sin6_addr, ":");
+
+		vps_if_delroute((struct sockaddr *)&ifra6->ifra_addr,
+			(struct sockaddr *)&ifra6->ifra_prefixmask, ifp);
+
+		break;
+
+        default:
+		/*
+                DBGIF("%s: cmd=%08lx\n", __func__, cmd);
+		*/
+		break;
+        }
+
+}
+
+
+static int
+vps_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+        struct ifreq *ifr;
+        struct ifaddr *ifa;
+        int error;
+
+        ifr = (struct ifreq *)data;
+        error = 0;
+
+	DBGIF("%s: cmd=%08lx data=%p ifp=%p\n",
+	    __func__, cmd, data, ifp);
+
+        switch (cmd) {
+        case SIOCSIFADDR:
+                ifp->if_flags |= IFF_UP;
+                ifp->if_drv_flags |= IFF_DRV_RUNNING;
+                ifa = (struct ifaddr *)data;
+                /*
+                 * Everything else is done at a higher level.
+                 */
+                break;
+
+	case SIOCAIFADDR:
+	case SIOCDIFADDR:
+	case SIOCAIFADDR_IN6:
+	case SIOCDIFADDR_IN6:
+		break;
+
+        case SIOCADDMULTI:
+        case SIOCDELMULTI:
+                if (ifr == 0) {
+                        error = EAFNOSUPPORT;           /* XXX */
+                        break;
+                }
+                switch (ifr->ifr_addr.sa_family) {
+
+#ifdef INET
+                case AF_INET:
+                        break;
+#endif
+#ifdef INET6
+                case AF_INET6:
+                        break;
+#endif
+
+                default:
+                        error = EAFNOSUPPORT;
+                        break;
+                }
+                break;
+
+        case SIOCSIFMTU:
+                ifp->if_mtu = ifr->ifr_mtu;
+                break;
+
+        case SIOCSIFFLAGS:
+                break;
+
+        default:
+                error = EINVAL;
+        }
+
+        return (error);
+}
+
+static void
+vps_if_init(void *dummy __unused)
+{
+}
+
+
+static int
+vps_if_clone_match(struct if_clone *ifc, const char *name)
+{
+        const char *cp;
+
+        DBGIF("name='%s'\n", name);
+
+        /*
+         * Our base name is vps.
+         * Our interfaces will be named vps<n>.
+         * So accept anything of the following list:
+         * - vps
+         * - vps<n>
+         */
+        if (strncmp(IFNAME, name, sizeof(IFNAME)-1) != 0)
+                return (0);
+
+        for (cp = name + sizeof(IFNAME) - 1; *cp != '\0'; cp++) {
+                if (*cp < '0' || *cp > '9')
+                        return (0);
+        }
+
+        return (1);
+}
+
+static int
+vps_if_clone_create(struct if_clone *ifc, char *name, size_t len,
+    caddr_t params)
+{
+        struct vps_if_softc *sc;
+        struct ifnet *ifp;
+        struct ifaddr *ifa;
+        struct sockaddr_dl *sdl;
+        int error, unit, wildcard;
+	u_int8_t ll[8];
+        char *dp;
+
+        error = ifc_name2unit(name, &unit);
+        if (error != 0)
+                return (error);
+        wildcard = (unit < 0);
+
+        error = ifc_alloc_unit(ifc, &unit);
+        if (error != 0)
+                return (error);
+        /*
+         * If no unit had been given, we need to adjust the ifName.
+         */
+        for (dp = name; *dp != '\0'; dp++);
+        if (wildcard) {
+                error = snprintf(dp, len - (dp - name), "%d", unit);
+                if (error > len - (dp - name) - 1) {
+                        /* ifName too long. */
+                        ifc_free_unit(ifc, unit);
+                        return (ENOSPC);
+                }
+                dp += error;
+        }
+        *dp = '\0';
+
+        /* Allocate memory for interface */
+        sc = malloc(sizeof (struct vps_if_softc), M_VPS_IF,
+	    M_WAITOK | M_ZERO);
+        refcount_init(&sc->refcount, 1);
+        sc->ifp = if_alloc(IFT_PROPVIRTUAL);
+        if (sc->ifp == NULL) {
+                free(sc, M_VPS_IF);
+                ifc_free_unit(ifc, unit);
+                return (ENOSPC);
+        }
+
+        /* Finish initialization of interface <n>. */
+        ifp = sc->ifp;
+        ifp->if_softc = sc;
+        ifp->if_dname = IFNAME;
+        ifp->if_dunit = unit;
+	snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", ifp->if_dname,
+	    ifp->if_dunit);
+	DBGIF("%s: ifp->if_xname=[%s]\n", __func__, ifp->if_xname);
+        ifp->if_flags = IFF_MULTICAST;
+        ifp->if_ioctl = vps_if_ioctl;
+        ifp->if_init  = vps_if_init;
+        ifp->if_output = vps_if_output;
+        ifp->if_snd.ifq_maxlen = ifqmaxlen;
+        ifp->if_mtu = IP_MAXPACKET;
+        if_attach(ifp);
+        bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
+        ifp->if_baudrate = ULONG_MAX; // IF_Gbps(10UL);       /* arbitrary maximum */
+
+	ifp->if_pspare[2] = (void *)vps_if_ioctl2;
+
+	/* XXX do something random ... */
+	{
+		int tmpticks = ticks;
+
+		memcpy(&ll[0], &curthread->td_vps, 0);
+		memcpy(&ll[4], &tmpticks, 4);
+	}
+        ifa = ifp->if_addr;
+        KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
+        sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+        sdl->sdl_type = IFT_PROPVIRTUAL;
+        sdl->sdl_alen = sizeof (ll);
+        bcopy(&ll, LLADDR(sdl), sdl->sdl_alen);
+
+        mtx_lock(&vps_if_mtx);
+        TAILQ_INSERT_TAIL(&vps_if_head, sc, vps_if_list);
+        mtx_unlock(&vps_if_mtx);
+
+        /* Tell the world, that we are ready to rock. */
+        sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
+
+	refcount_acquire(&vps_if_refcnt);
+
+	DBGIF("%s: ifp->if_xname=[%s]\n", __func__, ifp->if_xname);
+
+        return (0);
+}
+
+static int
+vps_if_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
+{
+        struct vps_if_softc *sc;
+        int unit;
+
+        DBGIF("ifp=%p\n", ifp);
+
+        unit = ifp->if_dunit;
+        sc = ifp->if_softc;
+
+        mtx_lock(&vps_if_mtx);
+        TAILQ_REMOVE(&vps_if_head, sc, vps_if_list);
+        mtx_unlock(&vps_if_mtx);
+
+        DBGIF("ifp=%p\n", ifp);
+        ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+        if_detach(ifp);
+        /*
+         * Wait for all packets to be dispatched to if_input.
+         * The numbers can only go down as the interfaces are
+         * detached so there is no need to use atomics.
+         */
+        DBGIF("sc refcnt=%u\n", sc->refcount);
+        KASSERT(sc->refcount == 1,
+            ("%s: sc->refcount!=1: %d",
+            __func__, sc->refcount));
+
+	/* Have all internal routes purged. */
+	vps_if_purgeroutes(ifp);
+
+        /* Finish cleaning up. Free them and release the unit. */
+        if_free(ifp);
+        free(sc, M_VPS_IF);
+        ifc_free_unit(ifc, unit);
+
+	refcount_release(&vps_if_refcnt);
+
+        return (0);
+}
+
+static int
+vps_modevent(module_t mod, int type, void *data)
+{
+	int error = 0;
+
+	CURVNET_SET(vnet0);
+
+        switch (type) {
+        case MOD_LOAD:
+                /* For now limit us to one global mutex and one inq. */
+		mtx_init(&vps_if_mtx, "if_vps", NULL, MTX_DEF);
+		vps_if_inithead();
+		/*
+		delete
+                if_clone_attach(&vps_if_cloner);
+		*/
+#ifndef VIMAGE
+		vps_if_cloner = if_clone_advanced(IFNAME, 0,
+		    vps_if_clone_match, vps_if_clone_create,
+		     vps_if_clone_destroy);
+#endif
+		refcount_init(&vps_if_refcnt, 0);
+                if (bootverbose)
+                        printf("%s initialized.\n", IFNAME);
+#if 0
+		printf("%s: SIOCSIFADDR=%08lx\n", __func__, SIOCSIFADDR); 
+		printf("%s: SIOCDIFADDR=%08lx\n", __func__, SIOCDIFADDR); 
+		printf("%s: SIOCAIFADDR=%08lx\n", __func__, SIOCAIFADDR); 
+#endif
+                break;
+        case MOD_UNLOAD:
+		if (vps_if_refcnt > 0)
+			return (EBUSY);
+		/*
+		delete
+                if_clone_detach(&vps_if_cloner);
+		*/
+#ifndef VIMAGE
+                if_clone_detach(vps_if_cloner);
+#endif
+		vps_if_detachhead();
+                mtx_destroy(&vps_if_mtx);
+                if (bootverbose)
+                        printf("%s unloaded.\n", IFNAME);
+                break;
+        default:
+                error = EOPNOTSUPP;
+		break;
+        }
+
+	CURVNET_RESTORE();
+
+        return (error);
+}
+
+static moduledata_t vps_mod = {
+        "if_vps",
+        vps_modevent,
+        0
+};
+
+DECLARE_MODULE(if_vps, vps_mod, SI_SUB_VNET_DONE, SI_ORDER_ANY);
+MODULE_VERSION(if_vps, 1);
+
+#ifdef VIMAGE
+static void
+vnet_vps_if_init(const void *unused __unused)
+{
+
+        vps_if_cloner = if_clone_advanced(IFNAME, 0, vps_if_clone_match,
+                    vps_if_clone_create, vps_if_clone_destroy);
+        V_vps_if_cloner = vps_if_cloner;
+}
+VNET_SYSINIT(vnet_vps_if_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
+    vnet_vps_if_init, NULL);
+
+static void
+vnet_vps_if_uninit(const void *unused __unused)
+{
+
+        if_clone_detach(V_vps_if_cloner);
+}
+VNET_SYSUNINIT(vnet_vps_if_uninit, SI_SUB_PROTO_IFATTACHDOMAIN,
+    SI_ORDER_FIRST, vnet_vps_if_uninit, NULL);
+#endif
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps.h head/sys/vps/vps.h
--- clean-head/sys/vps/vps.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps.h	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: vps.h 153 2013-06-03 16:18:17Z klaus $ */
+
+#ifndef _VPS_H
+#define _VPS_H
+
+#include <sys/cdefs.h>
+
+#ifdef VPS
+#ifndef VIMAGE
+#error "You can't have option VPS without option VIMAGE !"
+#endif
+#endif
+
+/* For sysctl stuff. */
+#include <sys/vnet2.h>
+
+#define TD_TO_VPS(x)	(x)->td_ucred->cr_vps
+#define P_TO_VPS(x)	(x)->p_ucred->cr_vps
+
+#define VPSYM(x)		curthread->td_vps->_##x
+
+/*
+ * At least for now, just use vnet's facility for virtualized
+ * global variables.
+ * But map to our own names for easier change in the future.
+ */
+
+/* Keep in sync with ''struct vps'' declared in vps/vps2.h ! */
+struct vps2 {
+	struct vnet *vnet;
+};
+
+#define VPS_NAME		VNET_NAME
+#define VPS_DECLARE		VNET_DECLARE
+#define VPS_DEFINE		VNET_DEFINE
+
+#define VPS_VPS(vps, n)		\
+    VNET_VNET(((struct vps2 *)vps)->vnet, n)
+#define VPS_VPS_PTR(vps, n)	\
+    VNET_VNET_PTR(((struct vps2 *)vps)->vnet, n)
+#define VPSV(n)			\
+    VNET_VNET(((struct vps2 *)curthread->td_vps)->vnet, n)
+
+#define SYSCTL_VPS_INT		SYSCTL_VNET_INT
+#define SYSCTL_VPS_PROC		SYSCTL_VNET_PROC
+#define SYSCTL_VPS_STRING	SYSCTL_VNET_STRING
+#define SYSCTL_VPS_STRUCT	SYSCTL_VNET_STRUCT
+#define SYSCTL_VPS_UINT		SYSCTL_VNET_UINT
+#define SYSCTL_VPS_LONG		SYSCTL_VNET_LONG
+#define SYSCTL_VPS_ULONG	SYSCTL_VNET_ULONG
+
+#define vps_sysctl_handle_int		vnet_sysctl_handle_int
+#define vps_sysctl_handle_opaque	vnet_sysctl_handle_opaque
+#define vps_sysctl_handle_string	vnet_sysctl_handle_string
+#define vps_sysctl_handle_uint		vnet_sysctl_handle_uint
+
+struct vps;
+extern struct vps *vps0;
+
+#endif /* _VPS_H */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps2.h head/sys/vps/vps2.h
--- clean-head/sys/vps/vps2.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps2.h	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,304 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: vps2.h 174 2013-06-12 15:39:22Z klaus $ */
+
+#ifndef _VPS2_H
+#define _VPS2_H
+
+#include <sys/cdefs.h>
+
+#ifdef VPS
+#ifndef VIMAGE
+#error "You can't have option VPS without option VIMAGE !"
+#endif
+#endif
+
+#include <sys/priv.h>
+#include <sys/lock.h>
+#include <sys/sx.h>
+#include <sys/taskqueue.h>
+
+/* For sysctl stuff. */
+#include <net/vnet.h>
+
+struct vps_param;
+struct vps_acc;
+
+#define TD_TO_VPS(x)	(x)->td_ucred->cr_vps
+#define P_TO_VPS(x)	(x)->p_ucred->cr_vps
+
+#define VPSYM(x)		curthread->td_vps->_##x
+
+LIST_HEAD(vps_list_head, vps);
+extern struct vps_list_head vps_head;
+
+#define PRIV_SET_SIZE	((_PRIV_HIGHEST + 8) / 8)
+
+#ifdef INVARIANTS
+struct vps_ref {
+	TAILQ_ENTRY(vps_ref) list;
+	void *arg;
+	uint64_t ticks;
+};
+#endif
+
+#ifdef DIAGNOSTIC
+#define DBGCORE if (vps_debug_core) printf
+extern int vps_debug_core;
+#else
+#define DBGCORE(x, ...)
+#endif /* ! DIAGNOSTIC */
+
+#ifdef VPS
+
+/* Keep in sync with ''struct vps2'' declared in vps/vps.h ! */
+struct vps {
+	struct vnet *vnet;
+
+        LIST_ENTRY(vps)	  vps_all;
+        LIST_ENTRY(vps)	  vps_sibling;
+        LIST_HEAD(, vps)  vps_child_head;
+        struct vps        *vps_parent;
+
+	struct sx vps_lock;
+	char	*vps_lock_name;
+
+	u_int	vps_id;
+	char 	vps_name[MAXHOSTNAMELEN];
+	u_char 	vps_status;
+
+	u_int	vps_refcnt;
+	struct mtx vps_refcnt_lock;
+#ifdef INVARIANTS
+	TAILQ_HEAD(, vps_ref)	vps_ref_head;
+#endif
+	/*
+	struct task vps_task;
+	*/
+	struct timeout_task vps_task;
+
+        u_char  priv_allow_set[PRIV_SET_SIZE];
+        u_char  priv_impl_set[PRIV_SET_SIZE];
+
+	struct vps_arg_ip4 *vps_ip4;
+	struct vps_arg_ip6 *vps_ip6;
+	u_int16_t vps_ip4_cnt;
+	u_int16_t vps_ip6_cnt;
+
+	u_int	vps_flags;
+
+	int	restore_count;
+
+	int64_t suspend_time;
+
+	struct vps_acc *vps_acc;	/* XXX do inline */
+
+	struct vnode *consolelog;
+	int consolelog_refcnt;
+	struct tty *console_tty;
+	struct file *console_fp_ma;
+	int console_flags;
+
+	struct ucred *vps_ucred;
+
+	struct devfs_rule *devfs_ruleset;
+
+        struct  vnode *_rootvnode;
+        char    _rootpath[MAXPATHLEN];
+};
+
+#define VPS_F_REBOOT	0x00000200
+
+struct vps_snapst_ctx;
+
+struct vps_dev_ctx {
+        LIST_ENTRY(vps_dev_ctx) list;
+        struct file *fp;
+	struct thread *td;
+	caddr_t data;
+	size_t length;
+	u_long cmd;
+	struct vps_snapst_ctx *snapst;
+};
+
+struct vps *vps_by_name(struct vps *, char *);
+struct vps *vps_alloc(struct vps *, struct vps_param *, char *,
+    int *errorval);
+int vps_free(struct vps *);
+int vps_free_locked(struct vps *);
+int vps_destroy(struct vps *);
+void vps_ref(struct vps *, struct ucred *);
+void vps_deref(struct vps *, struct ucred *);
+struct devfs_mount;
+struct cdev;
+struct cdev_priv;
+struct mount;
+int vps_canseemount (struct ucred *, struct mount *);
+
+int vps_devfs_ruleset_create(struct vps *vps);
+int vps_devfs_ruleset_destroy(struct vps *vps);
+int vps_devfs_mount_cb(struct devfs_mount *dm, int *rsnum);
+int vps_devfs_unmount_cb(struct devfs_mount *dm);
+int vps_devfs_whiteout_cb(struct devfs_mount *dm, struct cdev_priv *cdp);
+
+int vps_switch_proc(struct thread *, struct vps *, int);
+int vps_switch_proc_wait(struct thread *, struct vps *, int);
+int vps_proc_release(struct vps *, struct proc *);
+int vps_proc_exit(struct thread *, struct proc *);
+int vps_proc_signal(struct vps *, pid_t, int);
+
+int vps_reboot(struct thread *, int);
+int vps_shutdown_all(struct thread *);
+
+int vps_ioc_list(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_create(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_destroy(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_switch(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_switchwait(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_ifmove(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_suspend(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_resume(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_abort(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_snapshot(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_snapshot_finish(struct vps *, struct vps_dev_ctx *, u_long,
+    caddr_t, int, struct thread *);
+int vps_ioc_restore(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_argget(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_argset(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_getextinfo(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_fscalc(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_fscalcpath(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+int vps_ioc_getconsfd(struct vps *, struct vps_dev_ctx *, u_long, caddr_t,
+    int, struct thread *);
+
+void vps_priv_setdefault(struct vps *, struct vps_param *);
+int vps_priv_check(struct ucred *, int);
+struct vps_arg_item;
+int vps_priv_setitem(struct vps *, struct vps *, struct vps_arg_item *);
+int vps_priv_getitemall(struct vps *, struct vps *, caddr_t, size_t *);
+int vps_ip_setitem(struct vps *, struct vps *, struct vps_arg_item *);
+int vps_ip_getitemall(struct vps *, struct vps *, caddr_t, size_t *);
+struct in_addr;
+struct in6_addr;
+int vps_ip4_check(struct vps *, struct in_addr *, struct in_addr *);
+int vps_ip6_check(struct vps *, struct in6_addr *, u_int8_t);
+
+int vps_console_fdopen(struct cdev *, int, struct thread *, struct file *);
+int vps_console_init(void);
+int vps_console_uninit(void);
+int vps_console_alloc(struct vps *, struct thread *);
+int vps_console_free(struct vps *, struct thread *);
+int vps_console_getfd(struct vps *, struct thread *, int *);
+
+int vps_unmount_all(struct vps *vps);
+
+/* machdep stuff */
+struct vps_dump_thread;
+struct execve_args;
+void vps_md_print_thread(struct thread *td);
+void vps_md_print_pcb(struct thread *td);
+int vps_md_restore_thread(struct vps_dump_thread *vdtd, struct thread *ntd, struct proc *p);
+int vps_md_snapshot_sysentvec(struct sysentvec *sv, long *svtype);
+int vps_md_restore_sysentvec(long svtype, struct sysentvec **sv);
+int vps_md_restore_checkarch(u_int8_t ptrsize, u_int8_t byteorder);
+int vps_md_snapshot_thread_savefpu(struct vps_snapst_ctx *ctx, struct vps *vps, struct thread *td);
+int vps_md_restore_thread_savefpu(struct vps_snapst_ctx *ctx, struct vps *vps, struct thread *td);
+int vps_md_reboot_copyout(struct thread *td, struct execve_args *);
+int vps_md_syscall_fixup(struct vps *, struct thread *,
+    register_t *ret_code, register_t **ret_args, int *narg);
+int vps_md_syscall_fixup_setup_inthread(struct vps *, struct thread *, register_t);
+
+
+extern struct sx vps_all_lock;
+
+/*
+ * Flags used in vnet by vps.
+ */
+#define VPS_VNET_SUSPENDED	0x1000
+#define VPS_VNET_ABORT		0x2000
+
+/*
+ * Various vps internal flags.
+ */
+
+#endif /* VPS */
+
+/*
+ * At least for now, just use vnet's facility for virtualized
+ * global variables.
+ * But map to our own names for easier change in the future.
+ */
+
+#define VPS_NAME			VNET_NAME
+#define VPS_DECLARE			VNET_DECLARE
+#define VPS_DEFINE			VNET_DEFINE
+
+#define SYSCTL_VPS_INT			SYSCTL_VNET_INT
+#define SYSCTL_VPS_PROC			SYSCTL_VNET_PROC
+#define SYSCTL_VPS_STRING		SYSCTL_VNET_STRING
+#define SYSCTL_VPS_STRUCT		SYSCTL_VNET_STRUCT
+#define SYSCTL_VPS_UINT			SYSCTL_VNET_UINT
+#define SYSCTL_VPS_LONG			SYSCTL_VNET_LONG
+#define SYSCTL_VPS_ULONG		SYSCTL_VNET_ULONG
+
+#define vps_sysctl_handle_int		vnet_sysctl_handle_int
+#define vps_sysctl_handle_opaque	vnet_sysctl_handle_opaque
+#define vps_sysctl_handle_string	vnet_sysctl_handle_string
+#define vps_sysctl_handle_uint		vnet_sysctl_handle_uint
+
+/*
+ * Declare virtualized globals.
+ */
+
+#define      HOSTUUIDLEN     64
+
+VPS_DECLARE(char, hostname[MAXHOSTNAMELEN]);
+VPS_DECLARE(char, domainname[MAXHOSTNAMELEN]);
+VPS_DECLARE(char, hostuuid[HOSTUUIDLEN]);
+
+#endif /* _VPS2_H */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_account.c head/sys/vps/vps_account.c
--- clean-head/sys/vps/vps_account.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_account.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,1080 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: vps_account.c 153 2013-06-03 16:18:17Z klaus $";
+
+/*
+ * Resource accounting and limiting.
+ *
+ * This is an attempt to quickly provide a working solution rather
+ * than implementing the most perfect scheduling algorithms.
+ *
+ */
+
+#include "opt_ddb.h"
+#include "opt_global.h"
+
+#ifdef VPS
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/limits.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/libkern.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/ucred.h>
+#include <sys/ioccom.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/fcntl.h>
+#include <sys/namei.h>
+#include <sys/syscallsubr.h>
+#include <sys/resourcevar.h>
+#include <sys/sched.h>
+#include <sys/smp.h>
+#include <sys/kthread.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_extern.h>
+
+#include <fs/vpsfs/vpsfs.h>
+
+#include "vps_account.h"
+#include "vps_user.h"
+#include "vps.h"
+#include "vps2.h"
+
+/* kern/vfs_bio.c */
+int vps_bio_runningbufspace_high(void);
+
+#ifdef DIAGNOSTIC
+
+#define DBGACC if (vps_debug_acc) printf
+
+int vps_debug_acc = 1;
+SYSCTL_INT(_debug, OID_AUTO, vps_account_debug, CTLFLAG_RW,
+    &vps_debug_acc, 0, "");
+
+#else
+
+#define DBGACC(x, ...)
+
+#endif /* DIAGNOSTIC */
+
+SYSCTL_NODE(, OID_AUTO, vps, CTLFLAG_RD, NULL, "Virtual Private Systems");
+SYSCTL_NODE(_vps, OID_AUTO, acc, CTLFLAG_RD, NULL, "Limits and Accounting");
+
+/*
+static VPS_DEFINE(size_t, acc_kmem) = 0;
+#define V_acc_kmem	VPS(acc_kmem)
+
+SYSCTL_VPS_UINT(_vps_acc, OID_AUTO, kmem, CTLFLAG_RD,
+    &VPS_NAME(acc_kmem), 0, "");
+*/
+
+/* Interval between calls to vps_account_threads() in microseconds. */
+/* XXX determine a good default value */
+static u_int vps_account_threads_interval = 100*1000;
+SYSCTL_UINT(_vps_acc, OID_AUTO, account_threads_interval, CTLFLAG_RW,
+	&vps_account_threads_interval, 0,
+	"Interval for thread accounting in microseconds");
+
+struct mtx vps_pfault_mtx;
+struct rqhead vps_paused_threads_head;
+
+static u_int vps_account_suspensions;
+static u_int vps_account_failedsuspensions;
+struct sx vps_account_threads_sx;
+struct mtx vps_account_pausedqueue_mtx;
+struct task vps_account_threads_task;
+static struct proc *vps_account_kproc_p;
+static int vps_account_exit;
+
+static fixpt_t vps_account_cpu_idlepct;
+static u_long vps_account_cpu_last;
+static long vps_account_cpu_updated;
+
+static int _vps_account2(struct vps *, int, int, size_t);
+static void vps_account_check_threads(void);
+static void vps_account_thread_resume(struct thread *td);
+void vps_account_threads2(void *, int);
+void vps_account_kproc(void *);
+
+/*
+int (*vpsfs_calcusage_path_p)(const char *, struct vpsfs_limits *) = NULL;
+*/
+
+int
+vps_account_init(void)
+{
+	int error;
+
+	vps_account_suspensions = vps_account_failedsuspensions = 0;
+
+	mtx_init(&vps_pfault_mtx, "vps accounting page mutex",
+	    NULL, MTX_DEF);
+
+	sx_init(&vps_account_threads_sx, "vps accounting threads lock");
+
+	mtx_init(&vps_account_pausedqueue_mtx, "vps accounting paused "
+	    "queue lock", NULL, MTX_SPIN);
+
+	TAILQ_INIT(&vps_paused_threads_head);
+
+	error = kproc_create(vps_account_kproc, NULL, &vps_account_kproc_p,
+		0, 0, "vps_account");
+	KASSERT(error == 0, ("%s: kproc_create() error=%d\n",
+	    __func__, error));
+
+	vps_func->vps_account = _vps_account;
+	vps_func->vps_account_waitpfault = _vps_account_waitpfault;
+	vps_func->vps_account_bio = _vps_account_bio;
+	vps_func->vps_account_stats = _vps_account_stats;
+	vps_func->vps_account_runnable = _vps_account_runnable;
+	vps_func->vps_account_thread_pause = _vps_account_thread_pause;
+	vps_func->vps_limit_setitem = _vps_limit_setitem;
+	vps_func->vps_limit_getitemall = _vps_limit_getitemall;
+
+	return (0);
+}
+
+/*
+SYSINIT(vps_account, SI_SUB_RUN_SCHEDULER, SI_ORDER_ANY,
+    vps_account_init, NULL);
+*/
+
+int
+vps_account_uninit(void)
+{
+	struct thread *td, *td2;
+	struct vps *vps;
+
+	/* Tell kproc to exit. */
+	vps_account_exit = 1;
+
+	tsleep(vps_account_kproc_p, 0, "uninit", 0);
+
+	/* Wakeup vps instances that might sleep for resources. */
+	sx_slock(&vps_all_lock);
+	LIST_FOREACH(vps, &vps_head, vps_all)
+		wakeup(vps);
+	sx_sunlock(&vps_all_lock);
+
+	/* Resume paused threads. */
+	mtx_lock_spin(&vps_account_pausedqueue_mtx);
+	TAILQ_FOREACH_SAFE(td, &vps_paused_threads_head, td_runq, td2) {
+		mtx_unlock_spin(&vps_account_pausedqueue_mtx);
+		thread_lock(td);
+		if (td->td_flags & TDF_VPSLIMIT)
+			vps_account_thread_resume(td);
+		thread_unlock(td);
+		mtx_lock_spin(&vps_account_pausedqueue_mtx);
+	}
+	mtx_unlock_spin(&vps_account_pausedqueue_mtx);
+
+	vps_func->vps_account = NULL;
+	vps_func->vps_account_waitpfault = NULL;
+	vps_func->vps_account_bio = NULL;
+	vps_func->vps_account_stats = NULL;
+	vps_func->vps_account_runnable = NULL;
+	vps_func->vps_account_thread_pause = NULL;
+	vps_func->vps_limit_setitem = NULL;
+	vps_func->vps_limit_getitemall = NULL;
+
+	mtx_destroy(&vps_account_pausedqueue_mtx);
+	sx_destroy(&vps_account_threads_sx);
+	mtx_destroy(&vps_pfault_mtx);
+
+	return (0);
+}
+
+void
+vps_account_kproc(void *dummy)
+{
+
+	for (;;) {
+		vps_account_threads(NULL);
+		pause("pause", vps_account_threads_interval /
+		    (1000000 / hz));
+		if (vps_account_exit != 0)
+			kproc_exit(0);
+	}
+}
+
+int
+_vps_account(struct vps *vps, int type, int action, size_t size)
+{
+	return (_vps_account2(vps, type, action, size));
+}
+
+int
+_vps_account2(struct vps *vps, int type, int action, size_t size)
+{
+	struct vps_acc_val *val;
+	int error;
+
+	if (vps == NULL)
+		return (0);
+
+	switch (type) {
+		case VPS_ACC_VIRT:
+			val = &vps->vps_acc->virt;
+			break;
+		case VPS_ACC_PHYS:
+			val = &vps->vps_acc->phys;
+			break;
+		case VPS_ACC_KMEM:
+			val = &vps->vps_acc->kmem;
+			break;
+		case VPS_ACC_KERNEL:
+			val = &vps->vps_acc->kernel;
+			break;
+		case VPS_ACC_BUFFER:
+			val = &vps->vps_acc->buffer;
+			break;
+		case VPS_ACC_THREADS:
+			val = &vps->vps_acc->threads;
+			break;
+		case VPS_ACC_PROCS:
+			val = &vps->vps_acc->procs;
+			break;
+		/* not handled here
+		case VPS_ACC_PCTCPU:
+			val = &vps->vps_acc->pctcpu;
+			break;
+		*/
+		default:
+			printf("%s: unkown type %d\n", __func__, type);
+			return (ENOENT);
+			break;
+	}
+
+	mtx_lock_spin(&vps->vps_acc->lock);
+
+	/*
+	if (vps != vps0 && type==VPS_ACC_PHYS)
+		DBGACC("%s: pid=%d type=%d %zu %s %zu\n",
+			__func__, curthread->td_proc->p_pid, type,
+			val->cur, action==VPS_ACC_ALLOC ? "+" : "-", size);
+	*/
+
+	error = 0;
+
+	switch (action) {
+		case VPS_ACC_ALLOC:
+			if (val->hard == 0 && val->soft == 0) {
+				/* No limits, skip checks. */
+				val->cur += size;
+			} else
+			if (val->cur + size > val->hard) {
+				DBGACC("%s: type=%d hit hard limit cur=%zu "
+				    "soft=%zu hard=%zu size=%zu\n",
+				    __func__, type, val->cur, val->soft,
+				    val->hard, size);
+				++val->hits_hard;
+				error = ENOMEM;
+				/* XXX for some values ENOSPC might be
+				   more appropriate. */
+			} else
+			if (val->cur + size > val->soft) {
+				DBGACC("%s: type=%d hit soft limit cur=%zu "
+				    "soft=%zu hard=%zu size=%zu\n",
+				    __func__, type, val->cur, val->soft,
+				    val->hard, size);
+				val->cur += size;
+				++val->hits_soft;
+			} else {
+				/* below limits */
+				val->cur += size;
+			}
+			break;
+		case VPS_ACC_FREE:
+			val->cur -= size;
+			break;
+		default:
+			printf("%s: unkown action %d, type=%d size=%zu\n",
+				__func__, type, action, size);
+			break;
+	}
+
+	/*
+	if (type == VPS_ACC_VIRT && vps != vps0) {
+		DBGACC("%s: VPS_ACC_VIRT: %s %lx  --> %lx\n",
+			__func__,
+			action == VPS_ACC_ALLOC ? "ALLOC" : "FREE",
+			size,
+			val->cur);
+	}
+	*/
+
+	if (error == 0)
+		val->updated = ticks;
+
+	/* XXX only call if someone's waiting */
+	if (type == VPS_ACC_PHYS &&
+	    (val->cur < val->hard || (val->hard == 0 && val->soft == 0) ) )
+		wakeup(vps);
+
+	mtx_unlock_spin(&vps->vps_acc->lock);
+
+	return (error);
+}
+
+/*
+ * Called by vm_fault() if vps instance is currently not allowed to allocate
+ * more pages (physical memory).
+ *
+ * This will always lead to situation where the entire vps instance
+ * locks up, until either
+ * - the limit is raised
+ * - the limit is deactivated (zero)
+ *   (XXX have to do wakeup after setting new limit)
+ * - processes unmap (?) memory or exit.
+ *
+ * Or ...
+ */
+
+#if 0
+
+void
+_vps_account_waitpfault(struct vps *vps)
+{
+	mtx_lock(&vps_pfault_mtx);
+
+	msleep(vps, &vps_pfault_mtx, PDROP | PUSER, "pfault", 0);
+}
+
+#else
+
+/*
+ * Killing the biggest process in vps instance.
+ */
+
+/* Copied and adapted vm_pageout_oom(). */
+int
+_vps_account_waitpfault(struct vps *vps)
+{
+	struct proc *p, *bigproc;
+	vm_offset_t size, bigsize;
+	struct thread *td;
+	struct vmspace *vm;
+	int breakout;
+
+	bigproc = NULL;
+	bigsize = 0;
+
+	sx_slock(&VPS_VPS(vps, allproc_lock));
+	LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list) {
+
+		if (PROC_TRYLOCK(p) == 0)
+			continue;
+
+		if (p->p_state != PRS_NORMAL ||
+		    (p->p_flag & (P_INEXEC | P_PROTECTED | P_SYSTEM)) ||
+		    P_KILLED(p)) {
+			PROC_UNLOCK(p);
+			continue;
+		}
+
+		breakout = 0;
+		FOREACH_THREAD_IN_PROC(p, td) {
+			thread_lock(td);
+			if (!TD_ON_RUNQ(td) &&
+			    !TD_IS_RUNNING(td) &&
+			    !TD_IS_SLEEPING(td) &&
+			    !TD_IS_SUSPENDED(td)) {
+				thread_unlock(td);
+				breakout = 1;
+				break;
+			}
+			thread_unlock(td);
+		}
+		if (breakout) {
+			PROC_UNLOCK(p);
+			continue;
+		}
+
+		vm = vmspace_acquire_ref(p);
+		if (vm == NULL) {
+			PROC_UNLOCK(p);
+			continue;
+		}
+		if (!vm_map_trylock_read(&vm->vm_map)) {
+			vmspace_free(vm);
+			PROC_UNLOCK(p);
+			continue;
+		}
+		size = vmspace_swap_count(vm);
+		vm_map_unlock_read(&vm->vm_map);
+		size += vmspace_resident_count(vm);
+		vmspace_free(vm);
+
+		if (size > bigsize) {
+			if (bigproc != NULL)
+				PROC_UNLOCK(bigproc);
+			bigproc = p;
+			bigsize = size;
+		} else
+			PROC_UNLOCK(p);
+	}
+	sx_sunlock(&VPS_VPS(vps, allproc_lock));
+
+	if (bigproc != NULL) {
+		killproc(bigproc, "enforcing vps mem limit");
+		sched_nice(bigproc, PRIO_MIN);
+		PROC_UNLOCK(bigproc);
+	}
+
+	/* vm_fault() will abort we killed curproc, otherwise retry. */
+	if (bigproc == curproc)
+		return (1);
+	else
+		return (0);
+}
+
+#endif /* 0 */
+
+static
+void
+vps_account_bio_update(struct vps *vps)
+{
+	struct vps_acc_val *val;
+	size_t newval;
+
+	val = &vps->vps_acc->blockio;
+
+	if (((ticks - val->updated) / hz) == 0)
+		return;
+
+	/*
+	 * This is supposed to represent a sort of ''sliding window''
+	 * calculation.
+	 */
+	newval = (val->cnt_cur / ((ticks - val->updated) / hz));
+	val->cur = (newval + val->cur * 2) / 3;
+	val->cnt_cur = 0;
+	val->updated = ticks;
+
+	/*
+	DBGACC("%s: vps=%p [%s] blockio rate=%zu/sec val->cnt_cur=%zu "
+	    "val->updated=%d\n", __func__, vps, vps->vps_name, val->cur,
+	    val->cnt_cur, val->updated);
+	*/
+}
+
+/*
+ * XXX Attaching to vfs_aio !
+ */
+int
+_vps_account_bio(struct thread *td)
+{
+	struct vps_acc_val *val;
+	struct vps *vps;
+	int wait;
+
+	vps = td->td_vps;
+
+	if (vps == NULL || vps->vps_acc == NULL)
+		return (0);
+
+	mtx_lock_spin(&vps->vps_acc->lock);
+
+ retry:
+	val = &vps->vps_acc->blockio;
+
+	if (val->soft == 0 && val->hard == 0) {
+		wait = 0;
+	} else if (val->cur > val->hard) {
+		wait = 1;
+	} else if (val->cur > val->soft) {
+		/* Allow in case global I/O load (XXX or per device??)
+		   is moderate. */
+		if (vps_bio_runningbufspace_high())
+			wait = 1;
+		else
+			wait = 0;
+	} else {
+		wait = 0;
+	}
+
+	if (wait != 0) {
+		/*
+		DBGACC("%s: td=%p [%d] waiting\n",
+		    __func__, td, td->td_tid);
+		*/
+		mtx_unlock_spin(&vps->vps_acc->lock);
+		pause("vpsbio", hz);
+		mtx_lock_spin(&vps->vps_acc->lock);
+		vps_account_bio_update(vps);
+		goto retry;
+	}
+
+	++val->cnt_cur;
+
+	if ((ticks - val->updated) > hz)
+		vps_account_bio_update(vps);
+
+	mtx_unlock_spin(&vps->vps_acc->lock);
+
+	return (0);
+}
+
+/*
+ * Calculate cpu utilization.
+ *
+ * sched_pctcpu() * 100 / FSCALE == utilization in percent
+ *
+ * XXX: It isn't really doing what I expected.
+ *      The sum of pctcpu for all threads of a VPS is kept quite
+ *      close to the limit, but the real cpu utilization (monitored
+ *      in the vmware esx gui) increases with the number of active
+ *      threads ...
+ *
+ */
+void
+vps_account_threads(void *dummy)
+{
+	struct vps *vps;
+	struct thread *td;
+	struct proc *p;
+	fixpt_t pctcpu;
+	fixpt_t cpuvpstot;
+	fixpt_t biovpstot;
+	long cpu_time[CPUSTATES];
+	long ticks_delta;
+	int threads;
+
+	/*
+	 * Never run more than once at the same time.
+	 */
+	if (sx_try_xlock(&vps_account_threads_sx) == 0)
+		return;
+
+	/*
+	 * If we modify curthread->td_vps here,
+	 * we might pause ourselves ...
+	 */
+
+	threads = 0;
+	cpuvpstot = 0;
+	biovpstot = 0;
+
+	sx_slock(&vps_all_lock);
+	LIST_FOREACH(vps, &vps_head, vps_all) {
+		threads = 0;
+		cpuvpstot = 0;
+
+		//sx_slock(&vps->_proctree_lock);
+		sx_slock(&VPS_VPS(vps, allproc_lock));
+		LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list) {
+			if (p->p_state != PRS_NORMAL)
+				continue;
+			/*
+			if (p->p_flag & P_SYSTEM)
+				continue;
+			*/
+			PROC_LOCK(p);
+			TAILQ_FOREACH(td, &p->p_threads, td_plist) {
+
+				thread_lock(td);
+				++threads;
+				pctcpu = sched_pctcpu(td);
+				/* XXX Why not account P_SYSTEM procs ? */
+				if ((p->p_flag & P_SYSTEM) == 0)
+					cpuvpstot += pctcpu;
+				thread_unlock(td);
+			}
+			PROC_UNLOCK(p);
+		}
+		//sx_sunlock(&vps->_proctree_lock);
+		sx_sunlock(&VPS_VPS(vps, allproc_lock));
+
+		mtx_lock_spin(&vps->vps_acc->lock);
+
+		vps->vps_acc->pctcpu.cur = cpuvpstot;
+		vps->vps_acc->pctcpu.updated = ticks;
+
+		vps->vps_acc->nthreads.cur = threads;
+		vps->vps_acc->nthreads.updated = ticks;
+
+		/*
+		 * Make sure blockio stats get updated at least
+		 * every 4 seconds.
+		 */
+		if (vps->vps_acc->blockio.cur > 0 &&
+		    ((ticks - vps->vps_acc->blockio.updated) > (hz * 4)))
+			vps_account_bio_update(vps);
+
+		mtx_unlock_spin(&vps->vps_acc->lock);
+
+		/*
+		DBGACC("%s: vps=%p [%s] threads=%d cpuvpstot=%u\n",
+			__func__, vps, vps->vps_name, threads, cpuvpstot);
+		*/
+	}
+	sx_sunlock(&vps_all_lock);
+
+	/* Calculate global cpu idle time. */
+	/* XXX handle counter wrap */
+	read_cpu_time(cpu_time);
+	ticks_delta = ticks - vps_account_cpu_updated;
+	if (ticks_delta > 0) {
+		vps_account_cpu_idlepct = ((cpu_time[4] -
+		    vps_account_cpu_last) * FSCALE) / ticks_delta;
+	} else {
+		printf("%s: WARNING: ticks=%d "
+		    "vps_account_cpu_updated=%ld\n",
+		    __func__, ticks, vps_account_cpu_updated);
+	}
+	vps_account_cpu_last = cpu_time[4];
+	vps_account_cpu_updated = ticks;
+
+	vps_account_check_threads();
+
+	sx_unlock(&vps_account_threads_sx);
+}
+
+void
+_vps_account_thread_pause(struct thread *td)
+{
+
+	/*
+	 * We can't call sched_rem() because thread is already
+	 * removed from run queue.
+	 */
+
+	thread_lock(td);
+	TD_SET_CAN_RUN(td);
+	sched_rem_norunq(td);
+	thread_unlock(td);
+
+	mtx_lock_spin(&vps_account_pausedqueue_mtx);
+	/* Thread is already off the run queues. */
+	td->td_flags |= TDF_VPSLIMIT;	/* XXX _Should_ be protected
+					   by thread_lock */
+	TAILQ_INSERT_TAIL(&vps_paused_threads_head, td, td_runq);
+	mtx_unlock_spin(&vps_account_pausedqueue_mtx);
+	//DBGACC("%s: paused thread=%p/%d\n", __func__, td, td->td_tid);
+}
+
+static void
+vps_account_thread_resume(struct thread *td)
+{
+
+	THREAD_LOCK_ASSERT(td, MA_OWNED);
+
+	TAILQ_REMOVE(&vps_paused_threads_head, td, td_runq);
+	td->td_flags &= ~TDF_VPSLIMIT;
+	mtx_unlock_spin(&vps_account_pausedqueue_mtx);
+
+	sched_add(td, SRQ_BORING);
+	//DBGACC("%s: resumed thread=%p/%d\n", __func__, td, td->td_tid);
+
+}
+
+static void
+vps_account_check_threads(void)
+{
+	struct thread *td, *td2;
+
+	mtx_lock_spin(&vps_account_pausedqueue_mtx);
+	TAILQ_FOREACH_SAFE(td, &vps_paused_threads_head, td_runq, td2) {
+		mtx_unlock_spin(&vps_account_pausedqueue_mtx);
+		thread_lock(td);
+		if (_vps_account_runnable(td)) {
+			/* If TDF_VPSLIMIT is missing thread is
+			   already removed. */
+			mtx_lock_spin(&vps_account_pausedqueue_mtx);
+			if (td->td_flags & TDF_VPSLIMIT)
+				vps_account_thread_resume(td);
+			else
+				mtx_unlock_spin(
+				    &vps_account_pausedqueue_mtx);
+		}
+		thread_unlock(td);
+		mtx_lock_spin(&vps_account_pausedqueue_mtx);
+	}
+	mtx_unlock_spin(&vps_account_pausedqueue_mtx);
+}
+
+int
+_vps_account_runnable(struct thread *td)
+{
+	struct vps_acc *vacc;
+	struct vps *vps;
+	int rc;
+
+	rc = 1;
+
+	if (td->td_vps_acc == NULL)
+		return (1);
+
+	vacc = td->td_vps_acc;
+	vps = vacc->vps;
+
+	KASSERT(vps->vps_status != VPS_ST_DEAD,
+		("%s: vps=%p [%s] state=VPS_ST_DEAD, td=%p\n",
+		__func__, vps, vps->vps_name, td));
+
+	mtx_lock_spin(&vacc->lock);
+	if (vacc->pctcpu.soft == 0 && vacc->pctcpu.hard == 0) {
+		rc = 1;
+		goto out;
+	} else
+	/* Check if this thread is not one of the big cpu-consumers. */
+	if (vacc->nthreads.cur > 0 &&
+	   sched_pctcpu(td) < (vacc->pctcpu.cur / vacc->nthreads.cur)) {
+		rc = 1;
+		goto out;
+	} else
+	if (vacc->pctcpu.cur > vacc->pctcpu.hard) {
+		/* Don't run it. */
+		rc = 0;
+		goto out;
+	} else
+	if (vacc->pctcpu.cur > vacc->pctcpu.soft) {
+		/* If there's idle cpu time let it run. */
+		if (vps_account_cpu_idlepct > (FSCALE / 8))
+			rc = 1;
+		else
+			rc = 0;
+		goto out;
+	}
+
+ out:
+	/*
+	 * In case the thread has locks run it anyway.
+	 * Otherwise we introduce performance loss and blow up the system.
+	 *
+	 * If td was preempted while being in kernel mode,
+	 * TDF_PREEMPTED is set.
+	 * In this case we can't and don't want to keep td from running.
+	 */
+	if (rc == 0 && ((td->td_flags & TDF_PREEMPTED) || TD_ON_LOCK(td))) {
+		/*
+		DBGACC("%s: td=%p [%d][%s] is not to be run but was "
+		    "preempted or is on lock!\n",
+		    __func__, td, td->td_tid, td->td_proc->p_comm);
+		*/
+		rc = 1;
+		++vps_account_failedsuspensions;
+	}
+
+	if (rc == 0)
+		++vps_account_suspensions;
+
+	mtx_unlock_spin(&vacc->lock);
+
+	return (rc);
+}
+
+void
+_vps_account_stats(struct vps *vps)
+{
+	struct vps_acc *va;
+
+#ifdef DIAGNOSTIC
+	if (vps_debug_acc == 0)
+		return;
+#endif
+
+	va = vps->vps_acc;
+
+	mtx_lock_spin(&vps->vps_acc->lock);
+
+	printf("%s: vps=%p\n", __func__, vps);
+	printf("%s: virt=%zu\n", __func__, va->virt.cur);
+	printf("%s: phys=%zu\n", __func__, va->phys.cur);
+	/*
+	printf("%s: kmem=%zu (0-kmem=%zu)\n", __func__,
+	    va->kmem.cur, 0 - va->kmem.cur);
+	printf("%s: kernel=%zu (0-kernel=%zu)\n", __func__,
+	    va->kernel.cur, 0 - va->kernel.cur);
+	printf("%s: buffer=%zu (0-buffer=%zu)\n", __func__,
+	    va->buffer.cur, 0 - va->buffer.cur);
+	*/
+	printf("%s: pctcpu=%zu\n", __func__, va->pctcpu.cur);
+	printf("%s: blockio=%zu\n", __func__, va->blockio.cur);
+	printf("%s: threads=%zu\n", __func__, va->threads.cur);
+	printf("%s: procs=%zu\n", __func__, va->procs.cur);
+	printf("%s: ---------------\n", __func__);
+
+	mtx_unlock_spin(&vps->vps_acc->lock);
+}
+
+int
+_vps_limit_setitem(struct vps *vpsp, struct vps *vps,
+    struct vps_arg_item *item)
+{
+	struct vps_acc_val *val;
+	int error;
+
+	if (item->type != VPS_ARG_ITEM_LIMIT)
+		return (EINVAL);
+
+	if (vps->vps_acc == NULL)
+		return (EINVAL);
+
+	error = 0;
+	mtx_lock_spin(&vps->vps_acc->lock);
+
+	switch (item->u.limit.resource) {
+	case VPS_ACC_VIRT:
+		val = &vps->vps_acc->virt;
+		break;
+	case VPS_ACC_PHYS:
+		val = &vps->vps_acc->phys;
+		break;
+	case VPS_ACC_KMEM:
+		val = &vps->vps_acc->kmem;
+		break;
+	case VPS_ACC_KERNEL:
+		val = &vps->vps_acc->kernel;
+		break;
+	case VPS_ACC_BUFFER:
+		val = &vps->vps_acc->buffer;
+		break;
+	case VPS_ACC_PCTCPU:
+		val = &vps->vps_acc->pctcpu;
+		break;
+	case VPS_ACC_BLOCKIO:
+		val = &vps->vps_acc->blockio;
+		break;
+	case VPS_ACC_THREADS:
+		val = &vps->vps_acc->threads;
+		break;
+	case VPS_ACC_PROCS:
+		val = &vps->vps_acc->procs;
+		break;
+	default:
+		error = EINVAL;
+		goto out;
+		break;
+	}
+
+	/*
+	 * XXX
+	 * For hierarchical resource limits check
+	 * new limits against parent vps etc.
+	 */
+
+	val->soft = item->u.limit.soft;
+	val->hard = item->u.limit.hard;
+
+ out:
+	mtx_unlock_spin(&vps->vps_acc->lock);
+
+	return (error);
+}
+
+#define FILL(x, y, res) 					\
+	do {							\
+	(x)->type = VPS_ARG_ITEM_LIMIT;				\
+	(x)->u.limit.resource = res;				\
+	(x)->u.limit.cur = (y)->cur;				\
+	(x)->u.limit.soft = (y)->soft;				\
+	(x)->u.limit.hard = (y)->hard;				\
+	(x)->u.limit.hits_soft = (y)->hits_soft;		\
+	(x)->u.limit.hits_hard = (y)->hits_hard;		\
+	} while (0);
+
+int
+_vps_limit_getitemall(struct vps *vpsp, struct vps *vps,
+    caddr_t kdata, size_t *kdatalen)
+{
+	struct vps_arg_item *item;
+	int cnt;
+
+	if (vps->vps_acc == NULL) {
+		*kdatalen = 0;
+		return (0);
+	}
+
+	/* !!! */
+	cnt = 6;
+
+	if ((sizeof (*item) * cnt) > *kdatalen)
+		return (ENOSPC);
+
+	item = (struct vps_arg_item *)kdata;
+	memset(item, 0, sizeof (*item) * cnt);
+
+	mtx_lock_spin(&vps->vps_acc->lock);
+
+	FILL(item, &vps->vps_acc->virt, VPS_ACC_VIRT);
+	item++;
+	FILL(item, &vps->vps_acc->phys, VPS_ACC_PHYS);
+	item++;
+	/*
+	FILL(item, &vps->vps_acc->kmem, VPS_ACC_KMEM);
+	item++;
+	FILL(item, &vps->vps_acc->kernel, VPS_ACC_KERNEL);
+	item++;
+	FILL(item, &vps->vps_acc->buffer, VPS_ACC_BUFFER);
+	item++;
+	*/
+	FILL(item, &vps->vps_acc->pctcpu, VPS_ACC_PCTCPU);
+	item++;
+	FILL(item, &vps->vps_acc->blockio, VPS_ACC_BLOCKIO);
+	item++;
+	FILL(item, &vps->vps_acc->threads, VPS_ACC_THREADS);
+	item++;
+	FILL(item, &vps->vps_acc->procs, VPS_ACC_PROCS);
+	item++;
+
+	mtx_unlock_spin(&vps->vps_acc->lock);
+
+	*kdatalen = sizeof (*item) * cnt;
+	return (0);
+}
+
+#undef FILL
+
+void
+vps_account_print_pctcpu(struct vps *vps)
+{
+	struct proc *p;
+	struct thread *td;
+	int threads;
+	fixpt_t vpstot, pctcpu;
+
+	threads = 0;
+	vpstot = 0;
+
+	//sx_slock(&vps->_proctree_lock);
+	sx_slock(&VPS_VPS(vps, allproc_lock));
+	LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list) {
+		if (p->p_flag & P_SYSTEM)
+			continue;
+		PROC_LOCK(p);
+		TAILQ_FOREACH(td, &p->p_threads, td_plist) {
+			thread_lock(td);
+			++threads;
+			pctcpu = sched_pctcpu(td);
+			thread_unlock(td);
+			vpstot += pctcpu;
+			printf("%s: td=%p tid=%d pctcpu=%u\n",
+				__func__, td, td->td_tid, pctcpu);
+		}
+		PROC_UNLOCK(p);
+	}
+	//sx_sunlock(&vps->_proctree_lock);
+	sx_sunlock(&VPS_VPS(vps, allproc_lock));
+
+	printf("%s: vps=%p [%s] threads=%d vpstot=%u\n",
+		__func__, vps, vps->vps_name, threads, vpstot);
+}
+
+int
+vps_account_vpsfs_calc_mount(struct vps *vps, struct mount *mp,
+    caddr_t kdata, size_t *kdatalen)
+{
+
+	return (EOPNOTSUPP);
+}
+
+int
+vps_account_vpsfs_calc_path(struct vps *vps, const char *path,
+    caddr_t kdata, size_t *kdatalen)
+{
+	struct vpsfs_limits *usage;
+	struct vps_arg_item *item;
+	int error;
+
+	if (vps_func->vpsfs_calcusage_path == NULL)
+		return (EOPNOTSUPP);
+
+	usage = malloc(sizeof(*usage), M_TEMP, M_WAITOK | M_ZERO);
+
+	if ((error = vps_func->vpsfs_calcusage_path(path, usage))) {
+		free(usage, M_TEMP);
+		return (error);
+	}
+
+	item = (struct vps_arg_item *)kdata;
+        item->type = VPS_ARG_ITEM_LIMIT;
+        item->u.limit.resource = VPS_ACC_FSSPACE;
+        item->u.limit.cur = usage->space_used;
+        item++;
+        item->type = VPS_ARG_ITEM_LIMIT;
+        item->u.limit.resource = VPS_ACC_FSFILES;
+        item->u.limit.cur = usage->nodes_used;
+        item++;
+        *kdatalen = ((caddr_t)item) - kdata;
+
+	free(usage, M_TEMP);
+	return (0);
+}
+
+static int
+vps_account_modevent(module_t mod, int type, void *data)
+{
+	int error;
+
+	switch (type) {
+	case MOD_LOAD:
+	    error = vps_account_init();
+	    break;
+	case MOD_UNLOAD:
+	    error = vps_account_uninit();
+	    break;
+	default:
+	    error = EOPNOTSUPP;
+	    break;
+	}
+	return (error);
+}
+
+static moduledata_t vps_account_mod = {
+	"vps_account",
+	vps_account_modevent,
+	0
+};
+
+DECLARE_MODULE(vps_account, vps_account_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_account.h head/sys/vps/vps_account.h
--- clean-head/sys/vps/vps_account.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_account.h	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,190 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: vps_account.h 153 2013-06-03 16:18:17Z klaus $ */
+
+#include <sys/cdefs.h>
+
+#ifndef _VPS_ACCOUNT_H
+#define _VPS_ACCOUNT_H
+
+#ifdef VPS
+
+#define VPS_ACC_ALLOC	0x2
+#define VPS_ACC_FREE	0x4
+
+#define VPS_ACC_UNUSED00	0x0001
+#define VPS_ACC_UNUSED01	0x0002
+#define VPS_ACC_VIRT		0x0004
+#define VPS_ACC_PHYS		0x0008
+#define VPS_ACC_KMEM		0x0010
+#define VPS_ACC_KERNEL		0x0020
+#define VPS_ACC_BUFFER		0x0040
+#define VPS_ACC_PCTCPU		0x0080
+#define VPS_ACC_BLOCKIO		0x0100
+#define VPS_ACC_FSSPACE		0x0200
+#define VPS_ACC_FSFILES		0x0400
+#define VPS_ACC_THREADS		0x0800
+#define VPS_ACC_PROCS		0x1000
+
+#ifdef _KERNEL
+
+#include <vps/vps_int.h>
+
+struct vps;
+struct mount;
+
+struct vps_acc_val {
+	/* Current accounting value (counter or rate). */
+	size_t cur;
+	/* For rate calculation. */
+	size_t cnt_cur;
+	/* Preconfigured soft limit (a warning is emitted when limit
+	    is hit). */
+	size_t soft;
+	/* Preconfigured hard limit (allocation is denied and error returned
+	    where possible). */
+	size_t hard;
+	/* Counter of exceeding the soft limit. */
+	u_int16_t hits_soft;
+	/* Counter of attempts exceeding the hard limit. */
+	u_int16_t hits_hard;
+	/* Last updated (ticks) */
+	int updated;
+};
+
+struct vps_acc {
+	struct mtx lock;
+	struct vps *vps;
+#define	vps_acc_first	virt
+	struct vps_acc_val virt;
+	struct vps_acc_val phys;
+	struct vps_acc_val kmem;
+	struct vps_acc_val kernel;
+	struct vps_acc_val buffer;
+	struct vps_acc_val pctcpu;
+	struct vps_acc_val blockio;
+	struct vps_acc_val threads;
+	struct vps_acc_val procs;
+	struct vps_acc_val nthreads;	/* Only a pseudo record
+					   for cpu accounting. */
+#define vps_acc_last	nthreads
+};
+
+int vps_account_init(void);
+int vps_account_uninit(void);
+int _vps_account(struct vps *, int, int, size_t);
+void _vps_account_stats(struct vps *);
+int _vps_account_waitpfault(struct vps *);
+void vps_account_threads(void *dummy);
+int _vps_account_runnable(struct thread *);
+void _vps_account_thread_pause(struct thread *);
+void vps_account_print_pctcpu(struct vps *);
+int _vps_account_bio(struct thread *);
+int vps_account_vpsfs_calc_path(struct vps *, const char *,
+    caddr_t, size_t *);
+int vps_account_vpsfs_calc_mount(struct vps *, struct mount *,
+    caddr_t, size_t *);
+struct vps_arg_item;
+int _vps_limit_setitem(struct vps *, struct vps *, struct vps_arg_item *);
+int _vps_limit_getitemall(struct vps *, struct vps *, caddr_t, size_t *);
+
+static __inline int
+vps_account(struct vps *vps, int type, int action, size_t size)
+{
+	if (vps_func->vps_account == NULL)
+		return (0);
+	return (vps_func->vps_account(vps, type, action, size));
+}
+
+static __inline int
+vps_account_waitpfault(struct vps *vps)
+{
+	if (vps_func->vps_account_waitpfault == NULL)
+		return (0);
+	return (vps_func->vps_account_waitpfault(vps));
+}
+
+static __inline int
+vps_account_bio(struct thread *td)
+{
+	if (vps_func->vps_account_bio == NULL)
+		return (0);
+	return (vps_func->vps_account_bio(td));
+}
+
+static __inline void
+vps_account_stats(struct vps *vps)
+{
+	if (vps_func->vps_account_stats == NULL)
+		return;
+	vps_func->vps_account_stats(vps);
+}
+
+static __inline int
+vps_account_runnable(struct thread *td)
+{
+	if (vps_func->vps_account_runnable == NULL)
+		return (1);
+	return (vps_func->vps_account_runnable(td));
+}
+
+static __inline void
+vps_account_thread_pause(struct thread *td)
+{
+	if (vps_func->vps_account_thread_pause == NULL)
+		return;
+	vps_func->vps_account_thread_pause(td);
+}
+
+static __inline int
+vps_limit_setitem(struct vps *vpsp, struct vps *vps,
+    struct vps_arg_item *item)
+{
+	if (vps_func->vps_limit_setitem == NULL)
+		return (EOPNOTSUPP);
+	return (vps_func->vps_limit_setitem(vpsp, vps, item));
+}
+
+static __inline int
+vps_limit_getitemall(struct vps *vpsp, struct vps *vps, caddr_t kdata,
+    size_t *kdatalen)
+{
+	if (vps_func->vps_limit_getitemall == NULL)
+		return (EOPNOTSUPP);
+	return (vps_func->vps_limit_getitemall(vpsp, vps, kdata, kdatalen));
+}
+
+#endif /* _KERNEL */
+
+#endif /* VPS */
+
+#endif /* _VPS_ACCOUNT_H */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_console.c head/sys/vps/vps_console.c
--- clean-head/sys/vps/vps_console.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_console.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,545 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: vps_console.c 161 2013-06-06 17:51:19Z klaus $";
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/limits.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/libkern.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/ucred.h>
+#include <sys/ioccom.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/fcntl.h>
+#include <sys/namei.h>
+#include <sys/syscallsubr.h>
+#include <sys/resourcevar.h>
+#include <sys/ttycom.h>
+#include <sys/tty.h>
+#include <sys/filedesc.h>
+#include <sys/kthread.h>
+#include <sys/poll.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <security/mac/mac_framework.h>
+
+#include "vps_user.h"
+#include "vps.h"
+#include "vps2.h"
+
+#define CF_OPENED 1
+
+MALLOC_DECLARE(M_VPS_CORE);
+
+static struct mtx vps_console_mtx;
+static struct proc *vps_console_kproc_p = NULL;
+static int vps_console_exit = 0;
+static void vps_console_kproc(void *);
+static void *vps_console_readbuf;
+static size_t vps_console_readbuf_len;
+
+static th_getc_capture_t vps_console_getc_capture;
+
+static struct ttyhook vps_console_hook = {
+	.th_getc_capture = vps_console_getc_capture,
+};
+
+/*
+ * VPS pseudo system console.
+ *
+ * Allocates a PTS TTY and exposes it as /dev/console and /dev/ttyv0
+ * to the VPS instance.
+ * It can be attached via the VPS_IOC_GETCONSFD ioctl.
+ * NOTE: Output processing is forced, always converting NL to CR-LF.
+ */
+
+static void
+vps_console_doread(struct thread *td, struct file *fp)
+{
+	struct iovec iovec;
+	struct uio auio;
+	int error;
+
+	DBGCORE("%s: td=%p fp=%p\n", __func__, td, fp);
+
+	KASSERT(vps_console_readbuf != NULL,
+		("%s: vps_console_readbuf == NULL\n", __func__));
+
+	memset(&auio, 0, sizeof(auio));
+	auio.uio_rw = UIO_READ;
+	auio.uio_td = td;
+	auio.uio_resid = vps_console_readbuf_len;
+	auio.uio_segflg = UIO_SYSSPACE;
+	auio.uio_iovcnt = 1;
+	auio.uio_iov = &iovec;
+	iovec.iov_base = vps_console_readbuf;
+	iovec.iov_len = vps_console_readbuf_len;
+
+	if ((error = fo_read(fp, &auio, td->td_ucred, 0, td)) != 0) {
+		DBGCORE("%s: fo_read(): %d\n",
+			__func__, error);
+	} else {
+		DBGCORE("%s: fo_read(): read %lu bytes\n",
+			__func__, vps_console_readbuf_len -
+			(long unsigned int)auio.uio_resid);
+	}
+}
+
+/*
+ * Kernel process.
+ * Reads away console data to avoid blocking userspace.
+ * When userspace readers are attached, it does nothing.
+ * Also clears the CF_OPENED flag when console has no readers.
+ */
+static void
+vps_console_kproc(void *dummy)
+{
+	struct selinfo *si;
+	struct seltd *stp;
+	struct selfd *sfp;
+	struct selfd *sfn;
+	struct thread *td;
+	struct vps *vps;
+	struct file *fp;
+	int ev, flags, n;
+	int error;
+
+	td = curthread;
+
+	seltdinit(td);
+
+	stp = td->td_sel;
+
+	vps_console_readbuf_len = 0x10000;
+	vps_console_readbuf = malloc(vps_console_readbuf_len,
+		M_VPS_CORE, M_WAITOK);
+
+	/*
+	DBGCORE("%s: stp->st_wait = %p\n", __func__, &stp->st_wait);
+	*/
+
+	for (;;) {
+
+		/* Scan */
+		n = 0;
+		sx_slock(&vps_all_lock);
+		LIST_FOREACH(vps, &vps_head, vps_all) {
+			fp = vps->console_fp_ma;
+			ev = 0;
+			if (fp != NULL) {
+				fhold(fp);
+				if (fp->f_count == 2) {
+					vps->console_flags &= ~CF_OPENED;
+					/*
+					DBGCORE("%s: vps=%p console_flags="
+					    %08x\n", __func__, vps,
+					    vps->console_flags);
+					*/
+				}
+				flags = POLLIN|POLLRDNORM;
+				selfdalloc(td, (void *)fp);
+				ev = fo_poll(fp, flags, td->td_ucred, td);
+				/*
+				DBGCORE("%s: scan: fp=%p, fp->f_count=%d, "
+				    "ev=%08x\n", __func__, fp, fp->f_count,
+				    ev);
+				*/
+				if (ev & POLLIN || ev & POLLRDNORM) {
+					/* Read possible now, not
+					   select record. */
+					if (fp->f_count == 2)
+						vps_console_doread(td, fp);
+					fdrop(fp, td);
+				} else {
+					/* Select record created. */
+					n += 1;
+				}
+			}
+		}
+		sx_sunlock(&vps_all_lock);
+
+		if (n != 0) {
+			sbintime_t asbt, precision, rsbt;
+
+                        rsbt = SBT_1MS * 100;
+                        precision = rsbt;
+                        precision >>= tc_precexp;
+                        if (TIMESEL(&asbt, rsbt))
+                                asbt += tc_tick_sbt;
+                        asbt += rsbt;
+
+			error = seltdwait(td, asbt, precision);
+
+			if (error != 0 && error != EAGAIN) {
+				DBGCORE("%s: error seltdwait(): %d\n",
+					__func__, error);
+			}
+		} else {
+			/*
+			 * Nothing to select. We will be woken up when a new
+			 * vps console is created.
+			 * (Could also exit here and be re-created
+			 * when needed.)
+			 */
+			tsleep(vps_console_kproc, 0, "bored", hz * 1);
+		}
+
+		/* Re-scan */
+		stp = td->td_sel;
+		STAILQ_FOREACH_SAFE(sfp, &stp->st_selq, sf_link, sfn) {
+			fp = (struct file *)sfp->sf_cookie;
+			vps = (struct vps *)((struct tty *)
+			    (fp->f_data))->t_hooksoftc;
+			if (fp->f_count == 2) {
+				vps->console_flags &= ~CF_OPENED;
+				/*
+				DBGCORE("%s: vps=%p console_flags=%08x\n",
+					__func__, vps, vps->console_flags);
+				*/
+			}
+			si = sfp->sf_si;
+			selfdfree(stp, sfp);
+			/* If the selinfo wasn't cleared the event
+			   didn't fire. */
+			if (si != NULL) {
+				fdrop(fp, td);
+				continue;
+			}
+			flags = POLLIN|POLLRDNORM;
+			ev = fo_poll(fp, flags, td->td_ucred, td);
+			/*
+			DBGCORE("%s: re-scan: fp=%p, ev=%08x\n",
+			    __func__, fp, ev);
+			*/
+			if ((ev & POLLIN || ev & POLLRDNORM) &&
+			    fp->f_count == 2)
+				vps_console_doread(td, fp);
+			fdrop(fp, td);
+		}
+		stp->st_flags = 0;
+
+		if (vps_console_exit != 0)
+			break;
+	}
+
+	seltdclear(td);
+
+	free(vps_console_readbuf, M_VPS_CORE);
+	vps_console_readbuf = NULL;
+
+	kproc_exit(0);
+}
+
+/*
+ * Global init.
+ */
+int
+vps_console_init(void)
+{
+
+	mtx_init(&vps_console_mtx, "vps console lock", NULL, MTX_RECURSE);
+
+        selfd_zone = uma_zcreate("vps_console_selfd", sizeof(struct selfd),
+	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+
+	return (0);
+}
+
+__attribute__((unused))
+int
+vps_console_uninit(void)
+{
+
+	/* Tell kproc to exit. */
+	vps_console_exit = 1;
+
+	tsleep(vps_console_kproc_p, 0, "uninit", 0);
+
+	mtx_destroy(&vps_console_mtx);
+
+	return (0);
+}
+
+/*
+ * Init a console device for one vps instance.
+ */
+int
+vps_console_alloc(struct vps *vps, struct thread *td)
+{
+	struct vps *savevps;
+	struct ucred *vps_ucred;
+	struct cdev *dev_orig;
+	struct cdev *dev;
+	struct file *fp_ma;
+	struct tty *tp;
+	int error;
+//#ifdef DIAGNOSTIC_2
+#if 1
+	struct ucred *saveucred;
+	struct ucred *dbgucred;
+
+	dbgucred = crget();
+	crcopy(dbgucred, vps->vps_ucred);
+	saveucred = td->td_ucred;
+	td->td_ucred = dbgucred;
+	vps_ucred = dbgucred;
+#else
+	vps_ucred = crhold(vps->vps_ucred);
+#endif
+
+	DBGCORE("%s: td=%p vps=%p\n", __func__, td, vps);
+
+	if (vps_console_kproc_p == NULL) {
+        	error = kproc_create(vps_console_kproc, NULL,
+		    &vps_console_kproc_p, 0, 0, "vps_console");
+		KASSERT(error == 0, ("%s: kproc_create() error=%d\n",
+		    __func__, error));
+	} else {
+		wakeup(vps_console_kproc_p);
+	}
+
+	KASSERT(curthread->td_vps == vps0,
+		("%s: curthread->td_vps=%p != vps0 !\n",
+		__func__, curthread->td_vps));
+
+	if (vps->console_tty != NULL) {
+		DBGCORE("%s: vps->console_tty=%p != NULL !\n",
+			__func__, vps->console_tty);
+		return (EEXIST);
+	}
+
+	if ((error = falloc_noinstall(td, &fp_ma)) != 0) {
+		DBGCORE("%s: fp_alloc_noinstall(): %d\n",
+			__func__, error);
+		return (error);
+	}
+
+	savevps = td->td_vps;
+	td->td_vps = vps;
+
+	if ((error = pts_alloc(FREAD|FWRITE, td, fp_ma)) != 0) {
+		DBGCORE("%s: pts_alloc(): %d\n",
+			__func__, error);
+		fdrop(fp_ma, td);
+		return (error);
+	}
+
+	/* This is the master side. */
+	vps->console_flags = 0;
+	vps->console_fp_ma = fp_ma;
+	vps->console_tty = tp = fp_ma->f_data;
+
+	/* Destroy the original slave device later. */
+	dev_orig = tp->t_dev;
+
+	/* Expose slave device in vps instance. */
+
+	DBGCORE("%s: creating tty dev with ucred=%p vps=%p; fp_ma=%p\n",
+		__func__, vps_ucred, vps_ucred->cr_vps, fp_ma);
+
+	tty_makedev(tp, vps_ucred, "console");
+
+	/* vps->console_tty->t_dev is the slave character device. */
+	dev = tp->t_dev;
+
+	destroy_dev(dev_orig);
+
+	/* Will be deleted automatically on delete of parent device. */
+	make_dev_alias_cred(dev, vps_ucred, "ttyv0");
+
+	//DBGCORE("%s: tty=%p dev=%p (slave device)\n", __func__, tp, dev);
+
+	dev_lock();
+	dev->si_usecount++;
+	dev_unlock();
+
+	td->td_vps = savevps;
+
+	/* install tty hooks */
+	tty_lock(tp);
+	if (tp->t_flags & TF_HOOK) {
+		DBGCORE("%s: ERROR: tp->t_hook=%p "
+		    "(tp->t_flags & TF_HOOK)=%d\n",
+		    __func__, tp->t_hook, (tp->t_flags & TF_HOOK));
+	} else {
+		tp->t_flags |= TF_HOOK;
+		tp->t_hook = &vps_console_hook;
+		tp->t_hooksoftc = vps;
+	}
+	tty_unlock(tp);
+
+//#ifdef DIAGNOSTIC_2
+#if 1
+	td->td_ucred = saveucred;
+	crfree(dbgucred);
+
+	DBGCORE("%s: fp_ma=%p f_count=%d dev=%p si_refcount=%d "
+	    "si_cred=%p si_cred->cr_ref=%d\n",
+	    __func__, fp_ma, fp_ma->f_count, dev,
+	    dev->si_refcount, dev->si_cred, dev->si_cred->cr_ref);
+#else
+	crfree(vps_ucred);
+#endif
+
+	return (error);
+}
+
+/*
+ * Free (destruct) the console device of one vps instance.
+ */
+int
+vps_console_free(struct vps *vps, struct thread *td)
+{
+	struct cdev *dev;
+	struct file *fp;
+	struct tty *tp;
+
+	DBGCORE("%s: td=%p vps=%p\n", __func__, td, vps);
+
+	KASSERT(vps->console_fp_ma != NULL,
+		("%s: vps->console_fp_ma == NULL\n", __func__));
+	KASSERT(vps->console_tty != NULL,
+		("%s: vps->console_tty == NULL\n", __func__));
+
+	fp = vps->console_fp_ma;
+	tp = vps->console_tty;
+	dev = tp->t_dev;
+	vps->console_fp_ma = NULL;
+	vps->console_tty = NULL;
+	vps->console_flags = 0;
+
+	dev_lock();
+	dev->si_usecount--;
+	dev_unlock();
+
+	/* XXX get rid of remaining data, otherwise close will block. */
+
+	/* This will revoke the tty so readers of the master get EOF. */
+	dev->si_devsw->d_close(dev, FREAD|FWRITE, 0, td);
+
+	/*
+	DBGCORE("%s: before dropping my ref fp=%p f_count=%d dev=%p "
+	    "si_refcount=%d si_cred=%p\n",
+	    __func__, fp, fp->f_count, dev, dev->si_refcount, dev->si_cred);
+	*/
+
+	fdrop(fp, td);
+
+	/*
+	DBGCORE("%s: after dropping my ref fp=%p f_count=%d dev=%p "
+	    "si_refcount=%d si_cred=%p\n",
+	    __func__, fp, fp->f_count, dev, dev->si_refcount, dev->si_cred);
+	*/
+
+	tty_lock(tp);
+	ttyhook_unregister(tp);
+
+	return (0);
+}
+
+/*
+ * Get a file descriptor to a vps instance's console.
+ */
+int
+vps_console_getfd(struct vps *vps, struct thread *td, int *retfd)
+{
+	struct file *fp;
+	int fd;
+	int error;
+
+	DBGCORE("%s: td=%p vps=%p\n", __func__, td, vps);
+
+	/*
+	 * XXX make sure vps is a child of td->td_vps !
+	 *
+	if (td->td_vps != vps) {
+		DBGCORE("%s: td->td_vps=%p vps=%p\n",
+			__func__, td->td_vps, vps);
+		return (EPERM);
+	}
+	*/
+
+	fp = vps->console_fp_ma;
+
+	if (fp == NULL)
+		return (ENOENT);
+
+	if ((vps->console_flags & CF_OPENED) != 0) {
+		DBGCORE("%s: vps=%p console busy: flags=%08x "
+		    "fp->f_count=%d\n",
+		    __func__, vps, vps->console_flags, fp->f_count);
+		return (EBUSY);
+	}
+	vps->console_flags |= CF_OPENED;
+
+	if ((error = finstall(td, fp, &fd, FREAD|FWRITE, NULL)) != 0) {
+		DBGCORE("%s: finstall(): %d\n", __func__, error);
+		fdrop(fp, td);
+		return (error);
+	}
+
+	DBGCORE("%s: installed fp=%p for thread %p as fd=%d\n",
+		__func__, fp, td, fd);
+
+	*retfd = fd;
+
+	return (0);
+}
+
+/*
+ * Force newline to LF-CR conversion, otherwise all of init/rc output
+ * is totally unreadable.
+ */
+static void
+vps_console_getc_capture(struct tty *tp, const void *buf, size_t len)
+{
+
+	tp->t_termios.c_oflag |= OPOST|ONLCR;
+}
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_core.c head/sys/vps/vps_core.c
--- clean-head/sys/vps/vps_core.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_core.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,1871 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: vps_core.c 174 2013-06-12 15:39:22Z klaus $";
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/limits.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/libkern.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/ucred.h>
+#include <sys/ioccom.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/fcntl.h>
+#include <sys/namei.h>
+#include <sys/syscallsubr.h>
+#include <sys/resourcevar.h>
+#include <sys/sysproto.h>
+#include <sys/reboot.h>
+#include <sys/sysent.h>
+#include <sys/sleepqueue.h>
+#include <sys/syscall.h>
+#include <sys/systm.h>
+#include <sys/filedesc.h>
+#include <sys/buf.h>
+#include <sys/imgact.h>
+#include <sys/vmmeter.h>
+#include <sys/jail.h>
+#include <sys/loginclass.h>
+#include <sys/rwlock.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_kern.h>
+
+#include <machine/pcb.h>
+
+#include <net/if.h>
+#include <net/if_clone.h>
+#include <netinet/in.h>
+
+#include <security/mac/mac_framework.h>
+
+#ifdef DDB
+#include <ddb/ddb.h>
+#else
+#define db_trace_thread(x,y)
+#endif
+
+extern struct prison prison0;
+
+#include "vps_user.h"
+#include "vps.h"
+#include "vps2.h"
+#include "vps_int.h"
+#include "vps_account.h"
+#include <machine/vps_md.h>
+
+#ifdef DIAGNOSTIC
+int vps_debug_core = 1;
+
+SYSCTL_INT(_debug, OID_AUTO, vps_core_debug, CTLFLAG_RW,
+    &vps_debug_core, 0, "");
+#endif
+
+VPS_DECLARE(struct unrhdr *, pts_pool);
+
+static int vps_sysctl_reclaim(SYSCTL_HANDLER_ARGS);
+SYSCTL_PROC(_debug, OID_AUTO, vps_reclaim, CTLTYPE_INT | CTLFLAG_RW,
+    NULL, 0, vps_sysctl_reclaim, "I", "set to call vps_sysctl_reclaim()");
+
+/*
+ * Function pointers filled by the vps_* modules.
+ */
+
+struct vps_functions _vps_func;
+struct vps_functions *vps_func = &_vps_func;
+
+MALLOC_DEFINE(M_VPS_CORE, "vps_core",
+    "Virtual Private Systems core memory");
+
+static int last_vps_id;
+struct vps_list_head vps_head;
+
+struct vps *vps0;
+
+struct sx vps_all_lock;
+
+void vps_proc_release_timeout(void *);
+void vps_proc_release_taskq(void *, int);
+
+static int vps_prison_alloc(struct vps *, struct vps *);
+static void vps_prison_destroy(struct vps *);
+
+/* vps/vps_pager.c */
+void vps_pager_lowmem(void *arg);
+
+/* net/route.c */
+void vnet_route_init(const void *);
+void vnet_route_uninit(const void *);
+
+static void
+vps_init(void *unused)
+{
+
+	LIST_INIT(&vps_head);
+
+	/* init all the global locks here */
+	sx_init(&vps_all_lock, "lock of all vps instances");
+
+	sx_xlock(&vps_all_lock);
+	vps0 = vps_alloc(NULL, NULL, "", NULL);
+	sx_xunlock(&vps_all_lock);
+
+	curthread->td_vps = vps0;
+
+	vps_console_init();
+
+	DBGCORE("WARNING: VPS VIRTUAL PRIVATE SYSTEMS ENABLED. "
+	    "HIGHLY EXPERIMENTAL!\n");
+}
+
+SYSINIT(vps, SI_SUB_VPS, SI_ORDER_FIRST, vps_init, NULL);
+
+/*
+ * Shutdown all running instances except vps0.
+ * Called from reboot() on global shutdown.
+ */
+int
+vps_shutdown_all(struct thread *td)
+{
+	struct vps *vps;
+
+	KASSERT(td->td_vps == vps0,
+	 	("%s: calling vps != vps0 (td->td_vps=%p)\n",
+		__func__, td->td_vps));
+
+	printf("%s: VPS GLOBAL SHUTDOWN\n", __func__);
+
+	sx_xlock(&vps_all_lock);
+        LIST_FOREACH(vps, &vps_head, vps_all)
+		if (vps != vps0 &&
+		    vps->vps_status != VPS_ST_DEAD) {
+			sx_xlock(&vps->vps_lock);
+			vps_free_locked(vps);
+			sx_xunlock(&vps->vps_lock);
+		}
+	sx_xunlock(&vps_all_lock);
+
+	/*
+	 * At this point all processes are gone.
+	 * Due to TIME_WAIT sockets or similar things
+	 * some VPS instances might be still alive,
+	 * but that doesn't matter for global reboot.
+	 */
+
+        return (0);
+}
+
+/*
+ * We are called with allvps lock held exclusively.
+ */
+struct vps *
+vps_alloc(struct vps *vps_parent, struct vps_param *vps_pr,
+    char *vps_name, int *errorval)
+{
+	struct vps *vps;
+	struct vps *vps_save;
+	struct nameidata nd;
+	char *path;
+	int error;
+	char *tmpstr = NULL;
+	struct thread *td = curthread;
+
+	if (errorval)
+		*errorval = 0;
+
+	/* Only the first call is valid with vps_parent == NULL. */
+	if (vps_parent == NULL && ! LIST_EMPTY(&vps_head)) {
+		if (errorval)
+			*errorval = EINVAL;
+		return (NULL);
+	}
+
+	/* Allocating a vps instance in a jail (other than prison0)
+	   is forbidden. */
+	if (td->td_ucred != NULL && jailed(td->td_ucred)) {
+		*errorval = EPERM;
+		return (NULL);
+	}
+
+	if (vm_page_count_min()) {
+		printf("%s: low on memory: v_free_min=%u > "
+		    "(v_free_count=%u + v_cache_count=%u)\n",
+		    __func__, cnt.v_free_min, cnt.v_free_count,
+		    cnt.v_cache_count);
+		if (errorval)
+			*errorval = ENOMEM;
+		return (NULL);
+	}
+	DBGCORE("%s: v_free_min=%u v_free_count=%u + v_cache_count=%u\n",
+	    __func__, cnt.v_free_min, cnt.v_free_count, cnt.v_cache_count);
+
+	vps = malloc(sizeof(*vps), M_VPS_CORE, M_WAITOK | M_ZERO);
+
+	vps->vps_id = last_vps_id++;
+	LIST_INIT(&vps->vps_child_head);
+	snprintf(vps->vps_name, sizeof(vps->vps_name), "%s", vps_name);
+	vps->vps_parent = vps_parent;
+
+	mtx_init(&vps->vps_refcnt_lock, "vps_refcnt_lock", NULL, MTX_SPIN);
+	refcount_init(&vps->vps_refcnt, 1);
+#ifdef INVARIANTS
+	TAILQ_INIT(&vps->vps_ref_head);
+#endif
+
+	/* is freed in vps_destroy() */
+	tmpstr = malloc(0x100, M_VPS_CORE, M_WAITOK);
+	snprintf(tmpstr, 0x100, "vps instance %p lock", vps);
+	sx_init(&vps->vps_lock, tmpstr);
+	vps->vps_lock_name = tmpstr;
+	sx_xlock(&vps->vps_lock);
+
+	if (vps_parent) {
+
+		/* Alloc vnet. Apparently always succeeds. */
+		vps->vnet = vnet_alloc();
+
+	   	vps->vps_ucred = crget();
+		crcopy(vps->vps_ucred, td->td_ucred);
+		vps_ref(vps, vps->vps_ucred);
+		vps_deref(vps->vps_ucred->cr_vps, vps->vps_ucred);
+		vps->vps_ucred->cr_vps = vps;
+
+		getbintime(&VPS_VPS(vps, boottimebin));
+		bintime2timeval(&VPS_VPS(vps, boottimebin),
+		    &VPS_VPS(vps, boottime));
+
+		memset(VPS_VPS(vps, hostname), 0, sizeof(VPS_VPS(vps,
+		    hostname)));
+		memset(VPS_VPS(vps, domainname), 0, sizeof(VPS_VPS(vps,
+		    domainname)));
+		memset(VPS_VPS(vps, hostuuid), 0, sizeof(VPS_VPS(vps,
+		    hostuuid)));
+
+		/* Default is nprocs=1 for vps0, so set to 0 here. */
+		VPS_VPS(vps, nprocs) = 0;
+		VPS_VPS(vps, nprocs_zomb) = 0;
+
+		VPS_VPS(vps, vmaxproc) = VPS_VPS(vps0, vmaxproc);
+		VPS_VPS(vps, vmaxprocperuid) = VPS_VPS(vps0,
+		    vmaxprocperuid);
+
+		vps_save = td->td_vps;
+		td->td_vps = vps;
+
+		procinit();
+
+		KASSERT(VPS_VPS(vps, initpgrp) == NULL,
+		    ("%s: initpgrp != NULL", __func__));
+		KASSERT(VPS_VPS(vps, initproc) == NULL,
+		    ("%s: initproc != NULL", __func__));
+
+		td->td_vps = vps_save;
+
+		vps_priv_setdefault(vps, vps_pr);
+
+		(void)vps_devfs_ruleset_create(vps);
+
+		/* Filesystem root. */
+		if (vps_pr && vps_pr->fsroot[0])
+			path = vps_pr->fsroot;
+		else
+			path = "/";
+
+		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
+		    path, td);
+		if ((error = namei(&nd))) {
+	   		DBGCORE("%s: namei(path=[%s]): %d\n",
+			    __func__, path, error);
+			if (errorval)
+				*errorval = error;
+	   		goto fail;
+		}
+		vps->_rootvnode = nd.ni_vp;
+		strncpy(vps->_rootpath, path, sizeof(vps->_rootpath));
+		VOP_UNLOCK(nd.ni_vp, 0);
+		NDFREE(&nd, NDF_ONLY_PNBUF);
+
+		vps_prison_alloc(vps_parent, vps);
+		prison_hold(VPS_VPS(vps, prison0));
+		prison_free(vps->vps_ucred->cr_prison);
+		vps->vps_ucred->cr_prison = VPS_VPS(vps, prison0);
+
+		sx_xlock(&vps_parent->vps_lock);
+		LIST_INSERT_HEAD(&vps_parent->vps_child_head, vps,
+		    vps_sibling);
+		sx_xunlock(&vps_parent->vps_lock);
+
+	} else {
+
+		vps->vnet = vnet0;
+
+	   	vps->vps_ucred = crget();
+		vps->vps_ucred->cr_ngroups = 1;
+		vps->vps_ucred->cr_prison = &prison0;
+		prison_hold(&prison0);
+		/*
+		vps->vps_ucred->cr_uidinfo = uifind(0);
+		vps->vps_ucred->cr_ruidinfo = uifind(0);
+		vps->vps_ucred->cr_loginclass = loginclass_find("default");
+		*/
+		vps->vps_ucred->cr_uidinfo = NULL;
+		vps->vps_ucred->cr_ruidinfo = NULL;
+		vps->vps_ucred->cr_loginclass = NULL;
+	
+		vps_ref(vps, vps->vps_ucred);
+		vps->vps_ucred->cr_vps = vps;
+	
+		//vps->_maxproc = G_maxproc;
+		VPS_VPS(vps, vmaxproc) = maxproc;
+		VPS_VPS(vps, vmaxprocperuid) = maxprocperuid;
+
+		/* We grant every privilege for vps0. */
+		memset(vps->priv_allow_set, -1,
+		    sizeof(vps->priv_allow_set));
+		memset(vps->priv_impl_set, -1,
+		    sizeof(vps->priv_impl_set));
+	
+		/* Same goes for network. */
+		vps->vps_ip4_cnt = 1;
+		vps->vps_ip4 = malloc(sizeof(*vps->vps_ip4) * 1,
+		    M_VPS_CORE, M_WAITOK);
+		vps->vps_ip4->addr.s_addr = 0;
+		vps->vps_ip4->mask.s_addr = 0;
+	
+		vps->vps_ip6_cnt = 1;
+		vps->vps_ip6 = malloc(sizeof(*vps->vps_ip6) * 1,
+		    M_VPS_CORE, M_WAITOK);
+		memset(&vps->vps_ip6->addr, 0,
+		    sizeof(vps->vps_ip6->addr));
+		vps->vps_ip6->plen = 0;
+	
+		VPS_VPS(vps, prison0) = &prison0;
+	
+		DBGCORE("%s: vps=%p vmaxproc=%d\n", __func__,
+		    vps, VPS_VPS(vps, vmaxproc));
+
+	}
+
+	LIST_INSERT_HEAD(&vps_head, vps, vps_all);
+
+	vps->vps_acc = malloc(sizeof(*vps->vps_acc),
+	    M_VPS_CORE, M_WAITOK | M_ZERO);
+	//mtx_init(&vps->vps_acc->lock, "vps accounting", NULL, MTX_DEF);
+	mtx_init(&vps->vps_acc->lock, "vps accounting", NULL, MTX_SPIN);
+	vps->vps_acc->vps = vps;
+
+	VPS_VPS(vps, pts_pool) = new_unrhdr(0, INT_MAX, NULL);
+
+	/* Needs V_pts_pool initialized. */
+	if (vps_parent)
+		vps_console_alloc(vps, curthread);
+
+	vps_save = td->td_vps;
+	td->td_vps = vps;
+
+	EVENTHANDLER_INVOKE(vps_alloc, vps);
+
+	td->td_vps = vps_save;
+
+	vps->vps_status = VPS_ST_RUNNING;
+
+	sx_xunlock(&vps->vps_lock);
+
+	/* XXX stuff that should be moved somewhere appropriate */
+	TAILQ_INIT(&VPS_VPS(vps, allprison));
+
+	if (errorval)
+		*errorval = 0;
+	return (vps);
+
+  fail:
+
+	if (vps->vps_ucred)
+		crfree(vps->vps_ucred);
+
+	if (vps && VPS_VPS(vps, initpgrp)) {
+		free(VPS_VPS(vps, initpgrp)->pg_session, M_SESSION);
+		free(VPS_VPS(vps, initpgrp), M_PGRP);
+	}
+
+	if (vps && VPS_VPS(vps, proc_lock_names)) {
+		vps_save = td->td_vps;
+		td->td_vps = vps;
+		procuninit();
+		td->td_vps = vps_save;
+	}
+
+	if (vps->vps_acc) {
+		mtx_destroy(&vps->vps_acc->lock);
+		free(vps->vps_acc, M_VPS_CORE);
+	}
+
+	if (vps->vnet) {
+		/* see vps_free() */
+		VPS_VPS(vps, loif) = NULL;
+		vnet_destroy(vps->vnet);
+	}
+
+	if (tmpstr)
+		free(tmpstr, M_VPS_CORE);
+
+	if (vps) {
+		sx_xunlock(&vps->vps_lock);
+		sx_destroy(&vps->vps_lock);
+		mtx_destroy(&vps->vps_refcnt_lock);
+		free(vps, M_VPS_CORE);
+	}
+
+	return (NULL);
+}
+
+
+/*
+ * Unmount filesystems that were mounted by the vps instance.
+ */
+int
+vps_unmount_all(struct vps *vps)
+{
+	struct mount *mp;
+	int error;
+	struct thread *td = curthread;
+	struct vps *save_vps = td->td_vps;
+	struct ucred *save_ucred = td->td_ucred;
+
+	td->td_vps = vps;
+	td->td_ucred = vps->vps_ucred;
+
+	DBGCORE("%s: td->td_ucred=%p vps->vps_ucred=%p\n",
+	    __func__, td->td_ucred, vps->vps_ucred);
+
+  unmount_restart:
+	mtx_lock(&mountlist_mtx);
+	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
+		if (mp->mnt_vps != vps)
+			continue;
+		mtx_lock(&Giant);
+		mtx_unlock(&mountlist_mtx);
+		DBGCORE("%s: attempting unmount of mp=%p\n", __func__, mp);
+		if ((error = dounmount(mp, MNT_FORCE, curthread)))
+			DBGCORE("%s: dounmount() failed: %d\n",
+			    __func__, error);
+		mtx_unlock(&Giant);
+		goto unmount_restart;
+	}
+	mtx_unlock(&mountlist_mtx);
+
+	td->td_vps = save_vps;
+	td->td_ucred = save_ucred;
+
+	return (0);
+}
+
+int
+vps_free(struct vps *vps)
+{
+	int error;
+
+	sx_xlock(&vps->vps_lock);
+	error = vps_free_locked(vps);
+	sx_xunlock(&vps->vps_lock);
+
+	return (error);
+}
+
+/*
+ * We are called with vps locked exclusively.
+ */
+int
+vps_free_locked(struct vps *vps)
+{
+	struct ifnet *ifp, *ifp2;
+	struct vps *vps_save;
+	struct proc *p, *p2;
+	char *tmpstr;
+	int nonzombprocs;
+	int systemprocs;
+	int error;
+	int i;
+
+	sx_assert(&vps->vps_lock, SA_XLOCKED);
+
+	KASSERT(vps->vps_status != VPS_ST_DEAD,
+	    ("%s: vps=%p vps->vps_status == VPS_ST_DEAD\n", __func__, vps));
+
+	if (vps->vps_status == VPS_ST_SUSPENDED)
+		return (EBUSY);
+
+	/*
+	 * Status can be VPS_ST_INITISDYING here,
+	 * just treat is like _RUNNING
+	 */
+
+	vps_save = curthread->td_vps;
+	curthread->td_vps = vps;
+
+  again:
+	error = 0;
+	nonzombprocs = 0;
+	systemprocs = 0;
+
+	sx_xlock(&V_proctree_lock);
+	sx_xlock(&V_allproc_lock);
+
+	FOREACH_PROC_IN_SYSTEM(p) {
+		nonzombprocs++;
+		if (p->p_flag & P_SYSTEM)
+			systemprocs++;
+	}
+
+	if (systemprocs > 0) {
+		/*
+		 * XXX e.g. kernel procs created via mdconfig.
+		 */
+		DBGCORE("%s: vps %p [%s] has %d procs with P_SYSTEM "
+		    "flag.\n", __func__, vps, vps->vps_name, systemprocs);
+		sx_xunlock(&V_allproc_lock);
+		sx_xunlock(&V_proctree_lock);
+
+		error = EBUSY;
+		goto out;
+	}
+
+	if (nonzombprocs > 0) {
+		/*
+		 * In this case we have to do a broadcast kill
+		 * and sleep until there are no more active processes.
+		 */
+		sx_xunlock(&V_allproc_lock);
+		sx_xunlock(&V_proctree_lock);
+
+		sx_downgrade(&vps_all_lock);
+
+		vps_proc_signal(vps, -1, SIGKILL);
+
+		/* Sleep. */
+		do {
+	   		pause("vpskll", hz / 10);
+		} while (sx_try_upgrade(&vps_all_lock) == 0);
+
+		/*
+		 * XXX If we get stuck here, just clean up as much we can,
+		 *     keep system in a safe state and continue.
+		 */
+
+		goto again;
+	}
+
+	/*
+	 * At this point there MUST NOT be any non-zombie processes,
+	 * as we could release a parent of a still alive child !
+	 */
+	LIST_FOREACH_SAFE(p, &V_zombproc, p_list, p2)
+		vps_proc_release(vps, p);
+
+	i = 0;
+	do {
+		pause("vpskll", hz / 10);
+	} while (++i < 100 && VPS_VPS(vps, nprocs) > 0);
+
+	sx_xunlock(&V_allproc_lock);
+	sx_xunlock(&V_proctree_lock);
+
+	if (VPS_VPS(vps, nprocs)) {
+		DBGCORE("%s: nprocs still > 0: %d\n",
+		    __func__, VPS_VPS(vps, nprocs));
+		error = EBUSY;
+		goto out;
+	}
+
+	EVENTHANDLER_INVOKE(vps_free, vps);
+
+	vps->vps_status = VPS_ST_DEAD;
+	tmpstr = malloc(MAXHOSTNAMELEN, M_TEMP, M_WAITOK | M_ZERO);
+	snprintf(tmpstr, MAXHOSTNAMELEN-1, "dead_%s", vps->vps_name);
+	memcpy(vps->vps_name, tmpstr, MAXHOSTNAMELEN);
+	free(tmpstr, M_TEMP);
+
+	/* Point of no return. */
+
+	/*
+	 * Set all network interfaces to down; in order to avoid
+	 * receiving any more packets.
+	 */
+	CURVNET_SET_QUIET(vps->vnet);
+	//IFNET_RLOCK();
+	TAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, ifp2) {
+		DBGCORE("%s: if_down() <-- ifnet=%p dname=[%s] "
+		    "xname=[%s]\n", __func__, ifp, ifp->if_dname,
+		    ifp->if_xname);
+		if_down(ifp);
+	}
+	//IFNET_RUNLOCK();
+	/* --> rt_dispatch() *grrr* */
+	V_loif = NULL;
+	CURVNET_RESTORE();
+
+	if (vps->_rootvnode) {
+		vrele(vps->_rootvnode);
+		vps->_rootvnode = NULL;
+		vps->_rootpath[0] = '\0';
+	}
+	vrele(VPS_VPS(vps, prison0)->pr_root);
+	VPS_VPS(vps, prison0)->pr_root = NULL;
+
+	vps_unmount_all(vps);
+
+	vps_console_free(vps, curthread);
+
+	crfree(vps->vps_ucred);
+
+	/* This is the reference acquired by refcount_init() in
+	   vps_alloc(). */
+	vps_deref(vps, (void*)0xdeadbeef);
+
+  out:
+	curthread->td_vps = vps_save;
+
+	return (error);
+}
+
+/*
+ * We are called with vps locked exclusively.
+ */
+int
+vps_destroy(struct vps *vps)
+{
+	struct ifnet *ifp, *ifp2;
+	struct vps *vps_save;
+
+	KASSERT(vps != vps0,
+	    ("%s: attempting to destroy vps0 !\n", __func__));
+
+	KASSERT(vps->vps_status == VPS_ST_DEAD,
+	    ("%s: vps->vps_status != VPS_ST_DEAD", __func__));
+
+	vps_save = curthread->td_vps;
+	curthread->td_vps = vps;
+
+	sx_assert(&vps->vps_lock, SA_XLOCKED);
+
+	if ( ! LIST_EMPTY(&vps->vps_child_head)) {
+		DBGCORE("%s: vps_child_head not empty !\n", __func__);
+		sx_xunlock(&vps->vps_lock);
+		curthread->td_vps = vps_save;
+		return (EBUSY);
+	}
+
+	/*
+	 * Reclaim the network interfaces to parent vps now;
+	 * vpsctl needs to handle them !
+	 */
+	CURVNET_SET_QUIET(vps->vnet);
+	//IFNET_RLOCK();
+	TAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, ifp2) {
+		DBGCORE("%s: ifnet=%p dname=[%s] xname=[%s]\n",
+		    __func__, ifp, ifp->if_dname, ifp->if_xname);
+		if (ifp->if_vnet == ifp->if_home_vnet) {
+			DBGCORE("%s: non-inherited interface left: [%s]\n",
+			    __func__, ifp->if_xname);
+			continue;
+		} else if (strncmp(ifp->if_dname, "vps", 3) == 0) {
+			DBGCORE("%s: interface ''if_vps'' [%s] --> "
+			    "destroy.\n", __func__, ifp->if_xname);
+			if_clone_destroy(ifp->if_xname);
+		} else {
+			DBGCORE("%s: interface ifp=%p xname=[%s] reclaim "
+			    "to parent.\n", __func__, ifp, ifp->if_xname);
+			if_vmove_vps(curthread, ifp->if_xname, 0, vps_save,
+			    NULL);
+	   }
+	}
+	//IFNET_RUNLOCK();
+	CURVNET_RESTORE();
+
+	sx_xlock(&vps_all_lock);
+	LIST_REMOVE(vps, vps_all);
+	sx_xlock(&vps->vps_parent->vps_lock);
+	LIST_REMOVE(vps, vps_sibling);
+	sx_xunlock(&vps->vps_parent->vps_lock);
+	sx_xunlock(&vps_all_lock);
+
+	(void)vps_devfs_ruleset_destroy(vps);
+
+	vps_prison_destroy(vps);
+
+	procuninit();
+
+	delete_unrhdr(VPS_VPS(vps, pts_pool));
+
+	/* After this point V_* globals are invalid ! */
+
+	/* Destroy vnet. Apparently always succeeds. */
+	KASSERT(vps->vnet->vnet_sockcnt == 0, ("%s: vnet->vnet_sockcnt "
+	   "!= 0, vps=%p vnet=%p vnet->vnet_sockcnt=%d\n",
+	   __func__, vps, vps->vnet, vps->vnet->vnet_sockcnt));
+	DBGCORE("%s: right before vnet_destroy(%p)\n", __func__, vps->vnet);
+	vnet_destroy(vps->vnet);
+	curthread->td_vps = vps_save;
+	DBGCORE("%s: right after  vnet_destroy(%p)\n", __func__, vps->vnet);
+
+	vps_account_stats(vps);
+
+	mtx_destroy(&vps->vps_acc->lock);
+
+	sx_xunlock(&vps->vps_lock);
+	sx_destroy(&vps->vps_lock);
+	mtx_destroy(&vps->vps_refcnt_lock);
+	free(vps->vps_lock_name, M_VPS_CORE);
+
+	free(vps->vps_acc, M_VPS_CORE);
+	free(vps, M_VPS_CORE);
+
+	/* reclaim memory */
+	proc_zone_reclaim();
+	thread_zone_reclaim();
+	vmspace_zone_reclaim();
+	uma_reclaim();
+
+	return (0);
+}
+
+void
+vps_ref(struct vps *vps, struct ucred *ucred)
+{
+#ifdef INVARIANTS
+	struct vps_ref *ref;
+#endif
+
+#ifdef INVARIANTS
+	ref = malloc(sizeof(*ref), M_VPS_CORE, M_NOWAIT);
+#endif
+	mtx_lock_spin(&vps->vps_refcnt_lock);
+	refcount_acquire(&vps->vps_refcnt);
+#ifdef INVARIANTS
+	if (ref != NULL) {
+		ref->arg = ucred;
+		ref->ticks = ticks;
+		TAILQ_INSERT_TAIL(&vps->vps_ref_head, ref, list);
+	} else {
+		printf("%s: WARNING: could not allocate ref\n", __func__);
+	}
+#endif
+	mtx_unlock_spin(&vps->vps_refcnt_lock);
+
+	/*
+	DBGCORE("%s: adding ref, vps=%p refcnt=%d->%d ucred=%p\n",
+	   __func__, vps, vps->vps_refcnt-1, vps->vps_refcnt, ucred);
+	*/
+}
+
+static void
+vps_destroy_task(void *context, int pending)
+{
+	struct vps *vps;
+
+	vps = (struct vps *)context;
+
+	sx_xlock(&vps->vps_lock);
+
+	vps_destroy(vps);
+}
+
+void
+vps_deref(struct vps *vps, struct ucred *ucred)
+{
+	int last;
+#ifdef INVARIANTS
+	struct vps_ref *ref;
+#endif
+
+	/*
+	DBGCORE("%s: deleting ref, vps=%p refcnt=%d->%d ucred=%p\n",
+	   __func__, vps, vps->vps_refcnt, vps->vps_refcnt-1, ucred);
+	*/
+
+	mtx_lock_spin(&vps->vps_refcnt_lock);
+	last = refcount_release(&vps->vps_refcnt);
+#ifdef INVARIANTS
+	TAILQ_FOREACH(ref, &vps->vps_ref_head, list) {
+		if (ref->arg == ucred) {
+			TAILQ_REMOVE(&vps->vps_ref_head, ref, list);
+			break;
+		}
+	}
+#endif
+	mtx_unlock_spin(&vps->vps_refcnt_lock);
+
+#ifdef INVARIANTS
+	if (ref != NULL)
+		free(ref, M_VPS_CORE);
+#endif
+
+	if (last) {
+		KASSERT(vps->vps_status == VPS_ST_DEAD,
+		    ("%s: vps=%p; released last reference but "
+		    "vps_status = %d\n", __func__, vps, vps->vps_status));
+
+		DBGCORE("%s: vps=%p is DEAD and last reference gone"
+		    " --> scheduling destroy\n", __func__, vps);
+
+		KASSERT(vps->vps_task.q == NULL,
+		    ("%s: task is already initialized ! vps=%p "
+		    "timeout_task=%p\n", __func__, vps, &vps->vps_task));
+
+		/*
+		 * Not calling vps_destroy() directly because there
+		 * might be locks held we need to hold exclusively.
+		 */
+		/*
+		TASK_INIT(&vps->vps_task, 0, vps_destroy_task, vps);
+		taskqueue_enqueue(taskqueue_thread, &vps->vps_task);
+		*/
+		/*
+		 * Defer actual destroy routine by 10 seconds in case
+		 * e.g. network packets are still queued in netisr stuff.
+		 */
+		TIMEOUT_TASK_INIT(taskqueue_thread, &vps->vps_task, 0,
+		    vps_destroy_task, vps);
+		taskqueue_enqueue_timeout(taskqueue_thread, &vps->vps_task,
+		    1 * hz /* ticks */);
+	}
+}
+
+int
+vps_proc_signal(struct vps *vps, pid_t pid, int sig)
+{
+	struct vps *vps_save;
+	struct proc *p, *p2;
+
+	vps_save = curthread->td_vps;
+	curthread->td_vps = vps;
+
+	sx_xlock(&V_allproc_lock);
+
+	if (pid == -1) {
+		/* Broadcast. */
+		LIST_FOREACH_SAFE(p, &V_allproc, p_list, p2) {
+			PROC_LOCK(p);
+			kern_psignal(p, sig);
+			PROC_UNLOCK(p);
+		}
+	} else {
+		if ((p = pfind(pid))) {
+			PROC_LOCK(p);
+			kern_psignal(p, sig);
+			PROC_UNLOCK(p);
+		}
+	}
+
+	sx_xunlock(&V_allproc_lock);
+
+	curthread->td_vps = vps_save;
+
+	return (0);
+}
+
+int
+vps_proc_exit(struct thread *td, struct proc *p)
+{
+
+	return (0);
+}
+
+#if 0
+/*
+ * That doesn't work properly; there's no way to recognize
+ * if the zombproc hasn't already been reaped in case
+ * of 'vpsctl stop' ...
+ */
+int
+vps_proc_exit(struct thread *td, struct proc *p)
+{
+	struct vps *vps;
+
+	vps = td->td_vps;
+
+	KASSERT(VPS_VPS(vps, nprocs) > 0, ("%s: vps=%p nprocs=%d\n",
+		__func__, vps, VPS_VPS(vps, nprocs)));
+
+	if (VPS_VPS(vps, nprocs) > 1)
+		return (0);
+
+	/*
+	 * This process is the last in the vps,
+	 * so schedule the reaping of our zombie.
+	 */
+	vps_ref(vps, (void *)0x3478242);
+	timeout(vps_proc_release_timeout, (void *)p, hz);
+
+	return (0);
+}
+
+void
+vps_proc_release_timeout(void *arg)
+{
+	struct vps *vps;
+
+	vps = ((struct proc *)arg)->p_ucred->cr_vps;
+
+	TASK_INIT(&vps->vps_task, 0, vps_proc_release_taskq, arg);
+	taskqueue_enqueue(taskqueue_thread, &vps->vps_task);
+}
+
+void
+vps_proc_release_taskq(void *arg, int pending)
+{
+	struct vps *vps;
+	struct proc *p;
+
+	p = (struct proc *)arg;
+	vps = p->p_ucred->cr_vps;
+
+	sx_xlock(&VPS_VPS(vps, proctree_lock));
+	sx_xlock(&VPS_VPS(vps, allproc_lock));
+
+	/* Make sure zombie wasn't reaped by vps_free() already. */
+	if (VPS_VPS(vps, nprocs) == 0) {
+		vps_deref(vps, (void *)0x3478242);
+		return;
+	}
+
+	(void)vps_proc_release(vps, p);
+
+	sx_xunlock(&VPS_VPS(vps, allproc_lock));
+	sx_xunlock(&VPS_VPS(vps, proctree_lock));
+
+	vps_deref(vps, (void *)0x3478242);
+}
+#endif /* 0 */
+
+/*
+ * Used instead of kern_wait() to release a zombie process.
+ *
+ * Enter with exclusive allproc and proctree locks held.
+ *
+ * XXX Try to do this with proc_reap() instead duplicating code here.
+ */
+int
+vps_proc_release(struct vps *vps2, struct proc *p)
+{
+	struct vps *vps1;
+	int error;
+
+	vps1 = curthread->td_vps;
+	curthread->td_vps = vps2;
+
+	PROC_LOCK(p);
+	if (p->p_state != PRS_ZOMBIE) {
+		PROC_UNLOCK(p);
+		error = EBUSY;
+		goto fail;
+	}
+	sigqueue_take(p->p_ksi);
+	LIST_REMOVE(p, p_list);
+	if (p->p_pptr)
+		LIST_REMOVE(p, p_sibling);
+	PROC_UNLOCK(p);
+	leavepgrp(p);
+
+	/* XXX process/accounting stats */
+
+	vps_account(p->p_ucred->cr_vps, VPS_ACC_PROCS, VPS_ACC_FREE, 1);
+
+	chgproccnt(p->p_ucred->cr_uidinfo, -1, 0);
+	crfree(p->p_ucred);
+	p->p_ucred = NULL;
+	pargs_drop(p->p_args);
+	sigacts_free(p->p_sigacts);
+	p->p_sigacts = NULL;
+	thread_wait(p);
+	vm_waitproc(p);
+#ifdef MAC
+	mac_proc_destroy(p);
+#endif
+
+	KASSERT(FIRST_THREAD_IN_PROC(p),
+	   ("%s: p=%p no residual thread!", __func__, p));
+
+	uma_zfree(proc_zone, p);
+	V_nprocs--;
+	V_nprocs_zomb--;
+
+	error = 0;
+
+  fail:
+	curthread->td_vps = vps1;
+
+	return (error);
+}
+
+static struct pgrp *
+vps_alloc_pgrp(struct vps *vps)
+{
+	struct pgrp *pg;
+	struct session *sess;
+
+	sess = NULL;
+
+	pg = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO);
+
+	mtx_init(&pg->pg_mtx, "process group", NULL, MTX_DEF | MTX_DUPOK);
+
+	sess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO);
+
+	mtx_init(&sess->s_mtx, "session", NULL, MTX_DEF | MTX_DUPOK);
+	refcount_init(&sess->s_count, 1);
+
+	PGRP_LOCK(pg);
+	pg->pg_session = sess;
+	pg->pg_id = 1;
+	LIST_INIT(&pg->pg_members);
+	LIST_INSERT_HEAD(&VPS_VPS(vps, pgrphashtbl)[pg->pg_id &
+	    VPS_VPS(vps, pgrphash)], pg, pg_hash);
+	pg->pg_jobc = 0;
+	SLIST_INIT(&pg->pg_sigiolst);
+	PGRP_UNLOCK(pg);
+
+	return (pg);
+}
+
+static int
+vps_switch_rootvnode(struct thread *td, struct vps *vps)
+{
+	int error;
+
+	if (vps->_rootvnode == NULL)
+		return (0);
+
+	vn_lock(vps->_rootvnode, LK_EXCLUSIVE | LK_RETRY);
+	if ((error = change_dir(vps->_rootvnode, td)) != 0) {
+		VOP_UNLOCK(vps->_rootvnode, 0);
+		return (error);
+	}
+#ifdef MAC
+	if ((error = mac_vnode_check_chroot(td->td_ucred,
+	    vps->_rootvnode))) {
+		VOP_UNLOCK(vps->_rootvnode, 0);
+		return (error);
+	}
+#endif
+	VOP_UNLOCK(vps->_rootvnode, 0);
+	change_root(vps->_rootvnode, td);
+
+	kern_chdir(td, "/", UIO_SYSSPACE);
+
+	return (0);
+}
+
+/*
+ * Unshare vmspace.
+ */
+static int
+vps_switch_vmspace(struct thread *td, struct vps *vps1, struct vps *vps2,
+	struct ucred *ucr2, struct vmspace *vm)
+{
+	struct vm_map_entry *e, *e2;
+	struct ucred *ucr3;
+	vm_object_t obj;
+	char do_charge;
+	int ref_cnt;
+	int i, i2;
+
+#ifdef DIAGNOSTIC
+	ucr3 = crget();
+	crcopy(ucr3, ucr2);
+	DBGCORE("%s: ucr2=%p ref=%d ucr3=%p ref=%d\n",
+	    __func__, ucr2, ucr2->cr_ref, ucr3, ucr3->cr_ref);
+#else
+	ucr3 = ucr2;
+#endif
+
+	for (i = 0, e = vm->vm_map.header.next;
+		e != &vm->vm_map.header;
+		i++, e = e->next) {
+
+		/*
+		DBGCORE("%s: e=%p e->eflags=%08x e->inheritance=%d "
+		    "e->object.vm_object=%p\n", __func__, e, e->eflags,
+		    e->inheritance, e->object.vm_object);
+		*/
+
+		if (e->cred != NULL) {
+
+			crfree(e->cred);
+
+			/*
+			crhold(ucr3);
+			e->cred = ucr3;
+			*/
+
+			/*
+			 * XXX Don't know why but otherwise swap charge
+			 *     is released one extra time in vm_map_lookup
+			 *     on fault-in.
+			 */
+			e->cred = NULL;
+		}
+
+		if (e->eflags & MAP_ENTRY_IS_SUB_MAP) {
+			DBGCORE("%s: WARNING: skipping submap\n", __func__);
+			continue;
+		}
+
+		obj = e->object.vm_object;
+
+		/* Check if we own this object. */
+		if (obj != NULL && obj->cred != NULL && obj->ref_count == 1)
+			do_charge = 1;
+		else if (obj != NULL && obj->cred != NULL &&
+		    obj->ref_count > 1) {
+			ref_cnt = 0;
+			for (i2 = 0, e2 = vm->vm_map.header.next;
+			     e2 != &vm->vm_map.header;
+			     i2++, e2 = e2->next) {
+				if ((e2->eflags & MAP_ENTRY_IS_SUB_MAP)
+				    == 0 && e2->object.vm_object == obj)
+					ref_cnt += 1;
+				if (ref_cnt == obj->ref_count)
+					break;
+			}
+
+			if (ref_cnt == obj->ref_count) {
+				/* We own it. */
+				do_charge = 1;
+			} else {
+				/* Is shared with other vmspaces. */
+				do_charge = 0;
+			}
+		} else {
+			do_charge = 0;
+		}
+
+#if 1
+		if (e->inheritance == VM_INHERIT_SHARE &&
+			obj != NULL && obj->cred != NULL) {
+			/* Don't charge, don't change credentials. */
+			DBGCORE("%s: e=%p e->object=%p obj->cred=%p "
+			    "VM_INHERIT_SHARE\n", __func__, e,
+			    obj,obj->cred);
+			/*
+			 * XXX Maybe it would be better to deny having
+			 * shared map entries (with credentials).
+			 */
+			do_charge = 0;
+		}
+#endif
+
+		if (do_charge != 0) {
+			vps_account(vps1, VPS_ACC_PHYS, VPS_ACC_FREE,
+				obj->resident_page_count << PAGE_SHIFT);
+			vps_account(vps2, VPS_ACC_PHYS, VPS_ACC_ALLOC,
+				obj->resident_page_count << PAGE_SHIFT);
+			DBGCORE("%s: obj=%p cred=%p refcnt=%d virt=%zx "
+			    "phys=%zx\n", __func__, obj, obj->cred,
+			    obj->ref_count, (size_t)obj->charge,
+			    (size_t)obj->resident_page_count << PAGE_SHIFT);
+
+			swap_release_by_cred(obj->charge, obj->cred);
+			if (swap_reserve_by_cred(obj->charge, ucr3) == 0) {
+				DBGCORE("%s: swap_reserve_by_cred() "
+				    "error\n", __func__);
+			}
+
+			crfree(obj->cred);
+			crhold(ucr3);
+			obj->cred = ucr3;
+		}
+
+	}
+#ifdef DIAGNOSTIC
+	crfree(ucr3);
+	DBGCORE("%s: ucr2=%p ref=%d ucr3=%p ref=%d\n",
+		__func__, ucr2, ucr2->cr_ref, ucr3, ucr3->cr_ref);
+#endif
+
+	return (0);
+}
+
+int
+vps_switch_proc(struct thread *td, struct vps *vps2, int flag)
+{
+	struct proc *ppold, *p2, *p;
+	struct ucred *ucr1, *ucr2;
+	struct thread *td2;
+	struct vps *vps1;
+	char save_s_login[sizeof(td->td_proc->p_session->s_login)];
+
+	ppold = NULL;
+	p = td->td_proc;
+	vps1 = td->td_vps;
+
+	/*
+	 * XXX Add more checks for resources we don't
+	 *     switch from one vps instance to another.
+	 */
+	if (p->p_numthreads != 1) {
+		DBGCORE("%s: p->p_numthreads=%d\n",
+			__func__, p->p_numthreads);
+		return (EINVAL);
+	}
+
+	/*
+	 * XXX
+	 *
+	 * In the ideal case we should not allow any resources
+	 * referring to the vps instance moved from.
+	 *
+	 * But vpsctl requires at least a pts device
+	 * and the executable vnode.
+	 *
+	 * Calling process is responsible for closing the
+	 * /dev/vps handle.
+	 */
+	{
+		struct filedesc *fdp;
+		struct file *fp;
+		struct vnode *vp;
+		int i;
+
+		fdp = p->p_fd;
+		FILEDESC_XLOCK(fdp);
+
+		for (i = 0; i < fdp->fd_nfiles; i++) {
+
+			fp = fget_locked(fdp, i);
+			if (fp == NULL)
+				continue;
+
+			switch (fp->f_type) {
+			case DTYPE_PTS:
+				break;
+			case DTYPE_VNODE:
+				vp = fp->f_vnode;
+				if (vp->v_type != VCHR &&
+				    (strcmp(vp->v_rdev->si_name, "vps") == 0 ||
+				    strncmp(vp->v_rdev->si_name, "pts/", 4) == 0)) {
+					DBGCORE("%s: vnode=%p v_type=%d\n",
+					   __func__, vp, vp->v_type);
+					FILEDESC_XUNLOCK(fdp);
+					return (EINVAL);
+				}
+				break;
+			case DTYPE_PIPE:
+			case DTYPE_SOCKET:
+			case DTYPE_KQUEUE:
+			default:
+				DBGCORE("%s: file type=%d\n",
+				    __func__, fp->f_type);
+				FILEDESC_XUNLOCK(fdp);
+				return (EINVAL);
+				break;
+			}
+		}
+
+		FILEDESC_XUNLOCK(fdp);
+	}
+
+	sx_xlock(&vps2->vps_lock);
+	sx_xlock(&vps1->vps_lock);
+
+	if (vps2->vps_status != VPS_ST_RUNNING) {
+		sx_xunlock(&vps2->vps_lock);
+		sx_xunlock(&vps1->vps_lock);
+		return (EBUSY);
+	}
+
+	/*
+	 * Unshare things to ease accounting.
+	 */
+	if (vmspace_unshare(p)) {
+		sx_xunlock(&vps2->vps_lock);
+		sx_xunlock(&vps1->vps_lock);
+		return (ENOMEM);
+	}
+	fdunshare(p, td);
+
+        /*
+         * + copy ucred and set new vps
+	 * + set new vnet
+         * + remove from parents childlist
+         * + leave process group
+         * + remove from pidhash list
+         * + remove from allproc list
+         * +
+         * + insert into new allproc list
+         * + insert into new pidhash list
+         * + enter new process group
+         * + adjust session
+         * + reparent to initproc if available
+         * + ... much much more i guess
+         */
+
+	bcopy(p->p_session->s_login, save_s_login, sizeof(save_s_login));
+
+	sx_xlock(&VPS_VPS(vps1, proctree_lock));
+	sx_xlock(&VPS_VPS(vps2, proctree_lock));
+
+	leavepgrp(p);
+
+	ucr2 = crget();
+
+	/*
+	 * If no processes left (only one zombie typically) reap zombies
+	 * so initpgrp will be freed.
+	 */
+	if (LIST_EMPTY(&VPS_VPS(vps2, allproc)) && VPS_VPS(vps2, initpgrp)
+	    != NULL) {
+		struct proc *p3;
+
+		/*
+		 * Reap zombies.
+		 */
+		LIST_FOREACH_SAFE(p2, &VPS_VPS(vps2, zombproc), p_list, p3)
+			vps_proc_release(vps2, p2);
+
+		VPS_VPS(vps2, initpgrp) = NULL;
+	}
+
+	if (VPS_VPS(vps2, initpgrp) == NULL)
+		VPS_VPS(vps2, initpgrp) = vps_alloc_pgrp(vps2);
+
+	/*
+	 * Same for the initproc reference.
+	 */
+	if (VPS_VPS(vps2, initproc)) {
+		int found;
+
+		found = 0;
+		LIST_FOREACH(p2, &VPS_VPS(vps2, allproc), p_list)
+			if (p2 == VPS_VPS(vps2, initproc))
+				++found;
+		if (found == 0)
+			VPS_VPS(vps2, initproc) = NULL;
+	}
+
+	sx_xlock(&VPS_VPS(vps1, allproc_lock));
+	sx_xlock(&VPS_VPS(vps2, allproc_lock));
+
+	PROC_LOCK(p);
+
+	ppold = p->p_pptr;
+	PROC_LOCK(p->p_pptr);
+	sigqueue_take(p->p_ksi);
+	LIST_REMOVE(p, p_sibling);
+	PROC_UNLOCK(p->p_pptr);
+	p->p_pptr = NULL;
+
+	ucr1 = p->p_ucred;
+	setsugid(p); /* ? */
+	crcopy(ucr2, ucr1);
+	vps_deref(ucr2->cr_vps, ucr2);
+	/* crcopy() did prison_hold() */
+	prison_free(ucr2->cr_prison);
+	prison_proc_free(ucr2->cr_prison);
+	uifree(ucr2->cr_uidinfo);
+	uifree(ucr2->cr_ruidinfo);
+	ucr2->cr_vps = vps2;
+	ucr2->cr_prison = VPS_VPS(vps2, prison0);
+	vps_ref(ucr2->cr_vps, ucr2);
+	td->td_vps = vps2;
+	prison_hold(ucr2->cr_prison);
+	prison_proc_hold(ucr2->cr_prison);
+	ucr2->cr_uidinfo = uifind(ucr2->cr_uid);
+	ucr2->cr_ruidinfo = uifind(ucr2->cr_ruid);
+	td->td_vps = vps1;
+	p->p_ucred = ucr2;
+	FOREACH_THREAD_IN_PROC(p, td2) {
+		if (td2->td_ucred != ucr1)
+			DBGCORE("%s: WARNING: td2->td_ucred != ucr1\n",
+			    __func__);
+		crfree(td2->td_ucred);
+		td2->td_ucred = ucr2;
+		crhold(td2->td_ucred);
+		td2->td_vps_acc = vps2->vps_acc;
+		td2->td_vps = vps2;
+		//td->td_vps = vps2;
+		vps_account(vps1, VPS_ACC_THREADS, VPS_ACC_FREE, 1);
+	}
+	crfree(ucr1);
+
+	VPS_VPS(vps1, nprocs)--;
+	chgproccnt(ucr1->cr_uidinfo, -1, 0);
+	chgproccnt(ucr2->cr_uidinfo, 1, 0);
+	vps_account(vps1, VPS_ACC_PROCS, VPS_ACC_FREE, 1);
+
+	LIST_REMOVE(p, p_hash);
+	LIST_REMOVE(p, p_list);
+
+	if (VPS_VPS(vps2, initproc) == NULL) {
+		KASSERT(VPS_VPS(vps2, nprocs) == 0,
+		    ("%s: vps2 initproc == NULL && vps2 nprocs == %d",
+		    __func__, VPS_VPS(vps2, nprocs)));
+		p->p_pid = 1;
+		VPS_VPS(vps2, pidchecked) = 0;
+	}
+
+	PROC_UNLOCK(p);
+	vps_switch_vmspace(td, vps1, vps2, ucr2, p->p_vmspace);
+	PROC_LOCK(p);
+
+	LIST_INSERT_HEAD(&VPS_VPS(vps2, allproc), p, p_list);
+	LIST_INSERT_HEAD(&VPS_VPS(vps2, pidhashtbl)[p->p_pid &
+	    VPS_VPS(vps2, pidhash)], p, p_hash);
+
+	VPS_VPS(vps2, nprocs)++;
+	/* Intentionally not checking for limit here. */
+	vps_account(vps2, VPS_ACC_PROCS, VPS_ACC_ALLOC, 1);
+	vps_account(vps2, VPS_ACC_THREADS, VPS_ACC_ALLOC, 1);
+
+	sx_xunlock(&VPS_VPS(vps2, allproc_lock));
+	sx_xunlock(&VPS_VPS(vps1, allproc_lock));
+
+	if (VPS_VPS(vps2, initproc) == NULL) {
+		struct session *sess;
+
+		sess = VPS_VPS(vps2, initpgrp)->pg_session;
+		SESS_LOCK(sess);
+		sess->s_leader = p;
+		sess->s_sid = p->p_pid;
+		bcopy(save_s_login, sess->s_login, sizeof(sess->s_login));
+		SESS_UNLOCK(sess);
+
+		/* First proc in vps, so it becomes initproc. */
+		VPS_VPS(vps2, initproc) = p;
+
+	} else {
+		p->p_pptr = VPS_VPS(vps2, initproc);
+		PROC_LOCK(p->p_pptr);
+		LIST_INSERT_HEAD(&p->p_pptr->p_children, p, p_sibling);
+		PROC_UNLOCK(p->p_pptr);
+	}
+
+	p->p_pgrp = VPS_VPS(vps2, initpgrp);
+	PROC_UNLOCK(p);
+
+	PGRP_LOCK(p->p_pgrp);
+	LIST_INSERT_HEAD(&p->p_pgrp->pg_members, p, p_pglist);
+	PGRP_UNLOCK(p->p_pgrp);
+	fixjobc(p, p->p_pgrp, 1);
+
+	sx_xunlock(&VPS_VPS(vps2, proctree_lock));
+	sx_xunlock(&VPS_VPS(vps1, proctree_lock));
+
+	if (vps_switch_rootvnode(td, vps2))
+		goto fail;
+
+	if (ppold)
+		wakeup(ppold);
+
+	sx_xunlock(&vps2->vps_lock);
+	sx_xunlock(&vps1->vps_lock);
+
+	DBGCORE("%s: ucr1=%p ref=%d; ucr2=%p ref=%d\n",
+	    __func__, ucr1, ucr1->cr_ref, ucr2, ucr2->cr_ref);
+
+	return (0);
+
+  fail:
+	PROC_LOCK(p);
+	killproc(p, "vps_switchproc: unrecoverable error !\n");
+	PROC_UNLOCK(p);
+	if (ppold)
+		wakeup(ppold);
+
+	sx_xunlock(&vps2->vps_lock);
+	sx_xunlock(&vps1->vps_lock);
+
+	return (EINVAL);
+}
+
+/*
+ * Called by reboot().
+ */
+int
+vps_reboot(struct thread *td, int howto)
+{
+	struct vps *vps;
+	struct proc *p, *p2;
+	struct pargs *pargs;
+	struct execve_args args;
+	struct ifnet *ifp;
+	char *comm;
+	/*
+	struct image_args imgargs;
+	int arglen;
+	*/
+	int arg;
+	int reboot;
+	int error;
+
+	DBGCORE("%s: howto=%d\n", __func__, howto);
+
+	error = 0;
+
+	if ( ! ((howto & RB_HALT) || (howto & RB_POWEROFF)) ) {
+		reboot = 1;
+	} else
+		reboot = 0;
+
+	/*
+	 * Get rid of every process/thread in the vps instance.
+	 *
+	 * In case of reboot, we keep the current proc an reuse it.
+	 *
+	 * Otherwise we call vps_destroy() afterwards.
+	 *
+	 */
+
+	vps = td->td_vps;
+
+	KASSERT(vps != vps0, ("%s: attempt to reboot vps0 !\n", __func__));
+
+	if (reboot) {
+		KASSERT(VPS_VPS(vps, initproc) != NULL,
+		    ("%s: vps=%p initproc == NULL\n", __func__, vps));
+
+		p = VPS_VPS(vps, initproc);
+		PROC_SLOCK(p);
+		comm = NULL;
+		pargs = NULL;
+#if 0
+//notyet
+		/* Just ignore that for now. We always exec /sbin/init. */
+		if (p->p_args == NULL || p->p_args->ar_length == 0) {
+			if (p->p_comm[0] == '/') {
+				/* Hope it is null-terminated :-o. */
+				comm = strdup(p->p_comm, M_VPS_CORE);
+			} else {
+				/* Don't know what to execve() */
+				DBGCORE("%s: don't know what to "
+				    "execve() !\n", __func__);
+				reboot = 0;
+			}
+		} else {
+			pargs_hold(p->p_args);
+			pargs = p->p_args;
+		}
+#endif
+		PROC_SUNLOCK(p);
+	}
+
+	sx_slock(&V_allproc_lock);
+	FOREACH_PROC_IN_SYSTEM(p) {
+		PROC_LOCK(p);
+		if (reboot && p == td->td_proc ) {
+			PROC_UNLOCK(p);
+			continue;
+		}
+		if (p_cansignal(td, p, SIGKILL) == 0) {
+			kern_psignal(p, SIGKILL);
+		}
+		PROC_UNLOCK(p);
+	}
+	sx_sunlock(&V_allproc_lock);
+
+#if 0
+	/* No effect. */
+	vps->vps_flags |= VPS_F_REBOOT;
+
+	/* Broadcast kill. */
+	vps_proc_signal(vps, -1, SIGKILL);
+#endif
+
+	while ((V_nprocs - V_nprocs_zomb) > 1) {
+		/* Sleep. */
+		pause("vpsbot", hz / 10);
+	}
+
+	/*
+	 * Reap zombies.
+	 */
+	sx_xlock(&V_proctree_lock);
+	sx_xlock(&V_allproc_lock);
+	LIST_FOREACH_SAFE(p, &V_zombproc, p_list, p2)
+		vps_proc_release(vps, p);
+	sx_xunlock (&V_allproc_lock);
+	sx_xunlock (&V_proctree_lock);
+
+	if ( ! reboot ) {
+		/*
+		 * When the last proc has exited,
+		 * exit1() calls vps_destroy().
+		 * XXX not yet !
+		 */
+		//vps->f_destroy = 1;
+		return (error);
+	}
+
+	/*
+	 * Get rid of everything unwanted and reset
+	 * the process to a fresh state.
+	 */
+	arg = 0;
+	sys_closefrom(td, (struct closefrom_args *)&arg);
+
+	/* This proc is now pid 1. */
+	p = td->td_proc;
+	sx_xlock(&V_proctree_lock);
+	sx_xlock(&V_allproc_lock);
+	PROC_LOCK(p);
+	LIST_REMOVE(p, p_hash);
+	p->p_pid = 1;
+	LIST_INSERT_HEAD(PIDHASH(p->p_pid), p, p_hash);
+	p->p_pptr = NULL;
+	VPS_VPS(vps, initproc) = p;
+	VPS_VPS(vps, initpgrp) = p->p_pgrp;
+	PROC_UNLOCK(p);
+	sx_xunlock(&V_allproc_lock);
+	sx_xunlock(&V_proctree_lock);
+
+	/* Reset vps uptime. */
+	curthread->td_vps = vps0;
+	memset(&VPS_VPS(vps, boottimebin), 0, sizeof(struct bintime));
+	memset(&VPS_VPS(vps, boottime), 0, sizeof(struct timeval));
+	getbintime(&VPS_VPS(vps, boottimebin));
+	bintime2timeval(&VPS_VPS(vps, boottimebin),
+	    &VPS_VPS(vps, boottime));
+	curthread->td_vps = vps;
+
+	/* Reset hostname, domainname, hostuuid. */
+	memset(VPS_VPS(vps, hostname), 0, sizeof(VPS_VPS(vps, hostname)));
+	memset(VPS_VPS(vps, domainname), 0,
+	    sizeof(VPS_VPS(vps, domainname)));
+	memset(VPS_VPS(vps, hostuuid), 0, sizeof(VPS_VPS(vps, hostuuid)));
+
+	/* XXX Clean network interfaces, routing tables, mounts, etc. ... */
+
+	CURVNET_SET_QUIET(vps->vnet);
+
+	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+		if_purgeaddrs(ifp);
+		/* declared static in net/if.c ...
+		if_purgemaddrs(ifp);
+		*/
+	}
+	/* XXX We lose memory this way ...
+	vnet_route_uninit(NULL);
+	vnet_route_init(NULL);
+	*/
+
+	CURVNET_RESTORE();
+
+	vps_unmount_all(vps);
+
+	/*
+	 * XXX Clean this up ! Also fetch the arguments from
+	 *     the proc cmdline of the initproc.
+	 */
+
+#if 1
+
+	error = vps_md_reboot_copyout(td, &args);
+	if (error != 0)
+		goto fail;
+
+	DBGCORE("%s: args.fname=[%s] args.argv=%p \n"
+	    "argv[0]=%p/[%s] argv[1]=%p/[%s]\n",
+	    __func__, args.fname, args.argv,
+	    args.argv[0], args.argv[0],
+	    args.argv[1], args.argv[1]);
+
+	error = sys_execve(td, &args);
+
+#else
+//notyet
+
+	pargs_drop(pargs);
+
+	DBGCORE("%s: imgargs.fname=[%s] imgargs.begin_argv=%p/[%s] "
+	    "imgargs.begin_envv=%p\n", __func__, imgargs.fname,
+	    imgargs.begin_argv, imgargs.begin_argv, imgargs.begin_envv);
+
+	error = kern_execve(td, &imgargs, NULL);
+#endif
+
+	if (error == 0)
+		return (0);
+
+	DBGCORE("%s: execve error %d\n", __func__, error);
+
+  fail:
+	PROC_LOCK(p);
+	killproc(p, "vps reboot failed");
+	PROC_UNLOCK(p);
+
+	return (error);
+}
+
+static int
+vps_sysctl_reclaim(SYSCTL_HANDLER_ARGS)
+{
+
+	if (curthread->td_pinned != 0) {
+		printf("%s: thread is pinned\n", __func__);
+		return (1);
+	}
+
+	/* XXX M_WAITOK not safe
+	zone_drain_wait(proc_zone, M_WAITOK);
+	zone_drain_wait(thread_zone, M_WAITOK);
+	zone_drain_wait(vmspace_zone, M_WAITOK);
+	uma_reclaim();
+	uma_reclaim();
+	*/
+	proc_zone_reclaim();
+	thread_zone_reclaim();
+	vmspace_zone_reclaim();
+	uma_zone_reclaim(NULL);
+	vps_pager_lowmem(NULL);
+
+        return (0);
+}
+
+static int
+vps_prison_alloc(struct vps *vps_parent, struct vps *vps)
+{
+	struct prison *pp, *np;
+
+	const char *name = "0";
+	const char *path = "/";
+	const char *hostuuid = "00000000-0000-0000-0000-000000000000";
+
+	/* Like prison0 */
+
+	VPS_VPS(vps, prison0) = malloc(sizeof(struct prison),
+	    M_VPS_CORE, M_WAITOK|M_ZERO);
+	np = VPS_VPS(vps, prison0);
+	pp = VPS_VPS(vps_parent, prison0);
+
+	np->pr_id = 0;
+	strncpy(np->pr_name, name, strlen(name));
+	/* Keep an extra reference so this fake prison isn't
+	   freed by the last proc. */
+	/* XXX debug this; somethings wrong with references here */
+	np->pr_ref = 3;
+	np->pr_uref = 3;
+	strncpy(np->pr_path, path, strlen(name));
+	np->pr_securelevel = pp->pr_securelevel;
+	np->pr_childmax = pp->pr_childmax;
+	strncpy(np->pr_hostuuid, hostuuid, strlen(hostuuid));
+	LIST_INIT(&np->pr_children);
+	np->pr_flags = pp->pr_flags;
+	np->pr_allow = pp->pr_allow;
+	mtx_init(&np->pr_mtx, "jail mutex", NULL, MTX_DEF);
+
+	/* do all the extra stuff */
+	np->pr_vnet = vps->vnet;
+	VREF(vps->_rootvnode);
+	np->pr_root = vps->_rootvnode;
+	np->pr_cpuset = cpuset_ref(pp->pr_cpuset);
+
+	return (0);
+}
+
+static void
+vps_prison_destroy(struct vps *vps)
+{
+	struct prison *pr;
+
+	pr = VPS_VPS(vps, prison0);
+
+	cpuset_rel(pr->pr_cpuset);
+	//vrele(pr->pr_root);
+
+	mtx_destroy(&pr->pr_mtx);
+
+	KASSERT(LIST_EMPTY(&pr->pr_children),
+		("%s: pr->pr_children list not empty\n", __func__));
+
+	free(pr, M_VPS_CORE);
+	VPS_VPS(vps, prison0) = NULL;
+}
+
+/*
+ * taken from VIMAGE
+ *
+ * ''name'' must be null-terminated !
+ *
+ */
+struct vps *
+vps_by_name(struct vps *top, char *name)
+{
+        struct vps *vps;
+        char *next_name;
+        int namelen;
+
+	sx_assert(&vps_all_lock, SA_LOCKED);
+
+        next_name = strchr(name, '.');
+        if (next_name != NULL) {
+                namelen = next_name - name;
+                next_name++;
+                if (namelen == 0) {
+                        if (strlen(next_name) == 0)
+                                return (top);    /* '.' == this vps */
+                        else
+                                return (NULL);
+                }
+        } else
+                namelen = strlen(name);
+        if (namelen == 0)
+                return (NULL);
+        LIST_FOREACH(vps, &top->vps_child_head, vps_sibling)
+                if (strlen(vps->vps_name) == namelen &&
+                    strncmp(name, vps->vps_name, namelen) == 0) {
+                        if (next_name != NULL)
+                                return (vps_by_name(vps, next_name));
+                        else
+                                return (vps);
+                }
+        return (NULL);
+}
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_ddb.c head/sys/vps/vps_ddb.c
--- clean-head/sys/vps/vps_ddb.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_ddb.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,285 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: vps_ddb.c 180 2013-06-14 16:52:13Z klaus $ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_global.h"
+#include "opt_ddb.h"
+
+#ifdef VPS
+#ifdef DDB
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/refcount.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <net/bpf.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_clone.h>
+#include <net/if_var.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#include <net/vnet.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include "vps_user.h"
+#include "vps.h"
+#include "vps2.h"
+
+static int vps_ddb_refcnt;
+
+static const char *
+vps_statusstr(int status)
+{
+	switch (status) {
+	/*
+	case VPS_ST_INITISDYING:
+		return ("init_is_dying");
+	*/
+	case VPS_ST_CREATING:
+		return ("creating");
+	case VPS_ST_RUNNING:
+		return ("running");
+	case VPS_ST_SUSPENDED:
+		return ("suspended");
+	case VPS_ST_SNAPSHOOTING:
+		return ("snapshooting");
+	case VPS_ST_RESTORING:
+		return ("restoring");
+	case VPS_ST_DYING:
+		return ("dying");
+	case VPS_ST_DEAD:
+		return ("dead");
+	default:
+		return ("unknown");
+	}
+}
+
+#ifdef DDB
+#include <ddb/ddb.h>
+#include <ddb/db_command.h>
+#include <ddb/db_sym.h>
+
+DB_SHOW_COMMAND(vps, db_show_vps)
+{
+	db_expr_t decaddr;
+	struct vps *vps, *vps2;
+	struct proc *p;
+	int i;
+#ifdef INVARIANTS
+	struct vps_ref *ref;
+#endif
+
+	if (!have_addr) {
+		/* Summary list of all vps instances. */
+		db_printf("idx       addr     [name]             parent\n");
+		i = 0;
+		LIST_FOREACH(vps, &vps_head, vps_all) {
+			db_printf("%d %8p [%16s] %8p\n",
+				i, vps, vps->vps_name, vps->vps_parent);
+			i++;
+		}
+		db_printf("show vps <addr/index>\n");
+	} else {
+		decaddr = db_hex2dec(addr);
+		if (decaddr == -1) {
+			vps = (struct vps *)addr;
+		} else {
+			vps = NULL;
+			i = 0;
+			LIST_FOREACH(vps2, &vps_head, vps_all) {
+				if (i == decaddr) {
+					vps = vps2;
+					break;
+				}
+				i++;
+			}
+			if (vps == NULL)
+				return;
+		}
+
+		/* Detailed view of one instance. */
+		db_printf("vps:             %p\n", vps);
+		db_printf("name:            [%s]\n", vps->vps_name);
+		db_printf("parent:          %p\n", vps->vps_parent);
+		db_printf("status:          %s\n",
+		    vps_statusstr(vps->vps_status));
+		db_printf("vnet:            %p\n", vps->vnet);
+		db_printf("nprocs:          %d\n", VPS_VPS(vps, nprocs));
+		db_printf("nprocs_zomb:     %d\n",
+		    VPS_VPS(vps, nprocs_zomb));
+		db_printf("sockets:         %d\n", vps->vnet->vnet_sockcnt);
+		db_printf("refcnt:          %d\n", vps->vps_refcnt);
+		db_printf("restore_count:   %d\n", vps->restore_count);
+		db_printf("processes: \n");
+		LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list) {
+			db_printf("    p=%p pid=%d p_state=%d\n",
+				p, p->p_pid, p->p_state);
+		}
+		db_printf("zombie processes: \n");
+		LIST_FOREACH(p, &VPS_VPS(vps, zombproc), p_list) {
+			db_printf("    p=%p pid=%d p_state=%d\n",
+				p, p->p_pid, p->p_state);
+		}
+#ifdef INVARIANTS
+		db_printf("references: \n");
+		TAILQ_FOREACH(ref, &vps->vps_ref_head, list) {
+			db_printf("    ref=%p arg=%p ticks=%zu\n",
+				ref, ref->arg, (size_t)ref->ticks);
+		}
+#endif
+	}
+}
+
+/*
+ * For changing the current thread's vps reference for being able to use
+ * ddb commands like ''show all procs'' or ''show files''.
+ * Should be reset to original values _before_ leaving the debugger prompt !
+ */
+DB_COMMAND(setcurvps, db_setcurvps)
+{
+	db_expr_t decaddr;
+	struct vps *vps, *vps2;
+	int i;
+
+	if (!have_addr) {
+		db_printf("setcurvps <addr/index>\n");
+		return;
+	}
+
+	decaddr = db_hex2dec(addr);
+	if (decaddr == -1) {
+		vps = (struct vps *)addr;
+	} else {
+		vps = NULL;
+		i = 0;
+		LIST_FOREACH(vps2, &vps_head, vps_all) {
+			if (i == decaddr) {
+				vps = vps2;
+				break;
+			}
+			i++;
+		}
+		if (vps == NULL)
+			return;
+	}
+
+	db_printf("curthread=%p\n"
+		  "   td_vps=%p\n"
+		  "   td_ucred=%p\n"
+		  , curthread
+		  , curthread->td_vps
+		  , curthread->td_ucred
+		 );
+	if (curthread->td_ucred)
+		db_printf("   td_ucred->cr_vps=%p\n",
+		    curthread->td_ucred->cr_vps);
+
+	curthread->td_vps = vps;
+	if (curthread->td_ucred)
+		curthread->td_ucred->cr_vps = vps;
+
+	db_printf("curthread=%p\n"
+		  "   td_vps=%p\n"
+		  "   td_ucred=%p\n"
+		  , curthread
+		  , curthread->td_vps
+		  , curthread->td_ucred
+		 );
+	if (curthread->td_ucred)
+		db_printf("   td_ucred->cr_vps=%p\n",
+		    curthread->td_ucred->cr_vps);
+}
+
+DB_SHOW_COMMAND(ucred, db_show_ucred)
+{
+	struct ucred *ucred;
+
+	if (!have_addr) {
+		db_printf("show ucred <addr>\n");
+		return;
+	}
+
+	ucred = (struct ucred *)addr;
+
+	db_printf("ucred:       %p\n", ucred);
+	db_printf("cr_ref:      %d\n", ucred->cr_ref);
+	db_printf("cr_vps:      %p\n", ucred->cr_vps);
+	db_printf("cr_prison:   %p\n", ucred->cr_prison);
+	db_printf("cr_uid:	%d\n", ucred->cr_uid);
+	db_printf("cr_gid:	%d\n", ucred->cr_gid);
+}
+#endif /* DDB */
+
+static int
+vps_ddb_modevent(module_t mod, int type, void *data)
+{
+
+        switch (type) {
+        case MOD_LOAD:
+		refcount_init(&vps_ddb_refcnt, 0);
+                break;
+        case MOD_UNLOAD:
+		if (vps_ddb_refcnt > 0)
+			return (EBUSY);
+                break;
+        default:
+                return (EOPNOTSUPP);
+        }
+        return (0);
+}
+
+static moduledata_t vps_ddb_mod = {
+        "vps_ddb",
+        vps_ddb_modevent,
+        0
+};
+
+DECLARE_MODULE(vps_ddb, vps_ddb_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+MODULE_VERSION(vps_ddb, 1);
+
+#endif /* DDB */
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_dev.c head/sys/vps/vps_dev.c
--- clean-head/sys/vps/vps_dev.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_dev.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,421 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: vps_dev.c 153 2013-06-03 16:18:17Z klaus $";
+
+#include <sys/cdefs.h>
+
+#include "opt_ddb.h"
+#include "opt_global.h"
+
+#ifdef VPS
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/limits.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/libkern.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/ucred.h>
+#include <sys/ioccom.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/jail.h>
+
+#include <vm/pmap.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include "vps_user.h"
+#include "vps_int.h"
+#include "vps.h"
+#include "vps2.h"
+
+#ifdef DIAGNOSTIC
+
+#define DBGDEV	if (debug_dev) printf
+
+static int debug_dev = 0;
+SYSCTL_INT(_debug, OID_AUTO, vps_dev_debug, CTLFLAG_RW, &debug_dev, 0, "");
+
+#else
+
+#define DBGDEV(x, ...)
+
+#endif /* DIAGNOSTIC */
+
+static int vps_dev_refcnt = 0;
+
+static caddr_t vps_dev_emptypage;
+
+static struct cdev *vps_dev_p;
+static d_fdopen_t  vps_dev_fdopen;
+static d_open_t  vps_dev_open;
+static d_close_t vps_dev_close;
+static d_ioctl_t vps_dev_ioctl;
+static d_mmap_t  vps_dev_mmap;
+
+static struct cdevsw vps_dev_cdevsw = {
+	.d_version = D_VERSION,
+	.d_name = "vps control device",
+	.d_fdopen = vps_dev_fdopen,
+	.d_open = vps_dev_open,
+	.d_close = vps_dev_close,
+	.d_ioctl = vps_dev_ioctl,
+	.d_mmap = vps_dev_mmap,
+	.d_flags = D_TRACKCLOSE,
+};
+
+LIST_HEAD(vps_dev_ctx_le, vps_dev_ctx) vps_dev_ctx_head;
+
+MALLOC_DEFINE(M_VPS_DEV, "vps_dev",
+    "Virtual Private Systems Device memory");
+
+/* ----------------------- */
+
+static int
+vps_dev_attach(void)
+{
+
+	vps_dev_emptypage = malloc(PAGE_SIZE, M_VPS_DEV, M_WAITOK | M_ZERO);
+
+	vps_dev_p = make_dev(&vps_dev_cdevsw, 123, UID_ROOT,
+	    GID_WHEEL, 0600, "vps");
+
+	LIST_INIT(&vps_dev_ctx_head);
+
+	DBGDEV("%s: init done\n", __func__);
+
+	return (0);
+}
+
+static int
+vps_dev_detach(void)
+{
+
+	if (vps_dev_refcnt > 0)
+		return (EBUSY);
+
+	destroy_dev(vps_dev_p);
+
+	free(vps_dev_emptypage, M_VPS_DEV);
+
+	DBGDEV("%s: cleanup done\n", __func__);
+
+	return (0);
+}
+
+static int
+vps_dev_modevent(module_t mod, int type, void *data)
+{
+	int error;
+
+	switch (type) {
+	case MOD_LOAD:
+		error = vps_dev_attach();
+		break;
+	case MOD_UNLOAD:
+		error = vps_dev_detach();
+		break;
+	default:
+		error = EOPNOTSUPP;
+		break;
+	}
+	return (error);
+}
+
+static moduledata_t vps_dev_mod = {
+	"vps_dev",
+	vps_dev_modevent,
+	0
+};
+
+DECLARE_MODULE(vps_dev, vps_dev_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+
+static struct vps_dev_ctx *
+vps_dev_get_ctx(struct thread *td)
+{
+	struct vps_dev_ctx *ctx;
+
+	if (jailed(td->td_ucred)) {
+		printf("%s: td is jailed --> denying any vps-device "
+		    "action !\n", __func__);
+		return (NULL);
+	}
+
+	LIST_FOREACH(ctx, &vps_dev_ctx_head, list)
+		if (ctx->fp == td->td_fpop) {
+			DBGDEV("%s: td->td_fpop=%p ctx=%p\n",
+				__func__, td->td_fpop, ctx);
+			return (ctx);
+		}
+
+	printf("%s: ######## dev_ctx not found for td=%p td->td_fpop=%p "
+	    "pid=%d\n", __func__, td, td->td_fpop, td->td_proc->p_pid);
+
+	return (NULL);
+}
+
+static int
+vps_dev_fdopen(struct cdev *dev, int fflags, struct thread *td,
+    struct file *fp)
+{
+	struct vps_dev_ctx *ctx;
+
+	if (jailed(td->td_ucred)) {
+		printf("%s: td is jailed --> denying any vps-device "
+		    "action !\n", __func__);
+		return (EPERM);
+	}
+
+	atomic_add_int(&vps_dev_refcnt, 1);
+
+	ctx = malloc(sizeof(*ctx), M_VPS_DEV, M_WAITOK | M_ZERO);
+	ctx->fp = fp;
+
+	LIST_INSERT_HEAD(&vps_dev_ctx_head, ctx, list);
+
+	DBGDEV("%s: done refcnt=%d ctx=%p\n",
+	    __func__, vps_dev_refcnt, ctx);
+
+	return (0);
+}
+
+static int
+vps_dev_open(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+
+	return (EOPNOTSUPP);
+}
+
+static int
+vps_dev_close(struct cdev *dev, int flags, int fmt, struct thread *td)
+{
+	struct vps_dev_ctx *ctx;
+
+	ctx = vps_dev_get_ctx(td);
+
+	DBGDEV("%s: ctx=%p\n", __func__, ctx);
+
+	if (ctx == NULL) {
+		printf("%s: ctx == NULL !\n", __func__);
+		return (0);
+	}
+
+	LIST_REMOVE(ctx, list);
+
+	if (ctx->snapst && vps_func->vps_snapshot_finish)
+		vps_func->vps_snapshot_finish(ctx, NULL);
+
+	if (ctx->data)
+		free(ctx->data, M_VPS_DEV);
+
+	free(ctx, M_VPS_DEV);
+
+	atomic_subtract_int(&vps_dev_refcnt, 1);
+
+	DBGDEV("%s: done refcnt=%d ctx=%p\n",
+	    __func__, vps_dev_refcnt, ctx);
+
+	return (0);
+}
+
+static int
+vps_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
+        int flags, struct thread *td)
+{
+	struct vps *vps;
+	struct vps_dev_ctx *ctx;
+	int error;
+
+	ctx = vps_dev_get_ctx(td);
+	if (ctx == NULL) {
+		printf("%s: ctx == NULL !\n", __func__);
+		return (EBADF);
+	}
+
+	/* Needed for conext lookup in mmap pager function. */
+	ctx->td = td;
+
+	error = 0;
+	vps = TD_TO_VPS(td);
+
+	KASSERT(vps != NULL, ("%s: vps == NULL\n", __func__));
+
+	DBGDEV("%s: td=%p ctx=%p cmd=0x%08lx\n",
+	   __func__, td, ctx, cmd);
+
+	switch (cmd) {
+	case VPS_IOC_LIST:
+		error = vps_ioc_list(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_CREAT:
+		error = vps_ioc_create(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_DESTR:
+		error = vps_ioc_destroy(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_SWITCH:
+		error = vps_ioc_switch(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_SWITWT:
+		error = vps_ioc_switchwait(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_IFMOVE:
+		error = vps_ioc_ifmove(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_SUSPND:
+		error = vps_ioc_suspend(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_RESUME:
+		error = vps_ioc_resume(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_ABORT:
+		error = vps_ioc_abort(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_SNAPST:
+		error = vps_ioc_snapshot(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_SNAPSTFIN:
+		error = vps_ioc_snapshot_finish(vps, ctx, cmd, data, flags,
+		    td);
+		break;
+	case VPS_IOC_RESTOR:
+		error = vps_ioc_restore(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_ARGGET:
+		error = vps_ioc_argget(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_ARGSET:
+		error = vps_ioc_argset(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_GETXINFO:
+		error = vps_ioc_getextinfo(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_FSCALCPATH:
+		error = vps_ioc_fscalcpath(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_FSCALC:
+		error = vps_ioc_fscalc(vps, ctx, cmd, data, flags, td);
+		break;
+	case VPS_IOC_GETCONSFD:
+		error = vps_ioc_getconsfd(vps, ctx, cmd, data, flags, td);
+		break;
+	default:
+		error = EOPNOTSUPP;
+		break;
+	}
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_dev_mmap(struct cdev *dev, vm_ooffset_t offset,
+        vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr)
+{
+	struct vps_dev_ctx *ctx, *ctx2;
+	struct vps *vps;
+	int error;
+
+	/* td->td_fpop is not set here.
+	ctx = vps_dev_get_ctx(curthread);
+	*/
+
+	ctx = NULL;
+	LIST_FOREACH(ctx2, &vps_dev_ctx_head, list)
+		if (ctx2->td == curthread) {
+			ctx = ctx2;
+			break;
+		}
+
+	if (ctx == NULL) {
+		/*
+		 * Returning error from this function leads to panic.
+		 * Better return an empty page than let the
+		 * user cause a kernel panic.
+		 */
+		printf("%s: ctx == NULL !\n", __func__);
+		goto invalid;
+	}
+
+	if (ctx->data == NULL && ctx->cmd != VPS_IOC_SNAPST) {
+		printf("%s: ctx->data == NULL !\n", __func__);
+		goto invalid;
+	}
+
+	error = 0;
+	vps = TD_TO_VPS(curthread);
+
+	/* XXX assert vps != NULL */
+
+	if (offset < 0) {
+		printf("%s: offset=%zu < 0\n",
+		    __func__, (size_t)offset);
+		goto invalid;
+	}
+
+	if (nprot != PROT_READ) {
+		printf("%s: nprot=%d != PROT_READ\n",
+		    __func__, nprot);
+		goto invalid;
+	}
+
+	if (1) {
+		/* VPS_IOC_LIST */
+
+		if (offset > ctx->length) {
+			printf("%s: offset=%zu > ctx->length=%zu\n",
+			    __func__, (size_t)offset, ctx->length);
+			goto invalid;
+		}
+
+		*paddr = (vm_paddr_t)vtophys(ctx->data + offset);
+	}
+
+	return (0);
+
+  invalid:
+	*paddr = (vm_paddr_t)vtophys(vps_dev_emptypage);
+
+	return (0);
+}
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_devfsruleset.h head/sys/vps/vps_devfsruleset.h
--- clean-head/sys/vps/vps_devfsruleset.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_devfsruleset.h	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,299 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES, LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: vps_devfsruleset.h 126 2013-04-07 15:55:54Z klaus $ */
+
+#ifndef _VPS_DEVFSRULESET_H
+#define _VPS_DEVFSRULESET_H
+
+#include <sys/cdefs.h>
+
+struct devfs_rule vps_devfs_ruleset_default[] = {
+	/* Hide all. */
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 100),
+	.dr_icond = 0,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_HIDE,
+	},
+	/* Unhide some things. */
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 200),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "null",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 201),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "zero",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 202),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "crypto",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 203),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "random",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 204),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "urandom",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 205),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "console",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 300),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ptyp*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 301),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ptyq*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 302),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ptyr*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 303),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ptys*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 304),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ptyP*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 305),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ptyQ*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 306),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ptyR*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 307),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ptyS*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 308),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ttyp*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 309),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ttyq*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 310),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ttyr*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 311),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ttys*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 312),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ttyP*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 313),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ttyQ*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 314),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ttyR*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 315),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ttyS*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 316),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "pts",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 317),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "pts/*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 318),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "pty/*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 319),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "fd",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 320),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "fd/*",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 321),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "stdin",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 322),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "stdout",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 323),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "stderr",
+	},
+	{
+	.dr_magic = DEVFS_MAGIC,
+	.dr_id = mkrid(100, 324),
+	.dr_icond = DRC_PATHPTRN,
+	.dr_iacts = DRA_BACTS,
+	.dr_bacts = DRB_UNHIDE,
+	.dr_pathptrn = "ttyv*",
+	},
+};
+
+#endif /* _VPS_DEVFSRULESET_H */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_int.h head/sys/vps/vps_int.h
--- clean-head/sys/vps/vps_int.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_int.h	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,189 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: vps_int.h 160 2013-06-05 16:15:56Z klaus $ */;
+
+#ifndef _VPS_INT_H
+#define _VPS_INT_H
+
+#ifdef VPS
+
+struct vps_snapst_ctx;
+struct vps_dumpobj;
+struct vpsfs_limits;
+struct vps_arg_snapst;
+struct vps_arg_item;
+struct vps_dev_ctx;
+struct vps_dumpheader;
+struct mount;
+struct vnode;
+
+struct vps_functions {
+
+/* vps/vps_libdump.c */
+/* object functions */
+struct vps_dumpobj *	(*vps_dumpobj_create)(struct vps_snapst_ctx *ctx,
+				int type, int how);
+void *			(*vps_dumpobj_space)(struct vps_snapst_ctx *ctx,
+				long size, int how);
+int 			(*vps_dumpobj_append)(struct vps_snapst_ctx *ctx,
+				const void *data, long size, int how);
+void			(*vps_dumpobj_close)(struct vps_snapst_ctx *ctx);
+void			(*vps_dumpobj_discard)(struct vps_snapst_ctx *ctx,
+				struct vps_dumpobj *o);
+int			(*vps_dumpobj_checkobj)(struct vps_snapst_ctx *ctx,
+				struct vps_dumpobj *o);
+struct vps_dumpobj *	(*vps_dumpobj_next)(struct vps_snapst_ctx *ctx);
+struct vps_dumpobj *	(*vps_dumpobj_prev)(struct vps_snapst_ctx *ctx);
+int			(*vps_dumpobj_typeofnext)(struct vps_snapst_ctx
+				*ctx);
+int			(*vps_dumpobj_nextischild)(struct vps_snapst_ctx
+				*ctx, struct vps_dumpobj *op);
+int			(*vps_dumpobj_recurse)(struct vps_snapst_ctx *ctx,
+				struct vps_dumpobj *o,
+				void (*func)(struct vps_snapst_ctx *ctx,
+				struct vps_dumpobj *));
+/* tree functions */
+int			(*vps_dumpobj_makerelative)(struct vps_snapst_ctx
+				*ctx);
+int			(*vps_dumpobj_makeabsolute)(struct vps_snapst_ctx
+				*ctx);
+int			(*vps_dumpobj_printtree)(struct vps_snapst_ctx
+				*ctx);
+int			(*vps_dumpobj_checktree)(struct vps_snapst_ctx
+				*ctx);
+/* various subroutines */
+int			(*vps_dumpobj_checkptr)(struct vps_snapst_ctx *ctx,
+				void *p, size_t off);
+const char *		(*vps_libdump_objtype2str)(int objt);
+int			(*vps_libdump_checkheader)(struct vps_dumpheader
+				*h);
+void			(*vps_libdump_printheader)(struct vps_dumpheader
+				*h);
+
+
+/* vps/vps_snapst.c */
+int (*vps_snapshot)(struct vps_dev_ctx *, struct vps *,
+    struct vps_arg_snapst *);
+int (*vps_snapshot_finish)(struct vps_dev_ctx *, struct vps *);
+int (*vps_ctx_extend_hard)(struct vps_snapst_ctx *, struct vps *,
+    size_t, int);
+int (*vps_snapshot_ucred)(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct ucred *cr, int how);
+
+/* vps/vps_restore.c */
+int (*vps_restore)(struct vps_dev_ctx *, struct vps_arg_snapst *);
+int (*vps_restore_ucred)(struct vps_snapst_ctx *ctx, struct vps *vps);
+struct ucred *(*vps_restore_ucred_lookup)(struct vps_snapst_ctx *ctx,
+		struct vps *vps, void *orig_ptr);
+void (*vps_restore_return)(struct thread *td, struct trapframe *frame);
+
+/* vps/vps_suspend.c */
+int (*vps_suspend)(struct vps *, int flags);
+int (*vps_resume)(struct vps *, int flags);
+int (*vps_abort)(struct vps *, int flags);
+void (*vps_syscall_fixup_inthread)(register_t code,
+    struct trapframe *frame);
+int (*vps_access_vmspace)(struct vmspace *vm, vm_offset_t vaddr,
+    size_t len, void *buf, int prot);
+
+/* vps/vps_account.c */
+int (*vpsfs_calcusage_path)(const char *, struct vpsfs_limits *);
+int (*vps_account)(struct vps *vps, int type, int action, size_t size);
+int (*vps_account_waitpfault)(struct vps *vps);
+int (*vps_account_bio)(struct thread *td);
+void (*vps_account_stats)(struct vps *vps);
+int (*vps_account_runnable)(struct thread *td);
+void (*vps_account_thread_pause)(struct thread *td);
+int (*vps_limit_setitem)(struct vps *, struct vps *, struct vps_arg_item *);
+int (*vps_limit_getitemall)(struct vps *, struct vps *, caddr_t, size_t *);
+
+/* fs/vpsfs/vpsfs_vfsops.c */
+int (*vpsfs_nodeget)(struct mount *, struct vnode *, struct vnode **);
+const char *vpsfs_tag;
+
+/* kern/sysv_sem.c */
+int (*sem_snapshot_vps)(struct vps_snapst_ctx *, struct vps *);
+int (*sem_snapshot_proc)(struct vps_snapst_ctx *, struct vps *,
+    struct proc *);
+int (*sem_restore_vps)(struct vps_snapst_ctx *, struct vps *);
+int (*sem_restore_proc)(struct vps_snapst_ctx *, struct vps *,
+    struct proc *);
+int (*sem_restore_fixup)(struct vps_snapst_ctx *, struct vps *);
+
+/* kern/sysv_shm.c */
+int (*shm_snapshot_vps)(struct vps_snapst_ctx *, struct vps *);
+int (*shm_snapshot_proc)(struct vps_snapst_ctx *, struct vps *,
+    struct proc *);
+int (*shm_restore_vps)(struct vps_snapst_ctx *, struct vps *);
+int (*shm_restore_proc)(struct vps_snapst_ctx *, struct vps *,
+    struct proc *);
+int (*shm_restore_fixup)(struct vps_snapst_ctx *, struct vps *);
+
+/* kern/sysv_msg.c */
+int (*msg_snapshot_vps)(struct vps_snapst_ctx *, struct vps *);
+int (*msg_snapshot_proc)(struct vps_snapst_ctx *, struct vps *,
+    struct proc *);
+int (*msg_restore_vps)(struct vps_snapst_ctx *, struct vps *);
+int (*msg_restore_proc)(struct vps_snapst_ctx *, struct vps *,
+    struct proc *);
+int (*msg_restore_fixup)(struct vps_snapst_ctx *, struct vps *);
+
+};
+
+extern struct vps_functions *vps_func;
+
+/* vps/vps_libdump.c */
+/* vps_dumpobj_X --> vdo_X */
+/* vps_libdump_X --> vld_X */
+#define vdo_create 		vps_func->vps_dumpobj_create
+#define vdo_space		vps_func->vps_dumpobj_space
+#define vdo_append		vps_func->vps_dumpobj_append
+#define vdo_close		vps_func->vps_dumpobj_close
+#define vdo_discard		vps_func->vps_dumpobj_discard
+#define vdo_checkobj		vps_func->vps_dumpobj_checkobj
+#define vdo_next		vps_func->vps_dumpobj_next
+#define vdo_prev		vps_func->vps_dumpobj_prev
+#define vdo_typeofnext		vps_func->vps_dumpobj_typeofnext
+#define vdo_nextischild		vps_func->vps_dumpobj_nextischild
+#define vdo_recurse		vps_func->vps_dumpobj_recurse
+#define vdo_makerelative	vps_func->vps_dumpobj_makerelative
+#define vdo_makeabsolute	vps_func->vps_dumpobj_makeabsolute
+#define vdo_printtree		vps_func->vps_dumpobj_printtree
+#define vdo_checktree		vps_func->vps_dumpobj_checktree
+#define vdo_checkptr		vps_func->vps_dumpobj_checkptr
+#define vld_objtype2str		vps_func->vps_libdump_objtype2str
+#define vld_checkheader		vps_func->vps_libdump_checkheader
+#define vld_printheader		vps_func->vps_libdump_printheader
+
+#endif /* VPS */
+
+#endif /* _VPS_INT_H */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_libdump.c head/sys/vps/vps_libdump.c
--- clean-head/sys/vps/vps_libdump.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_libdump.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,1288 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: vps_libdump.c 164 2013-06-10 12:46:17Z klaus $";
+
+/*
+ * cc -o dumptest -I. -DTEST=1 vps/vps_libdump.c
+ */
+
+#ifndef _KERNEL
+
+#ifndef VIMAGE
+#define VIMAGE  1
+#endif
+#ifndef VPS
+#define VPS     1
+#endif
+
+#else
+#include "opt_ddb.h"
+#include "opt_global.h"
+#include "opt_compat.h"
+#endif
+
+#ifdef VPS
+
+#ifdef _KERNEL
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/refcount.h>
+#include <sys/sched.h>
+#include <sys/sockio.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/ttycom.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/uio.h>
+#include <sys/resourcevar.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/namei.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/reboot.h>
+#include <sys/conf.h>
+#include <sys/syscallsubr.h>
+#include <sys/mman.h>
+#include <sys/sleepqueue.h>
+#include <sys/filedesc.h>
+#include <sys/mount.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/pipe.h>
+#include <sys/tty.h>
+#include <sys/syscall.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
+#include <sys/sem.h>
+#include <sys/ktrace.h>
+#include <sys/buf.h>
+#include <sys/jail.h>
+#include <sys/event.h>
+#include <sys/eventvar.h>
+#include <sys/umtx.h>
+
+#include <machine/pcb.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_kern.h>
+
+#include <machine/pcb.h>
+
+#ifdef DDB
+#include <ddb/ddb.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_clone.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <net/radix.h>
+#include <net/route.h>
+#include <net/vnet.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include "vps_account.h"
+#include "vps_user.h"
+#include "vps_int.h"
+#include "vps.h"
+#include "vps2.h"
+
+#define _VPS_SNAPST_H_ALL
+#include <vps/vps_snapst.h>
+
+#define printf DBGCORE
+
+/* object functions */
+struct vps_dumpobj *vps_dumpobj_create(struct vps_snapst_ctx *ctx,
+    int type, int how);
+void *vps_dumpobj_space(struct vps_snapst_ctx *ctx, long size, int how);
+int vps_dumpobj_append(struct vps_snapst_ctx *ctx, const void *data,
+    long size, int how);
+void vps_dumpobj_close(struct vps_snapst_ctx *ctx);
+void vps_dumpobj_discard(struct vps_snapst_ctx *ctx, struct vps_dumpobj *o);
+int vps_dumpobj_checkobj(struct vps_snapst_ctx *ctx, struct vps_dumpobj *o);
+struct vps_dumpobj *vps_dumpobj_next(struct vps_snapst_ctx *ctx);
+struct vps_dumpobj *vps_dumpobj_prev(struct vps_snapst_ctx *ctx);
+int vps_dumpobj_typeofnext(struct vps_snapst_ctx *ctx);
+int vps_dumpobj_nextischild(struct vps_snapst_ctx *ctx,
+    struct vps_dumpobj *op);
+int vps_dumpobj_recurse(struct vps_snapst_ctx *ctx, struct vps_dumpobj *o,
+        void (*func)(struct vps_snapst_ctx *ctx, struct vps_dumpobj *));
+
+/* tree functions */
+int vps_dumpobj_makerelative(struct vps_snapst_ctx *ctx);
+int vps_dumpobj_makeabsolute(struct vps_snapst_ctx *ctx);
+int vps_dumpobj_printtree(struct vps_snapst_ctx *ctx);
+int vps_dumpobj_checktree(struct vps_snapst_ctx *ctx);
+
+/* various subroutines */
+int vps_dumpobj_checkptr(struct vps_snapst_ctx *ctx, void *p, size_t off);
+const char *vps_libdump_objtype2str(int objt);
+int vps_libdump_checkheader(struct vps_dumpheader *h);
+void vps_libdump_printheader(struct vps_dumpheader *h);
+
+#else /* !_KERNEL */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <err.h>
+
+#define panic	printf
+
+#endif /* !_KERNEL */
+
+struct vps_snapst_ctx;
+
+#include <vps/vps_libdump.h>
+
+/* XXX remove again from declarations */
+static void __vps_dumpobj_printtree(struct vps_snapst_ctx *ctx,
+    struct vps_dumpobj *o);
+
+#ifdef TEST
+
+int test01(void);
+int checkfile(const char *);
+
+int main(int argc, char **argv, char **envv)
+{
+	int error;
+
+	if (argc > 2 && strcmp(argv[1], "checkfile")==0) {
+		error = checkfile(argv[2]);
+	} else if (argc > 1 && strcmp(argv[1], "structsizes")==0) {
+		error = structsizes();
+	} else {
+		error = test01();
+	}
+
+	return (error);
+}
+
+#define TOSTRING(s) #s
+#define PRINT_STRUCT_SIZE(s)	\
+	printf("%s: %d %s\n",	\
+		TOSTRING(s),	\
+		sizeof(struct s),	\
+		(sizeof(struct s) % 8) ? "NOT 64bit aligned" : "ok"	\
+	);
+
+int structsizes(void)
+{
+
+	PRINT_STRUCT_SIZE(vps_dump_sysinfo);
+	PRINT_STRUCT_SIZE(vps_dump_vps);
+	PRINT_STRUCT_SIZE(vps_dump_mount);
+	PRINT_STRUCT_SIZE(vps_dump_vnet);
+	PRINT_STRUCT_SIZE(vps_dump_vnet_ifnet);
+	PRINT_STRUCT_SIZE(vps_dump_vnet_ifaddr);
+	PRINT_STRUCT_SIZE(vps_dump_vnet_sockaddr);
+	PRINT_STRUCT_SIZE(vps_dump_vnet_inet6_lifetime);
+	PRINT_STRUCT_SIZE(vps_dump_ucred);
+	PRINT_STRUCT_SIZE(vps_dump_prison);
+	PRINT_STRUCT_SIZE(vps_dump_pgrp);
+	PRINT_STRUCT_SIZE(vps_dump_session);
+	PRINT_STRUCT_SIZE(vps_dump_proc);
+	PRINT_STRUCT_SIZE(vps_dump_pargs);
+	PRINT_STRUCT_SIZE(vps_dump_savefpu);
+	PRINT_STRUCT_SIZE(vps_dump_sysentvec);
+	PRINT_STRUCT_SIZE(vps_dump_vmmap);
+	PRINT_STRUCT_SIZE(vps_dump_vmspace);
+	PRINT_STRUCT_SIZE(vps_dump_vmmapentry);
+	PRINT_STRUCT_SIZE(vps_dump_vmobject);
+	PRINT_STRUCT_SIZE(vps_dump_vmpages);
+	PRINT_STRUCT_SIZE(vps_dump_thread);
+	PRINT_STRUCT_SIZE(vps_dump_filedesc);
+	PRINT_STRUCT_SIZE(vps_dump_file);
+	PRINT_STRUCT_SIZE(vps_dump_pipe);
+	PRINT_STRUCT_SIZE(vps_dump_filepath);
+	PRINT_STRUCT_SIZE(vps_dump_pts);
+	PRINT_STRUCT_SIZE(vps_dump_socket);
+	PRINT_STRUCT_SIZE(vps_dump_unixpcb);
+	PRINT_STRUCT_SIZE(vps_dump_inetpcb);
+	PRINT_STRUCT_SIZE(vps_dump_udppcb);
+	PRINT_STRUCT_SIZE(vps_dump_tcppcb);
+	PRINT_STRUCT_SIZE(vps_dump_sockbuf);
+	PRINT_STRUCT_SIZE(vps_dump_mbufchain);
+	PRINT_STRUCT_SIZE(vps_dump_mbuf);
+	PRINT_STRUCT_SIZE(vps_dump_vmpageref);
+	PRINT_STRUCT_SIZE(vps_dump_route);
+	PRINT_STRUCT_SIZE(vps_dump_knote);
+	PRINT_STRUCT_SIZE(vps_dump_accounting_val);
+	PRINT_STRUCT_SIZE(vps_dump_accounting);
+	PRINT_STRUCT_SIZE(vps_dump_arg_ip4);
+	PRINT_STRUCT_SIZE(vps_dump_arg_ip6);
+	PRINT_STRUCT_SIZE(vps_dump_arg);
+	PRINT_STRUCT_SIZE(vps_dump_sysv_ipcperm);
+	PRINT_STRUCT_SIZE(vps_dump_sysvmsg_msginfo);
+	PRINT_STRUCT_SIZE(vps_dump_sysvmsg_msg);
+	PRINT_STRUCT_SIZE(vps_dump_sysvmsg_msqid);
+	PRINT_STRUCT_SIZE(vps_dump_sysvsem_seminfo);
+	PRINT_STRUCT_SIZE(vps_dump_sysvsem_semid);
+	PRINT_STRUCT_SIZE(vps_dump_sysvsem_sem);
+	PRINT_STRUCT_SIZE(vps_dump_sysvsem_sem_undo);
+	PRINT_STRUCT_SIZE(vps_dump_sysvshm_shmid);
+	PRINT_STRUCT_SIZE(vps_dump_sysvshm_shminfo);
+	PRINT_STRUCT_SIZE(vps_dump_sysvshm_shmmap_state);
+
+	return (0);
+}
+
+int checkfile(const char *path)
+{
+	int fd;
+	int size;
+	void *p;
+	struct stat sb;
+	struct vps_snapst_ctx *ctx;
+
+	if ((fd = open(path, O_RDONLY)) == -1)
+		err(1, "open");
+
+	if ((fstat(fd, &sb)) == -1)
+		err(1, "stat");
+	size = sb.st_size;
+
+	if ((p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
+	    fd, 0)) == MAP_FAILED)
+		err(1, "mmap");
+
+	ctx = malloc(sizeof(*ctx));
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->data = p;
+	ctx->dsize = size;
+	ctx->rootobj = (struct vps_dumpobj *)
+	    (ctx->data + sizeof(struct vps_dumpheader));
+	ctx->relative = 1;
+	ctx->elements = -1;
+
+	vps_libdump_printheader(p);
+
+        if (vps_dumpobj_printtree(ctx))
+		printf("%s: tree is invalid !\n", __func__);
+	else
+		printf("%s: tree is good !\n", __func__);
+
+	free(ctx);
+	munmap(p, size);
+	close(fd);
+
+	return (0);
+}
+
+int test01(void)
+{
+	void *data;
+	long size;
+	struct vps_snapst_ctx ctx2;
+	struct vps_snapst_ctx *ctx = &ctx2;
+	struct vps_dumpheader *h;
+	struct vps_dumpobj *o, *o2;
+
+	size = 0x10000;
+	data = malloc(size);
+
+	ctx->data = ctx->cpos = data;
+	ctx->maxsize = size;
+	ctx->dsize = 0;
+	if (vps_dumpobj_printtree(ctx))
+		printf("%s: tree is invalid !\n", __func__);
+	else
+		printf("%s: tree is good !\n", __func__);
+
+	memset(data, 0x0, size);
+
+	memset(ctx, 0x0, sizeof(*ctx));
+	ctx->data = ctx->cpos = data;
+	ctx->maxsize = size;
+	ctx->dsize = 0;
+	ctx->relative = 0;
+
+	h = (struct vps_dumpheader *)data;
+
+	h->byteorder = VPS_DUMPH_LSB;
+	h->ptrsize = VPS_DUMPH_64BIT;
+	h->pageshift = 12;
+	h->version = VPS_DUMPH_VERSION;
+	h->magic = VPS_DUMPH_MAGIC;
+	h->nsyspages = 10;
+	h->nuserpages = 20;
+	h->size = (h->nsyspages + h->nuserpages) << h->pageshift;
+
+	/*
+	memset(&h->hostname, 'x', 0x180);
+	*/
+
+	vps_libdump_printheader(h);
+
+	ctx->rootobj = vps_dumpobj_create(ctx, VPS_DUMPOBJT_ROOT, 0);
+	vps_dumpobj_append(ctx, main, 0x101, 0);
+	  vps_dumpobj_create(ctx, VPS_DUMPOBJT_VPS, 0);
+	  vps_dumpobj_close(ctx);
+	  //again:
+	  o2 = vps_dumpobj_create(ctx, VPS_DUMPOBJT_MOUNT, 0);
+	    vps_dumpobj_create(ctx, VPS_DUMPOBJT_UCRED, 0);
+	    //vps_dumpobj_discard(ctx, o2);
+	    //goto again;
+	    vps_dumpobj_close(ctx);
+	  vps_dumpobj_close(ctx);
+	  vps_dumpobj_create(ctx, VPS_DUMPOBJT_ARG, 0);
+	  vps_dumpobj_close(ctx);
+	vps_dumpobj_close(ctx);
+
+	if (ctx->level != 0) {
+		printf("ERROR: ctx->level = %d\n", ctx->level);
+	}
+	printf("ctx->elements = %d\n", ctx->elements);
+	printf("ctx->dsize = %d\n", ctx->dsize);
+
+	if (vps_dumpobj_printtree(ctx))
+		printf("%s: tree is invalid !\n", __func__);
+	else
+		printf("%s: tree is good !\n", __func__);
+
+	printf("####### absolute --> relative\n");
+	if (vps_dumpobj_makerelative(ctx))
+		printf("%s: tree is invalid !\n", __func__);
+	else
+		printf("%s: tree is good !\n", __func__);
+
+	if (vps_dumpobj_printtree(ctx))
+		printf("%s: tree is invalid !\n", __func__);
+	else
+		printf("%s: tree is good !\n", __func__);
+
+	printf("####### relative --> absolute\n");
+	if (vps_dumpobj_makeabsolute(ctx))
+		printf("%s: tree is invalid !\n", __func__);
+	else
+		printf("%s: tree is good !\n", __func__);
+
+	if (vps_dumpobj_printtree(ctx))
+		printf("%s: tree is invalid !\n", __func__);
+	else
+		printf("%s: tree is good !\n", __func__);
+
+	o = ctx->curobj = ctx->rootobj;
+	do {
+		if (vps_dumpobj_checkobj(ctx, o))
+			break;
+		__vps_dumpobj_printtree(ctx, o);
+		o = vps_dumpobj_next(ctx);
+	} while (o != NULL);
+
+	free(data);
+
+	return (0);
+}
+#endif /*TEST*/
+
+/* Create a new element. Is always a child of the current open element. */
+struct vps_dumpobj *
+vps_dumpobj_create(struct vps_snapst_ctx *ctx, int type, __unused int how)
+{
+	struct vps_dumpobj *o;
+	int inc;
+
+#ifdef _KERNEL
+	if ((how & ~(M_WAITOK|M_NOWAIT)) != 0) {
+		printf("%s: invalid alloc flag\n", __func__);
+		return (NULL);
+	}
+#endif /* !_KERNEL */
+
+	if (((offset)ctx->cpos & ALIGN_MASK) != 0) {
+		inc = sizeof(ptr) - ((offset)ctx->cpos & ALIGN_MASK);
+		printf("%s: spaced objects by %d bytes for alignment.\n",
+			__func__, inc);
+	} else {
+		inc = 0;
+	}
+
+	/* alloc */
+#ifdef _KERNEL
+	if (vps_ctx_extend(ctx, NULL, sizeof(*o) + inc, how)) {
+		printf("%s: allocation failed\n", __func__);
+		return (NULL);
+	}
+#endif /* !_KERNEL */
+	if (inc != 0) {
+		ctx->curobj->size += inc;
+		ctx->curobj->next = (char *)ctx->curobj->next + inc;
+		ctx->cpos = (char *)ctx->cpos + inc;
+		ctx->dsize += inc;
+	}
+	o = (struct vps_dumpobj *)ctx->cpos;
+	ctx->cpos = (char *)ctx->cpos + sizeof(*o);
+	ctx->dsize += sizeof(*o);
+
+	o->magic = VPS_DUMPH_MAGIC;
+	o->type = type;
+	o->level = ++ctx->level;
+	o->size = sizeof(*o);
+	o->next = ctx->cpos;
+	o->parent = ctx->curobj;
+	if (ctx->elements == 0) {
+		o->parent = o;
+		ctx->rootobj = o;
+	}
+
+	// insert list_children at o->parent
+	// insert list_all
+
+	ctx->curobj = o;
+	ctx->lastobj = o;
+
+	ctx->elements++;
+
+	/*
+	printf("o=%p, magic=%08x, type=%d, size=%u level=%d, next=%p\n",
+		o, o->magic, o->type, o->size, o->level, o->next);
+	*/
+
+	return (o);
+}
+
+/* Discard element (can be called in case further allocation failed). */
+void
+vps_dumpobj_discard(struct vps_snapst_ctx *ctx, struct vps_dumpobj *o)
+{
+	struct vps_dumpobj *o2, *op;
+	int cnt;
+
+	printf("%s: DISCARDING object %p: magic=%08x type=%d size=%d\n",
+		__func__, o, o->magic, o->type, o->size);
+
+	/* for debugging */
+	o->magic = 0xaaaaaaaa;
+
+	/* Edge case */
+	if (o == ctx->rootobj) {
+		ctx->cpos = ctx->data;
+		ctx->dsize = 0;
+		ctx->rootobj = NULL;
+		ctx->curobj = NULL;
+		ctx->lastobj = NULL;
+		ctx->elements = 0;
+		return;
+	}
+
+	/* Looking up the previous element. */
+	op = NULL;
+	o2 = ctx->rootobj;
+	cnt = 0;
+	do {
+		if (o2->next == o) {
+			op = o2;
+			break;
+		}
+		if (vps_dumpobj_checkptr(ctx, o2->next, 0)) {
+			//vps_dumpobj_printtree(ctx);
+			panic("%s: tree is invalid! ctx->rootobj=%p "
+			    "o=%p o2=%p cnt=%d\n",
+			    __func__, ctx->rootobj, o, o2, cnt);
+		}
+		o2 = o2->next;
+		cnt++;
+	} while (o2 < o);
+
+	if (op == NULL)
+		panic("%s: op == NULL (o=%p cnt=%d) !\n",
+			__func__, o, cnt);
+
+	ctx->cpos = o;
+	ctx->dsize = (char *)ctx->cpos - (char *)ctx->data;
+	ctx->curobj = op;
+	ctx->lastobj = op;
+	ctx->level = op->level;
+	ctx->elements = cnt + 1;
+	op->next = ctx->cpos;
+}
+
+/* Reserve space in the current element and return pointer. */
+void *
+vps_dumpobj_space(struct vps_snapst_ctx *ctx, long size, __unused int how)
+{
+	struct vps_dumpobj *o;
+	void *p;
+
+	o = ctx->curobj;
+
+	/* alloc */
+#ifdef _KERNEL
+	if ((how & ~(M_WAITOK|M_NOWAIT)) != 0) {
+		printf("%s: invalid alloc flag\n", __func__);
+		return (NULL);
+	}
+	if (vps_ctx_extend(ctx, NULL, size + 8, how)) {
+		printf("%s: allocation failed\n", __func__);
+		return (NULL);
+	}
+#endif /* !_KERNEL */
+
+	bzero(ctx->cpos, size + 8);
+
+	p = ctx->cpos;
+
+	ctx->cpos = (char *)ctx->cpos + size;
+	ctx->dsize += size;
+
+	o->size += size;
+	o->next = (char *)o->next + size;
+
+	return (p);
+}
+
+/* Append data to the current element. */
+int
+vps_dumpobj_append(struct vps_snapst_ctx *ctx, const void *data,
+    long size, __unused int how)
+{
+	struct vps_dumpobj *o;
+
+	o = ctx->curobj;
+
+	/* alloc */
+#ifdef _KERNEL
+	if ((how & ~(M_WAITOK|M_NOWAIT)) != 0) {
+		printf("%s: invalid alloc flag\n", __func__);
+		return (EINVAL);
+	}
+	if (vps_ctx_extend(ctx, NULL, size + 8, how)) {
+		printf("%s: allocation failed\n", __func__);
+		return (ENOMEM);
+	}
+#endif /* !_KERNEL */
+
+	memcpy(ctx->cpos, data, size);
+	ctx->cpos = (char *)ctx->cpos + size;
+	ctx->dsize += size;
+
+	o->size += size;
+	o->next = (char *)o->next + size;
+
+	return (0);
+}
+
+/* Close the current element. Its parent is the new current element. */
+void
+vps_dumpobj_close(struct vps_snapst_ctx *ctx)
+{
+	struct vps_dumpobj *o;
+	int inc;
+
+	o = ctx->curobj;
+
+	if (o == NULL) {
+		printf("%s: ctx->curobj == NULL !\n", __func__);
+		return;
+	}
+
+	/* _append and _space always reserve extra space for alignment. */
+	if (((offset)ctx->cpos & ALIGN_MASK) != 0) {
+		inc = sizeof(ptr) - ((offset)ctx->cpos & ALIGN_MASK);
+		o->size += inc;
+		o->next = (char *)o->next + inc;
+		ctx->cpos = (char *)ctx->cpos + inc;
+		ctx->dsize += inc;
+		printf("%s: increased object by %d bytes for alignment.\n",
+			__func__, inc);
+	}
+
+	ctx->level--;
+	ctx->curobj = o->parent;
+
+	if (ctx->level == 0)
+		ctx->lastobj->next = ctx->rootobj;
+}
+
+struct vps_dumpobj *
+vps_dumpobj_next(struct vps_snapst_ctx *ctx)
+{
+	struct vps_dumpobj *o;
+
+	if (ctx->relative)
+		return (NULL);
+
+	/* Assumes that the current object has been validated. */
+	o = ctx->curobj->next;
+	if (o == ctx->rootobj)
+		return (NULL);
+
+	if (vps_dumpobj_checkobj(ctx, o))
+		return (NULL);
+
+	ctx->lastobj = ctx->curobj;
+	ctx->curobj = o;
+
+	return (o);
+}
+
+int
+vps_dumpobj_typeofnext(struct vps_snapst_ctx *ctx)
+{
+	struct vps_dumpobj *o;
+
+	if (ctx->relative)
+		return (0);
+
+	/* Assumes that the current object has been validated. */
+	o = ctx->curobj->next;
+	if (o == ctx->rootobj)
+		return (0);
+
+	if (vps_dumpobj_checkobj(ctx, o))
+		return (0);
+
+	return (o->type);
+}
+
+int
+vps_dumpobj_nextischild(struct vps_snapst_ctx *ctx, struct vps_dumpobj *op)
+{
+	struct vps_dumpobj *o;
+
+	if (ctx->relative)
+		return (0);
+
+	/* Assumes that the current object has been validated. */
+	o = ctx->curobj->next;
+	if (o == ctx->rootobj)
+		return (0);
+
+	if (vps_dumpobj_checkobj(ctx, o))
+		return (0);
+
+	while (o != ctx->rootobj) {
+		if (o->parent == op)
+			return (1);
+		o = o->parent;
+	}
+
+	return (0);
+}
+
+/*
+ * XXX Can be only called once since ctx->lastobj is invalid after first
+ *     call without _next in between
+ */
+struct vps_dumpobj *
+vps_dumpobj_prev(struct vps_snapst_ctx *ctx)
+{
+	if (ctx->relative)
+		return (NULL);
+
+	if (ctx->curobj == ctx->lastobj) {
+		panic("%s: called twice !\n", __func__);
+	}
+
+	ctx->curobj = ctx->lastobj;
+
+	return (ctx->curobj);
+}
+
+/* Check a single object for sanity. */
+int
+vps_dumpobj_checkobj(struct vps_snapst_ctx *ctx, struct vps_dumpobj *o)
+{
+	struct vps_dumpobj *op, *on;
+
+	if (vps_dumpobj_checkptr(ctx, o, 0) ||
+	    vps_dumpobj_checkptr(ctx, o, sizeof(*o))) {
+		printf("%s: invalid #1\n", __func__);
+		return (1);
+	}
+
+	/* check parent object */
+	op = o->parent;
+	if (ctx->relative)
+		op = (void *)((offset)op + (offset)ctx->data);
+
+	if (vps_dumpobj_checkptr(ctx, op, 0) ||
+	    vps_dumpobj_checkptr(ctx, op, sizeof(*o))) {
+		printf("%s: invalid #2\n", __func__);
+		return (1);
+	}
+
+	/* only the root object can have itself as parent */
+	if (op == o && o != ctx->rootobj) {
+		printf("%s: invalid #3\n", __func__);
+		return (1);
+	}
+	if (op != o) {
+		/* is this exactly one level lower than the parent ? */
+		if (o->level != op->level + 1) {
+			printf("%s: invalid #4\n", __func__);
+			return (1);
+		}
+	}
+
+	/* check next object */
+	on = o->next;
+	if (ctx->relative)
+		on = (void *)((offset)on + (offset)ctx->data);
+
+	if (vps_dumpobj_checkptr(ctx, on, 0) ||
+	    vps_dumpobj_checkptr(ctx, on, sizeof(*o))) {
+		printf("%s: invalid #5\n", __func__);
+		return (1);
+	}
+
+	/* only the root object can have itself as next object  */
+	if (on == o && (o != ctx->rootobj || ctx->elements != 1)) {
+		printf("%s: invalid #6\n", __func__);
+		return (1);
+	}
+	if (on != o) {
+		if (ctx->elements != -1 && ctx->elements < 2) {
+			printf("%s: invalid #7\n", __func__);
+			return (1);
+		}
+		/* the next object must be exactly at this one
+		   plus its size */
+		if (on != ctx->rootobj && (offset)o + o->size !=
+		    (offset)on) {
+			printf("%s: invalid #8\n", __func__);
+			return (1);
+		}
+	}
+
+	return (0);
+}
+
+int
+vps_dumpobj_checkptr(struct vps_snapst_ctx *ctx, void *p, size_t off)
+{
+
+	if ((char *)p + off < (char *)ctx->data) {
+		printf("%s: invalid ptr=%p; < ctx->data=%p\n",
+			__func__, (char *)p + off, ctx->data);
+		return (1);
+	}
+	if ((char *)p + off > ((char *)ctx->data) + ctx->dsize) {
+		printf("%s: invalid ptr=%p; > ctx->data+ctx->dsize=%p\n",
+		    __func__, (char *)p + off,
+		    ((char *)ctx->data) + ctx->dsize);
+		return (1);
+	}
+
+	return (0);
+}
+
+int
+vps_dumpobj_recurse(struct vps_snapst_ctx *ctx, struct vps_dumpobj *o,
+	void (*func)(struct vps_snapst_ctx *ctx, struct vps_dumpobj *))
+{
+	struct vps_dumpobj *o2, *o3, *op;
+	/* XXX */
+	static int recurse = 0;
+
+	if (o == ctx->rootobj)
+		recurse = 0;
+
+	//printf("%s: recurse=%d o=%p\n", __func__, recurse, o);
+
+	if (vps_dumpobj_checkptr(ctx, o, 0)) {
+		printf("%s: invalid #1\n", __func__);
+		return (1);
+	}
+	if (vps_dumpobj_checkptr(ctx, o, sizeof(*o))) {
+		printf("%s: invalid #2\n", __func__);
+		return (1);
+	}
+
+	o2 = o->next;
+	if (ctx->relative)
+		o2 = (void *)((offset)o2 + (offset)ctx->data);
+
+	if (vps_dumpobj_checkobj(ctx, o))
+		return (1);
+
+	if (func != NULL)
+		func(ctx, o);
+
+	if (o2 == ctx->rootobj) {
+		//printf("%s: ret #1\n", __func__);
+		return (0);
+	}
+	if (vps_dumpobj_checkptr(ctx, o2, 0)) {
+		printf("%s: invalid #3\n", __func__);
+		return (1);
+	}
+	if (vps_dumpobj_checkptr(ctx, o2, sizeof(*o2))) {
+		printf("%s: invalid #4\n", __func__);
+		return (1);
+	}
+
+	while (o2 != NULL) {
+
+		o3 = o2->next;
+		op = o2->parent;
+		if (ctx->relative) {
+			o3 = (void *)((offset)o3 + (offset)ctx->data);
+			/*
+			printf("%s: fixed up %p --> %p (data=%p)\n",
+				__func__, o2->next, o3, ctx->data);
+			*/
+			op = (void *)((offset)o2->parent +
+			    (offset)ctx->data);
+		}
+
+		if (op == o) {
+			if (o2->level != o->level + 1) {
+				printf("%s: invalid #7\n", __func__);
+				return (1);
+			}
+			++recurse;
+			vps_dumpobj_recurse(ctx, o2, func);
+			--recurse;
+		}
+
+		if (o2->level <= o->level) {
+			//printf("%s: ret #3\n", __func__);
+			return (0);
+		}
+
+		if (o3 == ctx->rootobj) {
+			//printf("%s: ret #2\n", __func__);
+			return (0);
+		}
+		if (vps_dumpobj_checkptr(ctx, o3, 0)) {
+			printf("%s: invalid #5\n", __func__);
+			return (1);
+		}
+		if (vps_dumpobj_checkptr(ctx, o3, sizeof(*o3))) {
+			printf("%s: invalid #6\n", __func__);
+			return (1);
+		}
+
+		o2 = o3;
+
+		/*
+		printf("%s: o2=%p o2->level=%d o->level=%d recurse=%d\n",
+			__func__, o2, o2->level, o->level, recurse);
+		*/
+	}
+
+	//printf("%s: --recurse\n", __func__);
+
+	return (0);
+}
+
+/* Make all pointers in object tree relative to data start. */
+int
+vps_dumpobj_makeabsolute(struct vps_snapst_ctx *ctx)
+{
+	struct vps_dumpobj *o;
+
+	if (ctx->relative == 0) {
+		printf("%s: is not relative !\n", __func__);
+		return (1);
+	}
+
+	o = ctx->curobj = ctx->rootobj;
+	do {
+		o->next = (void *)((offset)o->next + (offset)ctx->data);
+		o->parent = (void *)((offset)o->parent + (offset)ctx->data);
+		o = o->next;
+	} while (o != ctx->rootobj);
+
+	ctx->relative = 0;
+
+	return (0);
+}
+
+/* Make all pointers in object tree relative to data start. */
+int
+vps_dumpobj_makerelative(struct vps_snapst_ctx *ctx)
+{
+	struct vps_dumpobj *o, *o2;
+
+	if (ctx->relative != 0) {
+		printf("%s: is already relative !\n", __func__);
+		return (1);
+	}
+
+	o = ctx->curobj = ctx->rootobj;
+	do {
+		o2 = o->next;
+		o->next = (void *)((char *)o->next - (char *)ctx->data);
+		o->parent = (void *)((char *)o->parent - (char *)ctx->data);
+		o = o2;
+	} while (o != NULL && o != ctx->rootobj);
+
+	ctx->relative = 1;
+
+	return (0);
+}
+
+static void
+__vps_dumpobj_printtree(__unused struct vps_snapst_ctx *ctx,
+   struct vps_dumpobj *o)
+{
+	char ident[0x100];
+
+	memset(ident, ' ', o->level * 4);
+	ident[o->level * 4] = 0;
+
+	printf("%so=%p\n", ident, o);
+	printf("%smagic=%08x\n", ident, o->magic);
+	printf("%stype=%d [%s]\n", ident, o->type,
+	    vps_libdump_objtype2str(o->type));
+	printf("%slevel=%d\n", ident, o->level);
+	printf("%ssize=%d\n", ident, o->size);
+	printf("%sparent=%p\n", ident, o->parent);
+	printf("%snext=%p\n", ident, o->next);
+}
+
+int
+vps_dumpobj_printtree(struct vps_snapst_ctx *ctx)
+{
+
+	return (vps_dumpobj_recurse(ctx, ctx->rootobj,
+	    __vps_dumpobj_printtree));
+}
+
+int
+vps_dumpobj_checktree(struct vps_snapst_ctx *ctx)
+{
+
+	return (vps_dumpobj_recurse(ctx, ctx->rootobj, NULL));
+}
+
+/* Check if a character string of given size is null-terminated. */
+__attribute__((unused))
+static int
+vps_libdump_strterminated(const char *str, long size)
+{
+	const char *p = str;
+
+	while (p < (str + size))
+		if (*p++ == '\0')
+			return (1);
+
+	return (0);
+}
+
+/*
+ * 0 --> valid
+ */
+int
+vps_libdump_checkheader(struct vps_dumpheader *h)
+{
+	int rv = 0;
+
+	if (h->byteorder != VPS_DUMPH_MSB && h->byteorder != VPS_DUMPH_LSB)
+		++rv;
+	if (h->ptrsize != VPS_DUMPH_32BIT && h->ptrsize != VPS_DUMPH_64BIT)
+		++rv;
+	if (h->version < 0x20120606)
+		++rv;
+	if (h->magic != VPS_DUMPH_MAGIC)
+		++rv;
+	if (h->nsyspages < 1)
+		++rv;
+	if ((h->nsyspages + h->nuserpages) << h->pageshift != h->size)
+		++rv;
+	if (h->pageshift != PAGE_SHIFT)
+		++rv;
+
+	/* check strings for null termination */
+	/*
+	if (!vps_libdump_strterminated(h->kernel, sizeof(h->kernel)))
+		++rv;
+	*/
+
+	/* XXX check checksum of syspages stuff */
+
+	return (rv);
+}
+
+void
+vps_libdump_printheader(struct vps_dumpheader *h)
+{
+	const char *byteorder;
+
+	if (vps_libdump_checkheader(h) == 0) {
+		printf("header is valid.\n");
+	} else {
+		printf("header is invalid.\n");
+	}
+
+	switch (h->byteorder) {
+	case VPS_DUMPH_MSB: byteorder = "MSB"; break;
+	case VPS_DUMPH_LSB: byteorder = "LSB"; break;
+	default: byteorder = "UNKNOWN"; break;
+	}
+	printf("byteorder:       %s\n",
+	    byteorder);
+	printf("ptrsize:         %u bit\n",
+	    h->ptrsize);
+	printf("pageshift:       %u --> pagesize=%u\n",
+	    h->pageshift, 1 << h->pageshift);
+	printf("version:         %08x\n",
+	    h->version);
+	printf("magic:           %08x\n",
+	    h->magic);
+	printf("time:            %lld\n",
+	    (long long signed int)h->time);
+	printf("size:            0x%016llx\n",
+	    (long long unsigned int)h->size);
+	printf("checksum:        0x%016llx\n",
+	    (long long unsigned int)h->checksum);
+	printf("nsyspages:       0x%08x\n",
+	    h->nsyspages);
+	printf("nuserpages:      0x%08x\n",
+	    h->nuserpages);
+}
+
+const char *
+vps_libdump_objtype2str(int objt)
+{
+
+	switch (objt) {
+	case VPS_DUMPOBJT_ROOT:
+		return ("VPS_DUMPOBJT_ROOT");
+	case VPS_DUMPOBJT_SYSINFO:
+		return ("VPS_DUMPOBJT_SYSINFO");
+	case VPS_DUMPOBJT_VPS:
+		return ("VPS_DUMPOBJT_VPS");
+	case VPS_DUMPOBJT_ARG:
+		return ("VPS_DUMPOBJT_ARG");
+	case VPS_DUMPOBJT_END:
+		return ("VPS_DUMPOBJT_END");
+	case VPS_DUMPOBJT_PROC:
+		return ("VPS_DUMPOBJT_PROC");
+	case VPS_DUMPOBJT_THREAD:
+		return ("VPS_DUMPOBJT_THREAD");
+	case VPS_DUMPOBJT_PGRP:
+		return ("VPS_DUMPOBJT_PGRP");
+	case VPS_DUMPOBJT_SESSION:
+		return ("VPS_DUMPOBJT_SESSION");
+	case VPS_DUMPOBJT_SYSENTVEC:
+		return ("VPS_DUMPOBJT_SYSENTVEC");
+	case VPS_DUMPOBJT_VMSPACE:
+		return ("VPS_DUMPOBJT_VMSPACE");
+	case VPS_DUMPOBJT_VMMAPENTRY:
+		return ("VPS_DUMPOBJT_VMMAPENTRY");
+	case VPS_DUMPOBJT_VMOBJECT:
+		return ("VPS_DUMPOBJT_VMOBJECT");
+	case VPS_DUMPOBJT_VMPAGE:
+		return ("VPS_DUMPOBJT_VMPAGE");
+	case VPS_DUMPOBJT_VMOBJ_VNPATH:
+		return ("VPS_DUMPOBJT_VMOBJ_VNPATH");
+	case VPS_DUMPOBJT_FDSET:
+		return ("VPS_DUMPOBJT_FDSET");
+	case VPS_DUMPOBJT_FILE:
+		return ("VPS_DUMPOBJT_FILE");
+	case VPS_DUMPOBJT_FILE_PATH:
+		return ("VPS_DUMPOBJT_FILE_PATH");
+	case VPS_DUMPOBJT_PTS:
+		return ("VPS_DUMPOBJT_PTS");
+	case VPS_DUMPOBJT_PIPE:
+		return ("VPS_DUMPOBJT_PIPE");
+	case VPS_DUMPOBJT_PARGS:
+		return ("VPS_DUMPOBJT_PARGS");
+	case VPS_DUMPOBJT_SOCKET:
+		return ("VPS_DUMPOBJT_SOCKET");
+	case VPS_DUMPOBJT_SOCKBUF:
+		return ("VPS_DUMPOBJT_SOCKBUF");
+	case VPS_DUMPOBJT_MBUFCHAIN:
+		return ("VPS_DUMPOBJT_MBUFCHAIN");
+	case VPS_DUMPOBJT_SOCKET_UNIX:
+		return ("VPS_DUMPOBJT_SOCKET_UNIX");
+	case VPS_DUMPOBJT_MOUNT:
+		return ("VPS_DUMPOBJT_MOUNT");
+	case VPS_DUMPOBJT_VNET_IFACE:
+		return ("VPS_DUMPOBJT_VNET_IFACE");
+	case VPS_DUMPOBJT_VNET_ADDR:
+		return ("VPS_DUMPOBJT_VNET_ADDR");
+	case VPS_DUMPOBJT_VNET_ROUTETABLE:
+		return ("VPS_DUMPOBJT_VNET_ROUTETABLE");
+	case VPS_DUMPOBJT_VNET_ROUTE:
+		return ("VPS_DUMPOBJT_VNET_ROUTE");
+	case VPS_DUMPOBJT_VNET:
+		return ("VPS_DUMPOBJT_VNET");
+	case VPS_DUMPOBJT_SYSVSEM_VPS:
+		return ("VPS_DUMPOBJT_SYSVSEM_VPS");
+	case VPS_DUMPOBJT_SYSVSEM_PROC:
+		return ("VPS_DUMPOBJT_SYSVSEM_PROC");
+	case VPS_DUMPOBJT_SYSVSHM_VPS:
+		return ("VPS_DUMPOBJT_SYSVSHM_VPS");
+	case VPS_DUMPOBJT_SYSVSHM_PROC:
+		return ("VPS_DUMPOBJT_SYSVSHM_PROC");
+	case VPS_DUMPOBJT_SYSVMSG_VPS:
+		return ("VPS_DUMPOBJT_SYSVMSG_VPS");
+	case VPS_DUMPOBJT_SYSVMSG_PROC:
+		return ("VPS_DUMPOBJT_SYSVMSG_PROC");
+	case VPS_DUMPOBJT_KQUEUE:
+		return ("VPS_DUMPOBJT_KQUEUE");
+	case VPS_DUMPOBJT_KNOTE:
+		return ("VPS_DUMPOBJT_KNOTE");
+	case VPS_DUMPOBJT_KEVENT:
+		return ("VPS_DUMPOBJT_KEVENT");
+	case VPS_DUMPOBJT_UMTX:
+		return ("VPS_DUMPOBJT_UMTX");
+	case VPS_DUMPOBJT_PRISON:
+		return ("VPS_DUMPOBJT_PRISON");
+	case VPS_DUMPOBJT_UCRED:
+		return ("VPS_DUMPOBJT_UCRED");
+	default:
+		return ("UNKOWN");
+	}
+}
+
+#ifdef _KERNEL
+
+static int
+vps_libdump_modevent(module_t mod, int type, void *data)
+{
+	int error = 0;
+
+	switch (type) {
+	case MOD_LOAD:
+		vps_func->vps_dumpobj_create =
+		    vps_dumpobj_create;
+		vps_func->vps_dumpobj_space =
+		    vps_dumpobj_space;
+		vps_func->vps_dumpobj_append =
+		    vps_dumpobj_append;
+		vps_func->vps_dumpobj_close =
+		    vps_dumpobj_close;
+		vps_func->vps_dumpobj_discard =
+		    vps_dumpobj_discard;
+		vps_func->vps_dumpobj_checkobj =
+		    vps_dumpobj_checkobj;
+		vps_func->vps_dumpobj_next =
+		    vps_dumpobj_next;
+		vps_func->vps_dumpobj_prev =
+		    vps_dumpobj_prev;
+		vps_func->vps_dumpobj_typeofnext =
+		    vps_dumpobj_typeofnext;
+		vps_func->vps_dumpobj_nextischild =
+		    vps_dumpobj_nextischild;
+		vps_func->vps_dumpobj_recurse =
+		    vps_dumpobj_recurse;
+		vps_func->vps_dumpobj_makerelative =
+		    vps_dumpobj_makerelative;
+		vps_func->vps_dumpobj_makeabsolute =
+		    vps_dumpobj_makeabsolute;
+		vps_func->vps_dumpobj_printtree =
+		    vps_dumpobj_printtree;
+		vps_func->vps_dumpobj_checktree =
+		    vps_dumpobj_checktree;
+		vps_func->vps_dumpobj_checkptr =
+		    vps_dumpobj_checkptr;
+		vps_func->vps_libdump_objtype2str =
+		    vps_libdump_objtype2str;
+		vps_func->vps_libdump_checkheader =
+		    vps_libdump_checkheader;
+		vps_func->vps_libdump_printheader =
+		    vps_libdump_printheader;
+		break;
+	case MOD_UNLOAD:
+		vps_func->vps_dumpobj_create = NULL;
+		vps_func->vps_dumpobj_space = NULL;
+		vps_func->vps_dumpobj_append = NULL;
+		vps_func->vps_dumpobj_close = NULL;
+		vps_func->vps_dumpobj_discard = NULL;
+		vps_func->vps_dumpobj_checkobj = NULL;
+		vps_func->vps_dumpobj_next = NULL;
+		vps_func->vps_dumpobj_prev = NULL;
+		vps_func->vps_dumpobj_typeofnext = NULL;
+		vps_func->vps_dumpobj_nextischild = NULL;
+		vps_func->vps_dumpobj_recurse = NULL;
+		vps_func->vps_dumpobj_makerelative = NULL;
+		vps_func->vps_dumpobj_makeabsolute = NULL;
+		vps_func->vps_dumpobj_printtree = NULL;
+		vps_func->vps_dumpobj_checktree = NULL;
+		vps_func->vps_dumpobj_checkptr = NULL;
+		vps_func->vps_libdump_objtype2str = NULL;
+		vps_func->vps_libdump_checkheader = NULL;
+		vps_func->vps_libdump_printheader = NULL;
+		break;
+	default:
+		error = EOPNOTSUPP;
+		break;
+	}
+
+	return (error);
+}
+
+static moduledata_t vps_libdump_mod = {
+	"vps_libdump",
+	vps_libdump_modevent,
+	0
+};
+
+DECLARE_MODULE(vps_libdump, vps_libdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+
+#endif /* _KERNEL */
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_libdump.h head/sys/vps/vps_libdump.h
--- clean-head/sys/vps/vps_libdump.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_libdump.h	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,1037 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: vps_libdump.h 162 2013-06-06 18:17:55Z klaus $ */
+
+#ifndef _VPS_LIBDUMP_H
+#define _VPS_LIBDUMP_H
+
+#include <machine/vps_md.h>
+
+#ifndef _KERNEL
+
+struct vps_snapst_ctx {
+	void *data;
+	void *cpos;
+	long dsize;
+	long maxsize;
+	struct vps_dumpobj *rootobj;
+	struct vps_dumpobj *lastobj;
+	struct vps_dumpobj *curobj;
+	int level;
+	int elements;
+	char relative;
+};
+
+struct vps_dumpheader;
+
+/* object functions */
+struct vps_dumpobj *vps_dumpobj_create(struct vps_snapst_ctx *ctx,
+    int type, int how);
+void *vps_dumpobj_space(struct vps_snapst_ctx *ctx, long size, int how);
+int vps_dumpobj_append(struct vps_snapst_ctx *ctx, const void *data,
+    long size, int how);
+void vps_dumpobj_close(struct vps_snapst_ctx *ctx);
+void vps_dumpobj_discard(struct vps_snapst_ctx *ctx, struct vps_dumpobj *o);
+int vps_dumpobj_checkobj(struct vps_snapst_ctx *ctx, struct vps_dumpobj *o);
+struct vps_dumpobj *vps_dumpobj_next(struct vps_snapst_ctx *ctx);
+struct vps_dumpobj *vps_dumpobj_prev(struct vps_snapst_ctx *ctx);
+int vps_dumpobj_typeofnext(struct vps_snapst_ctx *ctx);
+int vps_dumpobj_nextischild(struct vps_snapst_ctx *ctx,
+    struct vps_dumpobj *op);
+int vps_dumpobj_recurse(struct vps_snapst_ctx *ctx, struct vps_dumpobj *o,
+    void (*func)(struct vps_snapst_ctx *ctx, struct vps_dumpobj *));
+
+/* tree functions */
+int vps_dumpobj_makerelative(struct vps_snapst_ctx *ctx);
+int vps_dumpobj_makeabsolute(struct vps_snapst_ctx *ctx);
+int vps_dumpobj_printtree(struct vps_snapst_ctx *ctx);
+int vps_dumpobj_checktree(struct vps_snapst_ctx *ctx);
+
+/* various subroutines */
+int vps_dumpobj_checkptr(struct vps_snapst_ctx *ctx, void *p, size_t off);
+const char *vps_libdump_objtype2str(int objt);
+int vps_libdump_checkheader(struct vps_dumpheader *h);
+void vps_libdump_printheader(struct vps_dumpheader *h);
+
+#endif /* !_KERNEL */
+
+#define VPS_DUMPOBJT_ROOT                2
+#define VPS_DUMPOBJT_SYSINFO             3
+#define VPS_DUMPOBJT_VPS                 4
+#define VPS_DUMPOBJT_ARG                 6
+#define VPS_DUMPOBJT_END                 9
+#define VPS_DUMPOBJT_PROC               10
+#define VPS_DUMPOBJT_THREAD             12
+#define VPS_DUMPOBJT_PGRP               14
+#define VPS_DUMPOBJT_SESSION            15
+#define VPS_DUMPOBJT_SAVEFPU		18
+#define VPS_DUMPOBJT_SYSENTVEC          19
+#define VPS_DUMPOBJT_VMSPACE            20
+#define VPS_DUMPOBJT_VMMAPENTRY		22
+#define VPS_DUMPOBJT_VMOBJECT           23
+#define VPS_DUMPOBJT_VMPAGE             24
+#define VPS_DUMPOBJT_VMOBJ_VNPATH       25
+#define VPS_DUMPOBJT_FDSET              30
+#define VPS_DUMPOBJT_FILE               31
+#define VPS_DUMPOBJT_FILE_PATH          32
+#define VPS_DUMPOBJT_PTS                33
+#define VPS_DUMPOBJT_PIPE               34
+#define VPS_DUMPOBJT_PARGS              35
+#define VPS_DUMPOBJT_SOCKET             36
+#define VPS_DUMPOBJT_SOCKBUF            37
+#define VPS_DUMPOBJT_MBUFCHAIN          38
+#define VPS_DUMPOBJT_SOCKET_UNIX        39
+#define VPS_DUMPOBJT_MOUNT              40
+#define VPS_DUMPOBJT_VNET_IFACE         50
+#define VPS_DUMPOBJT_VNET_ADDR          52
+#define VPS_DUMPOBJT_VNET_ROUTETABLE    55
+#define VPS_DUMPOBJT_VNET_ROUTE         56
+#define VPS_DUMPOBJT_VNET               59
+#define VPS_DUMPOBJT_SYSVSEM_VPS        70
+#define VPS_DUMPOBJT_SYSVSEM_PROC       71
+#define VPS_DUMPOBJT_SYSVSHM_VPS        72
+#define VPS_DUMPOBJT_SYSVSHM_PROC       73
+#define VPS_DUMPOBJT_SYSVMSG_VPS        74
+#define VPS_DUMPOBJT_SYSVMSG_PROC       75
+#define VPS_DUMPOBJT_KQUEUE             80
+#define VPS_DUMPOBJT_KNOTE              81
+#define VPS_DUMPOBJT_KEVENT             82
+#define VPS_DUMPOBJT_UMTX               90
+#define VPS_DUMPOBJT_PRISON             100
+#define VPS_DUMPOBJT_UCRED              120
+
+#define VPS_DUMPH_MAGIC			0xc0debabe
+#define VPS_DUMPH_VERSION		0x20130512
+#define VPS_DUMPH_MSB			12
+#define VPS_DUMPH_LSB			21
+#define VPS_DUMPH_32BIT			32
+#define VPS_DUMPH_64BIT			64
+
+//#if defined(CPU_X86)
+#if defined(VPS_ARCH_AMD64)
+/* AMD64 declarations */
+typedef unsigned char	uint8;
+typedef unsigned short 	uint16;
+typedef unsigned int 	uint32;
+typedef unsigned long 	uint64;
+typedef signed char	sint8;
+typedef signed short 	sint16;
+typedef signed int 	sint32;
+typedef signed long 	sint64;
+typedef unsigned char	byte;
+typedef void * 		ptr;
+typedef uint64		offset;
+#define PTR(x)		ptr x
+#define ALIGN_MASK	0x7
+#define PTRTO64(x)	(uint64)(x)
+#define PTRFROM64(x)	(void *)(x)
+
+#ifndef PAGE_SHIFT
+#define PAGE_SHIFT	12
+#endif
+
+#ifndef _KERNEL
+/*
+typedef unsigned long size_t;
+*/
+#endif
+
+/* end amd64 declarations */
+
+//#elif defined(CPU_386)
+#elif defined(VPS_ARCH_I386)
+/* i386 declarations */
+typedef unsigned char	uint8;
+typedef unsigned short 	uint16;
+typedef unsigned int 	uint32;
+typedef unsigned long long	uint64;
+typedef signed char	sint8;
+typedef signed short 	sint16;
+typedef signed int 	sint32;
+typedef signed long long 	sint64;
+typedef unsigned char	byte;
+typedef void * 		ptr;
+typedef uint32		offset;
+#define PTR(x)		ptr x; uint32 _pad_##x
+#define ALIGN_MASK	0x3
+#define PTRTO64(x)	(uint64)(uint32)(x)
+#define PTRFROM64(x)	(void *)(uint32)(x)
+
+#ifndef PAGE_SHIFT
+#define PAGE_SHIFT	12
+#endif
+
+#ifndef _KERNEL
+typedef unsigned int size_t;
+#endif
+
+/* end i386 declarations */
+
+#elif defined(VPS_ARCH_MIPSEB64)
+
+/* mipseb64 declarations */
+typedef unsigned char	uint8;
+typedef unsigned short 	uint16;
+typedef unsigned int 	uint32;
+typedef unsigned long 	uint64;
+typedef signed char	sint8;
+typedef signed short 	sint16;
+typedef signed int 	sint32;
+typedef signed long 	sint64;
+typedef unsigned char	byte;
+typedef void * 		ptr;
+typedef uint64		offset;
+#define PTR(x)		ptr x
+#define ALIGN_MASK	0x7
+#define PTRTO64(x)	(uint64)(x)
+#define PTRFROM64(x)	(void *)(x)
+
+#ifndef PAGE_SHIFT
+#define PAGE_SHIFT	12
+#endif
+
+#ifndef _KERNEL
+/*
+typedef unsigned long size_t;
+*/
+#endif
+
+/* end mipseb64 declarations */
+
+#else
+#error "unsupported architecture"
+#endif
+
+
+struct vps_dumpobj {
+	uint32 magic;	/* for debugging purposes; 0x0 or 0xc0debabe */
+	uint16 type;
+	uint16 level;	/* level this object is in */
+	uint32 size;	/* size of this object including it's header */
+	uint32 pad0;
+	PTR(parent);	/* offset to parent object (from start of
+			   snapshot) */
+	PTR(next);	/* offset to next object (from start of
+			   snapshot) */
+	PTR(list_children);	/* internal: SLIST_ENTRY(vps_dumpobj)
+				   list */
+	PTR(list_siblings);	/* internal: SLIST_ENTRY(vps_dumpobj)
+				   list */
+	byte data[0];	/* amount of data specified by 'size' */
+	/* next object is always aligned to 'ptrsize' */
+};
+
+
+struct vps_dumpheader {
+	uint8 byteorder;	/* 0d12 == MSB; 0d21 == LSB */
+	uint8 ptrsize;		/* 0d32 == 32 bits; 0d64 == 64 bits; ... */
+	uint8 pageshift;	/* e.g. 0d12 for 4096 byte pages */
+	byte pad0[5];
+	uint32 version;		/* date in hexadecimal; e.g. 0x20120518 */
+	uint32 magic;
+	sint64 time;
+	uint64 size;
+	uint64 checksum;
+	uint32 nsyspages;
+	uint32 nuserpages;
+};
+
+#if 0
+/* Example of a vps_snapst_ctx. */
+struct vps_snapst_ctx {
+	void *data;
+	void *cpos;
+	long dsize;
+	long maxsize;
+	struct vps_dumpobj *rootobj;
+	struct vps_dumpobj *lastobj;
+	struct vps_dumpobj *curobj;
+	int level;
+	int elements;
+	char relative;
+};
+#endif
+
+/*
+ * functions
+ */
+
+
+
+/*
+ * dump object types
+ */
+
+struct vps_dump_sysinfo {
+	char kernel[0x100];
+	char hostname[0x100];
+	PTR(shared_page_obj);
+};
+
+struct vps_dump_vps {
+	char hostname[0x100];
+	char vps_name[0x100];
+	char rootpath[0x400];
+
+	struct {
+		sint64 tv_sec;
+		sint64 tv_usec;
+	} boottime;
+
+	sint32 lastpid;
+	sint32 initpgrp_id;
+	sint32 initproc_id;
+	uint32 restore_count;
+};
+
+struct vps_dump_mount {
+        char mntfrom[0x80];
+        char mnton[0x80];
+        char fstype[0x10];
+        uint8 vpsmount;
+        uint8 _pad0[7];
+        uint64 flags;
+        PTR(mnt_cred);
+};
+
+struct vps_dump_vnet {
+	PTR(orig_ptr);
+};
+
+struct vps_dump_vnet_ifnet {
+	char if_dname[0x10];
+	char if_xname[0x10];
+	uint32 if_dunit;
+	uint32 if_flags;
+};
+
+struct vps_dump_vnet_ifaddr {
+	uint8 have_addr;
+	uint8 have_dstaddr;
+	uint8 have_netmask;
+	uint8 _pad0[5];
+};
+
+// #define SOCK_MAXADDRLEN 255             /* longest possible addresses */
+struct vps_dump_vnet_sockaddr {
+	uint16 sa_len;
+	uint16 sa_family;
+	uint32 _pad0;
+	char sa_data[0x100];
+};
+
+struct vps_dump_vnet_inet6_lifetime {
+	sint64 ia6t_expire;
+	sint64 ia6t_preferred;
+	uint32 ia6t_vltime;
+	uint32 ia6t_pltime;
+};
+
+struct vps_dump_ucred {
+	uint32 cr_uid;
+	uint32 cr_ruid;
+	uint32 cr_svuid;
+	sint32 cr_ngroups;
+
+	uint32 cr_rgid;
+	uint32 cr_svgid;
+	uint32 cr_flags;
+	uint32 cr_ref;
+
+	PTR(cr_origptr);
+	PTR(cr_prison);
+	PTR(cr_vps);
+
+	uint32 cr_groups[0];	/* always padded to 64 bit alignment */
+};
+
+struct vps_dump_prison {
+	uint32 pr_id;
+	uint32 pr_securelevel;
+	uint32 pr_enforce_statfs;
+	uint32 pr_childmax;
+
+	uint32 pr_ip4s;
+	uint32 pr_ip6s;
+
+	uint64 pr_flags;
+	uint64 pr_allow;
+
+	char pr_name[0x100];
+	char pr_path[0x400];
+
+	PTR(pr_root);
+	PTR(pr_origptr);
+	PTR(pr_parent);
+
+	char pr_ipdata[0];
+};
+
+struct vps_dump_pgrp {
+	uint32 pg_id;
+	uint32 pg_jobc;
+
+	uint32 pg_session_id;
+	uint32 _pad0;
+};
+
+struct vps_dump_session {
+	uint32 s_sid;
+	uint32 s_leader_id;
+
+	uint32 s_count;
+	uint8 s_have_ttyvp;
+	uint8 _pad0[3];
+
+	char s_login[0x30];
+};
+
+struct vps_dump_proc {
+	sint32 p_pid;
+	uint32 p_swtick;
+
+	char p_comm[0x20];
+
+	sint64 p_cpulimit;
+
+	sint32 p_flag;
+	sint32 p_state;
+
+	uint32 p_stops;
+	uint32 p_stype;
+
+	sint8 p_nice;
+	sint8 p_step;
+	uint16 p_xstat;
+	sint32 p_oppid;
+
+	uint32 p_xthread_id;
+	sint32 p_sigparent;
+
+	PTR(p_ucred);
+
+	uint8 p_have_tracevp;
+	uint8 p_have_textvp;
+	uint16 _pad0;
+	sint32 p_traceflag;
+
+	PTR(p_tracecred);
+
+	sint32 p_pptr_id;
+	sint32 p_peers_id;
+
+	sint32 p_leader_id;
+	sint32 p_pgrp_id;
+
+	PTR(p_fd);
+
+	PTR(p_vmspace);
+
+	struct {
+		uint32 ps_maxsig;
+		uint32 ps_sigwords;
+		uint64 ps_sigact[0x80];
+		uint32 ps_catchmask[0x80][0x4];
+		uint32 ps_sigonstack[0x4];
+		uint32 ps_sigintr[0x4];
+		uint32 ps_sigreset[0x4];
+		uint32 ps_signodefer[0x4];
+		uint32 ps_siginfo[0x4];
+		uint32 ps_sigignore[0x4];
+		uint32 ps_sigcatch[0x4];
+		uint32 ps_freebsd4[0x4];
+		uint32 ps_osigset[0x4];
+		uint32 ps_usertramp[0x4];
+		uint32 ps_flag;
+		uint32 _pad0;
+	} p_sigacts;
+
+	struct {
+		uint32 pl_nlimits;
+		uint32 _pad1;
+		struct {
+			sint64 rlim_cur;
+			sint64 rlim_max;
+		} pl_rlimit[0x10];
+	} p_limit;
+};
+
+struct vps_dump_pargs {
+	uint32 ar_length;
+	uint32 _pad0;
+	char ar_args[0];	/* always padded to 64 bit alignment */
+};
+
+struct vps_dump_savefpu {
+	uint32 sf_length;
+	uint32 _pad0;
+	char sf_data[0];	/* always padded to 64 bit alignment */
+};
+
+struct vps_dump_sysentvec {
+	uint32 sv_type;
+	uint32 _pad0;
+};
+
+struct vps_dump_vmmap {
+	uint64 minoffset;
+	uint64 maxoffset;
+};
+
+struct vps_dump_vmspace {
+	PTR(vm_orig_ptr);
+	struct vps_dump_vmmap vm_map;
+	uint64 vm_tsize;
+	uint64 vm_dsize;
+	uint64 vm_ssize;
+};
+
+struct vps_dump_vmmapentry {
+	PTR(map_object);
+	PTR(cred);
+
+	uint32 eflags;
+	uint8 protection;
+	uint8 max_protection;
+	sint8 inheritance;
+	uint8 _pad0;
+
+	uint64 offset;
+	uint64 start;
+	uint64 end;
+	uint64 avail_ssize;
+};
+
+struct vps_dump_vmobject {
+	PTR(orig_ptr);
+	PTR(cred);
+	PTR(backing_object);
+
+	uint16 flags;
+	uint8 type;
+	uint8 have_vnode;
+	uint8 is_sharedpageobj;
+	uint8 _pad0[3];
+
+	uint64 size;
+	uint64 charge;
+	uint64 backing_object_offset;
+};
+
+struct vps_dump_vmpages {
+	uint64 count;
+};
+
+struct vps_dump_thread {
+	struct {
+		uint64 ss_sp;
+		uint64 ss_size;
+		sint32 ss_flags;
+		sint32 _pad0;
+	} td_sigstk;
+	uint32 td_sigmask[0x4];
+	uint32 td_oldsigmask[0x4];
+	sint32 td_xsig;
+	sint32 td_dbgflags;
+
+	uint8 td_rqindex;
+	uint8 td_base_pri;
+	uint8 td_priority;
+	uint8 td_pri_class;
+	uint8 td_user_pri;
+	uint8 td_base_user_pri;
+	uint8 _pad1[2];
+
+	uint64 td_retval[2];
+	sint32 td_errno;
+	uint32 _pad2;
+
+	sint32 td_tid;
+	uint32 td_kstack_pages;
+	char td_kstack[0];	/* always padded to 64 bit alignment */
+};
+
+struct vps_dump_filedesc {
+	PTR(fd_orig_ptr);
+
+	uint8 fd_have_cdir;
+	uint8 fd_have_rdir;
+	uint8 fd_have_jdir;
+	uint8 _pad0[5];
+
+	uint32 fd_nfiles;
+	uint32 _pad1;
+
+	struct {
+		PTR(fp);
+		uint8 flags;
+		uint8 _pad0[7];
+		uint64 rights;
+	} fd_entries[0];
+};
+
+struct vps_dump_file {
+	uint32 flags;
+	uint32 _pad0;
+
+	PTR(orig_ptr);
+	PTR(f_cred);
+
+	uint64 f_offset;
+
+	uint32 f_flag;
+	sint16 f_type;
+	uint16 _pad1;
+};
+
+struct vps_dump_pipe {
+	uint8 pi_have_dumped_pipe;
+	uint8 _pad0[7];
+	PTR(pi_localend);
+	PTR(pi_pair);
+	PTR(pi_rpipe);
+	PTR(pi_wpipe);
+};
+
+struct vps_dump_filepath {
+	uint32 fp_size;
+	uint32 _pad0;
+
+	char fp_path[0];	/* always padded to 64 bit alignment */
+};
+
+struct vps_dump_pts {
+	sint32 pt_index;
+	sint32 pt_pgrp_id;
+	uint32 pt_flags;
+	uint32 _pad0;
+	PTR(pt_cred);
+	struct {
+		uint32 c_iflag;
+		uint32 c_oflag;
+		uint32 c_cflag;
+		uint32 c_lflag;
+		uint8 c_cc[0x20];
+		uint32 c_ispeed;
+		uint32 c_ospeed;
+	} pt_termios;
+};
+
+struct vps_dump_socket {
+	PTR(so_orig_ptr);
+
+	PTR(so_cred);
+
+	sint16 so_family;
+	sint16 so_type;
+	sint16 so_protocol;
+	sint16 _pad0;
+
+	sint16 so_options;
+	uint16 so_qlimit;
+	sint16 so_state;
+	sint16 _pad1;
+
+	sint32 so_qstate;
+	uint16 so_qlen;
+	uint16 so_incqlen;
+};
+
+struct vps_dump_unixpcb {
+	uint8 unp_have_conn;
+	uint8 unp_have_addr;
+	uint8 unp_have_vnode;
+	uint8 _pad0[5];
+
+	sint16 unp_flags;
+	sint16 _pad1;
+	uint32 _pad2;
+
+	sint32 unp_cc;
+	sint32 unp_mbcnt;
+
+	PTR(unp_socket);
+
+	PTR(unp_conn_socket);
+
+	struct {
+		uint32 cr_uid;
+		uint16 cr_ngroups;
+		uint16 _pad3;
+
+		uint32 cr_groups[16];
+	} unp_peercred;
+};
+
+struct vps_dump_inetpcb {
+	uint8 inp_vflag;
+	uint8 inp_ip_p;
+	uint8 inp_have_ppcb;
+	uint8 _pad0[5];
+
+	sint32 inp_flags;
+	sint32 inp_flags2;
+
+	struct {
+		uint8 inc_flags;
+		uint8 inc_len;
+		uint16 inc_fibnum;
+		uint32 _pad0;
+
+		uint8 ie_ufaddr[0x10];
+
+		uint8 ie_uladdr[0x10];
+
+		uint16 ie_fport;
+		uint16 ie_lport;
+		uint32 _pad1;
+	} inp_inc;
+};
+
+struct vps_dump_udppcb {
+	uint8 u_have_tun_func;
+	uint8 _pad0[3];
+	uint32 u_flags;
+};
+
+struct vps_dump_tcppcb {
+	sint32 t_state;
+	sint32 t_flags;
+
+	uint32 snd_una;
+	uint32 snd_max;
+
+	uint32 snd_nxt;
+	uint32 snd_up;
+
+	uint32 snd_wl1;
+	uint32 snd_wl2;
+
+	uint32 iss;
+	uint32 irs;
+
+	uint32 rcv_nxt;
+	uint32 rcv_adv;
+
+	uint64 rcv_wnd;
+
+	uint32 rcv_up;
+	uint32 _pad0;
+
+	uint64 snd_wnd;
+
+	uint64 snd_cwnd;
+
+	uint64 snd_ssthresh;
+};
+
+struct vps_dump_sockbuf {
+	PTR(sb_mb);
+	PTR(sb_mbtail);
+	PTR(sb_lastrecord);
+	PTR(sb_sndptr);
+
+	sint16 sb_state;
+	sint16 sb_flags;
+	uint32 sb_sndptroff;
+
+	uint32 sb_cc;
+	uint32 sb_hiwat;
+
+	uint32 sb_mbcnt;
+	uint32 sb_mcnt;
+
+	uint32 sb_ccnt;
+	uint32 sb_mbmax;
+
+	uint32 sb_ctl;
+	sint32 sb_lowat;
+
+	uint32 sb_timeo;
+	uint32 _pad0;
+
+};
+
+struct vps_dump_mbufchain {
+	uint32 mc_mbcount;
+	uint32 _pad0;
+};
+
+struct vps_dump_mbuf {
+	PTR(mb_orig_ptr);
+
+	sint16 mb_type;
+	sint16 _pad0[3];
+
+	sint32 mb_len;
+	sint32 mb_flags;
+
+	uint8 mb_have_dat;
+	uint8 mb_have_ext;
+	uint8 mb_have_data;
+	uint8 _pad1[5];
+
+	/*
+	uint32 mb_dat_size;
+	uint32 mb_ext_size;
+	*/
+	uint32 mb_payload_size;
+	uint32 _pad2;
+
+	uint32 mb_data_off;
+	uint32 mb_checksum;
+
+	char mb_payload[0];	/* always padded to 64 bit alignment */
+};
+
+struct vps_dump_vmpageref {
+        PTR(pr_vmobject);
+        uint64 pr_pindex;
+};
+
+struct vps_dump_route {
+	sint32 rt_flags;
+	uint32 rt_fibnum;
+
+	uint8 rt_have_mask;
+	uint8 rt_have_gateway;
+	uint8 rt_have_ifp;
+	uint8 rt_have_ifa;
+	uint8 _pad0[4];
+
+	struct {
+		uint64 rmx_mtu;
+		uint64 rmx_expire;
+		uint64 rmx_pksent;
+		uint64 rmx_weight;
+	} rt_rmx;
+};
+
+struct vps_dump_knote {
+	sint32 kn_status;
+	uint32 _pad0;
+
+	sint16 ke_filter;
+	uint16 ke_flags;
+	uint32 ke_fflags;
+
+	uint64 ke_ident;
+	uint64 ke_data;
+	PTR(ke_udata);
+};
+
+struct vps_dump_accounting_val {
+	uint64 cur;
+	uint64 cnt_cur;
+	uint64 soft;
+	uint64 hard;
+	uint32 hits_soft;
+	uint32 hits_hard;
+};
+
+struct vps_dump_accounting {
+	struct vps_dump_accounting_val virt;
+	struct vps_dump_accounting_val phys;
+	struct vps_dump_accounting_val kmem;
+	struct vps_dump_accounting_val kernel;
+	struct vps_dump_accounting_val buffer;
+	struct vps_dump_accounting_val pctcpu;
+	struct vps_dump_accounting_val blockio;
+	struct vps_dump_accounting_val threads;
+	struct vps_dump_accounting_val procs;
+};
+
+struct vps_dump_arg_ip4 {
+	uint8 a4_addr[0x4];
+	uint8 a4_mask[0x4];
+};
+
+struct vps_dump_arg_ip6 {
+	uint8 a6_addr[0x10];
+	uint8 a6_plen;
+	uint8 _pad0[7];
+};
+
+struct vps_dump_arg {
+        uint32 ip4net_cnt;
+        uint32 ip6net_cnt;
+
+        uint32 privset_size;
+        uint8 have_accounting;
+	uint8 _pad0[3];
+};
+
+struct vps_dump_sysv_ipcperm {
+	uint32 cuid;
+	uint32 cgid;
+	uint32 uid;
+	uint32 gid;
+	uint16 mode;
+	uint16 seq;
+	uint32 _pad0;
+	sint64 key;
+};
+
+/* sysv msg */
+struct vps_dump_sysvmsg_msginfo {
+	sint32 msgmax;
+	sint32 msgmni;
+	sint32 msgmnb;
+	sint32 msgtql;
+	sint32 msgssz;
+	sint32 msgseg;
+
+	sint32 nfree_msgmaps;
+	sint32 free_msgmaps;
+	uint64 free_msghdrs_idx;
+};
+
+struct vps_dump_sysvmsg_msg {
+	sint64 msg_next;
+
+	sint64 msg_type;
+
+	uint16 msg_ts;
+	sint16 msg_spot;
+	uint32 _pad0;
+
+	PTR(label);
+};
+
+struct vps_dump_sysvmsg_msqid {
+	struct vps_dump_sysv_ipcperm msg_perm;
+	sint64 msg_first;
+	sint64 msg_last;
+	uint64 msg_cbytes;
+	uint64 msg_qnum;
+	uint64 msg_qbytes;
+	sint32 msg_lspid;
+	sint32 msg_lrpid;
+	uint64 msg_stime;
+	uint64 msg_rtime;
+	uint64 msg_ctime;
+	PTR(label);
+	PTR(cred);
+};
+
+/* sysv sem */
+
+struct vps_dump_sysvsem_seminfo {
+	sint32 semmni;
+	sint32 semmns;
+	sint32 semmnu;
+	sint32 semmsl;
+	sint32 semopm;
+	sint32 semume;
+	sint32 semusz;
+	sint32 semvmx;
+	sint32 semaem;
+	sint32 _pad0;
+
+        sint32 semtot;
+        sint32 semundo_active;
+};
+
+struct vps_dump_sysvsem_semid {
+	struct vps_dump_sysv_ipcperm sem_perm;
+	sint64 sem_base;
+	uint16 sem_nsems;
+	uint16 _pad0[3];
+	uint64 sem_otime;
+	uint64 sem_ctime;
+	PTR(label);
+	PTR(cred);
+};
+
+struct vps_dump_sysvsem_sem {
+	uint16 semval;
+	uint16 _pad0[3];
+	sint32 sempid;
+	uint16 semncnt;
+	uint16 semzcnt;
+};
+
+struct vps_dump_sysvsem_sem_undo {
+	sint32 un_proc;
+	sint16 un_cnt;
+	uint16 _pad0;
+
+	struct {
+		sint16 un_adjval;
+		sint16 un_num;
+		sint32 un_id;
+		uint16 un_seq;
+		uint16 _pad1[3];
+	} un_ent[0];
+};
+
+/* sysv shm */
+
+struct vps_dump_sysvshm_shmid {
+	struct vps_dump_sysv_ipcperm shm_perm;
+	uint64 shm_segsz;
+	sint32 shm_lpid;
+	sint32 shm_cpid;
+	sint32 shm_nattch;
+	sint32 _pad0;
+	uint64 shm_atime;
+	uint64 shm_dtime;
+	uint64 shm_ctime;
+	PTR(object);
+	PTR(label);
+	PTR(cred);
+};
+
+struct vps_dump_sysvshm_shminfo {
+	uint64 shmmax;
+	uint64 shmmin;
+	uint64 shmmni;
+	uint64 shmseg;
+	uint64 shmall;
+
+	sint32 shm_last_free;
+	sint32 shm_nused;
+	sint32 shmalloced;
+	sint32 _pad0;
+	uint64 shm_committed;
+
+	struct vps_dump_sysvshm_shmid shmsegs[0];
+};
+
+struct vps_dump_sysvshm_shmmap_state {
+	uint64 va;
+
+	sint32 shmid;
+	uint32 _pad0;
+};
+
+#endif /*_VPS_LIBDUMP_H*/
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_pager.c head/sys/vps/vps_pager.c
--- clean-head/sys/vps/vps_pager.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_pager.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,688 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Based on sys/vm/device_pager.c.
+ */
+
+static const char vpsid[] =
+    "$Id: vps_pager.c 153 2013-06-03 16:18:17Z klaus $";
+
+/*
+ * This pager makes it possible to provide a linear snapshot of
+ * a vps instance's userspace memory.
+ * It only maps pages that really exist, untouched virtual memory
+ * regions don't get included.
+ *
+ * Zero copying is done, instead fake pages are used that are
+ * allocated on demand and the backing real pages are wired down.
+ * On putting of those fake pages the backing real pages are
+ * unwired, so that they can be paged out any time necessary.
+ *
+ * Per snapshot exactly one vm object is provided to the vpsctl
+ * process. It includes the system pages and the user pages.
+ *
+ * Since all activity of a vps instance is suspended during
+ * snapshot there can't be any changes in vm maps or missing
+ * objects (tm).
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+#include <sys/mutex.h>
+#include <sys/mman.h>
+#include <sys/sx.h>
+#include <sys/malloc.h>
+
+#include <vps/vps.h>
+#include <vps/vps2.h>
+#include <vps/vps_int.h>
+#include <vps/vps_snapst.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_object.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/uma.h>
+
+int vps_pager_put_object(vm_object_t object, long desired);
+
+static void vps_pager_init(void);
+static vm_object_t vps_pager_alloc(void *, vm_ooffset_t, vm_prot_t,
+	vm_ooffset_t, struct ucred *);
+static void vps_pager_dealloc(vm_object_t);
+static int vps_pager_getpages(vm_object_t, vm_page_t *, int, int);
+static void vps_pager_putpages(vm_object_t, vm_page_t *, int,
+	boolean_t, int *);
+static boolean_t vps_pager_haspage(vm_object_t, vm_pindex_t, int *,
+	int *);
+void vps_pager_lowmem(void *);
+
+struct pagerops vps_pager_ops = {
+	.pgo_init =     vps_pager_init,
+	.pgo_alloc =    vps_pager_alloc,
+	.pgo_dealloc =  vps_pager_dealloc,
+	.pgo_getpages = vps_pager_getpages,
+	.pgo_putpages = vps_pager_putpages,
+	.pgo_haspage =  vps_pager_haspage,
+};
+
+/* list of vps pager objects */
+static struct pagerlst vps_pager_object_list;
+/* protect list manipulation */
+static struct mtx vps_pager_mtx;
+
+static int lowmem_registered;
+
+static void
+vps_pager_init(void)
+{
+
+	TAILQ_INIT(&vps_pager_object_list);
+	mtx_init(&vps_pager_mtx, "vps_pager list", NULL, MTX_DEF);
+}
+
+static vm_object_t
+vps_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot,
+	vm_ooffset_t foff, struct ucred *cred)
+{
+	vm_object_t object;
+
+	if (lowmem_registered == 0) {
+		lowmem_registered = 1;
+		EVENTHANDLER_REGISTER(vm_lowmem, vps_pager_lowmem, NULL,
+			EVENTHANDLER_PRI_ANY);
+	}
+
+	object = vm_object_allocate(OBJT_VPS, size);
+
+	object->handle = handle;
+	TAILQ_INIT(&object->un_pager.devp.devp_pglist);
+
+	DBGCORE("%s: handle=%p size=%zu\n", __func__, handle, (size_t)size);
+
+	mtx_lock(&vps_pager_mtx);
+	TAILQ_INSERT_TAIL(&vps_pager_object_list, object,
+	    pager_object_list);
+	mtx_unlock(&vps_pager_mtx);
+
+	return (object);
+}
+
+static void
+vps_pager_dealloc(vm_object_t object)
+{
+	vm_object_t object2;
+	vm_page_t *marr;
+	vm_page_t m1;
+	int *rtvals;
+	int found;
+	int count;
+	int i;
+
+	count = object->resident_page_count;
+	VM_OBJECT_WUNLOCK(object);
+
+	mtx_lock(&vps_pager_mtx);
+	found = 0;
+	TAILQ_FOREACH(object2, &vps_pager_object_list, pager_object_list)
+		if (object2 == object)
+			found = 1;
+	if (found == 0) {
+		/* Already removed.
+		   XXX find out why dealloc is called twice ! */
+		mtx_unlock(&vps_pager_mtx);
+		VM_OBJECT_WLOCK(object);
+		return;
+	}
+	TAILQ_REMOVE(&vps_pager_object_list, object, pager_object_list);
+	mtx_unlock(&vps_pager_mtx);
+
+	marr = malloc(sizeof(vm_page_t) * count, M_TEMP, M_WAITOK);
+	rtvals = malloc(sizeof(int) * count, M_TEMP, M_WAITOK);
+
+	VM_OBJECT_WLOCK(object);
+
+	i = 0;
+	TAILQ_FOREACH(m1, &object->memq, listq) {
+		marr[i] = m1;
+		i++;
+	}
+
+	vps_pager_putpages(object, marr, count, 0, rtvals);
+
+	VM_OBJECT_WUNLOCK(object);
+
+	free(marr, M_TEMP);
+	free(rtvals, M_TEMP);
+
+	VM_OBJECT_WLOCK(object);
+
+	DBGCORE("%s: vps_pager_dealloc: object=%p, freed %d pages\n",
+		__func__, object, count);
+}
+
+static vm_map_entry_t
+vps_vm_object_in_map(vm_map_t map, vm_object_t object)
+{
+	vm_map_entry_t entry;
+	vm_object_t obj;
+	int entcount;
+
+	/* XXX submaps */
+
+	entry = map->header.next;
+	entcount = map->nentries;
+	while (entcount-- && (entry != &map->header)) {
+		if ((obj = entry->object.vm_object) != NULL) {
+			for (; obj; obj = obj->backing_object) {
+				if (obj == object) {
+					return (entry);
+				}
+			}
+		}
+	}
+
+	return (NULL);
+}
+
+/*
+ * lowmem event
+ */
+void
+vps_pager_lowmem(void *arg)
+{
+	vm_object_t object, object2;
+	vm_page_t *marr;
+	vm_page_t m1;
+	vm_map_entry_t entry;
+	struct proc *p;
+	vm_map_t map;
+	int *rtvals;
+	int maxcount = 0x1000;
+	int i, j;
+
+
+	/*
+	 * Determine which pages we can release:
+	 * The lower pindexes are less likely to be accessed soon again.
+	 */
+
+	if ((marr = malloc(sizeof(vm_page_t) * maxcount,
+	    M_TEMP, M_NOWAIT)) == NULL)
+		return;
+	if ((rtvals = malloc(sizeof(int) * maxcount,
+	    M_TEMP, M_NOWAIT)) == NULL) {
+		free(marr, M_TEMP);
+		return;
+	}
+
+	mtx_lock(&vps_pager_mtx);
+	TAILQ_FOREACH_SAFE(object, &vps_pager_object_list,
+	    pager_object_list, object2) {
+		mtx_unlock(&vps_pager_mtx);
+		VM_OBJECT_WLOCK(object);
+
+		if ((object->flags & OBJ_DEAD) == 0 &&
+			object->resident_page_count > 0) {
+
+
+			/* Release the first half of resident pages
+			   in object. */
+			/* memq is sorted */
+
+			i = 0;
+			TAILQ_FOREACH(m1, &object->memq, listq) {
+				marr[i] = m1;
+				if (i >= maxcount)
+					break;
+				if (i >= object->resident_page_count / 2)
+					break;
+				i++;
+			}
+
+			VM_OBJECT_WUNLOCK(object);
+
+			/*
+			 * We have to manually release all pmap mappings
+			 * since our pages are fictious.
+			 * Worst of all, we have to walk through all
+			 * processes vmspace maps to find out which map
+			 * refers to our object.
+			 */
+			/* XXX per VPS */
+			sx_slock(&V_allproc_lock);
+			FOREACH_PROC_IN_SYSTEM(p) {
+				PROC_LOCK(p);
+				map = &p->p_vmspace->vm_map;
+				PROC_UNLOCK(p);
+				if (map == NULL)
+					continue;
+				if ((entry = vps_vm_object_in_map(map,
+				    object)) == NULL)
+					continue;
+
+				for (j = 0; j < i; j++) {
+					pmap_remove(map->pmap,
+					    entry->start +
+					    (marr[j]->pindex << PAGE_SHIFT),
+					    entry->start +
+					    ((marr[j]->pindex+1) <<
+					    PAGE_SHIFT));
+				}
+			}
+			sx_sunlock(&V_allproc_lock);
+
+			VM_OBJECT_WLOCK(object);
+
+			vps_pager_putpages(object, marr, i, 0, rtvals);
+
+			DBGCORE("%s: object=%p freed %d pages\n",
+				__func__, object, i);
+
+		}
+
+		VM_OBJECT_WUNLOCK(object);
+		mtx_lock(&vps_pager_mtx);
+	}
+	mtx_unlock(&vps_pager_mtx);
+
+	free(marr, M_TEMP);
+	free(rtvals, M_TEMP);
+
+}
+
+/*
+ * Called from pageout daemon whenever memory should be reclaimed.
+ *
+ * We put our fake pages in the requested object,
+ * which in turn unwires the backing pages.
+ * They can be paged out then any time.
+ */
+
+int
+vps_pager_put_object(vm_object_t object, long desired)
+{
+	vm_page_t *marr;
+	vm_page_t m1;
+	int *rtvals;
+	int count;
+	int i;
+
+	DBGCORE("%s: ENT object=%p desired=%ld nresident=%d\n",
+		__func__, object, desired, object->resident_page_count);
+
+	count = object->resident_page_count;
+	VM_OBJECT_WUNLOCK(object);
+
+	marr = malloc(sizeof(vm_page_t) * count, M_TEMP, M_WAITOK);
+	rtvals = malloc(sizeof(int) * count, M_TEMP, M_WAITOK);
+
+	VM_OBJECT_WLOCK(object);
+
+	i = 0;
+	TAILQ_FOREACH(m1, &object->memq, listq) {
+		marr[i] = m1;
+		i++;
+	}
+
+	vps_pager_putpages(object, marr, count, 0, rtvals);
+
+	VM_OBJECT_WUNLOCK(object);
+
+	free(marr, M_TEMP);
+	free(rtvals, M_TEMP);
+
+	VM_OBJECT_WLOCK(object);
+
+	DBGCORE("%s: RET object=%p nresident=%d\n",
+		__func__, object, object->resident_page_count);
+
+	return (count);
+}
+
+static int
+vps_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage)
+{
+	struct vps_snapst_ctx *ctx;
+	struct vps_page_ref *pref;
+	vm_memattr_t memattr;
+	vm_pindex_t pidx2;
+	vm_pindex_t pidx;
+	vm_paddr_t paddr;
+	vm_object_t obj2;
+	vm_page_t m1;
+	vm_page_t m2;
+	int origin;
+	int rv;
+	int i;
+	char need_wakeup = 0;
+
+	VM_OBJECT_ASSERT_WLOCKED(object);
+
+	KASSERT(object->handle != NULL,
+		("%s: handle == NULL, object=%p\n", __func__, object));
+
+	ctx = (struct vps_snapst_ctx *)object->handle;
+	pidx = m[reqpage]->pindex;
+	m1 = m[reqpage];
+	memattr = object->memattr;
+
+	VM_OBJECT_WUNLOCK(object);
+
+	if (pidx < ctx->nsyspages) {
+		/* system pages */
+
+		obj2 = ctx->vmobj;
+		pidx2 = pidx;
+		origin = 0;
+
+	} else if (pidx >= ctx->nsyspages &&
+	    pidx < (ctx->nsyspages + ctx->nuserpages)) {
+		/* user pages */
+
+		pref = &ctx->page_ref[pidx - ctx->nsyspages];
+		obj2 = pref->obj;
+		pidx2 = pref->pidx;
+		origin = pref->origin;
+
+	} else {
+		/* invalid */
+		VM_OBJECT_WLOCK(object);
+		DBGCORE("%s: requested invalid pindex %zu, object=%p\n",
+			__func__, (size_t)pidx, object);
+		return (VM_PAGER_FAIL);
+	}
+
+	VM_OBJECT_WLOCK(obj2);
+	if (obj2->type != OBJT_SWAP) {
+		m2 = vm_page_lookup(obj2, pidx2);
+		/* XXX also here there is no page sometimes
+		KASSERT(m2 != NULL, ("%s: obj2=%p type=%x pidx2=0x%lx "
+		    "no page\n", __func__, obj2, obj2->type, pidx2));
+		*/
+
+		if (m2)
+			ctx->pager_npages_res++;
+
+	} else if (obj2->type == OBJT_SWAP) {
+		m2 = vm_page_lookup(obj2, pidx2);
+		if (m2 == NULL) {
+			m2 = vm_page_grab(obj2, pidx2, VM_ALLOC_NORMAL |
+			    VM_ALLOC_RETRY);
+			pmap_zero_page(m2);
+			rv = vm_pager_get_pages(obj2, &m2, 1, 0);
+			/*
+			XXX
+			XXX
+			XXX
+			if (rv != VM_PAGER_OK)
+			*/
+			if (rv == VM_PAGER_ERROR)
+				panic("%s: vm_pager_get_pages: rv = %d\n"
+				    "obj1=%p pidx1=%zu obj2=%p pidx=%zu\n",
+				    __func__, rv, object, (size_t)pidx,
+				    obj2, (size_t)pidx2);
+			/* XXX
+			KASSERT(m2->valid == VM_PAGE_BITS_ALL,
+			    ("%s: m2=%p valid=0x%x\n",
+			    __func__, m2, m2->valid));
+			*/
+			need_wakeup = 1;
+
+			if (m2)
+				ctx->pager_npages_swap++;
+
+			/* Note that this page is not physically mapped
+			   now in user space. */
+		} else {
+			ctx->pager_npages_res++;
+		}
+	} else {
+		panic("%s: obj2=%p type=%x\n", __func__, obj2, obj2->type);
+	}
+
+	/* relookup */
+	if ((m2 = vm_page_lookup(obj2, pidx2))) {
+		vm_page_lock(m2);
+		vm_page_wire(m2);
+		paddr = m2->phys_addr;
+		vm_page_unlock(m2);
+		/*
+		KASSERT(m2->valid == VM_PAGE_BITS_ALL,
+		    ("%s: m2=%p valid=0x%x\n",
+		    __func__, m2, m2->valid));
+		*/
+	} else {
+		/* XXX
+		if (vm_pager_has_page(obj2, pidx2, NULL, NULL) == FALSE)
+			panic("%s: page vanished ! obj2=%p pidx=0x%lx\n",
+			    __func__, obj2, pidx2);
+		else
+			panic("%s: pager has page but doesn't come in ! "
+			    "obj2=%p pidx=0x%lx\n",
+			    __func__, obj2, pidx2);
+		*/
+		/* We still don't have a page, give up. */
+		ctx->pager_npages_miss++;
+		VM_OBJECT_WUNLOCK(obj2);
+		VM_OBJECT_WLOCK(object);
+		for (i = 0; i < count; i++) {
+			if (i != reqpage) {
+				vm_page_lock(m[i]);
+				vm_page_free(m[i]);
+				vm_page_unlock(m[i]);
+			}
+		}
+		/* XXX */
+		DBGCORE("%s: lost page: obj=%p pidx=%zu origin=%d\n",
+			__func__, obj2, (size_t)pidx2, origin);
+		return (VM_PAGER_FAIL);
+	}
+
+	if (need_wakeup)
+		vm_page_wakeup(m2);
+
+	VM_OBJECT_WUNLOCK(obj2);
+
+	/* Now we have a page. */
+
+	/* 0 <-- always replace page; makes cleanup easier. */
+	if (0 && (m1->flags & PG_FICTITIOUS) != 0) {
+		VM_OBJECT_WLOCK(object);
+		vm_page_updatefake(m1, paddr, object->memattr);
+		if (count > 1) {
+			for (i = 0; i < count; i++) {
+				if (i != reqpage) {
+					vm_page_lock(m[i]);
+					vm_page_free(m[i]);
+					vm_page_unlock(m[i]);
+				}
+			}
+		}
+
+	} else {
+		/*
+		 * Replace the passed in reqpage page with our own
+		 * fake page and free up all of the original pages.
+		 */
+		m1 = vm_page_getfake(paddr, object->memattr);
+		VM_OBJECT_WLOCK(object);
+		TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist,
+		    m1, pageq);
+		for (i = 0; i < count; i++) {
+			vm_page_lock(m[i]);
+			vm_page_free(m[i]);
+			vm_page_unlock(m[i]);
+		}
+		vm_page_insert(m1, object, pidx);
+		vm_page_lock(m1);
+
+		/* Since page is VPO_UNMANAGED, it is not put on
+		   any queues. */
+		vm_page_unwire(m1, 1);
+
+		KASSERT(m1->flags & PG_FICTITIOUS,
+			("%s: m1=%p not PG_FICTITIOUS\n", __func__, m1));
+
+		vm_page_unlock(m1);
+		m[reqpage] = m1;
+
+	}
+
+	m1->valid = VM_PAGE_BITS_ALL;
+
+	if (pidx + 1 == (ctx->nsyspages + ctx->nuserpages))
+		DBGCORE("%s: pages: resident: %d swap: %d missing: %d\n",
+			__func__,
+			ctx->pager_npages_res,
+			ctx->pager_npages_swap,
+			ctx->pager_npages_miss);
+
+	return (VM_PAGER_OK);
+}
+
+static void
+vps_pager_putpages(vm_object_t object, vm_page_t *m, int count,
+	boolean_t sync, int *rtvals)
+{
+	struct vps_snapst_ctx *ctx;
+	struct vps_page_ref *pref;
+	vm_pindex_t pidx2;
+	vm_pindex_t pidx;
+	vm_object_t obj2;
+	vm_page_t m1;
+	vm_page_t m2;
+	int i;
+
+	DBGCORE("%s: object=%p m=%p count=%d sync=%d rtvals=%p\n",
+		__func__, object, m, count, sync, rtvals);
+
+	KASSERT(object->handle != NULL,
+		("%s: handle == NULL, object=%p\n", __func__, object));
+
+	ctx = (struct vps_snapst_ctx *)object->handle;
+
+	for (i = 0; i < count; i++) {
+		m1 = m[i];
+		KASSERT(m1 != NULL,
+		    ("%s: m1 == NULL, i=%d\n", __func__, i));
+		pidx = m1->pindex;
+
+		vm_page_lock(m1);
+		if (m1->hold_count != 0) {
+			/* Not possible now. */
+			vm_page_unlock(m1);
+			rtvals[i] = VM_PAGER_FAIL;
+			continue;
+		}
+		TAILQ_REMOVE(&object->un_pager.devp.devp_pglist, m1, pageq);
+		vm_page_remove(m1);
+#if 0
+		/* XXX This is rather dirty !!! */
+		/* XXX XXX and does not work at all */
+		m1->oflags &= ~VPO_UNMANAGED;
+		pmap_remove_all(m1);
+		m1->oflags |= VPO_UNMANAGED;
+#endif
+		vm_page_unlock(m1);
+		vm_page_putfake(m1);
+
+		if (pidx < ctx->nsyspages) {
+			/* system pages */
+
+			obj2 = ctx->vmobj;
+			pidx2 = pidx;
+
+		} else if (pidx >= ctx->nsyspages &&
+		    pidx < (ctx->nsyspages + ctx->nuserpages)) {
+			/* user pages */
+
+			pref = &ctx->page_ref[pidx - ctx->nsyspages];
+			obj2 = pref->obj;
+			pidx2 = pref->pidx;
+
+		} else {
+			DBGCORE("%s: invalid pidx %zu, object=%p\n",
+				__func__, (size_t)pidx, object);
+			rtvals[i] = VM_PAGER_FAIL;
+			continue;
+		}
+
+		VM_OBJECT_WLOCK(obj2);
+		m2 = vm_page_lookup(obj2, pidx2);
+		VM_OBJECT_WUNLOCK(obj2);
+		KASSERT(m2 != NULL, ("%s: m2 == NULL\n", __func__));
+		vm_page_lock(m2);
+		vm_page_unwire(m2, 0);
+		vm_page_unlock(m2);
+
+		rtvals[i] = VM_PAGER_OK;
+	}
+}
+
+static boolean_t
+vps_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before,
+    int *after)
+{
+	struct vps_snapst_ctx *ctx;
+	struct vps_page_ref *ref;
+
+	KASSERT(object->handle != NULL,
+		("%s: handle == NULL, object=%p\n", __func__, object));
+
+	ctx = (struct vps_snapst_ctx *)object->handle;
+	ref = ctx->page_ref;
+
+	KASSERT(object == ctx->vps_vmobject,
+		("%s: object != ctx->vps_vmobject; object=%p pindex=%zu\n",
+		__func__, object, (size_t)pindex));
+
+	if (pindex >= (ctx->nsyspages + ctx->nuserpages))
+		return (FALSE);
+
+	if (before)
+		*before = pindex;
+	if (after)
+		*after = pindex < (ctx->nsyspages + ctx->nuserpages) ?
+			(ctx->nsyspages + ctx->nuserpages) - pindex - 1 :
+			0;
+
+	return (TRUE);
+}
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_priv.c head/sys/vps/vps_priv.c
--- clean-head/sys/vps/vps_priv.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_priv.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,943 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: vps_priv.c 175 2013-06-13 09:27:34Z klaus $";
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/limits.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/libkern.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/ucred.h>
+#include <sys/ioccom.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/fcntl.h>
+#include <sys/namei.h>
+#include <sys/syscallsubr.h>
+#include <sys/resourcevar.h>
+#include <sys/queue.h>
+#include <sys/jail.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <security/mac/mac_framework.h>
+
+#include <fs/devfs/devfs.h>
+#include <fs/devfs/devfs_int.h>
+
+#include "vps_user.h"
+#include "vps.h"
+#include "vps2.h"
+#include "vps_devfsruleset.h"
+
+/* local */
+int vps_ip4_check2(struct vps *, struct in_addr *, struct in_addr *, int);
+int vps_ip6_check2(struct vps *, struct in6_addr *, u_int8_t, int);
+
+MALLOC_DECLARE(M_VPS_CORE);
+
+#define BIT_SET(set, bit)       do {                            \
+            set[ bit >> 3 ] |= 1 << (bit - (bit >> 3 << 3 ));   \
+        } while (0)
+
+#define BIT_UNSET(set, bit)     do {                            \
+            set[ bit >> 3 ] &= ~( 1 << (bit - (bit >> 3 << 3 )));   \
+        } while (0)
+
+#define BIT_ISSET(set, bit)                                     \
+    (set[ bit >> 3 ] & 1 << (bit - (bit >> 3 << 3 )) ? 1 : 0)
+
+static struct unrhdr *vps_devfs_unrhdr;
+
+int
+vps_priv_check(struct ucred *cred, int priv)
+{
+        int rv;
+
+	/* Is this syscall/operation implemented ? */
+	rv = BIT_ISSET(cred->cr_vps->priv_impl_set, priv);
+
+	if (rv==0) {
+		DBGCORE("%s: cred=%p priv=%d NOSYS\n",
+			__func__, cred, priv);
+		return (ENOSYS);
+	}
+
+	/* Is this syscall/operation allowed ? */
+        rv = BIT_ISSET(cred->cr_vps->priv_allow_set, priv);
+
+        if (rv==0) {
+                DBGCORE("%s: cred=%p priv=%d EPERM\n",
+                        __func__, cred, priv);
+		return (EPERM);
+	}
+
+        return (0);
+}
+
+/*
+ * XXX
+ * This are some defaults taken from jail's priv check.
+ * In many cases these are very inappropriate for vps.
+ */
+void
+vps_priv_setdefault(struct vps *vps, struct vps_param *vps_pr)
+{
+	u_char *a_set, *i_set;
+
+	a_set = vps->priv_allow_set;
+	i_set = vps->priv_impl_set;
+
+	/* Set of allowed operations. */
+
+	memset (a_set, 0, PRIV_SET_SIZE);
+
+	BIT_SET(a_set, PRIV_VFS_MOUNT);
+	BIT_SET(a_set, PRIV_VFS_MOUNT_NONUSER);
+	BIT_SET(a_set, PRIV_VFS_UNMOUNT);
+
+	/* XXX ? */
+        BIT_SET(a_set, PRIV_VFS_GENERATION);
+        /* ---------- */
+
+        /* Will perform vps destruction if not the vps0. */
+        BIT_SET(a_set, PRIV_REBOOT);
+
+        BIT_SET(a_set, PRIV_KTRACE);
+        BIT_SET(a_set, PRIV_CRED_SETUID);
+        BIT_SET(a_set, PRIV_CRED_SETEUID);
+        BIT_SET(a_set, PRIV_CRED_SETGID);
+        BIT_SET(a_set, PRIV_CRED_SETEGID);
+        BIT_SET(a_set, PRIV_CRED_SETGROUPS);
+        BIT_SET(a_set, PRIV_CRED_SETREUID);
+        BIT_SET(a_set, PRIV_CRED_SETREGID);
+        BIT_SET(a_set, PRIV_CRED_SETRESUID);
+        BIT_SET(a_set, PRIV_CRED_SETRESGID);
+        BIT_SET(a_set, PRIV_SEEOTHERUIDS);
+        BIT_SET(a_set, PRIV_SEEOTHERGIDS);
+        BIT_SET(a_set, PRIV_DEBUG_DIFFCRED);
+        BIT_SET(a_set, PRIV_DEBUG_SUGID);
+        BIT_SET(a_set, PRIV_DEBUG_UNPRIV);
+        BIT_SET(a_set, PRIV_PROC_LIMIT);
+        BIT_SET(a_set, PRIV_PROC_SETLOGIN);
+        BIT_SET(a_set, PRIV_PROC_SETRLIMIT);
+        BIT_SET(a_set, PRIV_IPC_READ);
+        BIT_SET(a_set, PRIV_IPC_WRITE);
+        BIT_SET(a_set, PRIV_IPC_ADMIN);
+        BIT_SET(a_set, PRIV_IPC_MSGSIZE);
+        BIT_SET(a_set, PRIV_MQ_ADMIN);
+        BIT_SET(a_set, PRIV_SCHED_DIFFCRED);
+        BIT_SET(a_set, PRIV_SCHED_CPUSET);
+        BIT_SET(a_set, PRIV_SIGNAL_DIFFCRED);
+        BIT_SET(a_set, PRIV_SIGNAL_SUGID);
+        BIT_SET(a_set, PRIV_SYSCTL_WRITEJAIL);
+        BIT_SET(a_set, PRIV_VFS_GETQUOTA);
+        BIT_SET(a_set, PRIV_VFS_SETQUOTA);
+        BIT_SET(a_set, PRIV_VFS_READ);
+        BIT_SET(a_set, PRIV_VFS_WRITE);
+        BIT_SET(a_set, PRIV_VFS_ADMIN);
+        BIT_SET(a_set, PRIV_VFS_EXEC);
+        BIT_SET(a_set, PRIV_VFS_LOOKUP);
+        BIT_SET(a_set, PRIV_VFS_BLOCKRESERVE);
+        BIT_SET(a_set, PRIV_VFS_CHFLAGS_DEV);
+        BIT_SET(a_set, PRIV_VFS_CHOWN);
+        BIT_SET(a_set, PRIV_VFS_CHROOT);
+        BIT_SET(a_set, PRIV_VFS_RETAINSUGID);
+        BIT_SET(a_set, PRIV_VFS_FCHROOT);
+        BIT_SET(a_set, PRIV_VFS_LINK);
+        BIT_SET(a_set, PRIV_VFS_SETGID);
+        BIT_SET(a_set, PRIV_VFS_STAT);
+        BIT_SET(a_set, PRIV_VFS_STICKYFILE);
+        BIT_SET(a_set, PRIV_NETINET_RESERVEDPORT);
+        BIT_SET(a_set, PRIV_NETINET_REUSEPORT);
+        BIT_SET(a_set, PRIV_NETINET_SETHDROPTS);
+        BIT_SET(a_set, PRIV_NETINET_RAW);
+        BIT_SET(a_set, PRIV_NETINET_GETCRED);
+        BIT_SET(a_set, PRIV_NET_BRIDGE);
+        BIT_SET(a_set, PRIV_NET_GRE);
+        BIT_SET(a_set, PRIV_NET_BPF);
+        BIT_SET(a_set, PRIV_NET_RAW);
+        BIT_SET(a_set, PRIV_NET_ROUTE);
+        BIT_SET(a_set, PRIV_NET_TAP);
+        BIT_SET(a_set, PRIV_NET_SETIFMTU);
+        BIT_SET(a_set, PRIV_NET_SETIFFLAGS);
+        BIT_SET(a_set, PRIV_NET_SETIFCAP);
+        BIT_SET(a_set, PRIV_NET_SETIFNAME);
+        BIT_SET(a_set, PRIV_NET_SETIFMETRIC);
+        BIT_SET(a_set, PRIV_NET_SETIFPHYS);
+        BIT_SET(a_set, PRIV_NET_SETIFMAC);
+        BIT_SET(a_set, PRIV_NET_ADDMULTI);
+        BIT_SET(a_set, PRIV_NET_DELMULTI);
+        BIT_SET(a_set, PRIV_NET_HWIOCTL);
+        BIT_SET(a_set, PRIV_NET_SETLLADDR);
+        BIT_SET(a_set, PRIV_NET_ADDIFGROUP);
+        BIT_SET(a_set, PRIV_NET_DELIFGROUP);
+        BIT_SET(a_set, PRIV_NET_IFCREATE);
+        BIT_SET(a_set, PRIV_NET_IFDESTROY);
+        BIT_SET(a_set, PRIV_NET_ADDIFADDR);
+        BIT_SET(a_set, PRIV_NET_DELIFADDR);
+        BIT_SET(a_set, PRIV_NET_LAGG);
+
+	/* sysctls are either hidden or virtual */
+	BIT_SET(a_set, PRIV_SYSCTL_WRITE);
+
+	/* jail is virtualized */
+	BIT_SET(a_set, PRIV_JAIL_ATTACH);
+	BIT_SET(a_set, PRIV_JAIL_SET);
+
+	/* Set of available operations (not necessarily allowed). */
+	/* Set everything to available by default. */
+	memset (i_set, 0xff, PRIV_SET_SIZE);
+	/* Remove items in order to have ENOSYS returned. */
+	BIT_UNSET(i_set, PRIV_AUDIT_CONTROL);
+	BIT_UNSET(i_set, PRIV_AUDIT_FAILSTOP);
+	BIT_UNSET(i_set, PRIV_AUDIT_GETAUDIT);
+	BIT_UNSET(i_set, PRIV_AUDIT_SETAUDIT);
+	BIT_UNSET(i_set, PRIV_AUDIT_SUBMIT);
+}
+
+int
+vps_devfs_ruleset_create(struct vps *vps)
+{
+	struct devfs_rule *rule;
+	struct devfs_rule *rs;
+	size_t size;
+
+	DBGCORE("%s: vps=%p\n", __func__, vps);
+
+	size = sizeof(vps_devfs_ruleset_default);
+
+	rs = malloc(size + sizeof(*rule), M_VPS_CORE, M_WAITOK | M_ZERO);
+
+	memcpy(rs, vps_devfs_ruleset_default, size);
+
+	vps->devfs_ruleset = rs;
+
+	return (0);
+}
+
+int
+vps_devfs_ruleset_destroy(struct vps *vps)
+{
+
+	DBGCORE("%s: vps=%p\n", __func__, vps);
+
+	if (vps->devfs_ruleset == NULL)
+		return (0);
+
+	free(vps->devfs_ruleset, M_VPS_CORE);
+
+	vps->devfs_ruleset = NULL;
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_devfs_ruleset_apply(struct vps *vps, struct devfs_mount *dm,
+    int *ret_rsnum)
+{
+	struct ucred *save_ucred;
+	struct ucred *tmp_ucred;
+	struct devfs_rule *rule2;
+	struct devfs_rule *rule;
+	struct thread *td;
+	int ruleset_num;
+	int error;
+
+	DBGCORE("%s: vps=%p dm=%p\n", __func__, vps, dm);
+
+	/*
+	 * Devfs' ioctl interface checks for PRIV_DEVFS_RULE,
+	 * so we can't pass curthread's ucred but have to
+	 * set up a privileged one.
+	 *
+	 * Taking the parent vps make this safe, since the
+	 * devfs ruleset is also controlled by the parent vps.
+	 *
+	 * If the parent vps is not vps0 (no PRIV_DEVFS_RULE),
+	 * access will be denied.
+	 *
+	 * Note: This is way cleaner than the old hack.
+	 */
+	td = curthread;
+	/* Should never get called by a jailed thread. */
+	if (jailed(td->td_ucred)) {
+		DBGCORE("%s: td=%p is jailed --> EPERM\n",
+		    __func__, td);
+		return (EPERM);
+	}
+
+	rule = malloc(sizeof(*rule), M_TEMP, M_WAITOK);
+
+	save_ucred = td->td_ucred;
+	tmp_ucred = crget();
+	crcopy(tmp_ucred, save_ucred);
+
+	vps_deref(tmp_ucred->cr_vps, tmp_ucred);
+	tmp_ucred->cr_vps = vps->vps_parent;
+	vps_ref(tmp_ucred->cr_vps, tmp_ucred);
+
+	prison_free(tmp_ucred->cr_prison);
+	tmp_ucred->cr_prison = VPS_VPS(vps->vps_parent, prison0);
+	prison_hold(tmp_ucred->cr_prison);
+
+	td->td_ucred = tmp_ucred;
+	td->td_vps = vps->vps_parent;
+
+	KASSERT(vps->devfs_ruleset != NULL,
+	    ("%s: vps->devfs_ruleset == NULL, vps=%p\n",
+	    __func__, vps));
+
+	if (vps_devfs_unrhdr == NULL)
+		vps_devfs_unrhdr = new_unrhdr(1, INT_MAX, NULL);
+	ruleset_num = alloc_unr(vps_devfs_unrhdr);
+	dm->dm_vps_rsnum = ruleset_num;
+
+	rule2 = vps->devfs_ruleset;
+	while (rule2->dr_magic != 0) {
+
+		memcpy(rule, rule2, sizeof(*rule));
+
+		rule->dr_id = mkrid(ruleset_num, rid2rn(rule->dr_id));
+
+		DBGCORE("%s: rule=%p dr_id=%d dr_iacts=%d dr_bacts=%d "
+		    "dr_pathptrn=[%s]\n",
+		    __func__, rule, rule->dr_id, rule->dr_iacts,
+		    rule->dr_bacts, rule->dr_pathptrn);
+
+		sx_xlock(&dm->dm_lock);
+		error = devfs_rules_ioctl(dm, DEVFSIO_RADD, (caddr_t)rule, td);
+		sx_xunlock(&dm->dm_lock);
+		if (error != 0) {
+			DBGCORE("%s: devfs_rules_ioctl(%p, DEVFSIO_RADD, %p): %d\n",
+			    __func__, dm, rule, error);
+			goto out;
+		}
+
+		rule2++;
+	}
+
+	*ret_rsnum = ruleset_num;
+
+  out:
+	td->td_vps = vps;
+	td->td_ucred = save_ucred;
+	crfree(tmp_ucred);
+	free(rule, M_TEMP);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_devfs_ruleset_free(struct vps *vps, struct devfs_mount *dm)
+{
+	struct ucred *save_ucred;
+	struct ucred *tmp_ucred;
+	struct devfs_rule *rule2;
+	struct devfs_rule *rule;
+	struct thread *td;
+	int ruleset_num;
+	devfs_rid rid;
+	int error;
+
+	DBGCORE("%s: vps=%p dm=%p\n", __func__, vps, dm);
+
+	/* See comment in vps_devfs_ruleset_apply(). */
+
+	td = curthread;
+	if (jailed(td->td_ucred)) {
+		DBGCORE("%s: td=%p is jailed --> EPERM\n",
+		    __func__, td);
+		return (EPERM);
+	}
+
+	rule = malloc(sizeof(*rule), M_TEMP, M_WAITOK);
+
+	save_ucred = td->td_ucred;
+	tmp_ucred = crget();
+	crcopy(tmp_ucred, save_ucred);
+
+	vps_deref(tmp_ucred->cr_vps, tmp_ucred);
+	tmp_ucred->cr_vps = vps->vps_parent;
+	vps_ref(tmp_ucred->cr_vps, tmp_ucred);
+
+	prison_free(tmp_ucred->cr_prison);
+	tmp_ucred->cr_prison = VPS_VPS(vps->vps_parent, prison0);
+	prison_hold(tmp_ucred->cr_prison);
+
+	td->td_ucred = tmp_ucred;
+	td->td_vps = vps->vps_parent;
+
+	KASSERT(vps->devfs_ruleset != NULL,
+	    ("%s: vps->devfs_ruleset == NULL, vps=%p\n",
+	    __func__, vps));
+
+	ruleset_num = dm->dm_vps_rsnum;
+
+	rule2 = vps->devfs_ruleset;
+	while (rule2->dr_magic != 0) {
+
+		memcpy(rule, rule2, sizeof(*rule));
+
+		rule->dr_id = mkrid(ruleset_num, rid2rn(rule->dr_id));
+
+		DBGCORE("%s: rule=%p dr_id=%d dr_iacts=%d dr_bacts=%d "
+		    "dr_pathptrn=[%s]\n",
+		    __func__, rule, rule->dr_id, rule->dr_iacts,
+		    rule->dr_bacts, rule->dr_pathptrn);
+
+		rid = rid2rn(rule->dr_id);
+
+		sx_xlock(&dm->dm_lock);
+		error = devfs_rules_ioctl(dm, DEVFSIO_RDEL, (caddr_t)&rid, td);
+		sx_xunlock(&dm->dm_lock);
+		if (error != 0) {
+			DBGCORE("%s: devfs_rules_ioctl(%p, DEVFSIO_RDEL, %p): %d\n",
+			    __func__, dm, &rid, error);
+			goto out;
+		}
+
+		rule2++;
+	}
+
+  out:
+	td->td_vps = vps;
+	td->td_ucred = save_ucred;
+	crfree(tmp_ucred);
+	free(rule, M_TEMP);
+
+	return (error);
+}
+
+int
+vps_devfs_mount_cb(struct devfs_mount *dm, int *rsnum)
+{
+	struct vps *vps;
+	int error;
+
+	vps = curthread->td_vps;
+
+	vps_ref(vps, (void*)0xbeefc0de);
+	dm->dm_vps = vps;
+
+	if (vps == vps0)
+		return (0);
+
+	/* Load ruleset. */
+	error = vps_devfs_ruleset_apply(vps, dm, rsnum);
+
+	return (error);
+}
+
+int
+vps_devfs_unmount_cb(struct devfs_mount *dm)
+{
+	struct vps *vps;
+
+	vps = dm->dm_vps;
+	vps_deref(vps, (void*)0xbeefc0de);
+	dm->dm_vps = NULL;
+
+	if (vps == vps0)
+		return (0);
+
+	/* Free ruleset. */
+	(void)vps_devfs_ruleset_free(vps, dm);
+
+	return (0);
+}
+
+/*
+ * Check if a certain device entry should be visible or not to VPS instance
+ * referenced by ''dm->dm_vps''.
+ * Return code: 0 --> no whiteout
+ *              1 --> do whiteout
+ */
+int
+vps_devfs_whiteout_cb(struct devfs_mount *dm, struct cdev_priv *cdp)
+{
+
+	if (cdp->cdp_c.si_cred &&
+	    cdp->cdp_c.si_cred->cr_vps != dm->dm_vps) {
+		/*
+		 * This device is a user device (i.e. has user credentials)
+		 * AND does not belong in the vps instance this devfs is
+		 * mounted in.
+		 */
+		/*
+		DBGCORE("%s: device has ucred and different from "
+		    "mountpoint!\n", __func__);
+		*/
+
+		return (1);
+	}
+
+	return (0);
+}
+
+int
+vps_canseemount(struct ucred *cred, struct mount *mp)
+{
+	struct vps *vps;
+	char *vpsroot;
+	char *mnton;
+	int len;
+	int error;
+
+	vps = cred->cr_vps;
+	error = ENOENT;
+	mnton = mp->mnt_stat.f_mntonname;
+	vpsroot = vps->_rootpath;
+
+	if (vps->_rootvnode->v_mount == mp) {
+		error = 0;
+		goto out;
+	}
+
+	len = strlen (vpsroot);
+	if (vpsroot[len - 1] == '/')
+		len -= 1;
+
+	if ((strncmp (vpsroot, mnton, len)) == 0 &&
+		(mnton[len] == '\0' || mnton[len] == '/')) {
+		error = 0;
+		goto out;
+	}
+
+out:
+	return (error);
+}
+
+int
+vps_priv_setitem(struct vps *vpsp, struct vps *vps,
+    struct vps_arg_item *item)
+{
+	struct vps_arg_priv *priv;
+
+	if (item->type != VPS_ARG_ITEM_PRIV)
+		return (EINVAL);
+
+	priv = &item->u.priv;
+
+	if (item->revoke != 0)
+		return (EINVAL);
+
+	if (priv->priv < _PRIV_LOWEST || priv->priv > _PRIV_HIGHEST)
+		return (EINVAL);
+
+	switch (priv->value) {
+	case VPS_ARG_PRIV_DENY:
+		BIT_UNSET(vps->priv_allow_set, priv->priv);
+		BIT_SET(vps->priv_impl_set, priv->priv);
+		break;
+	case VPS_ARG_PRIV_NOSYS:
+		BIT_UNSET(vps->priv_impl_set, priv->priv);
+		BIT_UNSET(vps->priv_allow_set, priv->priv);
+		break;
+	case VPS_ARG_PRIV_ALLOW:
+		/* Check if parent vps is allowed the priv in question. */
+		if (BIT_ISSET(vpsp->priv_allow_set, priv->priv) == 0)
+			return (EPERM);
+		BIT_SET(vps->priv_allow_set, priv->priv);
+		BIT_SET(vps->priv_impl_set, priv->priv);
+		break;
+	default:
+		return (EINVAL);
+		break;
+	}
+
+	return (0);
+}
+
+int
+vps_priv_getitemall(struct vps *vpsp, struct vps *vps, caddr_t kdata,
+    size_t *kdatalen)
+{
+	struct vps_arg_item *item;
+	int priv;
+
+	for (item = (struct vps_arg_item *)kdata, priv = _PRIV_LOWEST;
+	    (caddr_t)(item+1) <= kdata + *kdatalen &&
+	    priv <= _PRIV_HIGHEST;
+	    item++, priv++) {
+
+		memset(item, 0, sizeof (*item));
+		item->type = VPS_ARG_ITEM_PRIV;
+		item->u.priv.priv = priv;
+		if (BIT_ISSET(vps->priv_impl_set, priv) == 0)
+			item->u.priv.value = VPS_ARG_PRIV_NOSYS;
+		else if (BIT_ISSET(vps->priv_allow_set, priv) == 0)
+			item->u.priv.value = VPS_ARG_PRIV_DENY;
+		else
+			item->u.priv.value = VPS_ARG_PRIV_ALLOW;
+	}
+
+	*kdatalen = (caddr_t)(item) - kdata;
+
+	if (priv != _PRIV_HIGHEST + 1)
+		return (ENOSPC);
+	else
+		return (0);
+}
+
+int
+vps_ip_setitem(struct vps *vpsp, struct vps *vps,
+    struct vps_arg_item *item)
+{
+	struct vps_arg_ip4 *ip4, *ip4new;
+	struct vps_arg_ip6 *ip6, *ip6new;
+	int i, j;
+
+	/* XXX locking */
+
+	switch (item->type) {
+	case VPS_ARG_ITEM_IP4:
+		if (item->revoke != 0) {
+
+			/* Does this entry actually exist ? */
+			if (vps_ip4_check2(vps, &item->u.ip4.addr,
+			    &item->u.ip4.mask, 1) != 0)
+				return (ENOENT);
+
+			ip4new = malloc(sizeof(*ip4) *
+			    (vps->vps_ip4_cnt - 1), M_VPS_CORE, M_WAITOK);
+
+			for (ip4 = vps->vps_ip4, i = j = 0;
+			    i < vps->vps_ip4_cnt;
+			    ip4++, i++)
+				if (memcmp(ip4, &item->u.ip4,
+				    sizeof(*ip4)) != 0)
+					memcpy(&ip4new[j++], ip4,
+					    sizeof(*ip4));
+
+			ip4 = vps->vps_ip4;
+			/* XXX locking ? */
+			vps->vps_ip4 = ip4new;
+			vps->vps_ip4_cnt--;
+			free(ip4, M_VPS_CORE);
+
+		} else {
+
+			/* Is parent allowed this adress/network ? */
+			if (vps_ip4_check2(vpsp, &item->u.ip4.addr,
+			    &item->u.ip4.mask, 0) != 0)
+				return (EPERM);
+
+			/* Is this adress/network already set ? */
+			if (vps_ip4_check2(vps, &item->u.ip4.addr,
+			    &item->u.ip4.mask, 1) == 0)
+				return (EEXIST);
+
+			ip4new = malloc(sizeof(*ip4) *
+			    (vps->vps_ip4_cnt + 1), M_VPS_CORE, M_WAITOK);
+			memcpy(ip4new, vps->vps_ip4, vps->vps_ip4_cnt *
+			    sizeof(*ip4));
+			memcpy(&ip4new[vps->vps_ip4_cnt], &item->u.ip4,
+			    sizeof(*ip4));
+
+			ip4 = vps->vps_ip4;
+			/* XXX locking ? */
+			vps->vps_ip4 = ip4new;
+			vps->vps_ip4_cnt++;
+			if (ip4 != NULL)
+				free(ip4, M_VPS_CORE);
+		}
+		break;
+
+	case VPS_ARG_ITEM_IP6:
+		if (item->revoke != 0) {
+
+			/* Does this entry actually exist ? */
+			if (vps_ip6_check2(vps, &item->u.ip6.addr,
+			    item->u.ip6.plen, 1) != 0)
+				return (ENOENT);
+
+			ip6new = malloc(sizeof(*ip6) *
+			    (vps->vps_ip6_cnt - 1), M_VPS_CORE, M_WAITOK);
+
+			for (ip6 = vps->vps_ip6, i = j = 0;
+			    i < vps->vps_ip6_cnt;
+			    ip6++, i++)
+				if (memcmp(ip6, &item->u.ip6,
+				    sizeof(*ip6)) != 0)
+					memcpy(&ip6new[j++], ip6,
+					    sizeof(*ip6));
+
+			ip6 = vps->vps_ip6;
+			/* XXX locking ? */
+			vps->vps_ip6 = ip6new;
+			vps->vps_ip6_cnt--;
+			free(ip6, M_VPS_CORE);
+
+		} else {
+
+			/* Is parent allowed this address/network ? */
+			if (vps_ip6_check2(vpsp, &item->u.ip6.addr,
+			    item->u.ip6.plen, 0) != 0)
+				return (EPERM);
+
+			/* Is this address/network already set ? */
+			if (vps_ip6_check2(vps, &item->u.ip6.addr,
+			    item->u.ip6.plen, 1) == 0)
+				return (EEXIST);
+
+			ip6new = malloc(sizeof(*ip6) *
+			    (vps->vps_ip6_cnt + 1), M_VPS_CORE, M_WAITOK);
+			memcpy(ip6new, vps->vps_ip6, vps->vps_ip6_cnt *
+			    sizeof(*ip6));
+			memcpy(&ip6new[vps->vps_ip6_cnt], &item->u.ip6,
+			    sizeof(*ip6));
+
+			ip6 = vps->vps_ip6;
+			/* XXX locking ? */
+			vps->vps_ip6 = ip6new;
+			vps->vps_ip6_cnt++;
+			if (ip6 != NULL)
+				free(ip6, M_VPS_CORE);
+		}
+		break;
+	default:
+		return (EINVAL);
+		break;
+	}
+
+	DBGCORE("%s: vps->vps_ip4=%p vps->vps_ip4_cnt=%d\n",
+		__func__, vps->vps_ip4, vps->vps_ip4_cnt);
+	DBGCORE("%s: vps->vps_ip6=%p vps->vps_ip6_cnt=%d\n",
+		__func__, vps->vps_ip6, vps->vps_ip6_cnt);
+
+	return (0);
+}
+
+int
+vps_ip_getitemall(struct vps *vpsp, struct vps *vps, caddr_t kdata,
+    size_t *kdatalen)
+{
+	struct vps_arg_item *item;
+	struct vps_arg_ip4 *ip4;
+	struct vps_arg_ip6 *ip6;
+	caddr_t kpos;
+
+	for (item = (struct vps_arg_item *)kdata, ip4 = vps->vps_ip4;
+	     ip4 != NULL &&
+	     	(caddr_t)(item+1) <= kdata + *kdatalen &&
+	     	(ip4 - vps->vps_ip4) < vps->vps_ip4_cnt;
+	     item++, ip4++) {
+
+		memset(item, 0, sizeof (*item));
+		item->type = VPS_ARG_ITEM_IP4;
+		memcpy(&item->u.ip4, ip4, sizeof (*ip4));
+	}
+	kpos = (caddr_t)(item);
+	for (item = (struct vps_arg_item *)kpos, ip6 = vps->vps_ip6;
+	     ip6 != NULL &&
+		(caddr_t)(item+1) <= kdata + *kdatalen &&
+		(ip6 - vps->vps_ip6) < vps->vps_ip6_cnt;
+	     item++, ip6++) {
+
+		memset(item, 0, sizeof (*item));
+		item->type = VPS_ARG_ITEM_IP6;
+		memcpy(&item->u.ip6, ip6, sizeof (*ip6));
+	}
+
+	*kdatalen = (caddr_t)(item) - kdata;
+
+	if (*kdatalen / sizeof (*item) != vps->vps_ip4_cnt +
+	    vps->vps_ip6_cnt)
+		return (ENOSPC);
+	else
+		return (0);
+}
+
+/*
+ * XXX
+ * For now do a simple linear lookup - of course later this has to
+ * be replaced by a tree or something else.
+ */
+
+int
+vps_ip4_check(struct vps *vps, struct in_addr *addr, struct in_addr *mask)
+{
+	int error;
+
+	/* XXX lock */
+	error = vps_ip4_check2(vps, addr, mask, 0);
+	/* XXX unlock */
+
+	return (error);
+}
+
+int
+vps_ip4_check2(struct vps *vps, struct in_addr *addr, struct in_addr *mask,
+    int exact)
+{
+	struct vps_arg_ip4 *ip4;
+
+	if (vps->vps_ip4 == NULL)
+		return (EPERM);
+
+	/* Look for exact matches (same netmask) */
+	for (ip4 = vps->vps_ip4; (ip4 - vps->vps_ip4) < vps->vps_ip4_cnt;
+	    ip4++)
+		if (ip4->addr.s_addr == addr->s_addr && ip4->mask.s_addr ==
+		    mask->s_addr)
+			return (0);
+
+	if (exact != 0)
+		return (EPERM);
+
+	/* It is not necessary to find the closest match,
+	   any match will do. */
+	for (ip4 = vps->vps_ip4; (ip4 - vps->vps_ip4) < vps->vps_ip4_cnt;
+	    ip4++)
+		if ((addr->s_addr & ip4->mask.s_addr) == ip4->addr.s_addr)
+			return (0);
+
+	return (EPERM);
+}
+
+int
+vps_ip6_check(struct vps *vps, struct in6_addr *addr, u_int8_t plen)
+{
+	int error;
+
+	/* XXX lock */
+	error = vps_ip6_check2(vps, addr, plen, 0);
+	/* XXX unlock */
+
+	return (error);
+}
+
+int
+vps_ip6_check2(struct vps *vps, struct in6_addr *addr, u_int8_t plen,
+    int exact)
+{
+	struct vps_arg_ip6 *ip6;
+	struct in6_addr net;
+
+	if (vps->vps_ip6 == NULL)
+		return (EPERM);
+
+	/* Look for exact matches (same prefixlen) */
+	for (ip6 = vps->vps_ip6; (ip6 - vps->vps_ip6) < vps->vps_ip6_cnt;
+	    ip6++)
+		if ((memcmp(&ip6->addr, addr, sizeof (*addr)) == 0) &&
+		    (ip6->plen == plen))
+			return (0);
+
+	if (exact != 0)
+		return (EPERM);
+
+	/* It is not necessary to find the closest match, any will do. */
+	for (ip6 = vps->vps_ip6; (ip6 - vps->vps_ip6) < vps->vps_ip6_cnt;
+	    ip6++) {
+
+		plen = ip6->plen;
+
+		if (plen == 0) {
+			net.s6_addr32[0] = 0;
+			net.s6_addr32[1] = 0;
+			net.s6_addr32[2] = 0;
+			net.s6_addr32[3] = 0;
+		} else
+		if (plen <= 32) {
+			net.s6_addr32[0] = htonl(ntohl(addr->s6_addr32[0]) &
+			    (0xffffffff << (32-plen)));
+			net.s6_addr32[1] = 0;
+			net.s6_addr32[2] = 0;
+			net.s6_addr32[3] = 0;
+		} else
+		if (plen <= 64) {
+			net.s6_addr32[0] = addr->s6_addr32[0];
+			net.s6_addr32[1] = htonl(ntohl(addr->s6_addr32[1]) &
+			    (0xffffffff << (32-plen-32)));
+			net.s6_addr32[2] = 0;
+			net.s6_addr32[3] = 0;
+		} else
+		if (plen <= 96) {
+			net.s6_addr32[0] = addr->s6_addr32[0];
+			net.s6_addr32[1] = addr->s6_addr32[1];
+			net.s6_addr32[2] = htonl(ntohl(addr->s6_addr32[2]) &
+			    (0xffffffff << (32-plen-64)));
+			net.s6_addr32[3] = 0;
+		} else
+		{
+			net.s6_addr32[0] = addr->s6_addr32[0];
+			net.s6_addr32[1] = addr->s6_addr32[1];
+			net.s6_addr32[2] = addr->s6_addr32[2];
+			net.s6_addr32[3] = htonl(ntohl(addr->s6_addr32[3]) &
+			    (0xffffffff << (32-plen-96)));
+		}
+
+		/*
+		printf("%s: memcmp %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
+		    "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x (%lu)\n",
+		    __func__,
+		    htons(net.s6_addr16[0]), htons(net.s6_addr16[1]),
+		    htons(net.s6_addr16[2]), htons(net.s6_addr16[3]),
+		    htons(net.s6_addr16[4]), htons(net.s6_addr16[5]),
+		    htons(net.s6_addr16[6]), htons(net.s6_addr16[7]),
+		    htons(ip6->addr.s6_addr16[0]),
+		    htons(ip6->addr.s6_addr16[1]),
+		    htons(ip6->addr.s6_addr16[2]),
+		    htons(ip6->addr.s6_addr16[3]),
+		    htons(ip6->addr.s6_addr16[4]),
+		    htons(ip6->addr.s6_addr16[5]),
+		    htons(ip6->addr.s6_addr16[6]),
+		    htons(ip6->addr.s6_addr16[7]),
+		    sizeof(*addr));
+		*/
+
+		if (memcmp(&net, &ip6->addr, sizeof(*addr)) == 0)
+			return (0);
+	}
+
+	return (EPERM);
+}
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_restore.c head/sys/vps/vps_restore.c
--- clean-head/sys/vps/vps_restore.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_restore.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,5249 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: vps_restore.c 164 2013-06-10 12:46:17Z klaus $";
+
+#include <sys/cdefs.h>
+
+#include "opt_ddb.h"
+#include "opt_ktrace.h"
+#include "opt_global.h"
+#include "opt_compat.h"
+#include "opt_kstack_max_pages.h"
+
+#ifdef VPS
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/refcount.h>
+#include <sys/sched.h>
+#include <sys/sockio.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/ttycom.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/uio.h>
+#include <sys/resourcevar.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/namei.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/reboot.h>
+#include <sys/conf.h>
+#include <sys/syscallsubr.h>
+#include <sys/mman.h>
+#include <sys/sleepqueue.h>
+#include <sys/filedesc.h>
+#include <sys/mount.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/pipe.h>
+#include <sys/tty.h>
+#include <sys/syscall.h>
+#include <sys/jail.h>
+#include <sys/ktrace.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
+#include <sys/loginclass.h>
+#include <sys/vmmeter.h>
+#include <sys/event.h>
+#include <sys/eventvar.h>
+#include <sys/stat.h>
+#include <sys/kdb.h>
+
+#include <net/if.h>
+#include <net/radix.h>
+#include <net/route.h>
+#include <netinet/in.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_pageout.h>
+
+#include <machine/pcb.h>
+
+#ifdef DDB
+#include <ddb/ddb.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_clone.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <net/vnet.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include "vps_account.h"
+#include "vps_user.h"
+#include "vps.h"
+#include "vps2.h"
+#include <machine/vps_md.h>
+
+#define _VPS_SNAPST_H_ALL
+#include "vps_snapst.h"
+
+#include "vps_libdump.h"
+
+/* see vm/vm_glue.c */
+#ifndef KSTACK_MAX_PAGES
+#define KSTACK_MAX_PAGES 32
+#endif
+
+
+#define ERRMSG vps_snapst_pusherrormsg
+
+#ifdef DIAGNOSTIC
+
+#define DBGR if (debug_restore) printf
+//#define DBGR if (debug_restore) vps_printf
+
+static int debug_restore = 1;
+SYSCTL_INT(_debug, OID_AUTO, vps_restore_debug, CTLFLAG_RW,
+    &debug_restore, 0, "");
+
+#else
+
+#define DBGR(x, ...)
+
+#endif /* DIAGNOSTIC */
+
+static int debug_restore_ktrace = 0;
+SYSCTL_INT(_debug, OID_AUTO, vps_restore_ktrace, CTLFLAG_RW,
+    &debug_restore_ktrace, 0, "");
+
+int sys_posix_openpt_unit(struct thread *, struct posix_openpt_args *, int);
+int ktrops(struct thread *,struct proc *,int,int,struct vnode *);
+
+MALLOC_DEFINE(M_VPS_RESTORE, "vps_restore",
+    "Virtual Private Systems Restore memory");
+
+void vps_restore_return(struct thread *, struct trapframe *);
+static struct prison *vps_restore_prison_lookup(
+	struct vps_snapst_ctx *ctx, struct vps *vps, struct prison *old_pr);
+
+static int vps_restore_mod_refcnt;
+
+/*
+ * * * * * Restore functions. * * * *
+ */
+
+static struct ucred * vps_restore_ucred_lookup(struct vps_snapst_ctx *ctx,
+	struct vps *vps, void *orig_ptr);
+
+__attribute__((noinline))
+static int
+vps_restore_ucred(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_restore_obj *ro;
+	struct vps_dumpobj *o1;
+	struct vps_dump_ucred *vdcr;
+	struct ucred *ncr;
+	gid_t *tmp_groups;
+	int i;
+
+	o1 = vdo_next(ctx);
+
+	if (o1->type != VPS_DUMPOBJT_UCRED) {
+		ERRMSG(ctx, "%s: o1=%p type=%d != VPS_DUMPOBJT_UCRED\n",
+			__func__, o1, o1->type);
+		return (EINVAL);
+	}
+	vdcr = (struct vps_dump_ucred *)o1->data;
+
+	KASSERT(vps != NULL, ("%s: vps == NULL\n", __func__));
+
+	if ((ncr = vps_restore_ucred_lookup(ctx, vps, vdcr->cr_origptr)) !=
+	    NULL) {
+		/* XXX debugging */
+		panic("%s: double restore, orig_ptr=%p !\n",
+		    __func__, vdcr->cr_origptr);
+		/* Already restored. */
+		crfree(ncr);
+		return (0);
+	}
+
+	ncr = crget();
+	ncr->cr_vps = vps;
+	vps_ref(ncr->cr_vps, ncr);
+
+	/* Is re-set in fixup routine, after prisons are restored. */
+	ncr->cr_prison = VPS_VPS(vps, prison0);
+	prison_hold(ncr->cr_prison);
+
+	ncr->cr_uid = vdcr->cr_uid;
+	ncr->cr_ruid = vdcr->cr_ruid;
+	ncr->cr_svuid = vdcr->cr_svuid;
+	ncr->cr_rgid = vdcr->cr_rgid;
+	ncr->cr_svgid = vdcr->cr_svgid;
+
+	ncr->cr_loginclass = loginclass_find("default");
+	ncr->cr_uidinfo = uifind(vdcr->cr_uid);
+	ncr->cr_ruidinfo = uifind(vdcr->cr_ruid);
+
+	/* XXX check that vdcr->cr_groups is big enough
+	   (start of next object) */
+	tmp_groups = malloc(sizeof(tmp_groups[0]) * vdcr->cr_ngroups,
+	    M_TEMP, M_WAITOK);
+	for (i = 0; i < vdcr->cr_ngroups; i++)
+		tmp_groups[i] = vdcr->cr_groups[i];
+	crsetgroups(ncr, vdcr->cr_ngroups, tmp_groups);
+	free(tmp_groups, M_TEMP);
+
+	ncr->cr_flags = vdcr->cr_flags;
+	ncr->cr_pspare2[0] = NULL;
+	ncr->cr_pspare2[1] = NULL;
+	ncr->cr_label = NULL;
+	memset(&ncr->cr_audit, 0, sizeof(ncr->cr_audit));
+
+	ro = malloc(sizeof(*ro), M_VPS_RESTORE, M_WAITOK | M_ZERO);
+	ro->type = VPS_DUMPOBJT_UCRED;
+	ro->orig_ptr = vdcr->cr_origptr;
+	ro->new_ptr = ncr;
+	ro->spare[0] = vdcr->cr_prison;
+	SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+
+	DBGR("%s: ncr=%p\n", __func__, ncr);
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_ucred_all(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dumpobj *o1, *o2;
+	int error = 0;
+	int cnt = 0;
+
+	o2 = ctx->curobj;
+	o1 = ctx->rootobj;
+	ctx->curobj = o1;
+	do {
+		if (vdo_typeofnext(ctx) != VPS_DUMPOBJT_UCRED) {
+			o1 = vdo_next(ctx);
+			continue;
+		}
+
+		if ((error = vps_restore_ucred(ctx, vps)))
+			break;
+
+		++cnt;
+
+	} while (o1 != NULL);
+
+	DBGR("%s: restored %d ucreds\n", __func__, cnt);
+
+	/* Reset ctx to where it was. */
+	ctx->curobj = o2;
+	ctx->lastobj = o2;
+
+	return (error);
+}
+
+__attribute__((noinline, unused))
+static int
+vps_restore_ucred_checkall(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dumpobj *o1, *o2;
+	struct vps_dump_ucred *vdcr;
+	struct ucred *ncr;
+	int cnt = 0;
+
+	o2 = ctx->curobj;
+	o1 = ctx->rootobj;
+	ctx->curobj = o1;
+	do {
+		if (vdo_typeofnext(ctx) != VPS_DUMPOBJT_UCRED) {
+			o1 = vdo_next(ctx);
+			continue;
+		}
+
+		o1 = vdo_next(ctx);
+		vdcr = (struct vps_dump_ucred *)o1->data;
+		ncr = vps_restore_ucred_lookup(ctx, vps, vdcr->cr_origptr);
+		crfree(ncr);
+		KASSERT(ncr != NULL, ("%s: ncr==NULL\n", __func__));
+		/* There is still one extra reference that is kept during
+		   the restore run. */
+		if (ncr->cr_ref != vdcr->cr_ref + 1)
+			DBGR("%s: ncr=%p orig=%p ncr->cr_ref=%d "
+			    "vdcr->cr_ref=%d\n", __func__, ncr,
+			    vdcr->cr_origptr, ncr->cr_ref - 1,
+			    vdcr->cr_ref);
+
+		++cnt;
+
+	} while (o1 != NULL);
+
+	DBGR("%s: checked %d ucreds\n", __func__, cnt);
+
+	/* Reset ctx to where it was. */
+	ctx->curobj = o2;
+	ctx->lastobj = o2;
+
+	return (0);
+}
+
+__attribute__((noinline))
+static struct ucred *
+vps_restore_ucred_lookup(struct vps_snapst_ctx *ctx, struct vps *vps,
+    void *orig_ptr)
+{
+	struct vps_restore_obj *ro;
+	struct ucred *ncr;
+
+	ncr = NULL;
+	SLIST_FOREACH(ro, &ctx->obj_list, list)
+		if (ro->type == VPS_DUMPOBJT_UCRED &&
+		    ro->orig_ptr == orig_ptr) {
+			ncr = ro->new_ptr;
+			break;
+		}
+
+	if (ncr != NULL) {
+		DBGR("%s: found ucred %p for %p, ncr->ref=%d\n",
+			__func__, ncr, orig_ptr, ncr->cr_ref+1);
+		crhold(ncr);
+		return (ncr);
+	} else {
+		DBGR("%s: no ucred found for %p\n", __func__, orig_ptr);
+		return (NULL);
+	}
+}
+
+__attribute__((noinline))
+static int
+vps_restore_ucred_fixup(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_restore_obj *ro;
+	struct prison *pr2;
+	struct ucred *cr;
+
+	SLIST_FOREACH(ro, &ctx->obj_list, list) {
+		if (ro->type != VPS_DUMPOBJT_UCRED)
+			continue;
+
+		cr = ro->new_ptr;
+		pr2 = vps_restore_prison_lookup(ctx, vps, ro->spare[0]);
+		KASSERT(pr2 != NULL, ("%s: prison not found for "
+		    "orig_ptr %p\n", __func__, ro->spare[0]));
+
+		DBGR("%s: cr=%p: %p -> %p\n", __func__, cr,
+		    cr->cr_prison, pr2);
+
+		prison_hold(pr2);
+		prison_free(cr->cr_prison);
+		cr->cr_prison = pr2;
+	}
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_vnet_route_one(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vnet *vnet, struct vps_dumpobj *o1, struct radix_node_head *rnh,
+    int fibnum, int af)
+{
+	struct vps_dump_route *vdr;
+	struct vps_dump_vnet_sockaddr *vds;
+	struct rtentry *rt_entry;
+	struct sockaddr *dst, *gateway, *netmask;
+	int flags;
+	int error = 0;
+
+	vdr = (struct vps_dump_route *)o1->data;
+	flags = vdr->rt_flags;
+
+	dst = netmask = gateway = NULL;
+
+	if (1) {
+		dst = malloc(sizeof(struct sockaddr_storage),
+		    M_TEMP, M_WAITOK|M_ZERO);
+		vds = (struct vps_dump_vnet_sockaddr *)(vdr + 1);
+		dst->sa_len = vds->sa_len;
+		dst->sa_family = vds->sa_family;
+		memcpy(dst->sa_data, vds->sa_data, vds->sa_len);
+	}
+
+	if (vdr->rt_have_mask==1) {
+		netmask = malloc(sizeof(struct sockaddr_storage),
+		    M_TEMP, M_WAITOK|M_ZERO);
+		vds = (struct vps_dump_vnet_sockaddr *)(vds + 1);
+		netmask->sa_len = vds->sa_len;
+		netmask->sa_family = vds->sa_family;
+		memcpy(netmask->sa_data, vds->sa_data, vds->sa_len);
+	}
+
+	if (vdr->rt_have_gateway==1 || vdr->rt_have_ifa==1) {
+		gateway = malloc(sizeof(struct sockaddr_storage),
+		    M_TEMP, M_WAITOK|M_ZERO);
+		/* Either rt->rt_gateway or rt->rt_ifa->ifa_addr */
+		vds = (struct vps_dump_vnet_sockaddr *)(vds + 1);
+		gateway->sa_len = vds->sa_len;
+		gateway->sa_family = vds->sa_family;
+		memcpy(gateway->sa_data, vds->sa_data, vds->sa_len);
+	}
+
+	CURVNET_SET_QUIET(vnet);
+
+	/* XXX Do these bits actually get copied ? */
+	error = rtrequest_fib(RTM_ADD, dst, gateway, netmask,
+	    flags, &rt_entry, vdr->rt_fibnum);
+	if (error)
+		ERRMSG(ctx, "%s: rtrequest_fib: error=%d\n",
+			__func__, error);
+
+	CURVNET_RESTORE();
+
+	if (dst != NULL)
+		free(dst, M_TEMP);
+	if (netmask != NULL)
+		free(netmask, M_TEMP);
+	if (gateway != NULL)
+		free(gateway, M_TEMP);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_vnet_route(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vnet *vnet)
+{
+	struct vps_dumpobj *o1, *o2;
+	struct radix_node_head *rnh;
+	int fibnum;
+	int af;
+	int error = 0;
+
+	CURVNET_SET_QUIET(vnet);
+
+	/* Freeing and reinitalizing routing tables to have them clean. */
+	/*
+	rtable_idetach(NULL);
+	memset(V_rt_tables, 0, sizeof(V_rt_tables));
+	rtable_init(NULL);
+	*/
+	/* XXX We lose memory this way ... */
+	vnet_route_uninit(NULL);
+	vnet_route_init(NULL);
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_VNET_ROUTETABLE) {
+
+		o1 = vdo_next(ctx);
+
+		fibnum = *(int *)(o1->data + (sizeof(int) * 0));
+		af =     *(int *)(o1->data + (sizeof(int) * 1));
+
+		DBGR("%s: fibnum=%d af=%d\n", __func__, fibnum, af);
+
+		rnh = NULL;
+
+		while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_VNET_ROUTE) {
+
+			o2 = vdo_next(ctx);
+			if ((error = vps_restore_vnet_route_one(ctx, vps,
+			    vnet, o2, rnh, fibnum, af)))
+				goto out;
+		}
+
+		/* Next. */
+	}
+
+	CURVNET_RESTORE();
+
+ out:
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_iface_ifaddr(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct ifnet *ifp)
+{
+	struct vps_dumpobj *o2;
+	struct vps_dump_vnet_ifaddr *vdifaddr;
+	struct vps_dump_vnet_sockaddr *vdsaddr;
+	struct vps_dump_vnet_inet6_lifetime *vdia6lt;
+	struct thread *td;
+	struct vnet *savevnet;
+	struct in_aliasreq *in_alreq;
+	struct in6_aliasreq *in6_alreq;
+	int error = 0;
+#ifdef DIAGNOSTIC
+	char ip6buf[INET6_ADDRSTRLEN];
+#endif
+
+	td = curthread;
+	curvnet = TD_TO_VNET(td);
+	savevnet = curvnet;
+
+	o2 = vdo_next(ctx);
+
+	vdifaddr = (struct vps_dump_vnet_ifaddr *)o2->data;
+
+	if (vdifaddr->have_addr == 0) {
+		DBGR("%s: vdifaddr->have_addr == 0\n", __func__);
+		return (0);
+	}
+
+	vdsaddr = (struct vps_dump_vnet_sockaddr *)
+	    (vdifaddr + 1);
+
+	switch (vdsaddr->sa_family) {
+	case AF_LINK:
+		DBGR("%s: AF_LINK: ignoring\n", __func__);
+		break;
+
+	case AF_INET:
+		in_alreq = (struct in_aliasreq *)malloc(sizeof(*in_alreq),
+		    M_TEMP, M_WAITOK | M_ZERO);
+		memcpy(in_alreq->ifra_name, ifp->if_xname,
+		    sizeof(in_alreq->ifra_name));
+
+		/* XXX check vdsaddr->sa_len */
+
+		if (vdifaddr->have_addr) {
+			in_alreq->ifra_addr.sin_family = vdsaddr->sa_family;
+			in_alreq->ifra_addr.sin_len = vdsaddr->sa_len;
+			memcpy(&in_alreq->ifra_addr.sin_port,
+			    vdsaddr->sa_data, vdsaddr->sa_len);
+			vdsaddr += 1;
+		}
+		if (vdifaddr->have_dstaddr) {
+			in_alreq->ifra_dstaddr.sin_family =
+			    vdsaddr->sa_family;
+			in_alreq->ifra_dstaddr.sin_len =
+			    vdsaddr->sa_len;
+			memcpy(&in_alreq->ifra_dstaddr.sin_port,
+			    vdsaddr->sa_data, vdsaddr->sa_len);
+			vdsaddr += 1;
+		}
+		if (vdifaddr->have_netmask) {
+			in_alreq->ifra_mask.sin_family = vdsaddr->sa_family;
+			in_alreq->ifra_mask.sin_len = vdsaddr->sa_len;
+			memcpy(&in_alreq->ifra_mask.sin_port,
+			    vdsaddr->sa_data, vdsaddr->sa_len);
+			vdsaddr += 1;
+		}
+
+		DBGR("%s: AF_INET: [%s] [%08x] [%08x] [%08x]\n",
+		    __func__, in_alreq->ifra_name,
+		    in_alreq->ifra_addr.sin_addr.s_addr,
+		    in_alreq->ifra_dstaddr.sin_addr.s_addr,
+		    in_alreq->ifra_mask.sin_addr.s_addr);
+
+		curvnet = ifp->if_vnet;
+		if ((error = in_control(NULL, SIOCAIFADDR,
+		    (caddr_t)in_alreq, ifp, td))) {
+			ERRMSG(ctx, "%s: in_control() error = %d\n",
+			    __func__, error);
+			free(in_alreq, M_TEMP);
+			curvnet = savevnet;
+			//goto next_ifaddr;
+			goto out;
+		}
+		if (ifp->if_pspare[2] != NULL)
+			((void (*) (u_long cmd, caddr_t data,
+			    struct ifnet *ifp, struct thread *td))
+			    ifp->if_pspare[2])
+			    (SIOCAIFADDR, (caddr_t)in_alreq, ifp, td);
+		free(in_alreq, M_TEMP);
+		curvnet = savevnet;
+
+		break;
+
+	case AF_INET6:
+		/*
+		if (difaddrp->ifa_addr) {
+			if (0&& ((struct sockaddr_in6 *)cpos)->sin6_scope_id
+			    < IPV6_ADDR_SCOPE_GLOBAL) {
+				DBGR("%s: AF_INET6: scopeid=%d, skipping\n",
+				    __func__, ((struct sockaddr_in6 *)
+				    cpos)->sin6_scope_id);
+				goto next_ifaddr;
+			}
+		}
+		*/
+		DBGR("%s: AF_INET6\n", __func__);
+
+		in6_alreq = (struct in6_aliasreq *)
+		    malloc(sizeof(*in6_alreq), M_TEMP, M_WAITOK | M_ZERO);
+		memcpy(in6_alreq->ifra_name, ifp->if_xname,
+		    sizeof(in6_alreq->ifra_name));
+
+		DBGR("%s: in6_aliasreq @ %p\n\tifra_name=[%s]\n",
+		    __func__, in6_alreq, in6_alreq->ifra_name);
+
+		/* XXX check vdsaddr->sa_len */
+
+		if (vdifaddr->have_addr) {
+			in6_alreq->ifra_addr.sin6_family =
+			    vdsaddr->sa_family;
+			in6_alreq->ifra_addr.sin6_len =
+			    vdsaddr->sa_len;
+			memcpy(&in6_alreq->ifra_addr.sin6_port,
+			    vdsaddr->sa_data, vdsaddr->sa_len);
+			vdsaddr += 1;
+
+			DBGR("\tifra_addr: %s\n",
+			    ip6_sprintf(ip6buf,
+			    &in6_alreq->ifra_addr.sin6_addr));
+		}
+		if (vdifaddr->have_dstaddr) {
+			in6_alreq->ifra_dstaddr.sin6_family =
+			    vdsaddr->sa_family;
+			in6_alreq->ifra_dstaddr.sin6_len =
+			    vdsaddr->sa_len;
+			memcpy(&in6_alreq->ifra_dstaddr.sin6_port,
+			    vdsaddr->sa_data, vdsaddr->sa_len);
+			vdsaddr += 1;
+
+			DBGR("\tifra_dstaddr: %s\n",
+			    ip6_sprintf(ip6buf,
+			    &in6_alreq->ifra_dstaddr.sin6_addr));
+		}
+		if (vdifaddr->have_netmask) {
+			in6_alreq->ifra_prefixmask.sin6_family =
+			    vdsaddr->sa_family;
+			in6_alreq->ifra_prefixmask.sin6_len =
+			    vdsaddr->sa_len;
+			memcpy(&in6_alreq->ifra_prefixmask.sin6_port,
+			    vdsaddr->sa_data, vdsaddr->sa_len);
+			vdsaddr += 1;
+
+			DBGR("\tifra_prefixmask: %s\n",
+			    ip6_sprintf(ip6buf,
+			    &in6_alreq->ifra_prefixmask.sin6_addr));
+		}
+
+		if (1) {
+			vdia6lt = (struct vps_dump_vnet_inet6_lifetime *)
+			    vdsaddr;
+			in6_alreq->ifra_lifetime.ia6t_expire =
+				vdia6lt->ia6t_expire;
+			in6_alreq->ifra_lifetime.ia6t_preferred =
+				vdia6lt->ia6t_preferred;
+			in6_alreq->ifra_lifetime.ia6t_vltime =
+				vdia6lt->ia6t_vltime;
+			in6_alreq->ifra_lifetime.ia6t_pltime =
+				vdia6lt->ia6t_pltime;
+
+			DBGR("\tia6_lifetime: ...\n");
+		}
+
+		/* Skipping link-local */
+		if (in6_alreq->ifra_addr.sin6_addr.s6_addr8[0] == 0xfe &&
+		    in6_alreq->ifra_addr.sin6_addr.s6_addr8[1] == 0x80) {
+			free(in6_alreq, M_TEMP);
+			goto out;
+		}
+
+		curvnet = ifp->if_vnet;
+		if ((error = in6_control(NULL, SIOCAIFADDR_IN6,
+				(caddr_t)in6_alreq, ifp, td))) {
+			ERRMSG(ctx, "%s: in6_control() error = %d\n",
+			    __func__, error);
+			free(in6_alreq, M_TEMP);
+			curvnet = savevnet;
+			goto out;
+		}
+		if (ifp->if_pspare[2] != NULL)
+			((void (*) (u_long cmd, caddr_t data,
+				struct ifnet *ifp, struct thread *td))
+				ifp->if_pspare[2])(SIOCAIFADDR_IN6,
+				(caddr_t)in6_alreq, ifp, td);
+		free(in6_alreq, M_TEMP);
+		curvnet = savevnet;
+
+		break;
+
+	default:
+		DBGR("%s: unhandled address family %d\n",
+			__func__, vdsaddr->sa_family);
+		error = EINVAL;
+		goto out;
+	}
+
+  out:
+	return (error);
+}
+
+
+__attribute__((noinline))
+static int
+vps_restore_vnet_iface(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vnet *vnet)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_vnet_ifnet *vdifnet;
+	struct thread *td;
+	struct vnet *savevnet;
+	struct ifnet *nifnetp;
+	char ifname[IFNAMSIZ];
+	int if_dunit;
+	int last_was_epair = 0;
+	int error = 0;
+
+	td = curthread;
+
+	curvnet = TD_TO_VNET(td);
+	savevnet = curvnet;
+	DBGR("curvnet=%p savevnet=%p\n", curvnet, savevnet);
+
+	nifnetp = NULL;
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_VNET_IFACE) {
+
+		o1 = vdo_next(ctx);
+
+		vdifnet = (struct vps_dump_vnet_ifnet *)o1->data;
+		DBGR("%s: vdifnet: if_xname=[%s] if_dname=[%s] "
+		    "if_dunit=%d\n", __func__, vdifnet->if_xname,
+		    vdifnet->if_dname, vdifnet->if_dunit);
+
+		/*
+		 * Skip "lo0" attach, because it is created on
+		 * vps instance allocation.
+		 */
+		if (strcmp(vdifnet->if_xname, "lo0") == 0) {
+
+			strcpy(ifname, "lo0");
+			CURVNET_SET_QUIET(vnet);
+			nifnetp = ifunit(ifname);
+			CURVNET_RESTORE();
+
+		} else {
+
+			/* Restore interface. */
+
+			/*
+			 * XXX For non-cloned interfaces,
+			 *     like hardware interfaces,
+			 *     we need special treatment.
+			 */
+
+			if (last_was_epair == 1) {
+				nifnetp = ((struct epair_softc *)
+				    (nifnetp->if_softc))->oifp;
+			} else {
+				/* Cloned interfaces. */
+				if_dunit = vdifnet->if_dunit;
+				do {
+					snprintf(ifname, IFNAMSIZ, "%s%d",
+					    vdifnet->if_dname, if_dunit++);
+					DBGR("%s: ifname=[%s]\n",
+					    __func__, ifname);
+					error = if_clone_create(ifname,
+					    sizeof(ifname), NULL);
+
+				} while (error == EEXIST);
+
+				if (error) {
+					ERRMSG(ctx, "%s: if_clone_create "
+						"returned error = %d\n",
+						__func__, error);
+					goto next_iface;
+				}
+				nifnetp = ifunit(ifname);
+			}
+
+			if (nifnetp == NULL) {
+				DBGR("%s: ifunit ([%s]) == NULL !\n",
+						__func__, ifname);
+				goto next_iface;
+			}
+
+			if (last_was_epair == 0) {
+				/* Move interface into new vps instance. */
+				if ((error = if_vmove_vps(td,
+				    nifnetp->if_xname, 0, vps,
+				    vdifnet->if_xname))) {
+					ERRMSG(ctx, "%s: if_vps_vmove() "
+					    "error = %d\n",
+					    __func__, error);
+					//goto next_iface;
+					goto out;
+				}
+				if (strcmp(vdifnet->if_dname, "epair") == 0)
+					last_was_epair = 1;
+			} else
+				last_was_epair = 0;
+		}
+
+		if (vdifnet->if_flags & IFF_UP) {
+			curvnet = nifnetp->if_vnet;
+			if_up(nifnetp);
+			DBGR("%s: setting IFF_UP on [%s]\n",
+			    __func__, nifnetp->if_xname);
+			curvnet = savevnet;
+		}
+
+		while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_VNET_ADDR) {
+
+			error = vps_restore_iface_ifaddr(ctx, vps, nifnetp);
+			if (error != 0)
+				goto out;
+
+			/* Next ifaddr. */
+		}
+
+		next_iface:
+		/* Next iface. */
+		;
+	}
+
+  out:
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_vnet(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vnet **vnetp)
+{
+	struct vps_dump_vnet *vdvnet;
+	struct vps_dumpobj *o1;
+	struct vnet *nvnet;
+	int error = 0;
+
+	o1 = vdo_next(ctx);
+	if (o1->type != VPS_DUMPOBJT_VNET) {
+		DBGR("%s: o1=%p o1->type=%d\n",
+			__func__, o1, o1->type);
+		error = EINVAL;
+		goto out;
+	}
+	vdvnet = (struct vps_dump_vnet *)o1->data;
+	DBGR("%s: orig_ptr=%p\n", __func__, vdvnet->orig_ptr);
+
+	if (*vnetp != NULL) {
+		nvnet = *vnetp;
+		DBGR("%s: vnet=%p (existed)\n", __func__, nvnet);
+	} else {
+		nvnet = vnet_alloc();
+		*vnetp = nvnet;
+		DBGR("%s: vnet=%p (allocated)\n", __func__, nvnet);
+	}
+
+	if ((error = vps_restore_vnet_iface(ctx, vps, nvnet)))
+		goto out;
+
+	if ((error = vps_restore_vnet_route(ctx, vps, nvnet)))
+		goto out;
+
+ out:
+	if (error)
+		*vnetp = NULL;
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_sysentvec(struct vps_snapst_ctx *ctx, struct vps *vps,
+			struct proc *p)
+{
+	struct vps_dump_sysentvec *vds;
+	struct vps_dumpobj *o1;
+	struct sysentvec *sv;
+
+	o1 = vdo_next(ctx);
+	if (o1->type != VPS_DUMPOBJT_SYSENTVEC) {
+		ERRMSG(ctx, "%s: wrong object type: %d\n",
+		    __func__, o1->type);
+		return (EINVAL);
+	}
+	vds = (struct vps_dump_sysentvec *)o1->data;
+
+	if (vps_md_restore_sysentvec(vds->sv_type, &sv) != 0) {
+		ERRMSG(ctx, "%s: unknown sysentvec type: %d\n",
+			__func__, vds->sv_type);
+		return (EINVAL);
+	}
+
+	p->p_sysent = sv;
+
+	return (0);
+}
+
+#define KQ_LOCK(kq) do {                                                \
+        mtx_lock(&(kq)->kq_lock);                                       \
+} while (0)
+
+#define KQ_UNLOCK(kq) do {                                                \
+        mtx_unlock(&(kq)->kq_lock);                                       \
+} while (0)
+
+int
+kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td,
+    int waitok);
+
+__attribute__((noinline))
+static int
+vps_restore_kqueue(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p)
+{
+	struct vps_dumpobj *o1, *o2;
+	struct vps_dump_knote *vdkn;
+	struct kevent *nkev;
+	struct kqueue *kq;
+	struct thread *td;
+	struct file *fp;
+	int error;
+	int dfl;
+
+	o1 = vdo_next(ctx);
+
+	if (o1->type != VPS_DUMPOBJT_KQUEUE)
+		return (EINVAL);
+
+	DBGR("%s: \n", __func__);
+
+	td = FIRST_THREAD_IN_PROC(p);
+
+	if ((error = sys_kqueue(td, NULL))) {
+		ERRMSG(ctx, "%s: sys_kqueue(): %d\n",
+			__func__, error);
+		return (error);
+	}
+	fget(td, td->td_retval[0], 0, &fp);
+	kq = fp->f_data;
+
+	KQ_LOCK(kq);
+	kq->kq_refcnt++;
+	KQ_UNLOCK(kq);
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_KNOTE) {
+
+		o2 = vdo_next(ctx);
+
+		vdkn = (struct vps_dump_knote *)o2->data;
+		dfl = vdkn->kn_status;
+
+		if (!vdkn->ke_filter)
+			continue;
+
+		nkev = malloc(sizeof(*nkev), M_TEMP, M_WAITOK);
+
+		nkev->ident  = vdkn->ke_ident;
+		nkev->filter = vdkn->ke_filter;
+		nkev->flags  = vdkn->ke_flags;
+		nkev->fflags = vdkn->ke_fflags;
+		nkev->data   = vdkn->ke_data;
+		nkev->udata  = vdkn->ke_udata;
+
+		nkev->flags = EV_ADD;
+
+		if (dfl & KN_ACTIVE)
+			DBGR("KN_ACTIVE\n");
+		if (dfl & KN_QUEUED)
+			DBGR("KN_QUEUED\n");
+		if (dfl & KN_DISABLED)
+			nkev->flags |= EV_DISABLE;
+
+		// XXX ?! kevp->flags &= ~EV_SYSFLAGS;
+
+		DBGR("kevent: ident  = 0x%016zx\n", (size_t)nkev->ident);
+		DBGR("kevent: filter = 0x%04hx\n", nkev->filter);
+		DBGR("kevent: flags  = 0x%04hx\n", nkev->flags);
+		DBGR("kevent: fflags = 0x%08x\n", nkev->fflags);
+		DBGR("kevent: data   = 0x%016zx\n", (size_t)nkev->data);
+		DBGR("kevent: udata  = 0x%016lx\n",
+		    (long unsigned int)nkev->udata);
+
+		error = kqueue_register(kq, nkev, td, 1);
+		if (error)
+			ERRMSG(ctx, "%s: kqueue_register: %d\n",
+				__func__, error);
+
+		free(nkev, M_TEMP);
+
+		/* XXX
+		if (dfl & KN_ACTIVE)
+			// set activate flag
+		if (dfl & KN_QUEUED)
+			//knote_enqueue()
+		*/
+
+		/* Next */
+		//vdo2 = (struct vps_dumpobj *)ctx->cpos;
+		;
+	}
+
+// out2:
+	KQ_LOCK(kq);
+	kq->kq_refcnt--;
+	if (kq->kq_refcnt == 1)
+		wakeup(&kq->kq_refcnt);
+	KQ_UNLOCK(kq);
+// out1:
+	fdrop(fp, td);
+
+	return (0);
+}
+
+/*
+ * This section is a little bit tricky because we have to deal
+ * with pairs of pipes that have one end closed.
+ */
+__attribute__((noinline))
+static int
+vps_restore_pipe(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_pipe *vdp;
+	struct vps_restore_obj *ro;
+	struct file *fp;
+	struct pipepair *npp;
+	int filedes[2];
+	int error = 0;
+
+	o1 = vdo_next(ctx);
+
+	if (o1->type != VPS_DUMPOBJT_PIPE)
+		return (EINVAL);
+
+	vdp = (struct vps_dump_pipe *)o1->data;
+
+	DBGR("%s: vdp: pi_have_dumped_pipe=%d pi_localend=%p pi_pair=%p "
+	    "pi_rpipe=%p pi_wpipe=%p\n",
+	    __func__, vdp->pi_have_dumped_pipe, vdp->pi_localend,
+	    vdp->pi_pair, vdp->pi_rpipe, vdp->pi_wpipe);
+
+	if (vdp->pi_have_dumped_pipe != 0) {
+
+		if ((error = kern_pipe(curthread, filedes))) {
+			ERRMSG(ctx, "%s: kern_pipe() error: %d\n",
+				__func__, error);
+			goto out;
+		}
+
+		/*
+		 * filedes[0] is the read endpoint,
+		 * filedes[1] the write endpoint.
+		 *
+		 * We only keep the endpoint connected to the file
+		 * descriptor to be restored and close the other endpoint.
+		 *
+		 * If the currently restored process has a reference to
+		 * the second endpoint, it will be connected again later
+		 * in another run.
+		 */
+
+		/* XXX CAP_ */
+		fget(curthread, filedes[0], 0, &fp);
+		npp = (struct pipepair *)
+		    ((struct pipe *)fp->f_data)->pipe_pair;
+		fdrop(fp, curthread);
+
+		/* Insert into restored objects list. */
+		ro = malloc(sizeof(*ro), M_VPS_RESTORE, M_WAITOK | M_ZERO);
+		ro->type = VPS_DUMPOBJT_PIPE;
+		ro->orig_ptr = vdp->pi_pair;
+		ro->new_ptr = npp;
+		/* These references have to be released later. */
+		/* XXX CAP_ */
+		fget(curthread, filedes[0], 0, &fp);
+		ro->spare[0] = fp;
+		/* XXX CAP_ */
+		fget(curthread, filedes[1], 0, &fp);
+		ro->spare[1] = fp;
+		SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+
+		if (vdp->pi_localend == vdp->pi_rpipe) {
+
+			/* We want the read endpoint. */
+			/* XXX CAP_ */
+			fget(curthread, filedes[0], 0, &fp);
+			fp->f_data = &npp->pp_rpipe;
+			fdrop(fp, curthread);
+
+			/* Close the write endpoint. */
+			/* XXX CAP_ */
+			fget(curthread, filedes[1], 0, &fp);
+			fdclose(curthread->td_proc->p_fd, fp,
+			    filedes[1], curthread);
+			fdrop(fp, curthread);
+
+			curthread->td_retval[0] = filedes[0];
+
+		} else if (vdp->pi_localend == vdp->pi_wpipe) {
+
+			/* We want the write endpoint. */
+			/* XXX CAP_ */
+			fget(curthread, filedes[1], 0, &fp);
+			fp->f_data = &npp->pp_wpipe;
+			fdrop(fp, curthread);
+
+			/* Close the read endpoint. */
+			/* XXX CAP_ */
+			fget(curthread, filedes[0], 0, &fp);
+			fdclose(curthread->td_proc->p_fd, fp,
+			    filedes[0], curthread);
+			fdrop(fp, curthread);
+
+			curthread->td_retval[0] = filedes[1];
+
+		} else {
+			DBGR("%s: vdp->pi_localend != vdp->pi_rpipe && "
+				"vdp->pi_localend != vdp->pi_wpipe\n",
+				__func__);
+			/* XXX Clean up. */
+			error = EINVAL;
+			goto out;
+		}
+
+	} else {
+
+		fp = NULL;
+		npp = NULL;
+		SLIST_FOREACH(ro, &ctx->obj_list, list)
+			if (ro->type == VPS_DUMPOBJT_PIPE &&
+			    ro->orig_ptr == vdp->pi_pair)
+				break;
+
+		if (ro == NULL) {
+			ERRMSG(ctx, "%s: pipe pair (old_ptr %p) "
+				"which should be there was not found !\n",
+				__func__, vdp->pi_pair);
+			error = EINVAL;
+			goto out;
+		}
+
+		npp = ro->new_ptr;
+
+		if (vdp->pi_localend == vdp->pi_rpipe) {
+
+			/* We want the read endpoint. */
+			fp = (struct file *)ro->spare[0];
+
+		} else if (vdp->pi_localend == vdp->pi_wpipe) {
+
+			/* We want the write endpoint. */
+			fp = (struct file *)ro->spare[1];
+
+		} else {
+			ERRMSG(ctx, "%s: vdp->pi_localend != vdp->pi_rpipe "
+			    "&& vdp->pi_localend != vdp->pi_wpipe\n",
+			    __func__);
+			/* XXX Clean up. */
+			error = EINVAL;
+			goto out;
+		}
+
+		fhold(fp);
+
+		FILEDESC_XLOCK (curthread->td_proc->p_fd);
+		if ((error = fdalloc(curthread, 0, &filedes[0]))) {
+			FILEDESC_XUNLOCK(curthread->td_proc->p_fd);
+			ERRMSG(ctx, "%s: fdalloc() error: %d\n",
+				__func__, error);
+			goto out;
+		}
+		curthread->td_proc->p_fd->fd_ofiles[filedes[0]].fde_file
+		    = fp;
+		FILEDESC_XUNLOCK(curthread->td_proc->p_fd);
+
+		curthread->td_retval[0] = filedes[0];
+	}
+
+ out:
+	return (error);
+}
+
+__attribute__((noinline))
+static void
+vps_restore_cleanup_pipe(struct vps_snapst_ctx *ctx, struct vps *vps,
+	struct _vps_restore_obj_list *obj_list)
+{
+	struct vps_restore_obj *obj, *obj2;
+
+	/* XXX Is it safe to fdrop() in different vps context ? */
+
+	SLIST_FOREACH_SAFE(obj, obj_list, list, obj2) {
+		if (obj->type != VPS_DUMPOBJT_PIPE)
+			continue;
+		if (obj->spare[0])
+			fdrop((struct file *)obj->spare[0], curthread);
+		if (obj->spare[1])
+			fdrop((struct file *)obj->spare[1], curthread);
+		/* Let the generic cleanup unlink and free the list item. */
+	}
+}
+
+__attribute__((noinline))
+static void
+vps_restore_cleanup_ucred(struct vps_snapst_ctx *ctx, struct vps *vps,
+	struct _vps_restore_obj_list *obj_list)
+{
+	struct vps_restore_obj *obj, *obj2;
+
+	SLIST_FOREACH_SAFE(obj, obj_list, list, obj2) {
+		if (obj->type != VPS_DUMPOBJT_UCRED)
+			continue;
+		crfree(obj->new_ptr);
+		/* Let the generic cleanup unlink and free the list item. */
+	}
+}
+
+/*
+ * XXX
+ *
+ * All the socket snapshot and restore code is still incomplete.
+ * Most socket options are not supported,
+ */
+
+__attribute__((noinline, unused))
+static void
+vps_sbcheck(struct sockbuf *sb)
+{
+        struct mbuf *m;
+        struct mbuf *n = 0;
+        u_long len = 0, mbcnt = 0;
+
+        SOCKBUF_LOCK_ASSERT(sb);
+
+        for (m = sb->sb_mb; m; m = n) {
+            n = m->m_nextpkt;
+        	for (; m; m = m->m_next) {
+			len += m->m_len;
+			mbcnt += MSIZE;
+			if (m->m_flags & M_EXT)
+				/*XXX*/ /* pretty sure this is bogus */
+				mbcnt += m->m_ext.ext_size;
+		}
+        }
+        if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) {
+		/*
+                DBGR("cc %ld != %u || mbcnt %ld != %u\n", len, sb->sb_cc,
+                    mbcnt, sb->sb_mbcnt);
+                panic("sbcheck");
+		*/
+		printf("cc %ld != %u || mbcnt %ld != %u\n",
+			len, sb->sb_cc, mbcnt, sb->sb_mbcnt);
+		kdb_enter(KDB_WHY_BREAK, "VPS break to debugger");
+        }
+}
+
+/*
+ * Pointers m1, m2, m3, ... contain mbuf pointers of the system
+ * where the snapshot was taken.
+ * We compare them to the mbufs we restore and replace them with the new
+ * pointer (XXX: , or NULL if not available).
+ *
+ * Since there *shouldn't* be any activity on the socket,
+ * it *should* be safe to sleep for allocating mbufs.
+ */
+__attribute__((noinline))
+static int
+vps_restore_mbufchain(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct mbuf **mptrs)
+{
+	struct vps_dump_mbufchain *vdmc;
+	struct vps_dump_mbuf *vdmb;
+	struct vps_dumpobj *o1;
+	struct mbuf *nm, *lnm, *nm0;
+	struct mbuf **mptrs2;
+	int i, j;
+
+	/* caller verified type */
+	o1 = vdo_next(ctx);
+
+	vdmc = (struct vps_dump_mbufchain *)o1->data;
+
+	mptrs2 = malloc(sizeof(struct mbuf *) * vdmc->mc_mbcount,
+	    M_TEMP, M_WAITOK);
+
+	lnm = nm0 = NULL;
+	vdmb = (struct vps_dump_mbuf *)(vdmc + 1);
+
+	for (i = 0; i < vdmc->mc_mbcount; i++) {
+
+		nm = m_get(M_WAITOK, vdmb->mb_type);
+		nm->m_len = vdmb->mb_len;
+
+		if (i == 0)
+			nm0 = nm;
+
+		mptrs2[i] = vdmb->mb_orig_ptr;
+
+		if (vdmb->mb_have_dat==1) {
+
+			memcpy(nm->m_dat, vdmb->mb_payload,
+			    vdmb->mb_payload_size);
+			nm->m_flags = vdmb->mb_flags;
+			if (vdmb->mb_have_data==1)
+				nm->m_data = nm->m_dat + vdmb->mb_data_off;
+
+			//vps_print_ascii(nm->m_dat, nm->m_len);
+
+		} else if (vdmb->mb_have_ext==1) {
+
+			m_cljget(nm, M_WAITOK, vdmb->mb_payload_size);
+			memcpy(nm->m_ext.ext_buf, vdmb->mb_payload,
+			    vdmb->mb_payload_size);
+			nm->m_flags = vdmb->mb_flags;
+			if (vdmb->mb_have_data==1)
+				nm->m_data = nm->m_ext.ext_buf +
+				    vdmb->mb_data_off;
+
+			DBGR("%s: M_EXT m_ext.ext_size=%u "
+			    "mb_payload_size=%u\n", __func__,
+			    nm->m_ext.ext_size, vdmb->mb_payload_size);
+
+			/*
+			vps_print_ascii(nm->m_ext.ext_buf,
+			    nm->m_ext.ext_size);
+			*/
+
+			/* checksum */
+			{
+				int sum = 0, i;
+
+				for (i = 0; i < nm->m_ext.ext_size; i++)
+					sum += (u_char)nm->m_ext.ext_buf[i];
+				DBGR("%s: computed checksum=%08x, "
+				    "original checksum=%08x\n",
+				    __func__, sum, vdmb->mb_checksum);
+				if (sum != vdmb->mb_checksum) {
+					DBGR("%s: checksum failure !\n",
+					    __func__);
+					return (-1);
+				}
+			}
+
+		} else {
+			DBGR("%s: DON'T KNOW HOW TO HANDLE MBUF\n",
+			    __func__);
+			DBGR("%s: vdmb->mb_have_dat=%d "
+			    "vdmb->mb_have_ext=%d\n",
+			    __func__, vdmb->mb_have_dat,
+			    vdmb->mb_have_ext);
+			return (-1);
+		}
+
+		if (nm->m_flags & M_PKTHDR) {
+			DBGR("%s: nm=%p M_PKTHDR\n", __func__, nm);
+			nm->m_pkthdr.rcvif = NULL;
+			nm->m_pkthdr.header = NULL;
+			/* XXX
+			if (dm->m_pkthdr.header != NULL)
+				nm->m_pkthdr.header = (caddr_t)nm +
+					((caddr_t)dm->m_pkthdr.header -
+					(caddr_t)vdm->morigptr[i]);
+			*/
+			/*
+			DBGR("%s: nm=%p dm_orig=%p header=%p rcvif=%p\n",
+				__func__, nm, vdm->morigptr[i],
+				dm->m_pkthdr.header, dm->m_pkthdr.rcvif);
+			*/
+			/* XXX */
+			SLIST_INIT(&nm->m_pkthdr.tags);
+		}
+
+		if (lnm)
+			lnm->m_next = nm;
+
+		lnm = nm;
+
+		DBGR("%s: nm=%p type=%d flags=%08x len=%d next=%p "
+		    "nextpkt=%p\n", __func__, nm, nm->m_type,
+		    nm->m_flags, nm->m_len, nm->m_next, nm->m_nextpkt);
+
+		for (j = 0; mptrs[j]; j++)
+			if (mptrs[j] == mptrs2[i]) {
+				mptrs[j] = nm;
+				DBGR("%s: replaced %p --> %p, i=%d j=%d\n",
+				    __func__, mptrs2[i], nm, i, j);
+				/* No 'break' because we may have the
+				   same pointer twice. */
+			}
+
+		/* Next. */
+		DBGR("%s: vdmb=%p vdmb->mb_payload=%p "
+		    "vdmb->mb_payload_size=%u\n",
+		    __func__, vdmb, vdmb->mb_payload,
+		    vdmb->mb_payload_size);
+		/* Always padded to meet 64 bit alignment ! */
+		vdmb = (struct vps_dump_mbuf *)(vdmb->mb_payload +
+			roundup(vdmb->mb_payload_size, 8));
+	}
+
+	DBGR("%s: restored %d mbufs\n", __func__, i);
+
+	free(mptrs2, M_TEMP);
+
+	if (nm0 && m_sanity(nm0, 1) != 1) {
+		DBGR("%s: m_sanity: BAD mbuf(chain)\n", __func__);
+	}
+
+	return (i);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_sockbuf(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct sockbuf *nsb)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_sockbuf *vdsb;
+	struct mbuf *mptrs[5];
+	int rc;
+	int error = 0;
+
+	o1 = vdo_next(ctx);
+
+	if (o1->type != VPS_DUMPOBJT_SOCKBUF)
+		return (-1);
+
+	vdsb = (struct vps_dump_sockbuf *)o1->data;
+
+	mptrs[0] = vdsb->sb_mb;
+	mptrs[1] = vdsb->sb_mbtail;
+	mptrs[2] = vdsb->sb_lastrecord;
+	mptrs[3] = vdsb->sb_sndptr;
+	mptrs[4] = NULL;
+
+	DBGR("%s: mptrs[]: 0=%p 1=%p 2=%p 3=%p\n",
+			__func__, mptrs[0], mptrs[1], mptrs[2], mptrs[3]);
+
+	if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_MBUFCHAIN)
+		rc = vps_restore_mbufchain(ctx, vps, mptrs);
+	else
+		rc = 0;
+
+	if (rc != vdsb->sb_mcnt) {
+		ERRMSG(ctx, "%s: vps_restore_mbufchain()=%d != "
+		    "dsb->sb_mcnt=%d\n", __func__, rc, vdsb->sb_mcnt);
+		return (EINVAL);
+	}
+
+	DBGR("%s: mptrs[]: 0=%p 1=%p 2=%p 3=%p\n",
+			__func__, mptrs[0], mptrs[1], mptrs[2], mptrs[3]);
+
+	nsb->sb_mb =			mptrs[0];
+	nsb->sb_mbtail =		mptrs[1];
+	nsb->sb_lastrecord =	 	mptrs[2];
+	nsb->sb_sndptr = 		mptrs[3];
+	nsb->sb_state = 		vdsb->sb_state;
+	nsb->sb_sndptroff = 		vdsb->sb_sndptroff;
+	nsb->sb_cc = 			vdsb->sb_cc;
+	nsb->sb_hiwat = 		vdsb->sb_hiwat;
+	nsb->sb_mbcnt = 		vdsb->sb_mbcnt;
+	nsb->sb_mcnt = 			vdsb->sb_mcnt;
+	nsb->sb_ccnt = 			vdsb->sb_ccnt;
+	nsb->sb_mbmax = 		vdsb->sb_mbmax;
+	nsb->sb_ctl = 			vdsb->sb_ctl;
+	nsb->sb_lowat = 		vdsb->sb_lowat;
+	nsb->sb_hiwat = 		vdsb->sb_hiwat;
+	nsb->sb_timeo = 		vdsb->sb_timeo;
+	nsb->sb_flags = 		vdsb->sb_flags;
+	/*
+	nsb->sb_upcall = 		vdsb->sb_upcall;
+	nsb->sb_upcallarg = 		vdsb->sb_upcallarg;
+	*/
+	nsb->sb_upcall =		NULL;
+	nsb->sb_upcallarg =		NULL;
+
+	DBGR("%s: restored sockbuf=%p sb_cc=%u sb_mcnt=%u "
+	    "sb_sndptroff=%u\n", __func__, nsb, nsb->sb_cc,
+	    nsb->sb_mcnt, nsb->sb_sndptroff);
+
+	vps_sbcheck(nsb);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_fixup_unixsockets(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_restore_obj *obj1, *obj2;
+	struct socket *srvso_old, *srvso_new, *cltso;
+	struct unpcb *cltunp, *srvunp;
+	int error = 0;
+
+	SLIST_FOREACH(obj1, &ctx->obj_list, list) {
+		if (obj1->type != VPS_DUMPOBJT_SOCKET_UNIX)
+			continue;
+
+		if (obj1->spare[0] != (void*)'c')
+			/* not client socket */
+			continue;
+
+		cltso = (struct socket *)obj1->new_ptr;
+		srvso_old = (struct socket *)obj1->spare[1];
+		srvso_new = NULL;
+
+		SLIST_FOREACH(obj2, &ctx->obj_list, list) {
+			if (obj2->type != VPS_DUMPOBJT_SOCKET_UNIX)
+				continue;
+			if (obj2->orig_ptr == (void*)srvso_old) {
+				srvso_new = obj2->new_ptr;
+				break;
+			}
+		}
+
+		if (srvso_new == NULL) {
+			DBGR("%s: srvso_new == NULL for srvso_old=%p\n",
+				__func__, srvso_old);
+			/*
+			error = EINVAL;
+			break;
+			*/
+			continue;
+		}
+
+		cltunp = sotounpcb((struct socket *)obj1->new_ptr);
+		srvunp = sotounpcb((struct socket *)srvso_new);
+
+		cltunp->unp_conn = srvunp;
+		cltso->so_state |= SS_ISCONNECTED;
+
+		if (cltso->so_type == SOCK_DGRAM) {
+			LIST_INSERT_HEAD(&srvunp->unp_refs, cltunp,
+			    unp_reflink);
+		} else {
+			srvunp->unp_conn = cltunp;
+			srvso_new->so_state |= SS_ISCONNECTED;
+		}
+
+		DBGR("%s: cltso=%p srvso_new=%p\n",
+		    __func__, cltso, srvso_new);
+
+		/* Let the generic cleanup unlink and free the list item. */
+	}
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_socket(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_socket *vds;
+	struct vps_dump_inetpcb *vdinpcb;
+	struct vps_dump_unixpcb *vdunpcb;
+	struct vps_dump_udppcb *vdudpcb;
+	struct vps_dump_tcppcb *vdtcpcb;
+	struct vps_dump_vnet_sockaddr *vdsaddr;
+	struct vps_restore_obj *ro;
+	struct socket *nso, *nso2;
+	struct inpcb *ninpcb;
+	struct tcpcb *ntcpcb;
+	struct unpcb *nunpcb;
+	struct udpcb *nudpcb;
+	struct sockaddr_un *saddr_un;
+	struct socket_args sockargs; /* 3 * int */
+	struct ucred *save_ucred, *ncr;
+	struct filedesc *cfd;
+	struct stat *statp;
+	struct file *fp;
+	caddr_t cpos;
+	int fdidx, fdidx_save;
+	int error;
+	int i;
+
+	nso = NULL;
+	fdidx = -1;
+
+	o1 = vdo_next(ctx);
+
+	if (o1->type != VPS_DUMPOBJT_SOCKET)
+		return (-1);
+
+	/* XXX prison with own vnet ! */
+	CURVNET_SET_QUIET(vps->vnet);
+	/* We have to temporarily change our ucred too. */
+	save_ucred = curthread->td_ucred;
+	ncr = NULL;
+
+	cpos = o1->data;
+	vds = (struct vps_dump_socket *)cpos;
+	cpos += sizeof(*vds);
+
+	if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_UCRED) {
+		vdo_next(ctx);//vps_restore_ucred(ctx, vps);
+		/* XXX don't put child objects in the middle of data ! */
+		cpos = ctx->cpos;
+	}
+	ncr = vps_restore_ucred_lookup(ctx, vps, vds->so_cred);
+	curthread->td_ucred = ncr;
+
+	DBGR("%s: family=%d protocol=%d type=%d\n",
+		__func__, vds->so_family, vds->so_protocol, vds->so_type);
+
+	sockargs.domain = vds->so_family;
+	sockargs.type = vds->so_type;
+	sockargs.protocol = vds->so_protocol;
+
+	if ((error = sys_socket(curthread, &sockargs))) {
+		ERRMSG(ctx, "%s: sys_socket() error: %d\n",
+			__func__, error);
+		goto out;
+	}
+	fdidx = curthread->td_retval[0];
+	if ((error = getsock(curthread->td_proc->p_fd, fdidx, &fp, NULL))) {
+		ERRMSG(ctx, "%s: getsock() error: %d\n",
+			__func__, error);
+		goto out;
+	}
+	nso = fp->f_data;
+	sblock(&nso->so_rcv, SBL_WAIT | SBL_NOINTR);
+	sblock(&nso->so_snd, SBL_WAIT | SBL_NOINTR);
+	SOCKBUF_LOCK(&nso->so_rcv);
+	SOCKBUF_LOCK(&nso->so_snd);
+	nso->so_vnet = curvnet;
+	nso->so_state = vds->so_state;
+	if (vds->so_options & SO_ACCEPTCONN)
+		nso->so_options |= SO_ACCEPTCONN;
+	nso->so_qlimit = vds->so_qlimit;
+	nso->so_qstate = vds->so_qstate;
+
+	/* XXX restore all socket options at all levels ! */
+
+	DBGR("%s: nso=%p dso->so_state = %08x\n",
+	    __func__, nso, vds->so_state);
+	DBGR("%s: nso->so_cred=%p nso->so_cred->cr_vps=%p "
+	    "nso->so_vnet=%p\n", __func__, nso->so_cred,
+	    nso->so_cred->cr_vps, nso->so_vnet);
+
+	switch (vds->so_family) {
+	case PF_UNIX:
+
+		SOCKBUF_UNLOCK(&nso->so_snd);
+		SOCKBUF_UNLOCK(&nso->so_rcv);
+
+		vdunpcb = (struct vps_dump_unixpcb *)cpos;
+		cpos += sizeof(*vdunpcb);
+
+		nunpcb = (struct unpcb *)nso->so_pcb;
+
+		if (vdunpcb->unp_have_addr) {
+			vdsaddr = (struct vps_dump_vnet_sockaddr *)cpos;
+			cpos += sizeof(*vdsaddr);
+
+			saddr_un = malloc(sizeof(struct sockaddr_un),
+			    M_TEMP, M_WAITOK | M_ZERO);
+			saddr_un->sun_len = vdsaddr->sa_len;
+			saddr_un->sun_family = vdsaddr->sa_family;
+			memcpy(saddr_un->sun_path, vdsaddr->sa_data,
+			    vdsaddr->sa_len);
+			/* Make sure sun_path is null terminated. */
+			saddr_un->sun_path[saddr_un->sun_len -
+			    offsetof(struct sockaddr_un, sun_path[0])] =
+			    '\0';
+		} else
+			saddr_un = NULL;
+
+		if (vdunpcb->unp_have_conn==0 &&
+		    vdunpcb->unp_have_vnode==1 &&
+		    vdunpcb->unp_have_addr==1) {
+
+			/* Socket was bound. */
+			DBGR("%s: socket was bound: [%s]\n",
+			    __func__, saddr_un->sun_path);
+
+			/* Remove name from filesystem first. */
+			statp = malloc(sizeof(*statp), M_TEMP, M_WAITOK);
+			error = kern_stat(curthread, saddr_un->sun_path,
+			    UIO_SYSSPACE, statp);
+			if (error) {
+				ERRMSG(ctx, "%s: kern_stat() error: "
+				    "%d [%s]\n", __func__, error,
+				    saddr_un->sun_path);
+				free(statp, M_TEMP);
+				free(saddr_un, M_TEMP);
+				SOCKBUF_LOCK(&nso->so_rcv);
+				SOCKBUF_LOCK(&nso->so_snd);
+				goto out_unlock;
+			}
+			kern_unlink(curthread, saddr_un->sun_path,
+			    UIO_SYSSPACE);
+
+			error = sobind(nso, (struct sockaddr *)saddr_un,
+			    curthread);
+			if (error) {
+				ERRMSG(ctx, "%s: sobind() error: %d [%s]\n",
+				    __func__, error, saddr_un->sun_path);
+				free(statp, M_TEMP);
+				free(saddr_un, M_TEMP);
+				SOCKBUF_LOCK(&nso->so_rcv);
+				SOCKBUF_LOCK(&nso->so_snd);
+				goto out_unlock;
+			}
+
+			/* Restore permissions. */
+			error = kern_chown(curthread, saddr_un->sun_path,
+			    UIO_SYSSPACE, statp->st_uid, statp->st_gid);
+			if (error) {
+				ERRMSG(ctx, "%s: kern_chown() error: "
+				    "%d [%s]\n", __func__, error,
+				    saddr_un->sun_path);
+				free(statp, M_TEMP);
+				free(saddr_un, M_TEMP);
+				SOCKBUF_LOCK(&nso->so_rcv);
+				SOCKBUF_LOCK(&nso->so_snd);
+				goto out_unlock;
+			}
+			error = kern_chmod(curthread, saddr_un->sun_path,
+			    UIO_SYSSPACE, statp->st_mode);
+			if (error) {
+				ERRMSG(ctx, "%s: kern_chmod() error: "
+				    "%d [%s]\n", __func__, error,
+				    saddr_un->sun_path);
+				free(statp, M_TEMP);
+				free(saddr_un, M_TEMP);
+				SOCKBUF_LOCK(&nso->so_rcv);
+				SOCKBUF_LOCK(&nso->so_snd);
+				goto out_unlock;
+			}
+			free(statp, M_TEMP);
+
+			if (vdunpcb->unp_flags & UNP_HAVEPCCACHED) {
+				/* Socket was listening. */
+				DBGR("%s: socket was listening\n",
+				    __func__);
+				error = solisten(nso, vds->so_qlimit,
+				    curthread);
+				if (error) {
+					ERRMSG(ctx, "%s: solisten() error: "
+					    "%d [%s]\n", __func__, error,
+					    saddr_un->sun_path);
+					free(saddr_un, M_TEMP);
+					SOCKBUF_LOCK(&nso->so_rcv);
+					SOCKBUF_LOCK(&nso->so_snd);
+					goto out_unlock;
+				}
+			}
+
+			/* insert into global list of unix sockets */
+			ro = malloc(sizeof(*ro), M_VPS_RESTORE,
+			    M_WAITOK | M_ZERO);
+			ro->type = VPS_DUMPOBJT_SOCKET_UNIX;
+			ro->orig_ptr = vdunpcb->unp_socket;
+			ro->new_ptr = nso;
+			ro->spare[0] = (void*)'s';
+			ro->spare[1] = NULL;
+
+			SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+
+		/*
+		 * Both client and server sockets are put into a global list
+		 * that is walked through at the end of vps restore.
+		 * All references can be restored then.
+		 */
+		} else if (vdunpcb->unp_have_conn==1 &&
+		    vdunpcb->unp_have_addr==1 &&
+		    (vdunpcb->unp_flags & UNP_HAVEPC)) {
+			DBGR("%s: connected; server\n", __func__);
+			/* insert into global list of unix sockets */
+			ro = malloc(sizeof(*ro), M_VPS_RESTORE,
+			    M_WAITOK | M_ZERO);
+			ro->type = VPS_DUMPOBJT_SOCKET_UNIX;
+			ro->orig_ptr = vdunpcb->unp_socket;
+			ro->new_ptr = nso;
+			ro->spare[0] = (void*)'s';
+			ro->spare[1] = NULL;
+
+			SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+
+			DBGR("%s: server socket: orig_ptr=%p new_ptr=%p "
+			    "unp_socket=%p\n", __func__, ro->orig_ptr,
+			    ro->new_ptr, vdunpcb->unp_socket);
+
+		} else if (vdunpcb->unp_have_conn) {
+			DBGR("%s: connected; client\n", __func__);
+			/* insert into global list of unix sockets */
+			ro = malloc(sizeof(*ro), M_VPS_RESTORE,
+			    M_WAITOK | M_ZERO);
+			ro->type = VPS_DUMPOBJT_SOCKET_UNIX;
+			ro->orig_ptr = vdunpcb->unp_socket;
+			ro->new_ptr = nso;
+			ro->spare[0] = (void*)'c';
+			ro->spare[1] = (void*)vdunpcb->unp_conn_socket;
+
+			SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+
+			DBGR("%s: client socket: orig_ptr=%p new_ptr=%p "
+			    "unp_conn_socket=%p\n", __func__, ro->orig_ptr,
+			    ro->new_ptr, vdunpcb->unp_conn_socket);
+
+		} else {
+			DBGR("%s: unknown socket state\n", __func__);
+		}
+
+		if (vdunpcb->unp_flags & UNP_HAVEPCCACHED) {
+			nunpcb->unp_flags |= UNP_HAVEPCCACHED;
+			nunpcb->unp_peercred.cr_uid =
+			    vdunpcb->unp_peercred.cr_uid;
+			nunpcb->unp_peercred.cr_ngroups =
+			    vdunpcb->unp_peercred.cr_ngroups;
+			for (i = 0; i < nunpcb->unp_peercred.cr_ngroups;
+			    i++)
+				nunpcb->unp_peercred.cr_groups[i] =
+					vdunpcb->unp_peercred.cr_groups[i];
+		}
+
+		/* XXX not used at all ? */
+		if (vdunpcb->unp_have_vnode==1 && vdo_typeofnext(ctx) ==
+				VPS_DUMPOBJT_FILE_PATH) {
+			DBGR("%s: unused vnode object !\n", __func__);
+			vdo_next(ctx);
+		}
+
+		DBGR("%s: nso=%p so_state=%d unpcb->unp_conn=%p\n",
+			__func__, nso, nso->so_state, nunpcb->unp_conn);
+
+		free(saddr_un, M_TEMP);
+		SOCKBUF_LOCK(&nso->so_rcv);
+		SOCKBUF_LOCK(&nso->so_snd);
+		break;
+
+	case PF_INET:
+	case PF_INET6:
+		vdinpcb = (struct vps_dump_inetpcb *)cpos;
+		cpos += sizeof(*vdinpcb);
+
+		ninpcb = (struct inpcb *)nso->so_pcb;
+
+		INP_INFO_WLOCK(ninpcb->inp_pcbinfo);
+		INP_HASH_WLOCK(ninpcb->inp_pcbinfo);
+		INP_WLOCK(ninpcb);
+
+		ninpcb->inp_vnet = curvnet;
+
+		/* Connection info (endpoints). */
+
+		ninpcb->inp_inc.inc_flags = vdinpcb->inp_inc.inc_flags;
+		ninpcb->inp_inc.inc_len = vdinpcb->inp_inc.inc_len;
+		ninpcb->inp_inc.inc_fibnum = vdinpcb->inp_inc.inc_fibnum;
+		ninpcb->inp_inc.inc_ie.ie_fport= vdinpcb->inp_inc.ie_fport;
+		ninpcb->inp_inc.inc_ie.ie_lport= vdinpcb->inp_inc.ie_lport;
+		if (vdinpcb->inp_vflag & INP_IPV6) {
+			memcpy(&ninpcb->inp_inc.inc6_faddr,
+			    vdinpcb->inp_inc.ie_ufaddr, 0x10);
+			memcpy(&ninpcb->inp_inc.inc6_laddr,
+			    vdinpcb->inp_inc.ie_uladdr, 0x10);
+		} else {
+			memcpy(&ninpcb->inp_inc.inc_faddr,
+			    vdinpcb->inp_inc.ie_ufaddr, 0x4);
+			memcpy(&ninpcb->inp_inc.inc_laddr,
+			    vdinpcb->inp_inc.ie_uladdr, 0x4);
+		}
+
+		/*
+		DBGR("%s: inc_flags=%08x inc_len=%d inc_fibnum=%d\n",
+		    __func__,
+		    vdinpcb->inp_inc.inc_flags,
+		    vdinpcb->inp_inc.inc_len,
+		    vdinpcb->inp_inc.inc_fibnum);
+		DBGR("%s: inc_flags=%08x inc_len=%d inc_fibnum=%d\n",
+		    __func__,
+		    ninpcb->inp_inc.inc_flags,
+		    ninpcb->inp_inc.inc_len,
+		    ninpcb->inp_inc.inc_fibnum);
+		DBGR("%s: inp_inc.ie_fport=%u inp_inc.ie_lport=%u\n",
+		    __func__,
+		    vdinpcb->inp_inc.ie_fport,
+		    vdinpcb->inp_inc.ie_lport);
+		DBGR("%s: inp_inc.ie_fport=%u inp_inc.ie_lport=%u\n",
+		    __func__,
+		    ninpcb->inp_inc.inc_ie.ie_fport,
+		    ninpcb->inp_inc.inc_ie.ie_lport);
+		DBGR("%s: inp_inc.inc6_faddr: %16D\n",
+		    __func__, vdinpcb->inp_inc.ie_ufaddr, ":");
+		DBGR("%s: inp_inc.inc6_laddr: %16D\n",
+		    __func__, vdinpcb->inp_inc.ie_uladdr, ":");
+		DBGR("%s: inp_inc.inc6_faddr: %16D\n",
+		    __func__, &ninpcb->inp_inc.inc6_faddr, ":");
+		DBGR("%s: inp_inc.inc6_laddr: %16D\n",
+		    __func__, &ninpcb->inp_inc.inc6_laddr, ":");
+		*/
+
+		ninpcb->inp_vflag = vdinpcb->inp_vflag;
+		ninpcb->inp_flags = vdinpcb->inp_flags;
+		ninpcb->inp_flags2 = vdinpcb->inp_flags2;
+		/* in_pcbinshash() has NOT been called */
+		ninpcb->inp_flags &= ~INP_INHASHLIST;
+
+		in_pcbinshash(ninpcb);
+
+		DBGR("%s: ninpcb=%p inp_vflag=%02hhx inp_flags=%08x "
+		    "inp_flags2=%08x\n",
+		    __func__, ninpcb, ninpcb->inp_vflag,
+		    ninpcb->inp_flags, ninpcb->inp_flags2);
+
+		/* XXX IP options. */
+
+		if (vdinpcb->inp_have_ppcb != 0) {
+
+			/*
+			 * XXX For now panic, otherwise we never know
+			 *     if this case can happen.
+			 *     Later just return EINVAL, user might
+			 *     made up rubbish.
+			 */
+			KASSERT(ninpcb->inp_ppcb != NULL,
+				("%s: ninpcb->inp_ppcb == NULL", __func__));
+			if (ninpcb->inp_ppcb == NULL) {
+				ERRMSG(ctx, "%s: ninpcb->inp_ppcb == "
+				    "NULL\n", __func__);
+				error = EINVAL;
+				goto out_unlock;
+			}
+
+			/* inpcb->inp_ip_p seems to be 0 and only used for
+			   raw ip and divert sockets! */
+
+			switch (vds->so_protocol) {
+
+			case IPPROTO_TCP:
+				vdtcpcb = (struct vps_dump_tcppcb *)cpos;
+				ntcpcb = (struct tcpcb *)ninpcb->inp_ppcb;
+
+				INP_INFO_WLOCK(&V_tcbinfo);
+				ntcpcb->t_state = vdtcpcb->t_state;
+				ntcpcb->snd_una = vdtcpcb->snd_una;
+				ntcpcb->snd_max = vdtcpcb->snd_max;
+				ntcpcb->snd_nxt = vdtcpcb->snd_nxt;
+				ntcpcb->snd_up = vdtcpcb->snd_up;
+				ntcpcb->snd_wl1 = vdtcpcb->snd_wl1;
+				ntcpcb->snd_wl2 = vdtcpcb->snd_wl2;
+				ntcpcb->iss = vdtcpcb->iss;
+				ntcpcb->irs = vdtcpcb->irs;
+				ntcpcb->rcv_nxt = vdtcpcb->rcv_nxt;
+				ntcpcb->rcv_adv = vdtcpcb->rcv_adv;
+				ntcpcb->rcv_wnd = vdtcpcb->rcv_wnd;
+				ntcpcb->rcv_up = vdtcpcb->rcv_up;
+				ntcpcb->snd_wnd = vdtcpcb->snd_wnd;
+				ntcpcb->snd_cwnd = vdtcpcb->snd_cwnd;
+				ntcpcb->snd_ssthresh =
+				    vdtcpcb->snd_ssthresh;
+				INP_INFO_WUNLOCK(&V_tcbinfo);
+
+				break;
+
+			case IPPROTO_UDP:
+				vdudpcb = (struct vps_dump_udppcb *)cpos;
+				nudpcb = (struct udpcb *)ninpcb->inp_ppcb;
+
+				if (vdudpcb->u_have_tun_func != 0) {
+					ERRMSG(ctx, "%s: ucb->u_tun_func "
+					    "!= NULL, unsupported\n",
+					    __func__);
+					error = EINVAL;
+					goto out_unlock;
+				}
+				nudpcb->u_flags = vdudpcb->u_flags;
+				nudpcb->u_tun_func = NULL;
+
+				break;
+
+			case IPPROTO_RAW:
+			case IPPROTO_ICMP:
+				/* Nothing to do. */
+				break;
+
+			default:
+				ERRMSG(ctx, "%s: unhandled IPPROTO "
+				    "%d / %d\n", __func__,
+				    vds->so_protocol, vdinpcb->inp_ip_p);
+				error = EINVAL;
+				goto out_unlock;
+				break;
+			}
+		}
+
+		INP_WUNLOCK(ninpcb);
+		INP_HASH_WUNLOCK(ninpcb->inp_pcbinfo);
+		INP_INFO_WUNLOCK(ninpcb->inp_pcbinfo);
+
+		break;
+
+	default:
+		ERRMSG(ctx, "%s: unhandled protocol family %d\n",
+			__func__, vds->so_family);
+		error = EINVAL;
+		goto out_unlock;
+		break;
+	}
+
+	if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_SOCKBUF)
+		if ((error = vps_restore_sockbuf(ctx, vps, &nso->so_rcv)))
+			goto out_unlock;
+	if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_SOCKBUF)
+		if ((error = vps_restore_sockbuf(ctx, vps, &nso->so_snd)))
+			goto out_unlock;
+
+	/*
+	 * On success, the only thing to return is the new fd index
+	 * in curthread->td_retval[0].
+	 */
+
+ out_unlock:
+
+	SOCKBUF_UNLOCK(&nso->so_snd);
+	SOCKBUF_UNLOCK(&nso->so_rcv);
+	sbunlock(&nso->so_snd);
+	sbunlock(&nso->so_rcv);
+
+	fdrop(fp, curthread);
+
+ out:
+
+	if (error) {
+		/* XXX destroy socket. */
+		ERRMSG(ctx, "%s: error = %d\n", __func__, error);
+	}
+
+	curthread->td_retval[0] = fdidx;
+	curthread->td_ucred = save_ucred;
+	if (ncr)
+		crfree(ncr);
+	CURVNET_RESTORE();
+
+	//ctx->cpos = (caddr_t)o1->data + o1->size;
+
+	/* Sockets that were on the accept queue of this socket. */
+	if (vds->so_qlen > 0 || vds->so_incqlen > 0) {
+		DBGR("%s: so_qlen=%d so_incqlen=%d\n",
+			__func__, vds->so_qlen, vds->so_incqlen);
+
+		fdidx_save = fdidx;
+		cfd = curthread->td_proc->p_fd;
+
+		for (i = 0; i < (vds->so_qlen + vds->so_incqlen); i++) {
+			//o2 = (struct vps_dumpobj *)ctx->cpos;
+			if ((error = vps_restore_socket(ctx, vps, p)))
+				return (error);
+			/*
+			 * We have to remove it from the fdset and link it
+			 * up to the listening socket.
+			 */
+			fdidx = (int)curthread->td_retval[0];
+			DBGR("%s: open returned fd %d\n", __func__, fdidx);
+
+			FILEDESC_XLOCK(cfd);
+			fp = cfd->fd_ofiles[fdidx].fde_file;
+			nso2 = (struct socket *)fp->f_data;
+			cfd->fd_ofiles[fdidx].fde_file = NULL;
+			cfd->fd_ofiles[fdidx].fde_flags = 0;
+			fdunused(cfd, fdidx);
+			FILEDESC_XUNLOCK(cfd);
+
+			/*
+			 * Have to do ugly things here ...
+			 * Better allocate sockets using soalloc() rather
+			 * than sys_socket().
+			 *
+			 */
+			fp->f_ops = &badfileops;
+			fdrop(fp, curthread);
+
+			nso2->so_count = 0;
+
+			if (i < vds->so_qlen) {
+				TAILQ_INSERT_TAIL(&nso->so_comp, nso2,
+				    so_list);
+				nso->so_qlen++;
+			} else {
+				TAILQ_INSERT_TAIL(&nso->so_incomp, nso2,
+				    so_list);
+				nso->so_incqlen++;
+			}
+
+		}
+		curthread->td_retval[0] = fdidx_save;
+	}
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_pathtovnode(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vnode **vnp)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_filepath *vdfp;
+	struct nameidata nd;
+	int error;
+
+	o1 = vdo_next(ctx);
+
+	if (o1->type != VPS_DUMPOBJT_FILE_PATH)
+		return (EINVAL);
+
+	vdfp = (struct vps_dump_filepath *)o1->data;
+
+	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
+		vdfp->fp_path, curthread);
+	error = namei(&nd);
+	if (error)
+		return (error);
+
+	/* XXX VREF() ?! */
+	*vnp = nd.ni_vp;
+
+	VOP_UNLOCK(nd.ni_vp, 0);
+	NDFREE(&nd, NDF_ONLY_PNBUF);
+
+	if (strcmp(vdfp->fp_path, "/VPSRELINKED_") == 0)
+		/* XXX oldinum -> 0 ? */
+		kern_unlinkat(curthread, AT_FDCWD, vdfp->fp_path,
+		    UIO_SYSSPACE, 0);
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_file_vnode(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p, struct thread *curtd, struct vps_dump_file *vdf)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_filepath *vdfp;
+	int oflags;
+	int error = 0;
+
+	o1 = vdo_next(ctx);
+
+	if (o1->type != VPS_DUMPOBJT_FILE_PATH) {
+		ERRMSG(ctx, "%s: DTYPE_VNODE without path information "
+			"-> skipping !\n", __func__);
+		error = EINVAL;
+		goto out;
+	}
+	vdfp = (struct vps_dump_filepath *)o1->data;
+
+	oflags = OFLAGS(vdf->f_flag);
+
+	/*
+	 * We have to open the file in our current thread's context,
+	 * because e.g. devfs relies on td == curthread.
+	 * Afterwards we simply move the reference into the new proc's fd.
+	 */
+	if ((error = kern_openat(curtd, AT_FDCWD /* XXX */, vdfp->fp_path,
+				UIO_SYSSPACE, oflags, 0))) {
+		ERRMSG(ctx, "%s: open error: [%s] %d\n",
+			__func__, vdfp->fp_path, error);
+#ifdef DIAGNOSTIC
+		/* XXX debugging */
+		if (error == ENOENT && !strcmp(vdfp->fp_path, "/dev/null"))
+			kdb_enter(KDB_WHY_BREAK, "VPS break to debugger");
+		error = 0;
+#else
+		error = EINVAL;
+		goto out;
+#endif
+	}
+
+	if (strncmp(vdfp->fp_path, "/VPSRELINKED_", 13) == 0) {
+		DBGR("%s: unlinking [%s]\n", __func__, vdfp->fp_path);
+		/* XXX oldinum -> 0 ? */
+		kern_unlinkat(curtd, AT_FDCWD, vdfp->fp_path,
+		    UIO_SYSSPACE, 0);
+	}
+
+	/* Returning new fd index in curthread->td_retval[0]. */
+
+ out:
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_file_pts(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p, struct thread *curtd, struct vps_dump_file *vdf)
+{
+	struct vps_dumpobj *o1, *o2;
+	struct vps_restore_obj *ro;
+	struct vps_dump_filepath *vdfp;
+	struct filedesc *fdp;
+	struct file *fp;
+	struct tty *ttyp;
+	struct vps_dump_pts *vdp;
+	struct pts_softc *psc;
+	struct termios *termiosp;
+	int oflags;
+	int fdidx;
+	int found;
+	int i;
+	int error = 0;
+
+	o1 = vdo_next(ctx);
+	if (o1->type != VPS_DUMPOBJT_PTS) {
+		ERRMSG(ctx, "%s: DTYPE_PTS without VPS_DUMPOBJT_PTS\n",
+				__func__);
+		error = EINVAL;
+		goto out;
+	}
+
+	vdp = (struct vps_dump_pts *)o1->data;
+
+	if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_UCRED)
+		vdo_next(ctx);//vps_restore_ucred(ctx, vps);
+
+	o2 = vdo_next(ctx);
+	if (o2->type != VPS_DUMPOBJT_FILE_PATH) {
+		ERRMSG(ctx, "%s: DTYPE_PTS without "
+		    "VPS_DUMPOBJT_FILE_PATH\n", __func__);
+		error = EINVAL;
+		goto out;
+	}
+
+	vdfp = (struct vps_dump_filepath *)o2->data;
+
+	oflags = OFLAGS(vdf->f_flag);
+
+	fdp = curtd->td_proc->p_fd;
+	FILEDESC_XLOCK(fdp);
+
+	found = 0;
+	for (fdidx = 0; fdidx < fdp->fd_nfiles; fdidx++) {
+		fp = fget_locked(fdp, fdidx);
+		if (fp && fp->f_type == DTYPE_PTS) {
+			if (strncmp(vdfp->fp_path,
+			    tty_devname((struct tty *)fp->f_data),
+			    vdfp->fp_size) == 0) {
+				found = 1;
+				curtd->td_retval[0] = fdidx;
+				break;
+			}
+		}
+	}
+
+	FILEDESC_XUNLOCK(fdp);
+
+	if (found == 0) {
+		ERRMSG(ctx, "%s: pts [%s] not found !\n",
+			__func__, vdfp->fp_path);
+		error = EINVAL;
+		goto out;
+	}
+
+	ttyp = (struct tty *)fp->f_data;
+	termiosp = malloc(sizeof(*termiosp), M_TEMP, M_WAITOK);
+	termiosp->c_iflag = vdp->pt_termios.c_iflag;
+	termiosp->c_oflag = vdp->pt_termios.c_oflag;
+	termiosp->c_cflag = vdp->pt_termios.c_cflag;
+	termiosp->c_lflag = vdp->pt_termios.c_lflag;
+	termiosp->c_ispeed = vdp->pt_termios.c_ispeed;
+	termiosp->c_ospeed = vdp->pt_termios.c_ospeed;
+	for (i = 0; i < NCCS; i++)
+		termiosp->c_cc[i] = vdp->pt_termios.c_cc[i];
+	error = kern_ioctl(curtd, /* fd */ curtd->td_retval[0],
+				TIOCSETAW, (caddr_t)termiosp);
+	free(termiosp, M_TEMP);
+	if (error)
+		ERRMSG(ctx, "%s: ttydev_ioctl() error=%d\n",
+			__func__, error);
+	ttyp->t_pgrp = (void*)(size_t)vdp->pt_pgrp_id; /* ID */
+	psc = tty_softc(ttyp);
+	psc->pts_flags = vdp->pt_flags;
+
+	if (vdp->pt_cred != NULL) {
+		if (psc->pts_cred != NULL)
+			crfree(psc->pts_cred);
+		psc->pts_cred = vps_restore_ucred_lookup(ctx, vps,
+		    vdp->pt_cred);
+	}
+
+	/* Insert into restored objects list. */
+	ro = malloc(sizeof(*ro), M_VPS_RESTORE, M_WAITOK | M_ZERO);
+	ro->type = VPS_DUMPOBJT_PTS;
+	ro->new_ptr = ttyp;
+	SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+
+ out:
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_file_kqueue(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p, struct thread *curtd, struct vps_dump_file *vdf)
+{
+	struct filedesc *nfd, *cfd;
+	struct file *nfp;
+	char tmpflags;
+	int idx;
+	int error = 0;
+
+	/* XXX kqueue has to be last (after all other fds) */
+	if ((error = vps_restore_kqueue(ctx, vps, p))) {
+		ERRMSG(ctx, "%s: vps_restore_kqueue() error: %d\n",
+			__func__, error);
+		goto out;
+	}
+	/* The file was restored in newproc so move it to curproc. */
+
+	idx = (int)FIRST_THREAD_IN_PROC(p)->td_retval[0];
+
+	nfd = p->p_fd;
+	cfd = curtd->td_proc->p_fd;
+
+	FILEDESC_XLOCK(nfd);
+	nfp = nfd->fd_ofiles[idx].fde_file;
+	fhold(nfp);
+	tmpflags = nfd->fd_ofiles[idx].fde_flags;
+	nfd->fd_ofiles[idx].fde_file = NULL;
+	nfd->fd_ofiles[idx].fde_flags = 0;
+	fdunused(nfd, idx);
+	FILEDESC_XUNLOCK(nfd);
+
+	FILEDESC_XLOCK(cfd);
+	/* XXX
+	idx = fd_first_free(cfd, 0, 100);
+	XXX
+	*/
+	idx = 10;
+	fdgrowtable(cfd, idx);
+	cfd->fd_ofiles[idx].fde_file = nfp;
+	cfd->fd_ofiles[idx].fde_flags = tmpflags;
+	fdrop(nfp, curtd);
+	fdused(cfd, idx);
+	FILEDESC_XUNLOCK(cfd);
+	curtd->td_retval[0] = idx;
+
+ out:
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_file(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_file *vdf;
+	struct vps_restore_obj *ro;
+	struct filedesc *cfd;
+	struct file *nfp;
+	struct vps *save_vps;
+	struct ucred *save_ucred, *ncr;
+	struct vnode *save_rdir, *save_cdir;
+	struct thread *curtd;
+	char tmpflags;
+	int idx;
+	int error = 0;
+
+	curtd = curthread;
+	save_vps = curtd->td_vps;
+	save_ucred = curtd->td_ucred;
+	save_rdir = curtd->td_proc->p_fd->fd_rdir;
+	save_cdir = curtd->td_proc->p_fd->fd_cdir;
+	curtd->td_vps = vps;
+	curtd->td_proc->p_fd->fd_rdir = p->p_fd->fd_rdir;
+	curtd->td_proc->p_fd->fd_cdir = p->p_fd->fd_cdir;
+
+	ncr = NULL;
+
+	/* caller verified type */
+	o1 = vdo_next(ctx);
+
+	/*
+	DBGR("%s: o1=%p: VPS_DUMPOBJT_FILE size=%d\n",
+	    __func__, o1, o1->size);
+	*/
+
+	vdf = (struct vps_dump_file *)o1->data;
+	ncr = NULL;
+
+	DBGR("%s: index= origidx= origptr=%p type=%d flag=%08x offset=%d\n",
+		__func__, /*vdf->index, vdf->orig_index, */vdf->orig_ptr,
+		vdf->f_type, vdf->f_flag, (int)vdf->f_offset);
+
+	/* Lookup in list of restored file objects. */
+	SLIST_FOREACH(ro, &ctx->obj_list, list)
+		if (ro->type == VPS_DUMPOBJT_FILE && ro->orig_ptr ==
+		    vdf->orig_ptr)
+			break;
+
+	if (ro != NULL) {
+
+		DBGR("%s: found in restored obj list: orig_ptr=%p "
+		    "new_ptr=%p\n", __func__, ro->orig_ptr, ro->new_ptr);
+
+		/* skip over child objects if exist */
+		while (vdo_nextischild(ctx, o1))
+			vdo_next(ctx);
+
+		error = 0;
+		goto out;
+	}
+
+	if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_UCRED) {
+		vdo_next(ctx);//vps_restore_ucred(ctx, vps);
+	}
+	ncr = vps_restore_ucred_lookup(ctx, vps, vdf->f_cred);
+	save_ucred = curtd->td_ucred;
+	curtd->td_ucred = ncr;
+
+	switch (vdf->f_type) {
+
+	case DTYPE_VNODE:
+		/* Returns new fd index in curtd->td_retval[0]. */
+		if ((error = vps_restore_file_vnode(ctx, vps, p, curtd,
+		    vdf))) {
+			ERRMSG(ctx, "%s: vps_restore_file_vnode() "
+			    "error: %d\n", __func__, error);
+			goto out;
+		}
+		break;
+
+	case DTYPE_PTS:
+		/* Returns new fd index in curtd->td_retval[0]. */
+		if ((error = vps_restore_file_pts(ctx, vps, p, curtd,
+		    vdf))) {
+			ERRMSG(ctx, "%s: vps_restore_file_pts() "
+			    "error: %d\n", __func__, error);
+			goto out;
+		}
+		break;
+
+        case DTYPE_SOCKET:
+		/* Returns new fd index in curtd->td_retval[0]. */
+		if ((error = vps_restore_socket(ctx, vps, p))) {
+			ERRMSG(ctx, "%s: vps_restore_socket() error: %d\n",
+				__func__, error);
+			goto out;
+		}
+		break;
+
+	case DTYPE_PIPE:
+		/* Returns new fd index in curtd->td_retval[0]. */
+		if ((error = vps_restore_pipe(ctx, vps, p))) {
+			ERRMSG(ctx, "%s: vps_restore_pipe() error: %d\n",
+				__func__, error);
+			goto out;
+		}
+		break;
+
+	case DTYPE_KQUEUE:
+		/* Returns new fd index in curtd->td_retval[0]. */
+		if ((error = vps_restore_file_kqueue(ctx, vps, p, curtd,
+		    vdf))) {
+			ERRMSG(ctx, "%s: vps_restore_file_kqueue() "
+			    "error: %d\n", __func__, error);
+			goto out;
+		}
+		break;
+
+	default:
+		ERRMSG(ctx, "%s: unhandled file type %d\n",
+			__func__, vdf->f_type);
+		error = ENOTSUP;
+		goto out;
+		break;
+	}
+
+	idx = (int)curtd->td_retval[0];
+	DBGR("%s: open returned fd %d\n", __func__, idx);
+
+	cfd = curtd->td_proc->p_fd;
+
+	FILEDESC_XLOCK(cfd);
+	nfp = cfd->fd_ofiles[idx].fde_file;
+	fhold(nfp);
+	tmpflags = cfd->fd_ofiles[idx].fde_flags;
+	cfd->fd_ofiles[idx].fde_file = NULL;
+	cfd->fd_ofiles[idx].fde_flags = 0;
+	fdunused(cfd, idx);
+	FILEDESC_XUNLOCK(cfd);
+
+	fhold(nfp);
+	/* Skip for pseudo ttys for now.
+	if (strncmp((char *)o2->data, "/dev/pts/", strlen("/dev/pts/")))
+	*/
+		nfp->f_offset = vdf->f_offset;
+	fdrop(nfp, curtd);
+
+	/* Restore f_flag XXX */
+	if (vdf->f_flag & FNONBLOCK)
+		nfp->f_flag |= FNONBLOCK;
+
+	/* Insert into restored objects list. */
+	ro = malloc(sizeof(*ro), M_VPS_RESTORE, M_WAITOK | M_ZERO);
+	ro->type = VPS_DUMPOBJT_FILE;
+	ro->orig_ptr = vdf->orig_ptr;
+	/* Having an extra reference now for list. */
+	ro->new_ptr = nfp;
+	SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+	fdrop(nfp, curtd);
+
+ out:
+	curtd->td_vps = save_vps;
+	curtd->td_proc->p_fd->fd_rdir = save_rdir;
+	curtd->td_proc->p_fd->fd_cdir = save_cdir;
+
+	if (ncr) {
+		curtd->td_ucred = save_ucred;
+		crfree(ncr);
+		ncr = NULL;
+	}
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_fdset(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p, struct filedesc *orig_fdp)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_filedesc *vdfd;
+	struct vps_restore_obj *ro;
+	struct filedesc *nfd, *cfd;
+	struct file *nfp;
+	struct vps *save_vps;
+	struct ucred *save_ucred;
+	struct vnode *save_rdir;
+	struct vnode *save_cdir;
+	int error = 0;
+	int i;
+
+	if (vdo_typeofnext(ctx) != VPS_DUMPOBJT_FDSET) {
+		/* Lookup in list of restored file objects. */
+		SLIST_FOREACH(ro, &ctx->obj_list, list)
+			if (ro->type == VPS_DUMPOBJT_FDSET &&
+			    ro->orig_ptr == orig_fdp)
+				break;
+		if (ro == NULL) {
+			DBGR("%s: fdset orig_ptr=%p not found !\n",
+				__func__, orig_fdp);
+			return (EINVAL);
+		}
+		p->p_fd = fdshare(ro->new_ptr);
+		DBGR("%s: linked shared fdset %p (orig %p) to proc %p/%d\n",
+			__func__, p->p_fd, orig_fdp, p, p->p_pid);
+
+		return (0);
+	}
+
+	/* verified type */
+	o1 = vdo_next(ctx);
+
+	/*
+	DBGR("%s: o1=%p: VPS_DUMPOBJT_FDSET size=%d\n",
+	    __func__, o1, o1->size);
+	*/
+
+	vdfd = (struct vps_dump_filedesc *)o1->data;
+
+	DBGR("%s: fdset has %d entries\n", __func__, vdfd->fd_nfiles);
+
+	p->p_fd = nfd = fdinit(NULL);
+	cfd = curthread->td_proc->p_fd;
+
+	if (vdfd->fd_have_cdir != 0) {
+		if ((error = vps_restore_pathtovnode(ctx, vps,
+		    &p->p_fd->fd_cdir)))
+			return (error);
+	}
+	if (vdfd->fd_have_rdir != 0) {
+		if ((error = vps_restore_pathtovnode(ctx, vps,
+		    &p->p_fd->fd_rdir)))
+			return (error);
+	}
+	if (vdfd->fd_have_jdir != 0) {
+		if ((error = vps_restore_pathtovnode(ctx, vps,
+		    &p->p_fd->fd_jdir)))
+			return (error);
+	}
+
+	save_vps = curthread->td_vps;
+	save_ucred = curthread->td_ucred;
+	save_rdir = curthread->td_proc->p_fd->fd_rdir;
+	save_cdir = curthread->td_proc->p_fd->fd_cdir;
+	curthread->td_vps = vps;
+	curthread->td_proc->p_fd->fd_rdir = p->p_fd->fd_rdir;
+	curthread->td_proc->p_fd->fd_cdir = p->p_fd->fd_cdir;
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_FILE) {
+		if ((error = vps_restore_file(ctx, vps, p)))
+			goto out;
+	}
+
+	/* Now all files should exist, so link them into fdset. */
+	for (i = 0; i < vdfd->fd_nfiles; i++) {
+
+		DBGR("%s: vdfd->fd_entries[%d].fp = %p\n",
+			__func__, i, vdfd->fd_entries[i].fp);
+		if (vdfd->fd_entries[i].fp == NULL)
+			continue;
+
+                /* Lookup in list of restored file objects. */
+		SLIST_FOREACH(ro, &ctx->obj_list, list)
+			if (ro->type == VPS_DUMPOBJT_FILE &&
+			    ro->orig_ptr == vdfd->fd_entries[i].fp)
+				break;
+
+		if (ro == NULL) {
+			DBGR("%s: can't find file fp=%p\n",
+				__func__, vdfd->fd_entries[i].fp);
+			error = EINVAL;
+			goto out;
+		}
+		nfp = (struct file *)ro->new_ptr;
+		fhold(nfp);
+
+		FILEDESC_XLOCK(nfd);
+		if (i >= nfd->fd_nfiles)
+			fdgrowtable(nfd, i);
+		nfd->fd_ofiles[i].fde_file = nfp;
+		nfd->fd_ofiles[i].fde_flags = vdfd->fd_entries[i].flags;
+		nfd->fd_ofiles[i].fde_rights = vdfd->fd_entries[i].rights;
+		fdused(nfd, i);
+		FILEDESC_XUNLOCK(nfd);
+
+		DBGR("%s: linked up fp: idx=%d new=%p orig=%p\n",
+			__func__, i, ro->new_ptr, ro->orig_ptr);
+	}
+
+	curthread->td_vps = save_vps;
+	curthread->td_proc->p_fd->fd_rdir = save_rdir;
+	curthread->td_proc->p_fd->fd_cdir = save_cdir;
+
+	/* Insert into restored objects list. */
+	ro = malloc(sizeof(*ro), M_VPS_RESTORE, M_WAITOK | M_ZERO);
+	ro->type = VPS_DUMPOBJT_FDSET;
+	ro->orig_ptr = vdfd->fd_orig_ptr;
+	ro->new_ptr = nfd;
+	SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+
+	DBGR("%s: restored fdset orig=%p new=%p\n",
+	    __func__, vdfd->fd_orig_ptr, nfd);
+
+  out:
+	return (error);
+}
+
+__attribute__((noinline))
+static void
+vps_restore_cleanup_fdset(struct vps_snapst_ctx *ctx, struct vps *vps,
+	struct _vps_restore_obj_list *obj_list)
+{
+	struct vps_restore_obj *obj, *obj2;
+
+	SLIST_FOREACH_SAFE(obj, obj_list, list, obj2) {
+		if (obj->type != VPS_DUMPOBJT_FILE)
+			continue;
+		if (obj->new_ptr)
+			fdrop((struct file *)obj->new_ptr, curthread);
+		/* Let the generic cleanup unlink and free the list item. */
+	}
+}
+
+__attribute__((noinline))
+static int
+vps_restore_pargs(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_pargs *vdp;
+	int error = 0;
+
+	/* caller verified type */
+	o1 = vdo_next(ctx);
+
+	vdp = (struct vps_dump_pargs *)o1->data;
+
+	p->p_args = pargs_alloc(vdp->ar_length);
+	memcpy(p->p_args->ar_args, vdp->ar_args, vdp->ar_length);
+
+	DBGR("%s: len=%d [%s]\n", __func__,
+	    vdp->ar_length, p->p_args->ar_args);
+
+	return (error);
+}
+
+/*
+ * Return one logical memory page named by index, from the userspace dump.
+ */
+__attribute__((noinline))
+static struct vm_page *
+vps_restore_getuserpage(struct vps_snapst_ctx *ctx, int idx, int test)
+{
+	vm_map_t map;
+	vm_object_t obj;
+	vm_map_entry_t entry;
+	vm_pindex_t index;
+	vm_prot_t prot;
+	vm_page_t m;
+	boolean_t wired;
+	vm_offset_t vaddr;
+
+	vaddr = (vm_offset_t)(ctx->userpagesaddr + (idx << PAGE_SHIFT));
+
+	map = &curthread->td_proc->p_vmspace->vm_map;
+
+ retry:
+	if ((vm_map_lookup(&map, vaddr, VM_PROT_READ, &entry, &obj,
+	    &index, &prot, &wired))) {
+		DBGR("%s: vm_map_lookup(): error\n", __func__);
+		m = NULL;
+		goto out;
+	}
+
+	VM_OBJECT_WLOCK(obj);
+
+	m = vm_page_lookup(obj, index);
+
+	vm_map_lookup_done(map, entry);
+
+	//DBGR("%s: userpage idx=%d at %p\n", __func__, idx, mem);
+
+	if (m == NULL) {
+		/* Try to page in. */
+
+		/* Note: unlocks the object if it has to sleep */
+		m = vm_page_grab(obj, index,
+		    VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
+
+		if (m == NULL)
+			panic("%s: vm_page_alloc() == NULL", __func__);
+
+		if ((vm_pager_get_pages(obj, &m, 1, 0)) != VM_PAGER_OK) {
+			vm_page_lock(m);
+			vm_page_free(m);
+			vm_page_unlock(m);
+			VM_OBJECT_WUNLOCK(obj);
+			m = NULL;
+			goto out;
+		}
+
+		m = vm_page_lookup(obj, index);
+
+		vm_page_wakeup(m);
+	}
+
+	/*
+	 * The pageout daemon might have already decided to swap out
+	 * this very page.
+	 */
+	if (m->oflags & VPO_SWAPINPROG || m->busy > 0) {
+		DBGR("%s: m->oflags & VPO_SWAPINPROG || m->busy > 0   "
+			"--> vm_page_sleep()\n", __func__);
+		vm_page_sleep(m, "swpinp");
+		VM_OBJECT_WUNLOCK(obj);
+		goto retry;
+	}
+
+	vm_page_busy(m);
+
+	VM_OBJECT_WUNLOCK(obj);
+
+  out:
+	KASSERT( !(test == 0 && m == NULL),
+	    ("vps_restore_getuserpage: unable to retrieve page, "
+	    "idx=%d/offset=%d", idx, idx << PAGE_SHIFT));
+
+	return (m);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_vmobject(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vm_object **nvo_out)
+{
+	struct vps_dumpobj *o1, *o2;
+	struct vps_dump_vmobject *vdvmo;
+	struct vps_dump_vmpages *vdvmp;
+	struct vps_dump_filepath *vdfp;
+	struct vps_restore_obj *vbo;
+	struct vm_object *nvo, *vo2;
+	struct vm_page *m;
+	struct ucred *ncr;
+	struct nameidata nd;
+	int error = 0;
+
+	/*
+	DBGR("%s: o=%p: type=%d size=%d\n",
+	    __func__, o, o->type, o->size);
+	*/
+
+	*nvo_out = NULL;
+
+	/* caller verified type */
+	o1 = vdo_next(ctx);
+
+	vdvmo = (struct vps_dump_vmobject *)o1->data;
+
+	DBGR("%s: old obj=%p: size=%d flags=%04x type=%02x cred=%p "
+	    "origptr=%p\n",
+	    __func__, vdvmo, (int)vdvmo->size, vdvmo->flags,
+	    vdvmo->type, vdvmo->cred, vdvmo->orig_ptr);
+
+	if (vdvmo->type == OBJT_VNODE && vdvmo->have_vnode) {
+		o2 = vdo_next(ctx);
+		if (o2->type != VPS_DUMPOBJT_FILE_PATH) {
+			ERRMSG(ctx, "%s: wrong object, expected "
+				"VPS_DUMPOBJT_FILE_PATH\n", __func__);
+			error = EINVAL;
+			goto out;
+		}
+		vdfp = (struct vps_dump_filepath *)o2->data;
+
+		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
+			vdfp->fp_path, curthread);
+		if ((error = namei(&nd))) {
+			ERRMSG(ctx, "%s: namei([%s]): error = %d\n",
+				__func__, vdfp->fp_path, error);
+			goto out;
+		}
+		if ((error = VOP_OPEN(nd.ni_vp, FREAD, curthread->td_ucred,
+			curthread, NULL))) {
+			ERRMSG(ctx, "%s: VOP_OPEN(...): error = %d\n",
+				__func__, error);
+			VOP_UNLOCK(nd.ni_vp, 0);
+			NDFREE(&nd, NDF_ONLY_PNBUF);
+			goto out;
+		}
+		nvo = nd.ni_vp->v_object;
+		vm_object_reference(nvo);
+		vrele(nd.ni_vp);
+		VOP_UNLOCK(nd.ni_vp, 0);
+		NDFREE(&nd, NDF_ONLY_PNBUF);
+
+		KASSERT(nvo->cred == NULL,
+			("%s: nvo=%p ->cred=%p\n",
+			__func__, nvo, nvo->cred));
+
+		DBGR("%s: path [%s] got vnode %p v_object %p\n",
+			__func__, vdfp->fp_path, nd.ni_vp, nvo);
+
+	} else if (vdvmo->type == OBJT_DEFAULT ||
+	    vdvmo->type == OBJT_SWAP) {
+
+		nvo = vm_object_allocate(OBJT_DEFAULT, vdvmo->size);
+
+	} else if (vdvmo->type == OBJT_PHYS &&
+		   vdvmo->is_sharedpageobj != 0) {
+
+		DBGR("%s: shared_page_obj\n", __func__);
+
+		nvo = shared_page_obj;
+		vm_object_reference(nvo);
+
+	} else if (vdvmo->type == OBJT_PHYS) {
+
+		DBGR("%s: OBJT_PHYS\n", __func__);
+		nvo = vm_object_allocate(OBJT_PHYS, vdvmo->size);
+
+	} else {
+		/*
+		 * XXX We don't support that yet.
+		 */
+
+		DBGR("%s: unsupported vm object: vdvmo=%p type=%d\n",
+			__func__, vdvmo, vdvmo->type);
+		/* XXX missing the sibling list here */
+		error = EINVAL;
+		goto out;
+	}
+
+	if (vdvmo->cred != NULL && vdo_typeofnext(ctx) ==
+			VPS_DUMPOBJT_UCRED) {
+		vdo_next(ctx);//vps_restore_ucred(ctx, vps);
+	}
+	if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_UCRED &&
+	    vdvmo->cred == NULL)
+		DBGR("%s: have ucred but vdvmo->cred == NULL!!!\n",
+		    __func__);
+
+	if (nvo != shared_page_obj) {
+		nvo->flags = vdvmo->flags;
+		nvo->charge = vdvmo->charge;
+		KASSERT(nvo->cred == NULL,
+			("%s: nvo->cred = %p\n", __func__, nvo->cred));
+		//DBGR("%s: charge=%lu\n", __func__, nvo->charge);
+		if (vdvmo->cred != NULL) {
+			ncr = vps_restore_ucred_lookup(ctx, vps,
+			    vdvmo->cred);
+			KASSERT(ncr != NULL,
+			    ("%s: ucred not found\n", __func__));
+			nvo->cred = ncr;
+			swap_reserve_by_cred(nvo->charge, nvo->cred);
+		}
+	}
+
+	if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_VMPAGE) {
+
+		struct vps_dump_vmpageref *vdvmpr;
+		int i;
+
+		/*
+		DBGR("%s: o2=%p: type=VMPAGE size=%d (pindex=%08x)\n",
+				__func__, o2, o2->size, *((int*)o2->data) );
+		*/
+
+		o2 = vdo_next(ctx);
+
+		vdvmp = (struct vps_dump_vmpages *)o2->data;
+		vdvmpr = (struct vps_dump_vmpageref *)(vdvmp + 1);
+
+		DBGR("%s: vdvmp=%p count=%u vdvmpr=%p\n",
+			__func__, vdvmp, (u_int)vdvmp->count, vdvmpr);
+
+		for (i = 0; i < vdvmp->count; i++) {
+
+			m = vps_restore_getuserpage(ctx,
+			    ctx->userpagesidx++, 0);
+
+			vo2 = m->object;
+			VM_OBJECT_WLOCK(nvo);
+			VM_OBJECT_WLOCK(vo2);
+			vm_page_lock(m);
+
+			pmap_remove_all(m);
+
+			KASSERT((m->oflags & VPO_SWAPINPROG) == 0,
+				("%s: m=%p oflags 0x%x & VPO_SWAPINPROG\n",
+				__func__, m, m->oflags));
+
+			KASSERT(vdvmpr->pr_vmobject == vdvmo->orig_ptr,
+				("%s: object mismatch ! "
+				"(vdvmpr->pr_vmobject=%p)\n",
+				__func__, vdvmpr->pr_vmobject));
+
+			vm_page_rename(m, nvo, vdvmpr->pr_pindex);
+
+			if (vdvmo->type == OBJT_PHYS)
+				vm_page_wire(m);
+
+			vm_page_unlock(m);
+
+			VM_OBJECT_WUNLOCK(vo2);
+			VM_OBJECT_WUNLOCK(nvo);
+
+			/* Next mem page. */
+			vdvmpr++;
+		}
+	}
+
+	if (vdvmo->backing_object) {
+		/*
+		 * We search in our list for the referenced backing object.
+		 * If it's not there, something went wrong badly.
+		 */
+
+		SLIST_FOREACH(vbo, &ctx->obj_list, list)
+			if (vbo->type == VPS_DUMPOBJT_VMOBJECT &&
+			    vbo->orig_ptr == vdvmo->backing_object) {
+				nvo->backing_object = vbo->new_ptr;
+				break;
+			}
+
+		if (nvo->backing_object == NULL) {
+			ERRMSG(ctx, "%s: backing object not found "
+			    "(orig_ptr=%p)\n",
+			    __func__, vdvmo->backing_object);
+			error = EINVAL;
+			goto out;
+		}
+
+		vm_object_reference(nvo->backing_object);
+		LIST_INSERT_HEAD(&nvo->backing_object->shadow_head,
+			nvo, shadow_list);
+		nvo->backing_object->shadow_count++;
+		nvo->backing_object->generation++;
+
+		nvo->backing_object_offset = vdvmo->backing_object_offset;
+
+		DBGR("%s: found backing object %p for object %p\n",
+			__func__, nvo->backing_object, nvo);
+	}
+
+	/*
+	 * Add this object to our list of vm (backing) objects.
+	 *
+	 * Note: the reference that we have now is released
+	 * when this list is cleaned up.
+	 */
+	vbo = malloc(sizeof(*vbo), M_VPS_RESTORE, M_WAITOK);
+	vbo->type = VPS_DUMPOBJT_VMOBJECT;
+	vbo->orig_ptr = vdvmo->orig_ptr;
+	vbo->new_ptr = nvo;
+
+	SLIST_INSERT_HEAD(&ctx->obj_list, vbo, list);
+
+	DBGR("%s: object=%p put in list of vm objects, orig_ptr=%p\n",
+		__func__, nvo, vbo->orig_ptr);
+
+	KASSERT(!(nvo->type != 2 && nvo != shared_page_obj &&
+	        nvo->ref_count != 1),
+		("%s: nvo=%p ->ref_count = %d\n",
+		__func__, nvo, nvo->ref_count));
+
+	*nvo_out = nvo;
+	//DBGR("%s: *nvo_out=%p nvo=%p\n", __func__, *nvo_out, nvo);
+
+ out:
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_vmspace(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p, struct vmspace *orig_vmspace)
+{
+	struct vps_dumpobj *o1, *o2;
+	struct vps_restore_obj *ro;
+	struct vps_dump_vmspace *vdvms;
+	struct vps_dump_vmmapentry *vdvme;
+	struct vps_restore_obj *vbo;
+	struct vmspace *ns;
+	struct vm_map_entry *nme;
+	struct vm_object *nvo;
+	struct ucred *ncr;
+	int cow;
+	int error = 0;
+
+	ncr = NULL;
+
+	if (vdo_typeofnext(ctx) != VPS_DUMPOBJT_VMSPACE) {
+		/* Lookup in list of restored file objects. */
+		SLIST_FOREACH(ro, &ctx->obj_list, list)
+			if (ro->type == VPS_DUMPOBJT_VMSPACE &&
+			    ro->orig_ptr == orig_vmspace)
+				break;
+		if (ro == NULL) {
+			DBGR("%s: vmspace orig_ptr=%p not found !\n",
+				__func__, orig_vmspace);
+			return (EINVAL);
+		}
+		p->p_vmspace = ro->new_ptr;
+		atomic_add_int(&p->p_vmspace->vm_refcnt, 1);
+
+		DBGR("%s: linked shared vmspace %p (orig %p) "
+		    "to proc %p/%d\n",
+		    __func__, p->p_vmspace, orig_vmspace, p, p->p_pid);
+
+		return (0);
+	}
+
+	/* verified type. */
+	o1 = vdo_next(ctx);
+
+	vdvms = (struct vps_dump_vmspace *)o1->data;
+
+	ns = vmspace_alloc(vdvms->vm_map.minoffset,
+	     vdvms->vm_map.maxoffset);
+
+	DBGR("%s: map=%p\n", __func__, &ns->vm_map);
+
+	/* o1 --> vmspace */
+	/* o2 --> map entry */
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_VMMAPENTRY) {
+
+		o2 = vdo_next(ctx);
+		vdvme = (struct vps_dump_vmmapentry *)o2->data;
+
+		nvo = NULL;
+
+		DBGR("%s: vm_map_entry=%p: start=%p end=%p orig_obj=%p\n",
+		    __func__, vdvme, PTRFROM64(vdvme->start),
+		    PTRFROM64(vdvme->end), vdvme->map_object);
+
+		if (vdvme->map_object == NULL) {
+
+			/* No VM objects, next map entry follows. */
+
+			DBGR("%s: no object\n", __func__);
+
+			/* Move on to next map entry. */
+
+		} else {
+
+			/* Look if vm object is already restored
+			   (shared memory). */
+			SLIST_FOREACH(vbo, &ctx->obj_list, list)
+				if (vbo->orig_ptr == vdvme->map_object) {
+					nvo = vbo->new_ptr;
+					break;
+				}
+
+			if (nvo) {
+				/* Move on to next map entry. */
+				DBGR("%s: found vm_object (shared memory): "
+				    "orig=%p nvo=%p\n",
+				    __func__, vdvme->map_object, nvo);
+			}
+
+		}
+
+		if (vdvme->cred != NULL) {
+			if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_UCRED)
+				vdo_next(ctx);
+			ncr = vps_restore_ucred_lookup(ctx, vps,
+			    vdvme->cred);
+		} else
+			ncr = NULL;
+		DBGR("%s: ncr=%p\n", __func__, ncr);
+
+		while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_VMOBJECT) {
+			if ((error = vps_restore_vmobject(ctx, vps, &nvo)))
+				goto out;
+		}
+
+		/* This is the last vm object for this map entry,
+		   so insert the entry. */
+		cow = 0;
+
+		DBGR("%s: entry (%016zx-%016zx, size=%016zx, prot=%02x, "
+		    "max_prot=%02x, object=%p, offset=%016zx) eflags=%08x; "
+		    "nvo=%p\n",
+		    __func__, (size_t)vdvme->start, (size_t)vdvme->end,
+		    (size_t)(vdvme->end - vdvme->start),
+		    vdvme->protection, vdvme->max_protection,
+		    vdvme->map_object, (size_t)vdvme->offset,
+		    vdvme->eflags, nvo);
+
+		if (nvo != NULL)
+			vm_object_reference(nvo);
+
+		vm_map_lock(&ns->vm_map);
+		if ((error = vm_map_insert(&ns->vm_map, nvo, vdvme->offset,
+				vdvme->start, vdvme->end, vdvme->protection,
+				vdvme->max_protection, cow))) {
+			ERRMSG(ctx, "%s: vm_map_insert(): error %d\n",
+				__func__, error);
+			error = EINVAL;
+			if (nvo)
+				vm_object_deallocate(nvo);
+			vm_map_unlock(&ns->vm_map);
+			goto out;
+		}
+
+		vm_map_lookup_entry(&ns->vm_map, vdvme->start, &nme);
+		nme->inheritance = vdvme->inheritance;
+		if (vdvme->eflags & MAP_STACK_GROWS_DOWN)
+			nme->eflags |= MAP_STACK_GROWS_DOWN;
+		if (vdvme->eflags & MAP_STACK_GROWS_UP)
+			nme->eflags |= MAP_STACK_GROWS_UP;
+		if (vdvme->eflags & MAP_ENTRY_COW)
+			nme->eflags |= MAP_ENTRY_COW;
+		if (vdvme->eflags & MAP_ENTRY_NEEDS_COPY)
+			nme->eflags |= MAP_ENTRY_NEEDS_COPY;
+		if (vdvme->eflags & MAP_ENTRY_NOCOREDUMP)
+			nme->eflags |= MAP_ENTRY_NOCOREDUMP;
+		/* XXX audit this value */
+		if (vdvme->avail_ssize > 0)
+			nme->avail_ssize = vdvme->avail_ssize;
+
+		if (nme->cred != NULL) {
+			swap_release_by_cred(nme->end - nme->start,
+			    nme->cred);
+			crfree(nme->cred);
+			nme->cred = NULL;
+		}
+		if (ncr != NULL) {
+			nme->cred = crhold(ncr);
+			swap_reserve_by_cred(nme->end - nme->start,
+			    nme->cred);
+		}
+
+		vm_map_unlock(&ns->vm_map);
+
+		if (ncr != NULL) {
+			crfree(ncr);
+			ncr = NULL;
+		}
+
+		/* Next map entry. */
+	}
+
+
+	ns->vm_tsize = vdvms->vm_tsize;
+	ns->vm_dsize = vdvms->vm_dsize;
+	ns->vm_ssize = vdvms->vm_ssize;
+
+	/* Insert into restored objects list. */
+	ro = malloc(sizeof(*ro), M_VPS_RESTORE, M_WAITOK | M_ZERO);
+	ro->type = VPS_DUMPOBJT_VMSPACE;
+	ro->orig_ptr = vdvms->vm_orig_ptr;
+	ro->new_ptr = ns;
+	SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+
+	DBGR("%s: restored vmspace orig=%p new=%p\n",
+		__func__, vdvms->vm_orig_ptr, ns);
+
+	p->p_vmspace = ns;
+
+ out:
+	if (ncr != NULL) {
+		crfree(ncr);
+		ncr = NULL;
+	}
+
+	if (error) {
+		ERRMSG(ctx, "%s: error = %d\n", __func__, error);
+	}
+
+	return (error);
+}
+
+__attribute__((noinline))
+static void
+vps_restore_cleanup_vmspace(struct vps_snapst_ctx *ctx, struct vps *vps,
+	struct _vps_restore_obj_list *obj_list)
+{
+	struct vps_restore_obj *obj, *obj2;
+
+	SLIST_FOREACH_SAFE(obj, obj_list, list, obj2) {
+		if (obj->type != VPS_DUMPOBJT_VMOBJECT)
+			continue;
+		if (obj->new_ptr)
+			vm_object_deallocate(obj->new_ptr);
+		/* Let the generic cleanup unlink and free the list item. */
+	}
+}
+
+__attribute__((noinline))
+static int
+vps_restore_thread_savefpu(struct vps_snapst_ctx *ctx, struct vps *vps,
+	struct thread *td)
+{
+
+	return (vps_md_restore_thread_savefpu(ctx, vps, td));
+}
+
+__attribute__((noinline))
+static int
+vps_restore_thread(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_thread *vdtd;
+	struct thread *ntd;
+#if defined(VPS_ARCH_I386) || defined(VPS_ARCH_AMD64)
+	void *pcb_save;
+#endif
+	int kstack_pages;
+	int error = 0;
+	int i;
+
+	/* caller verified type */
+	o1 = vdo_next(ctx);
+
+	vdtd = (struct vps_dump_thread *)o1->data;
+
+	DBGR("%s: old thread: tid=%d\n", __func__, vdtd->td_tid);
+
+	kstack_pages = vdtd->td_kstack_pages;
+	if (kstack_pages > KSTACK_MAX_PAGES) {
+		ERRMSG(ctx, "%s: requested %d pages for kstack but system "
+		    "maximum is %d\n",
+		    __func__, kstack_pages, KSTACK_MAX_PAGES);
+		error = EINVAL;
+		goto out;
+	}
+
+	if ((ntd = thread_alloc(kstack_pages)) == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+
+	tidhash_add(ntd);
+
+	memset(&ntd->td_startzero, 0,
+		__rangeof(struct thread, td_startzero, td_endzero));
+	memset(&ntd->td_rux, 0, sizeof(ntd->td_rux));
+
+	ntd->td_rqindex = vdtd->td_rqindex;
+	ntd->td_base_pri = vdtd->td_base_pri;
+	ntd->td_priority = vdtd->td_priority;
+	ntd->td_pri_class = vdtd->td_pri_class;
+	ntd->td_user_pri = vdtd->td_user_pri;
+	ntd->td_base_user_pri = vdtd->td_base_user_pri;
+
+	ntd->td_sigstk.ss_sp = PTRFROM64(vdtd->td_sigstk.ss_sp);
+	ntd->td_sigstk.ss_size = vdtd->td_sigstk.ss_size;
+	ntd->td_sigstk.ss_flags = vdtd->td_sigstk.ss_flags;
+	ntd->td_xsig = vdtd->td_xsig;
+	ntd->td_dbgflags = vdtd->td_dbgflags;
+	for (i = 0; i < _SIG_WORDS; i++) {
+		ntd->td_sigmask.__bits[i] = vdtd->td_sigmask[i];
+		ntd->td_oldsigmask.__bits[i] = vdtd->td_oldsigmask[i];
+	}
+
+#if defined(VPS_ARCH_I386) || defined(VPS_ARCH_AMD64)
+	/* Remember because it will be overwritten. */
+	pcb_save = ntd->td_pcb->pcb_save;
+#endif
+
+	/* Restore kernel stack (this includes the PCB). */
+	memcpy((char *)ntd->td_kstack, vdtd->td_kstack,
+	    kstack_pages * PAGE_SIZE);
+
+#if defined(VPS_ARCH_I386) || defined(VPS_ARCH_AMD64)
+	ntd->td_pcb->pcb_save = pcb_save;
+#endif
+
+	/*
+	 * XXX
+	 * There are some registers/values restored along with the PCB
+	 * that have to be audited !
+	 */
+
+	/*
+	vps_md_print_thread(ntd);
+	*/
+
+	if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_SAVEFPU) {
+		if ((error = vps_restore_thread_savefpu(ctx, vps, ntd)))
+			goto out;
+	}
+
+	error = vps_md_restore_thread(vdtd, ntd, p);
+	if (error != 0)
+		goto out;
+
+	ntd->td_proc = p;
+	ntd->td_ucred = crhold(p->p_ucred);
+	ntd->td_vps = vps;
+	ntd->td_vps_acc = vps->vps_acc;
+
+	thread_link(ntd, p);
+
+	/* not yet */
+	if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_UMTX)
+		vdo_next(ctx);
+
+	DBGR("%s: created thread=%p tid=%d\n",
+			__func__, ntd, ntd->td_tid);
+
+ out:
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_proc_one(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_proc *vdp;
+	struct ucred *save_ucred;
+	struct proc *np;
+	struct vps *save_vps;
+	struct thread *ntd;
+	struct nameidata nd;
+	caddr_t cpos;
+	int error = 0;
+	int i;
+
+	/* calling functions make sure the next object is of type _PROC */
+	o1 = vdo_next(ctx);
+
+	DBGR("%s: o1=%p\n", __func__, o1);
+
+	save_ucred = curthread->td_ucred;
+
+	vdp = (struct vps_dump_proc *)o1->data;
+	cpos = (caddr_t)(vdp + 1);
+
+	/*
+	DBGR("%s: dtd->td_tid=%d dtd->td_ucred=%p dp->p_ucred=%p\n",
+		__func__, dtd->td_tid, dtd->td_ucred, dp->p_ucred);
+	*/
+
+	/*
+	 * We get a struct proc that already contains loads
+	 * of resources, e.g. a thread ...
+	 * So release them all first ...
+	 * XXX p_stats
+	 * XXX p_ksi
+	 */
+
+	np = uma_zalloc(proc_zone, M_WAITOK);
+	if ((ntd = FIRST_THREAD_IN_PROC(np)) != NULL) {
+		PROC_LOCK(np);
+		thread_unlink(ntd);
+		PROC_UNLOCK(np);
+		thread_free(ntd);
+	}
+
+	bzero(&np->p_startzero, __rangeof(struct proc,
+		p_startzero, p_endzero));
+
+	/* assemble proc */
+	np->p_magic = P_MAGIC;
+	np->p_pid = vdp->p_pid;
+	np->p_swtick = vdp->p_swtick; /* XXX apply delta */
+
+	/* sigacts */
+
+	/* XXX checks:
+	vdp->p_sigacts.ps_maxsig == _SIG_MAXSIG
+	vdp->p_sigacts.ps_sigwords == _SIG_WORDS
+	*/
+
+	np->p_sigacts = malloc(sizeof(struct sigacts), M_SUBPROC,
+	    M_WAITOK | M_ZERO);
+	np->p_sigacts->ps_refcnt = 1;
+	mtx_init(&np->p_sigacts->ps_mtx, "sigacts", NULL, MTX_DEF);
+
+	np->p_sigacts->ps_flag = vdp->p_sigacts.ps_flag;
+	for (i = 0; i < _SIG_MAXSIG; i++) {
+		np->p_sigacts->ps_sigact[i] =
+		    PTRFROM64(vdp->p_sigacts.ps_sigact[i]);
+		np->p_sigacts->ps_catchmask[i].__bits[0] =
+		    vdp->p_sigacts.ps_catchmask[i][0];
+		np->p_sigacts->ps_catchmask[i].__bits[1] =
+		    vdp->p_sigacts.ps_catchmask[i][1];
+		np->p_sigacts->ps_catchmask[i].__bits[2] =
+		    vdp->p_sigacts.ps_catchmask[i][2];
+		np->p_sigacts->ps_catchmask[i].__bits[3] =
+		    vdp->p_sigacts.ps_catchmask[i][3];
+	}
+	for (i = 0; i < _SIG_WORDS; i++) {
+		np->p_sigacts->ps_sigonstack.__bits[i] =
+		    vdp->p_sigacts.ps_sigonstack[i];
+		np->p_sigacts->ps_sigintr.__bits[i] =
+		    vdp->p_sigacts.ps_sigintr[i];
+		np->p_sigacts->ps_sigreset.__bits[i] =
+		    vdp->p_sigacts.ps_sigreset[i];
+		np->p_sigacts->ps_signodefer.__bits[i] =
+		    vdp->p_sigacts.ps_signodefer[i];
+		np->p_sigacts->ps_siginfo.__bits[i] =
+		    vdp->p_sigacts.ps_siginfo[i];
+		np->p_sigacts->ps_sigignore.__bits[i] =
+		    vdp->p_sigacts.ps_sigignore[i];
+		np->p_sigacts->ps_sigcatch.__bits[i] =
+		    vdp->p_sigacts.ps_sigcatch[i];
+		np->p_sigacts->ps_freebsd4.__bits[i] =
+		   vdp->p_sigacts.ps_freebsd4[i];
+		np->p_sigacts->ps_osigset.__bits[i] =
+		   vdp->p_sigacts.ps_osigset[i];
+		np->p_sigacts->ps_usertramp.__bits[i] =
+		   vdp->p_sigacts.ps_usertramp[i];
+	}
+
+	/* plimit */
+	/* XXX check: vdp->p_limit.pl_nlimits == RLIM_NLIMITS */
+
+	np->p_limit = lim_alloc();
+
+	for (i = 0; i < RLIM_NLIMITS; i++) {
+		np->p_limit->pl_rlimit[i].rlim_cur =
+		    vdp->p_limit.pl_rlimit[i].rlim_cur;
+		np->p_limit->pl_rlimit[i].rlim_max =
+		    vdp->p_limit.pl_rlimit[i].rlim_max;
+	}
+
+	/* --- */
+	np->p_cpulimit = vdp->p_cpulimit;
+
+	knlist_init(&np->p_klist, &np->p_mtx, NULL, NULL, NULL, NULL);
+	STAILQ_INIT(&np->p_ktr);
+	strlcpy(np->p_comm, vdp->p_comm, sizeof(np->p_comm));
+
+	np->p_flag = vdp->p_flag;
+	np->p_stops = vdp->p_stops;
+	np->p_oppid = vdp->p_oppid;
+	np->p_xstat = vdp->p_xstat;
+	np->p_sigparent = vdp->p_sigparent;
+	/* XXX */
+	np->p_stype = vdp->p_stype;
+	np->p_step = vdp->p_step;
+	np->p_args = NULL;
+
+	DBGR("%s: pid=%d p_flag=%08x p_oppid=%d\n",
+		__func__, np->p_pid, np->p_flag, np->p_oppid);
+
+	/* --> from proc_linkup() */
+	sigqueue_init(&np->p_sigqueue, np);
+	np->p_ksi = ksiginfo_alloc(1);
+	np->p_ksi->ksi_flags = KSI_EXT | KSI_INS;
+	LIST_INIT(&np->p_mqnotifier);
+	np->p_numthreads = 0;
+
+	/* ucred */
+	if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_UCRED)
+		vdo_next(ctx);//vps_restore_ucred(ctx, vps);
+	np->p_ucred = vps_restore_ucred_lookup(ctx, vps, vdp->p_ucred);
+	KASSERT(np->p_ucred != NULL,
+	    ("%s: np->p_ucred == NULL\n", __func__));
+	(void)chgproccnt(np->p_ucred->cr_ruidinfo, 1, 0);
+	curthread->td_ucred = np->p_ucred;
+	prison_proc_hold(np->p_ucred->cr_prison);
+
+	/* sysentvec */
+	if ((error = vps_restore_sysentvec(ctx, vps, np)))
+		goto out;
+
+	/* ktrace */
+	if (vdp->p_have_tracevp) {
+		if ((error = vps_restore_pathtovnode(ctx, vps,
+		    &np->p_tracevp)))
+			goto out;
+		/*
+		DBGR("%s: p_tracevp: path [%s] got vnode %p\n",
+			__func__, o2->data, np->p_tracevp);
+		*/
+
+		/* XXX - could be different than p->p_ucred */
+		if (vdp->p_tracecred != NULL)
+			np->p_tracecred = crhold(np->p_ucred);
+
+		np->p_traceflag = vdp->p_traceflag;
+	}
+
+	callout_init(&np->p_itcallout, CALLOUT_MPSAFE);
+
+	/* textvp */
+	if (vdp->p_have_textvp) {
+		if ((error = vps_restore_pathtovnode(ctx, vps,
+		    &np->p_textvp)))
+			goto out;
+		DBGR("%s: p_textvp: path [...] got vnode %p\n",
+			__func__, np->p_textvp);
+	}
+
+	/* vmspace */
+	if ((error = vps_restore_vmspace(ctx, vps, np, vdp->p_vmspace)))
+		goto out;
+
+	TAILQ_INIT(&np->p_threads);
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_THREAD) {
+		if ((error = vps_restore_thread(ctx, vps, np)))
+			goto out;
+		vps_account(vps, VPS_ACC_THREADS, VPS_ACC_ALLOC, 1);
+		/* Next. */
+		;
+	}
+	/* XXX lookup by id */
+	/*
+	if (vdp->p_xthread_id != 0)
+		np->p_xthread = FIRST_THREAD_IN_PROC(np);
+	*/
+
+	vps_account(vps, VPS_ACC_PROCS, VPS_ACC_ALLOC, 1);
+
+	if ((error = vps_restore_fdset(ctx, vps, np, vdp->p_fd)))
+		goto out;
+
+	while (vdo_nextischild(ctx, o1)) {
+
+		switch (vdo_typeofnext(ctx)) {
+		case VPS_DUMPOBJT_PARGS:
+			if ((error = vps_restore_pargs(ctx, vps, np)))
+				goto out;
+			break;
+		case VPS_DUMPOBJT_SYSVSEM_PROC:
+			if (vps_func->sem_restore_proc && (error =
+			    vps_func->sem_restore_proc(ctx, vps, np)))
+				goto out;
+			break;
+		case VPS_DUMPOBJT_SYSVSHM_PROC:
+			if (vps_func->shm_restore_proc && (error =
+			    vps_func->shm_restore_proc(ctx, vps, np)))
+				goto out;
+			break;
+		case VPS_DUMPOBJT_SYSVMSG_PROC:
+			if (vps_func->msg_restore_proc && (error =
+			    vps_func->msg_restore_proc(ctx, vps, np)))
+				goto out;
+			break;
+		default:
+			DBGR("%s: unknown type=%d\n",
+			    __func__, vdo_typeofnext(ctx));
+			break;
+		}
+
+	}
+
+	/* proc tree */
+	save_vps = curthread->td_vps;
+	curthread->td_vps = vps;
+
+	sx_xlock(&VPS_VPS(vps, allproc_lock));
+	sx_xlock(&VPS_VPS(vps, proctree_lock));
+
+	LIST_INSERT_HEAD(&VPS_VPS(vps, allproc), np, p_list);
+	LIST_INSERT_HEAD(&VPS_VPS(vps, pidhashtbl)[(np->p_pid) &
+		VPS_VPS(vps, pidhash)], np, p_hash);
+	VPS_VPS(vps, nprocs)++;
+
+	/* These are ids rather than pointers. */
+	np->p_pptr = (struct proc *)((size_t)vdp->p_pptr_id);
+	np->p_peers = (struct proc *)((size_t)vdp->p_peers_id);
+	np->p_leader = (struct proc *)((size_t)vdp->p_leader_id);
+	np->p_pgrp = (struct pgrp *)((size_t)vdp->p_pgrp_id);
+
+	sx_xunlock(&VPS_VPS(vps, proctree_lock));
+	sx_xunlock(&VPS_VPS(vps, allproc_lock));
+
+	if (TAILQ_EMPTY(&np->p_threads)) {
+		ERRMSG(ctx, "%s: process has no threads !\n", __func__);
+		error = 0;
+		goto out;
+	}
+	np->p_state = vdp->p_state;
+
+	/* Add the extra lock that was set in vps_suspend(). */
+	np->p_lock++;
+
+	PROC_LOCK(np);
+	FOREACH_THREAD_IN_PROC(np, ntd) {
+
+		/* Sets scheduler lock and cpuset, besides some
+		   other stuff. */
+		thread_lock(curthread);
+		sched_fork_thread(curthread, ntd);
+		thread_unlock(curthread);
+		np->p_suspcount++;
+		TD_SET_SUSPENDED(ntd);
+	}
+
+	PROC_UNLOCK(np);
+
+	/* Enable ktrace for debugging. */
+	if (debug_restore_ktrace) {
+		int error1, flags;
+		struct vnode *vp;
+
+		NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE,
+			"/tmp/ktrace-all.out", curthread);
+		flags = FREAD | FWRITE | O_NOFOLLOW;
+		error1 = vn_open(&nd, &flags, 0, NULL);
+		if (error1 == 0) {
+			NDFREE(&nd, NDF_ONLY_PNBUF);
+			vp = nd.ni_vp;
+			VOP_UNLOCK(vp, 0);
+			/* ktrops() unlocks proc */
+			PROC_LOCK(np);
+			curthread->td_pflags |= TDP_INKTRACE;
+			ktrops(curthread, np, KTROP_SET,
+			    0xffffffff & ~KTRFAC_CSW, vp);
+			curthread->td_pflags &= ~TDP_INKTRACE;
+			(void)vn_close(vp, FWRITE, curthread->td_ucred,
+			    curthread);
+		} else
+			ERRMSG(ctx, "%s: ktrace / vn_open error: %d\n",
+				__func__, error1);
+	}
+
+ out:
+	curthread->td_ucred = save_ucred;
+
+	if (error)
+		ERRMSG(ctx, "%s: error = %d\n", __func__, error);
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_proc_session(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_session *vdsess;
+	struct vps_dump_filepath *vdfp;
+	struct session *nsess;
+	struct vps_restore_obj *ro;
+	struct nameidata nd;
+	int error = 0;
+
+	o1 = vdo_next(ctx);
+
+	vdsess = (struct vps_dump_session *)o1->data;
+	nsess = malloc(sizeof(*nsess), M_SESSION, M_WAITOK | M_ZERO);
+	mtx_init(&nsess->s_mtx, "session", NULL, MTX_DEF | MTX_DUPOK);
+	nsess->s_count = vdsess->s_count;
+	/* This is a pid, fixup later. */
+	nsess->s_ttyvp = NULL;
+	nsess->s_ttyp = NULL;
+	nsess->s_sid = vdsess->s_sid;
+	memcpy(nsess->s_login, vdsess->s_login, sizeof(nsess->s_login));
+
+	if (vdsess->s_have_ttyvp && vdo_typeofnext(ctx) ==
+	    VPS_DUMPOBJT_FILE_PATH) {
+
+		o1 = vdo_next(ctx);
+		vdfp = (struct vps_dump_filepath *)o1->data;
+		if ((strncmp(vdfp->fp_path, "/dev/pts/", 9)) == 0) {
+			struct posix_openpt_args args;
+			int unit;
+
+			args.flags = O_RDWR;
+			if ((sscanf(vdfp->fp_path, "/dev/pts/%d", &unit))
+			    != 1) {
+				ERRMSG(ctx, "%s: unable to find unit "
+				    "number in pts name [%s]\n",
+				    __func__, vdfp->fp_path);
+				error = EINVAL;
+				goto out;
+			}
+			DBGR("%s: pts unit number=%d\n", __func__, unit);
+			if ((error = sys_posix_openpt_unit(curthread, &args,
+					unit))) {
+				ERRMSG(ctx, "%s: sys_posix_openpt_unit() "
+					"error: %d\n", __func__, error);
+				goto out;
+			}
+			/* is used later in vps_restore_fdset */
+		}
+		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF,
+		    UIO_SYSSPACE, vdfp->fp_path, curthread);
+		if ((error = namei(&nd))) {
+			ERRMSG(ctx, "%s: namei([%s]): error = %d\n",
+			    __func__, vdfp->fp_path, error);
+			goto out;
+		}
+		/* XXX VREF() ?! */
+		nsess->s_ttyvp = nd.ni_vp;
+		VOP_UNLOCK(nd.ni_vp, 0);
+		NDFREE(&nd, NDF_ONLY_PNBUF);
+		DBGR("%s: path [%s] got vnode %p\n",
+		    __func__, vdfp->fp_path, nd.ni_vp);
+
+		if ( ! (nsess->s_ttyvp->v_type == VCHR &&
+		    nsess->s_ttyvp->v_rdev)) {
+			DBGR("%s: not a device !\n", __func__);
+			error = EINVAL;
+			goto out;
+		}
+
+		nsess->s_ttyp = nsess->s_ttyvp->v_rdev->si_drv1;
+
+	}
+
+	ro = malloc(sizeof(*ro), M_VPS_RESTORE, M_WAITOK | M_ZERO);
+
+	ro->type = VPS_DUMPOBJT_SESSION;
+	ro->new_ptr = nsess;
+	ro->orig_id = nsess->s_sid;
+	ro->spare[0] = (void *)(size_t)vdsess->s_leader_id;
+
+	SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+
+	DBGR("%s: restored session %p/%d ttyvp=%p ttyp=%p\n",
+	    __func__, nsess, nsess->s_sid,
+	    nsess->s_ttyvp, nsess->s_ttyp);
+
+  out:
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_proc(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_pgrp *vdpg;
+	struct pgrp *npg, *pg;
+	struct session *nsess;
+	struct proc *p;
+	struct vps_restore_obj *ro, *ro1;
+	struct vps *save_vps;
+	struct ucred *save_ucred;
+	struct vnode *saverootvnode;
+	struct tty *ttyp;
+	int found;
+	int error = 0;
+
+	/* XXX See comment in vps_restore_mounts(). */
+	save_vps = curthread->td_vps;
+	save_ucred = curthread->td_ucred;
+
+	curthread->td_vps = vps;
+	curthread->td_ucred = ctx->vps_ucred;
+
+	/*
+	 * Temporarily change our root directory to the one of the vps
+	 * instance to be restored.
+	 * Makes namei() lookups much easier.
+	 */
+	FILEDESC_XLOCK(curthread->td_proc->p_fd);
+	VREF(vps->_rootvnode);
+	saverootvnode = curthread->td_proc->p_fd->fd_rdir;
+	curthread->td_proc->p_fd->fd_rdir = vps->_rootvnode;
+	FILEDESC_XUNLOCK(curthread->td_proc->p_fd);
+
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_PGRP) {
+
+		o1 = vdo_next(ctx);
+
+		ro = malloc(sizeof(*ro), M_VPS_RESTORE, M_WAITOK | M_ZERO);
+
+		vdpg = (struct vps_dump_pgrp *)o1->data;
+		npg = malloc(sizeof(*npg), M_PGRP, M_WAITOK | M_ZERO);
+		mtx_init(&npg->pg_mtx, "process group", NULL,
+		    MTX_DEF | MTX_DUPOK);
+		LIST_INIT(&npg->pg_members);
+		npg->pg_id = vdpg->pg_id;
+		npg->pg_jobc = vdpg->pg_jobc;
+		/* This is the session id, fixup later. */
+		npg->pg_session = NULL;
+		/* XXX Restore this stuff too. */
+		SLIST_INIT(&npg->pg_sigiolst);
+
+		ro->type = VPS_DUMPOBJT_PGRP;
+		ro->new_ptr = npg;
+		ro->orig_id = npg->pg_id;
+		ro->spare[0] = (void *)(size_t)vdpg->pg_session_id;
+
+		SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+
+		DBGR("%s: restored pgrp %p/%d\n",
+		    __func__, npg, npg->pg_id);
+
+		if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_SESSION) {
+			error = vps_restore_proc_session(ctx, vps);
+			if (error != 0)
+				goto out;
+
+		}
+
+		//next:
+		/* Next. */
+		;
+	}
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_PROC) {
+
+		if ((error = vps_restore_proc_one(ctx, vps)))
+			goto out;
+
+		/* Next. */
+		;
+	}
+
+	/* Now fixup stuff like the proc tree. */
+	curthread->td_vps = vps;
+
+	/* Fix up sessions. */
+	SLIST_FOREACH(ro, &ctx->obj_list, list)
+		if (ro->type == VPS_DUMPOBJT_SESSION) {
+			nsess = (struct session *)ro->new_ptr;
+			if ((nsess->s_leader = pfind((size_t)ro->spare[0])))
+				PROC_UNLOCK(nsess->s_leader);
+			DBGR("%s: fixed up session=%p s_leader=%p/%d\n",
+			    __func__, nsess, nsess->s_leader,
+			    nsess->s_leader ? nsess->s_leader->p_pid : -1);
+			/* XXX check if every pointer is fixed up now. */
+		}
+
+	/* For every pgrp, lookup session. */
+	SLIST_FOREACH(ro, &ctx->obj_list, list)
+		if (ro->type == VPS_DUMPOBJT_PGRP) {
+			pg = ro->new_ptr;
+			found = 0;
+			SLIST_FOREACH(ro1, &ctx->obj_list, list)
+				if (ro1->type == VPS_DUMPOBJT_SESSION &&
+				    ro1->orig_id == (size_t)ro->spare[0]) {
+					DBGR("%s: found session %p/%d for "
+					    "pgrp %p/%d\n", __func__,
+					    ro1->new_ptr, ro1->orig_id,
+					    pg, pg->pg_id);
+					pg->pg_session = ro1->new_ptr;
+					found = 1;
+					/* XXX check if every pointer is
+					   fixed up now. */
+				}
+			KASSERT(found == 1, ("%s: no session found for "
+			    "pgrp=%p/%d\n", __func__, pg, pg->pg_id));
+			LIST_INSERT_HEAD(&VPS_VPS(vps, pgrphashtbl)
+			    [pg->pg_id & VPS_VPS(vps, pgrphash)],
+			    pg, pg_hash);
+			DBGR("%s: inserted pgrp %p/%d\n",
+			    __func__, pg, pg->pg_id);
+		}
+
+	/* Fix up ttys. */
+	sx_slock(&VPS_VPS(vps, proctree_lock));
+	SLIST_FOREACH(ro, &ctx->obj_list, list) {
+		struct tty *tp;
+		if (ro->type != VPS_DUMPOBJT_PTS)
+			continue;
+		tp = ro->new_ptr;
+		DBGR("%s: tp=%p tp->t_pgrp = %zu\n",
+		    __func__, tp, (intptr_t)tp->t_pgrp);
+		tp->t_pgrp = pgfind((intptr_t)tp->t_pgrp);
+		if (tp->t_pgrp)
+			PGRP_UNLOCK(tp->t_pgrp);
+		DBGR("%s: tp=%p tp->t_pgrp = %p\n",
+		    __func__, tp, tp->t_pgrp);
+	}
+	sx_sunlock(&VPS_VPS(vps, proctree_lock));
+
+	/* Fix up unix domain sockets. */
+	if ((error = vps_restore_fixup_unixsockets(ctx, vps)))
+		goto out;
+
+	/* Traverse V_allproc, lookup pgrp for each one. */
+	sx_xlock(&VPS_VPS(vps, proctree_lock));
+	LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list) {
+		if ((pg = pgfind((intptr_t) p->p_pgrp)))
+			PGRP_UNLOCK(pg);
+		DBGR("%s: pgfind: pg=%p/%zu\n",
+		    __func__, pg, (intptr_t)p->p_pgrp);
+		/* XXX check NULL */
+		//PROC_LOCK(p);
+		p->p_pgrp = pg;
+		LIST_INSERT_HEAD(&pg->pg_members, p, p_pglist);
+		/* XXX not needed fixjobc(p, p->p_pgrp, 1); */
+		if ((p->p_peers = pfind((intptr_t)p->p_peers)))
+			PROC_UNLOCK(p->p_peers);
+		if ((p->p_leader = pfind((intptr_t)p->p_leader)))
+			PROC_UNLOCK (p->p_leader);
+		if ((p->p_pptr = pfind((intptr_t)p->p_pptr)))
+			PROC_UNLOCK(p->p_pptr);
+		if (p->p_pptr)
+			LIST_INSERT_HEAD(&p->p_pptr->p_children, p,
+			    p_sibling);
+		if (p->p_pgrp->pg_session && SESS_LEADER(p) &&
+		    p->p_session->s_ttyp) {
+			ttyp = p->p_session->s_ttyp;
+			tty_lock(ttyp);
+			ttyp->t_session = p->p_session;
+			ttyp->t_sessioncnt++;
+			//ttyp->t_pgrp = p->p_pgrp;
+			tty_unlock(ttyp);
+			DBGR("%s: set controlling session %p for ttyp %p\n",
+			    __func__, p->p_session, p->p_session->s_ttyp);
+		}
+		//PROC_UNLOCK(p);
+		DBGR("%s: fixed up proc=%p/%d p->p_pgrp=%p p->p_session=%p "
+			"p->p_pptr=%p p->p_stype=%08x\n",
+			__func__, p, p->p_pid, p->p_pgrp,
+			p->p_session, p->p_pptr, p->p_stype);
+	}
+
+	if ((VPS_VPS(vps, initpgrp) = pgfind((intptr_t)VPS_VPS(vps,
+	    initpgrp))))
+		PGRP_UNLOCK(VPS_VPS(vps, initpgrp));
+	/* XXX pfind() locks allproc_lock again ! */
+	if ((VPS_VPS(vps, initproc) = pfind((intptr_t)VPS_VPS(vps,
+	    initproc))))
+		PROC_UNLOCK(VPS_VPS(vps, initproc));
+
+	DBGR("%s: V_initpgrp=%p V_initproc=%p\n",
+	    __func__, VPS_VPS(vps, initpgrp), VPS_VPS(vps, initproc));
+
+	/* debug */
+	if (1) {
+		if (PTRTO64(VPS_VPS(vps, initpgrp)) < 0x1000 ||
+		    PTRTO64(VPS_VPS(vps, initproc)) < 0x1000) {
+			ERRMSG(ctx, "%s: STOP\n", __func__);
+			return (EINVAL);
+		}
+	}
+
+	sx_xunlock(&VPS_VPS(vps, proctree_lock));
+
+ out:
+	FILEDESC_XLOCK(curthread->td_proc->p_fd);
+	curthread->td_proc->p_fd->fd_rdir = saverootvnode;
+	vrele(vps->_rootvnode);
+	FILEDESC_XUNLOCK(curthread->td_proc->p_fd);
+
+	curthread->td_vps = save_vps;
+	curthread->td_ucred = save_ucred;
+
+	if (error)
+		ERRMSG(ctx, "%s: error = %d\n", __func__, error);
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_arg(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_arg *vda;
+	struct vps_dump_arg_ip4 *vda4;
+	struct vps_dump_arg_ip6 *vda6;
+	struct vps_dump_accounting *vdacc;
+	size_t privsetsize_round;
+	caddr_t cpos;
+	int len;
+	int i;
+
+	o1 = vdo_next(ctx);
+
+	if (o1->type != VPS_DUMPOBJT_ARG) {
+		DBGR("%s: VPS_DUMPOBJT_ARG missing !\n", __func__);
+		return (-1);
+	}
+
+	vda = (struct vps_dump_arg *)o1->data;
+	cpos = o1->data + sizeof(*vda);
+
+	if (vda->privset_size != PRIV_SET_SIZE) {
+		ERRMSG(ctx, "%s: vda->privset_size (%d) != "
+		    "PRIV_SET_SIZE (%d)\n",
+		    __func__, vda->privset_size, PRIV_SET_SIZE);
+		return (EINVAL);
+	}
+
+	/*
+	 * XXX We must check here if the current vps is allowed
+	 *     the privs and networks etc. that we are about to restore.
+	 *     (In case of nested vps instances.)
+	 */
+	privsetsize_round = roundup(vda->privset_size, 8);
+	len = vda->privset_size > PRIV_SET_SIZE ? PRIV_SET_SIZE :
+	    vda->privset_size;
+
+	memcpy(vps->priv_allow_set, cpos, len);
+	cpos += privsetsize_round;
+
+	memcpy(vps->priv_impl_set, cpos, len);
+	cpos += privsetsize_round;
+
+	if (vda->ip4net_cnt > 0) {
+
+		len = sizeof(struct vps_arg_ip4) * vda->ip4net_cnt;
+		vps->vps_ip4 = malloc(len, M_VPS_CORE, M_WAITOK);
+
+		for (i = 0; i < vda->ip4net_cnt; i++) {
+			vda4 = (struct vps_dump_arg_ip4 *)cpos;
+			memcpy(&vps->vps_ip4[i].addr, vda4->a4_addr, 0x4);
+			memcpy(&vps->vps_ip4[i].mask, vda4->a4_mask, 0x4);
+			cpos = (caddr_t)(vda4 + 1);
+		}
+
+		vps->vps_ip4_cnt = vda->ip4net_cnt;
+	}
+
+	if (vda->ip6net_cnt > 0) {
+
+		len = sizeof(struct vps_arg_ip6) * vda->ip6net_cnt;
+		vps->vps_ip6 = malloc(len, M_VPS_CORE, M_WAITOK);
+
+		for (i = 0; i < vda->ip6net_cnt; i++) {
+			vda6 = (struct vps_dump_arg_ip6 *)cpos;
+			memcpy(&vps->vps_ip6[i].addr, vda6->a6_addr, 0x10);
+			vps->vps_ip6[i].plen = vda6->a6_plen;
+			cpos = (caddr_t)(vda6 + 1);
+		}
+
+		vps->vps_ip6_cnt = vda->ip6net_cnt;
+	}
+
+
+	if (vda->have_accounting) {
+
+		vdacc = (struct vps_dump_accounting *)cpos;
+
+#define FILL_ACCVAL(x)  					\
+        vps->vps_acc->x.soft = vdacc->x.soft;			\
+        vps->vps_acc->x.hard = vdacc->x.hard;			\
+        vps->vps_acc->x.hits_soft = vdacc->x.hits_soft;		\
+        vps->vps_acc->x.hits_hard = vdacc->x.hits_hard
+
+		FILL_ACCVAL(virt);
+		FILL_ACCVAL(phys);
+		FILL_ACCVAL(kmem);
+		FILL_ACCVAL(kernel);
+		FILL_ACCVAL(buffer);
+		FILL_ACCVAL(pctcpu);
+		FILL_ACCVAL(blockio);
+		FILL_ACCVAL(threads);
+		FILL_ACCVAL(procs);
+
+#undef FILL_ACCVAL
+	}
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_mounts(struct vps_snapst_ctx *ctx, struct vps *vps,
+    char *rootfspath)
+{
+	struct vps_dump_mount *dvm;
+	struct vps_dumpobj *o1;
+	struct vps *savevps;
+	struct ucred *saveucred, *ncr;
+	struct vnode *save_rdir, *save_cdir;
+	struct mntarg *ma;
+	int errmsg_len;
+	char *fspath;
+	char *errmsg;
+	int error = 0;
+
+	ncr = NULL;
+
+	if (vps != NULL) {
+		savevps = curthread->td_vps;
+		saveucred = curthread->td_ucred;
+		save_rdir = curthread->td_proc->p_fd->fd_rdir;
+		save_cdir = curthread->td_proc->p_fd->fd_cdir;
+	} else {
+		savevps = NULL;
+		saveucred = NULL;
+		save_rdir = save_cdir = NULL;
+	}
+
+	errmsg_len = 0x100;
+	errmsg = malloc(errmsg_len, M_TEMP, M_WAITOK);
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_MOUNT) {
+
+		o1 = vdo_next(ctx);
+
+		dvm = (struct vps_dump_mount *)o1->data;
+
+		ncr = NULL;
+
+		/* Only do root fs mount now. */
+		if (vps == NULL && strcmp(dvm->mnton, rootfspath))
+			goto next;
+
+		/* Do all mounts now except root fs. */
+		if (vps != NULL && !strcmp(dvm->mnton, rootfspath))
+			goto next;
+
+		if (vdo_typeofnext(ctx) == VPS_DUMPOBJT_UCRED) {
+			vdo_next(ctx);//vps_restore_ucred(ctx, vps);
+		}
+
+		DBGR("dvm=%p mntfrom=[%s] mnton=[%s] fstype=[%s] flags=%zx "
+		    "vpsmount=%d\n", dvm, dvm->mntfrom, dvm->mnton,
+		    dvm->fstype, (size_t)dvm->flags, dvm->vpsmount);
+
+		if (vps != NULL && dvm->vpsmount) {
+			curthread->td_vps = vps;
+			curthread->td_proc->p_fd->fd_rdir = vps->_rootvnode;
+			curthread->td_proc->p_fd->fd_cdir = vps->_rootvnode;
+
+			/* Note that ucred gets duplicated in
+			   vfs_mount_alloc(). */
+
+			if (dvm->mnt_cred != NULL) {
+				ncr = vps_restore_ucred_lookup(ctx, vps,
+				    dvm->mnt_cred);
+				if (ncr == NULL) {
+					ERRMSG(ctx, "%s: ucred not found "
+					    "!\n", __func__);
+					error = EINVAL;
+					goto out;
+				}
+				curthread->td_ucred = ncr;
+			}
+		}
+
+		if (dvm->vpsmount)
+			/* dvm->mnton is always absolute, so we have to
+			   strip it. */
+			fspath = dvm->mnton + strlen (rootfspath);
+		else
+			fspath = dvm->mnton;
+
+#if 0
+		error = kernel_vmount(
+			dvm->flags,
+			"fstype", dvm->fstype,
+			/* "fspath", dvm->mnton, */
+			"fspath", fspath,
+			/* --> nullfs */
+			"target", dvm->mntfrom,
+			"from", dvm->mntfrom,
+			"errmsg", errmsg,
+			NULL
+		);
+#endif
+		ma = NULL;
+		ma = mount_arg(ma, "fstype", dvm->fstype, -1);
+		ma = mount_arg(ma, "fspath", fspath, -1);
+		if (!strcmp(dvm->fstype, "nullfs") ||
+		    !strcmp(dvm->fstype, "vpsfs"))
+			ma = mount_arg(ma, "target", dvm->mntfrom, -1);
+		ma = mount_arg(ma, "from", dvm->mntfrom, -1);
+		ma = mount_arg(ma, "errmsg", errmsg, errmsg_len);
+		memset(errmsg, 0, errmsg_len);
+		error = kernel_mount(ma, dvm->flags);
+
+		if (error) {
+			ERRMSG(ctx, "%s: kernel_mount() error: %d [%s]\n",
+				__func__, error, errmsg);
+			goto out;
+		}
+
+		if (vps != NULL && dvm->vpsmount) {
+			curthread->td_vps = savevps;
+			curthread->td_ucred = saveucred;
+			curthread->td_proc->p_fd->fd_rdir = save_rdir;
+			curthread->td_proc->p_fd->fd_cdir = save_cdir;
+
+			if (ncr != NULL)
+				crfree(ncr);
+		}
+
+		next:
+		/* Next. */
+		;
+	}
+
+ out:
+	free(errmsg, M_TEMP);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static void
+vps_restore_prison_fixup(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_restore_obj *obj1;
+	struct prison *pr;
+
+	SLIST_FOREACH(obj1, &ctx->obj_list, list) {
+		if (obj1->type != VPS_DUMPOBJT_PRISON)
+			continue;
+		pr = (struct prison *)obj1->new_ptr;
+
+		/* Clear the extra references that we had while
+		   restoring. */
+		prison_lock(pr);
+		pr->pr_ref--;
+		pr->pr_uref--;
+		prison_unlock(pr);
+	}
+}
+
+__attribute__((noinline))
+static struct prison *
+vps_restore_prison_lookup(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct prison *old_pr)
+{
+	struct vps_restore_obj *obj1;
+	struct prison *new_pr;
+
+	/*
+	if (old_pr == NULL)
+		return (VPS_VPS(vps, prison0));
+	*/
+
+	new_pr = NULL;
+	SLIST_FOREACH(obj1, &ctx->obj_list, list) {
+		if (obj1->type != VPS_DUMPOBJT_PRISON)
+			continue;
+		if (obj1->orig_ptr == old_pr) {
+			new_pr = obj1->new_ptr;
+			DBGR("%s: found new prison ptr: orig=%p new=%p\n",
+				__func__, obj1->orig_ptr, obj1->new_ptr);
+			break;
+		}
+	}
+	KASSERT(new_pr != NULL,
+		("%s: old_pr=%p new_pr==NULL\n", __func__, old_pr));
+
+	return (new_pr);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_prison_one(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct prison *npr, *ppr, *tpr;
+	struct vps_dumpobj *o1;
+	struct vps_dump_prison *vdpr;
+	struct vps_restore_obj *ro;
+	caddr_t cpos;
+	int error = 0;
+	int i;
+
+	o1 = vdo_next(ctx);
+
+	KASSERT(o1->type == VPS_DUMPOBJT_PRISON,
+		("%s: o1=%p o1->type = %d\n", __func__, o1, o1->type));
+
+	vdpr = (struct vps_dump_prison *)o1->data;
+
+	DBGR("%s: orig_ptr=%p id=%d name=[%s]\n",
+		__func__, vdpr->pr_origptr, vdpr->pr_id, vdpr->pr_name);
+
+	if (vdpr->pr_parent != NULL) {
+
+		npr = malloc(sizeof(*npr), M_PRISON, M_WAITOK|M_ZERO);
+		LIST_INIT(&npr->pr_children);
+		mtx_init(&npr->pr_mtx, "jail mutex", NULL,
+		    MTX_DEF | MTX_DUPOK);
+		npr->pr_id = vdpr->pr_id;
+		strlcpy(npr->pr_name, vdpr->pr_name, sizeof(npr->pr_name));
+		/*
+		 * We copy this from dumped one, but root vnode must be
+		 * restored from old vnode, since the path might have
+		 * been moved !
+		 */
+		strlcpy(npr->pr_path, vdpr->pr_path, sizeof(vdpr->pr_path));
+
+		if ((error = vps_restore_pathtovnode(ctx, vps,
+		    &npr->pr_root)))
+			return (error);
+
+		npr->pr_parent = vps_restore_prison_lookup(ctx, vps,
+		    vdpr->pr_parent);
+		ppr = npr->pr_parent;
+
+		ppr->pr_ref++;
+		ppr->pr_uref++;
+
+		if (vdpr->pr_flags & PR_PERSIST) {
+			npr->pr_flags |= PR_PERSIST;
+			npr->pr_ref++;
+			npr->pr_uref++;
+		}
+
+		/* We free them after processes are attached. */
+		npr->pr_ref++;
+		npr->pr_uref++;
+
+		/* XXX */
+		cpuset_create_root(ppr, &npr->pr_cpuset);
+
+		/* XXX */
+		npr->pr_flags = vdpr->pr_flags;
+
+		/* XXX check against parent's values */
+		npr->pr_securelevel = vdpr->pr_securelevel;
+		npr->pr_childmax = vdpr->pr_childmax;
+
+		/*
+		npr->pr_allow = dpr->pr_allow;
+		npr->pr_enforce_statfs = dpr->pr_enforce_statfs;
+		*/
+		npr->pr_allow = vdpr->pr_allow;
+		npr->pr_enforce_statfs = vdpr->pr_enforce_statfs;
+
+		npr->pr_ip4s = vdpr->pr_ip4s;
+		npr->pr_ip6s = vdpr->pr_ip6s;
+
+		npr->pr_ip4 = malloc(sizeof(npr->pr_ip4[0]) * npr->pr_ip4s,
+				M_PRISON, M_WAITOK);
+		npr->pr_ip6 = malloc(sizeof(npr->pr_ip6[0]) * npr->pr_ip6s,
+				M_PRISON, M_WAITOK);
+
+		cpos = vdpr->pr_ipdata;
+
+		/*
+		vps_print_ascii(vdpr->pr_ipdata,
+		    roundup(vdpr->pr_ip4s * 0x4, 8) +
+		    vdpr->pr_ip6s * 0x10);
+		*/
+
+		for (i = 0; i < vdpr->pr_ip4s; i++) {
+			memcpy(&npr->pr_ip4[i], cpos, 0x4);
+			cpos += 0x4;
+		}
+		cpos = (caddr_t)roundup((size_t)cpos, 8);
+
+		for (i = 0; i < vdpr->pr_ip6s; i++) {
+			memcpy(&npr->pr_ip6[i], cpos, 0x10);
+			cpos += 0x10;
+		}
+
+		if (vdpr->pr_flags & PR_VNET) {
+			npr->pr_flags |= PR_VNET;
+			if ((error = vps_restore_vnet(ctx, vps,
+			    &npr->pr_vnet))) {
+				ERRMSG(ctx, "%s: vps_restore_vnet(): %d\n",
+					__func__, error);
+				return (error);
+			}
+			DBGR("%s: PR_VNET: npr->pr_vnet = %p\n",
+				__func__, npr->pr_vnet);
+		} else {
+			npr->pr_vnet = ppr->pr_vnet;
+			DBGR("%s: inherit vnet: npr->pr_vnet = %p\n",
+				__func__, npr->pr_vnet);
+		}
+
+		TAILQ_FOREACH(tpr, &VPS_VPS(vps, allprison), pr_list)
+			if (tpr->pr_id >= npr->pr_id) {
+				TAILQ_INSERT_BEFORE(tpr, npr, pr_list);
+				break;
+			}
+		if (tpr == NULL)
+			TAILQ_INSERT_TAIL(&VPS_VPS(vps, allprison), npr,
+			    pr_list);
+		LIST_INSERT_HEAD(&ppr->pr_children, npr, pr_sibling);
+			for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent)
+				tpr->pr_childcount++;
+
+	} else {
+		/* this is dumped prison0 */
+
+		npr = VPS_VPS(vps, prison0);
+
+		/* Skip over filepath object. */
+		vdo_next(ctx);
+	}
+
+	ro = malloc(sizeof(*ro), M_VPS_RESTORE, M_WAITOK|M_ZERO);
+	ro->type = VPS_DUMPOBJT_PRISON;
+	ro->orig_ptr = vdpr->pr_origptr;
+	ro->new_ptr = npr;
+
+	SLIST_INSERT_HEAD(&ctx->obj_list, ro, list);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_restore_prison(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	int error = 0;
+
+	while (vdo_typeofnext(ctx) == VPS_DUMPOBJT_PRISON) {
+
+		if ((error = vps_restore_prison_one(ctx, vps)))
+			goto out;
+
+	}
+
+ out:
+	return (error);
+}
+
+/*
+ * Restore vps instance.
+ */
+
+__attribute__((noinline))
+static int
+vps_restore_vps(struct vps_snapst_ctx *ctx, const char *vps_name,
+    struct vps **vps_in)
+{
+	struct vps_param vps_pr;
+	struct vps_dumpobj *o1;
+	struct vps_dump_vps *vdi;
+	struct vps *vps;
+	int nexttype;
+	int error = 0;
+
+	memset(&vps_pr, 0, sizeof(vps_pr));
+
+	*vps_in = NULL;
+
+	o1 = vdo_next(ctx);
+	if (o1->type != VPS_DUMPOBJT_VPS) {
+		ERRMSG(ctx, "%s: wrong object type: %p type=%d\n",
+			__func__, o1, o1->type);
+		error = EINVAL;
+		goto out;
+	}
+	vdi = (struct vps_dump_vps *)o1->data;
+
+	// XXX dvps->vps_name check string termination
+	// XXX dvps->_rootpath check string termination
+
+	/* Name */
+	if (vps_name[0])
+		strlcpy(vps_pr.name, vps_name, sizeof(vps_pr.name));
+	else
+		strlcpy(vps_pr.name, vdi->vps_name, sizeof(vps_pr.name));
+
+	/* Filesystem root */
+	strlcpy(vps_pr.fsroot, vdi->rootpath, sizeof(vps_pr.fsroot));
+
+	/* Restore vfs root mount. */
+	if ((error = vps_restore_mounts(ctx, NULL, vps_pr.fsroot))) {
+		goto out;
+	}
+
+	/*
+	 * Actually allocating a vps.
+	 *
+	 * XXX Doing this first and then mounting the root filesystem
+	 *     would make things much easier.
+	 */
+	if ((vps = vps_alloc(curthread->td_vps, &vps_pr, vps_pr.name,
+	    &error)) == NULL) {
+		goto out;
+	}
+	*vps_in = vps;
+
+	vps->vps_status = VPS_ST_SUSPENDED;
+
+	/*
+	 * Get a generic ucred we can use for various vps system things.
+	 */
+	ctx->vps_ucred = crdup(curthread->td_ucred);
+	vps_deref(ctx->vps_ucred->cr_vps, ctx->vps_ucred);
+	ctx->vps_ucred->cr_vps = vps;
+	vps_ref(ctx->vps_ucred->cr_vps, ctx->vps_ucred);
+	prison_free(ctx->vps_ucred->cr_prison);
+	ctx->vps_ucred->cr_prison = VPS_VPS(vps, prison0);
+	prison_hold(ctx->vps_ucred->cr_prison);
+	DBGR("%s: ctx->vps_ucred = %p\n", __func__, ctx->vps_ucred);
+	//ctx->vps_ucred = (struct ucred *)0xc0debabe0000;
+
+	/* Restore all ucreds at once. */
+	if ((error = vps_restore_ucred_all(ctx, vps))) {
+		goto out;
+	}
+
+	/* Restore all the remaining vfs mounts. */
+	ctx->curobj = o1;
+	if ((error = vps_restore_mounts(ctx, vps, vps_pr.fsroot))) {
+		goto out;
+	}
+
+	if ((error = vps_restore_arg(ctx, vps))) {
+		goto out;
+	}
+
+	/* Restore network related stuff. */
+	if ((error = vps_restore_vnet(ctx, vps, &vps->vnet))) {
+		goto out;
+	}
+
+	/* Restore prisons (jails). */
+	if ((error = vps_restore_prison(ctx, vps))) {
+		goto out;
+	}
+
+	/* Link prisons back into ucreds */
+	if ((error = vps_restore_ucred_fixup(ctx, vps))) {
+		goto out;
+	}
+
+	while ((nexttype = vdo_typeofnext(ctx)) != VPS_DUMPOBJT_PGRP) {
+		switch (nexttype) {
+		case VPS_DUMPOBJT_SYSVSEM_VPS:
+			if (vps_func->sem_restore_vps)
+				error = vps_func->sem_restore_vps(ctx, vps);
+			else
+				error = EOPNOTSUPP;
+			break;
+		case VPS_DUMPOBJT_SYSVSHM_VPS:
+			if (vps_func->shm_restore_vps)
+				error = vps_func->shm_restore_vps(ctx, vps);
+			else
+				error = EOPNOTSUPP;
+			break;
+		case VPS_DUMPOBJT_SYSVMSG_VPS:
+			if (vps_func->msg_restore_vps)
+				error = vps_func->msg_restore_vps(ctx, vps);
+			else
+				error = EOPNOTSUPP;
+			break;
+		default:
+			/* Just ignore and skip. */
+			vdo_next(ctx);
+			break;
+		}
+		if (error)
+			goto out;
+	}
+
+	VPS_VPS(vps, initproc) = (struct proc *)
+	    ((long)vdi->initproc_id); /* ID */
+	VPS_VPS(vps, initpgrp) = (struct pgrp *)
+	    ((long)vdi->initpgrp_id); /* ID */
+	strlcpy(VPS_VPS(vps, hostname), vdi->hostname,
+	    sizeof(VPS_VPS(vps, hostname)));
+
+	VPS_VPS(vps, boottimebin).sec = vdi->boottime.tv_sec;
+	VPS_VPS(vps, boottimebin).frac = 0;
+	VPS_VPS(vps, boottime).tv_sec = vdi->boottime.tv_sec;
+	VPS_VPS(vps, boottime).tv_usec = vdi->boottime.tv_usec;
+	VPS_VPS(vps, lastpid) = vdi->lastpid;
+
+	vps->restore_count = vdi->restore_count + 1;
+
+	/*
+	 * Restore processes.
+	 */
+	if ((error = vps_restore_proc(ctx, vps))) {
+		goto out;
+	}
+	VPS_VPS(vps, lastpid) = vdi->lastpid;
+
+	/*
+	 * Various fixup routines.
+	 */
+
+	vps_restore_prison_fixup(ctx, vps);
+
+	if (vps_func->sem_restore_fixup &&
+	    (error = vps_func->sem_restore_fixup(ctx, vps)))
+		goto out;
+
+	if (vps_func->shm_restore_fixup &&
+	    (error = vps_func->shm_restore_fixup(ctx, vps)))
+		goto out;
+
+	if (vps_func->msg_restore_fixup &&
+	    (error = vps_func->msg_restore_fixup(ctx, vps)))
+		goto out;
+
+ out:
+	return (error);
+}
+
+/*
+ * Go through the dump image and link every dump object into this list.
+ */
+
+#if 0
+__attribute__((noinline))
+static int
+vps_restore_fixup_objlist(struct vps_snapst_ctx *ctx,
+    struct vps_dumpheader *dumphdr, struct vps_dumpobj *o)
+{
+	int error = 0;
+	int cnt = 0;
+
+	DBGR("%s: \n", __func__);
+
+	SLIST_INIT(&vdi->dumpobj_list);
+	ctx->dumpobj_list = &vdi->dumpobj_list;
+
+	while ( ( ((caddr_t)o) + sizeof(*o) < ctx->data + ctx->dsize) &&
+			( ((caddr_t)o) > ctx->data) &&
+				o->type && o->size) {
+
+		/*
+		DBGR("%s: o=%p o->type=%d o->size=%d\n",
+		    __func__, o, o->type, o->size);
+		*/
+
+		SLIST_INSERT_HEAD(ctx->dumpobj_list, o, list);
+
+		++cnt;
+
+		/*
+		 * If the end-of-snapshot record is missing, the range check
+		 * breaks the loop.
+		 */
+		if (o->type == VPS_DUMPOBJT_END) {
+			/* Reached end of snapshot. */
+			break;
+		}
+
+		/* Next object. */
+		o = (struct vps_dumpobj *)(o->data + o->subsize);
+	}
+
+	DBGR("%s: got %d elements\n", __func__, cnt);
+
+	return (error);
+}
+#endif /* 0 */
+
+/*
+ * The user supplies an userspace address, where the snapshot
+ * dump is located.
+ * The first part of this dump contains the kernel memory parts,
+ * which will be copied or newly assembled anyway.
+ *
+ * The second (usually much larger) part is the userspace memory
+ * of the dumped processes. The pages will be moved into the
+ * new processes vmspaces without copying.
+ */
+
+__attribute__((noinline))
+static int
+vps_restore_copyin(struct vps_snapst_ctx *ctx, struct vps_arg_snapst *va)
+{
+	struct vps_dumpheader *dumphdr;
+	struct vps_dumpobj *o1;
+	vm_offset_t kvaddr;
+	u_int checksum1, checksum2;
+	vm_page_t m;
+	int npages;
+	int i;
+	int error = 0;
+
+	DBGR("%s: \n", __func__);
+
+	ctx->data = NULL;
+	ctx->vmobj = NULL;
+
+	/* Snapshot must be page-aligned! */
+	if ((void *)trunc_page((unsigned long)va->database) !=
+	    va->database) {
+		ERRMSG(ctx, "%s: dump must be page aligned but is not: "
+		    "%p\n", __func__, va->database);
+		error = EFAULT;
+		goto fail;
+	}
+
+	if (vm_page_count_min()) {
+		ERRMSG(ctx, "%s: low on memory: v_free_min=%u > "
+		    "(v_free_count=%u + v_cache_count=%u)\n",
+		    __func__, cnt.v_free_min, cnt.v_free_count,
+		    cnt.v_cache_count);
+		ERRMSG(ctx, "%s: cnt.v_inactive_count=%u\n",
+			__func__, cnt.v_inactive_count);
+		error = ENOMEM;
+		goto fail;
+	}
+	DBGR("%s: v_free_min=%u v_free_count=%u + v_cache_count=%u\n",
+	    __func__, cnt.v_free_min, cnt.v_free_count, cnt.v_cache_count);
+
+	ctx->data = malloc(4 << PAGE_SHIFT, M_VPS_RESTORE,
+	    M_WAITOK | M_ZERO);
+
+	/*
+	 * First copy only the first page in, to look how much kernel
+	 * memory is needed.
+	 */
+	if ((error = copyin(va->database, ctx->data, PAGE_SIZE)))
+		goto fail;
+	dumphdr = (struct vps_dumpheader *)ctx->data;
+
+	if (vld_checkheader(dumphdr)) {
+		ERRMSG(ctx, "%s: dump is invalid\n", __func__);
+		vld_printheader(dumphdr);
+		error = EINVAL;
+		goto fail;
+	}
+#ifdef DIAGNOSTIC
+	if (debug_restore)
+		vld_printheader(dumphdr);
+#endif
+
+	if (vps_md_restore_checkarch(dumphdr->ptrsize,
+	    dumphdr->byteorder) != 0) {
+		ERRMSG(ctx, "%s: wrong architecture: ptrsize=%x "
+		    "byteorder=%x !\n",
+		    __func__, dumphdr->ptrsize, dumphdr->byteorder);
+		error = EINVAL;
+		goto fail;
+	}
+
+	if (dumphdr->version != VPS_DUMPH_VERSION) {
+		ERRMSG(ctx, "%s: unsupported dump version %08x, "
+		    "want %08x\n",
+		    __func__, dumphdr->version, VPS_DUMPH_VERSION);
+		error = EINVAL;
+		goto fail;
+	}
+
+	/*
+	 * Since there is swap not all has to fit in memory,
+	 * but try to avoid total memory exhaustion.
+	 */
+#ifndef INVARIANTS
+	if (1 && (dumphdr->nuserpages + dumphdr->nsyspages) / 2 >
+	    (cnt.v_free_count + cnt.v_cache_count + cnt.v_inactive_count)) {
+		DBGR("%s: (dumphdr->nuserpages=%u + dumphdr->nsyspages=%u) "
+		     "/ 2 > \n"
+		     "          (v_free_count=%u + v_cache_count=%u + "
+		     "v_inactive_count=%u)\n",
+		    __func__, dumphdr->nuserpages, dumphdr->nsyspages,
+		    cnt.v_free_count, cnt.v_cache_count,
+		    cnt.v_inactive_count);
+		ERRMSG(ctx, "%s: low on memory, not restoring "
+			"VPS instance (pid=%u)\n",
+			__func__, curthread->td_proc->p_pid);
+		error = ENOMEM;
+		goto fail;
+	}
+#endif
+
+	ctx->nuserpages = dumphdr->nuserpages;
+	ctx->nsyspages = dumphdr->nsyspages;
+	ctx->dsize = dumphdr->nsyspages << PAGE_SHIFT;
+	ctx->userpagesaddr = ((caddr_t)va->database) + ctx->dsize;
+	ctx->userpagesidx = 0;
+	SLIST_INIT(&ctx->obj_list);
+
+	free(ctx->data, M_VPS_RESTORE);
+
+	ctx->vmobj = vm_object_allocate(OBJT_DEFAULT, ctx->nsyspages);
+	if (ctx->vmobj == NULL) {
+		error = ENOMEM;
+		goto fail;
+	}
+
+	vm_map_lock(kernel_map);
+	/* Find free space in kernel virtual address space. */
+	if (vm_map_findspace(kernel_map, vm_map_min(kernel_map),
+		ctx->nsyspages << PAGE_SHIFT, &kvaddr) != KERN_SUCCESS) {
+		vm_map_unlock(kernel_map);
+		vm_object_deallocate(ctx->vmobj);
+		ctx->vmobj = NULL;
+		DBGR("%s: vm_map_findspace failed\n", __func__);
+		error = ENOMEM;
+		goto fail;
+	}
+
+	if (vm_map_insert(kernel_map, ctx->vmobj,
+	     kvaddr - VM_MIN_KERNEL_ADDRESS,
+	     kvaddr, kvaddr + (ctx->vmobj->size << PAGE_SHIFT),
+	     VM_PROT_ALL, VM_PROT_ALL, 0) != KERN_SUCCESS) {
+		vm_map_unlock(kernel_map);
+		vm_object_deallocate(ctx->vmobj);
+		ctx->vmobj = NULL;
+		DBGR("%s: vm_map_findspace failed\n", __func__);
+		DBGR("%s: vm_map_insert failed\n", __func__);
+		error = ENOMEM;
+		goto fail;
+	}
+	vm_map_unlock(kernel_map);
+
+	VM_OBJECT_WLOCK(ctx->vmobj);
+	for (i = 0; i < ctx->vmobj->size; i++) {
+		do {
+			m = vm_page_alloc(ctx->vmobj, i,
+			    VM_ALLOC_NORMAL|VM_ALLOC_WIRED);
+			if (m == NULL) {
+				/* Assume that object will not be
+				   modified. */
+				VM_OBJECT_WUNLOCK(ctx->vmobj);
+				vm_waitpfault();
+				VM_OBJECT_WLOCK(ctx->vmobj);
+			}
+		} while (m == NULL);
+		pmap_qenter(kvaddr + (i << PAGE_SHIFT), &m, 1);
+		vm_page_wakeup(m);
+	}
+	VM_OBJECT_WUNLOCK(ctx->vmobj);
+
+	DBGR("%s: mapped syspages vm object %p at %zx - %zx\n",
+		__func__, ctx->vmobj, (size_t)kvaddr,
+		(size_t)(kvaddr + (ctx->vmobj->size << PAGE_SHIFT)));
+
+	ctx->data = ctx->cpos = (void *)kvaddr;
+
+	DBGR("%s: ctx->data=%p ctx->dsize=%zx\n",
+		__func__, ctx->data, (size_t)ctx->dsize);
+
+	if ((error = copyin(va->database, ctx->data, ctx->dsize)))
+		goto fail;
+
+	dumphdr = (struct vps_dumpheader *)ctx->data;
+	ctx->dumphdr = dumphdr;
+
+	checksum1 = dumphdr->checksum;
+	dumphdr->checksum = 0;
+	checksum2 = vps_cksum(ctx->data, ctx->dsize);
+	if (checksum1 != checksum2) {
+		ERRMSG(ctx, "%s: CHECKSUM mismatch: snapshot info: "
+			"%08x calculated: %08x\n",
+			__func__, checksum1, checksum2);
+		error = EINVAL;
+		goto fail;
+	} else
+		DBGR("%s: CHECKSUM is valid !\n", __func__);
+	dumphdr->checksum = checksum1;
+
+	o1 = (struct vps_dumpobj *)(dumphdr + 1);
+	ctx->rootobj = o1;
+	ctx->relative = 1;
+	ctx->elements = -1;
+
+	if (vdo_checktree(ctx)) {
+		ERRMSG(ctx, "%s: dump tree is invalid !\n", __func__);
+		vdo_printtree(ctx);
+		return (EINVAL);
+	}
+	vdo_makeabsolute(ctx);
+	DBGR("%s: dump tree is valid and contains %d elements\n",
+		__func__, ctx->elements);
+
+	/* XXX maybe link together wil lists/tailqs ... */
+
+	/*
+	if ((error = vps_restore_fixup_objlist(ctx, dumphdr, o1)))
+		goto fail;
+	*/
+
+	vm_map_protect(kernel_map, kvaddr, kvaddr +
+		(ctx->vmobj->size << PAGE_SHIFT),
+		VM_PROT_READ, 0);
+
+	DBGR("%s: set map entry to readonly\n", __func__);
+
+	/*
+	*(char*)(ctx->data+100) = 'H';
+	*/
+
+	/* Check if the user really has the memory containing
+	   the userpages. */
+	if ((m = vps_restore_getuserpage(ctx, ctx->nuserpages - 1,
+	    1)) == NULL) {
+		ERRMSG(ctx, "%s: user supplied memory range "
+		    "inaccessible !\n", __func__);
+		error = EFAULT;
+		goto fail;
+	}
+	VM_OBJECT_WLOCK(m->object);
+	vm_page_wakeup(m);
+	VM_OBJECT_WUNLOCK(m->object);
+
+	return (0);
+
+ fail:
+
+	if (ctx->data != NULL && ctx->vmobj == NULL)
+		free(ctx->data, M_VPS_RESTORE);
+	else if (ctx->vmobj != NULL) {
+#if 0
+		pmap_qremove(kvaddr, ctx->vmobj->size);
+		(void)vm_map_unwire(kernel_map, kvaddr, kvaddr +
+			(ctx->vmobj->size << PAGE_SHIFT), 0);
+		/* This also destroys the vm object. */
+		(void)vm_map_remove(kernel_map, kvaddr, kvaddr +
+			(ctx->vmobj->size << PAGE_SHIFT));
+#endif
+
+		npages = ctx->vmobj->size;
+
+		pmap_qremove(kvaddr, npages);
+		VM_OBJECT_WLOCK(ctx->vmobj);
+		while (npages) {
+			npages--;
+			m = TAILQ_LAST(&ctx->vmobj->memq, pglist);
+			vm_page_lock(m);
+			vm_page_unwire(m, 0);
+			vm_page_free(m);
+			vm_page_unlock(m);
+		}
+		VM_OBJECT_WUNLOCK(ctx->vmobj);
+
+		/* This also destroys the vm object. */
+		(void)vm_map_remove(kernel_map, kvaddr, kvaddr +
+			(ctx->vmobj->size << PAGE_SHIFT));
+	}
+
+	return (error);
+}
+
+__attribute__((noinline))
+int
+vps_restore(struct vps_dev_ctx *dev_ctx, struct vps_arg_snapst *va)
+{
+	struct vps_snapst_ctx *ctx;
+	struct vps_dumpheader *dumphdr;
+	struct vps *vps, *vps_save;
+	struct vps_dumpobj *o1;
+	time_t starttime;
+	void *ptr;
+	int error = 0;
+
+#ifdef DIAGNOSTIC
+	vps_snapst_print_errormsgs = debug_restore;
+#endif
+
+	starttime = time_second;
+
+	vps_restore_mod_refcnt++;
+
+	DBGR("%s: \n", __func__);
+
+	vps = NULL;
+	vps_save = curthread->td_vps;
+
+	ctx = malloc(sizeof(*ctx), M_VPS_RESTORE, M_WAITOK|M_ZERO);
+	LIST_INIT(&ctx->errormsgs);
+
+	if (vps_func->vps_dumpobj_create == NULL) {
+		ERRMSG(ctx, "%s: vps_libdump module not loaded\n",
+		    __func__);
+		error = EOPNOTSUPP;
+		goto out;
+	}
+
+#ifdef INVARIANTS
+	/* XXX debugging: if more than 3 dead vpses, stop */
+	{
+		struct vps *vps2;
+		int dead_cnt = 0;
+
+		LIST_FOREACH(vps2, &vps_head, vps_all)
+			if (vps2->vps_status == VPS_ST_DEAD)
+				dead_cnt++;
+
+		if (dead_cnt > 3) {
+			printf("%s: more than 3 dead vps instances\n",
+			    __func__);
+			kdb_enter(KDB_WHY_BREAK, "VPS break to debugger");
+		}
+	}
+#endif
+
+	if ((error = vps_restore_copyin(ctx, va)))
+		goto out;
+
+	ctx->cpos = ctx->data;
+	dumphdr = ctx->dumphdr;
+	o1 = ctx->rootobj;
+
+	if (o1->type != VPS_DUMPOBJT_ROOT) {
+		ERRMSG(ctx, "%s: missing root object\n", __func__);
+		error = EINVAL;
+		goto out;
+	}
+
+	o1 = vdo_next(ctx);
+	if (o1->type != VPS_DUMPOBJT_SYSINFO) {
+		ERRMSG(ctx, "%s: missing sysinfo object\n", __func__);
+		error = EINVAL;
+		goto out;
+	}
+	ctx->old_sysinfo = (struct vps_dump_sysinfo *)o1->data;
+
+	if ((error = vps_restore_vps(ctx, va->vps_name, &vps))) {
+		goto out;
+	}
+
+	/*
+	 * Free resources.
+	 */
+
+	vps_restore_cleanup_vmspace(ctx, vps, &ctx->obj_list);
+	vps_restore_cleanup_pipe(ctx, vps, &ctx->obj_list);
+	vps_restore_cleanup_fdset(ctx, vps, &ctx->obj_list);
+#ifdef INVARIANTS
+	vps_restore_ucred_checkall(ctx, vps);
+#endif
+	vps_restore_cleanup_ucred(ctx, vps, &ctx->obj_list);
+
+	while ( ! SLIST_EMPTY(&ctx->obj_list)) {
+		ptr = SLIST_FIRST(&ctx->obj_list);
+		SLIST_REMOVE_HEAD(&ctx->obj_list, list);
+		free(ptr, M_VPS_RESTORE);
+	}
+	if (ctx->vps_ucred) {
+		DBGR("%s: ctx->vps_ucred->cr_ref=%d\n",
+		    __func__, ctx->vps_ucred->cr_ref);
+		crfree(ctx->vps_ucred);
+	}
+
+ out:
+
+	if (ctx->vmobj != NULL) {
+#if 0
+		pmap_qremove((vm_offset_t)ctx->data, ctx->vmobj->size);
+
+		(void)vm_map_unwire(kernel_map, (vm_offset_t)ctx->data,
+		    (vm_offset_t)ctx->data +
+		    (ctx->vmobj->size << PAGE_SHIFT), 0);
+
+		/* This also destroys the vm object. */
+		(void)vm_map_remove(kernel_map, (vm_offset_t)ctx->data,
+		    (vm_offset_t)ctx->data +
+		    (ctx->vmobj->size << PAGE_SHIFT));
+#endif
+		vm_offset_t kvaddr;
+		vm_page_t m;
+		int npages;
+
+		kvaddr = (vm_offset_t)ctx->data;
+		npages = ctx->vmobj->size;
+
+		pmap_qremove(kvaddr, npages);
+		VM_OBJECT_WLOCK(ctx->vmobj);
+		while (npages) {
+			npages--;
+			m = TAILQ_LAST(&ctx->vmobj->memq, pglist);
+			/* On early error condition we might have less
+			   than npages */
+			if (m == NULL)
+				break;
+			vm_page_lock(m);
+			vm_page_unwire(m, 0);
+			vm_page_free(m);
+			vm_page_unlock(m);
+		}
+		VM_OBJECT_WUNLOCK(ctx->vmobj);
+
+		/* This also destroys the vm object. */
+		(void)vm_map_remove(kernel_map, kvaddr, kvaddr +
+			(ctx->vmobj->size << PAGE_SHIFT));
+	}
+
+	{
+		struct vps_snapst_errmsg *msg;
+		char *buf, *bufpos;
+		size_t buflen;
+		int error2;
+
+		buflen = 0;
+
+		LIST_FOREACH(msg, &ctx->errormsgs, list) {
+			printf("%s\n", msg->str);
+			buflen += strlen(msg->str);
+		}
+
+		buf = bufpos = malloc(buflen + 1, M_TEMP, M_WAITOK);
+		LIST_FOREACH(msg, &ctx->errormsgs, list) {
+			memcpy(bufpos, msg->str, strlen(msg->str));
+			bufpos += strlen(msg->str);
+		}
+		*(bufpos) = '\0';
+		bufpos += 1;
+
+		DBGR("%s: va->msgbase=%p va->msglen=%zu\n",
+			__func__, va->msgbase, va->msglen);
+		if (va->msgbase != NULL && va->msglen > 0) {
+			if (va->msglen < (bufpos - buf))
+				printf("%s: warning: user-supplied buffer "
+				    "too small for error messages\n",
+				    __func__);
+			if ((error2 = copyout(buf, va->msgbase,
+			    min(va->msglen, (bufpos - buf)))))
+				printf("%s: error messages copyout=%d\n",
+				     __func__, error2);
+		}
+		free(buf, M_TEMP);
+
+		while (!LIST_EMPTY(&ctx->errormsgs)) {
+			msg = LIST_FIRST(&ctx->errormsgs);
+			LIST_REMOVE(msg, list);
+			free(msg, M_TEMP);
+		}
+	}
+
+	free(ctx, M_VPS_RESTORE);
+
+#if 0
+	/*
+	 * Remove all dump pages from process.
+	 */
+	pmap_remove(vmspace_pmap(curthread->td_proc->p_vmspace),
+	    (vm_offset_t)ctx->userpagesaddr,
+	    (vm_offset_t)ctx->userpagesaddr +
+	    (ctx->nuserpages << PAGE_SHIFT));
+#endif
+	if (error) {
+		/* XXX Perform a proper cleanup ! */
+		if (vps != NULL) {
+			vps->vps_status = VPS_ST_DEAD;
+			snprintf(vps->vps_name, sizeof(vps->vps_name),
+			    "dead_%p", vps);
+		}
+		DBGR("%s: error = %d\n", __func__, error);
+	}
+
+	curvnet = NULL;
+	curthread->td_vps = vps_save;
+	KASSERT(curthread->td_vps == curthread->td_ucred->cr_vps,
+	    ("%s: curthread->td_vps=%p curthread->td_ucred->cr_vps=%p\n",
+	    __func__, curthread->td_vps, curthread->td_ucred->cr_vps));
+
+	vps_restore_mod_refcnt--;
+
+	DBGR("%s: total time: %lld seconds\n",
+		__func__, (long long int)(time_second - starttime));
+
+	return (error);
+}
+
+/* XXX This code should be protected by module refcount as well. */
+void
+vps_restore_return(struct thread *td, struct trapframe *frame)
+{
+
+	cpu_set_syscall_retval(td, td->td_errno);
+
+	userret(td, frame);
+
+#ifdef KTRACE
+	if (KTRPOINT(td, KTR_STRUCT))
+		ktrstruct("VPS", "VPS RESTORED", 13);
+#endif
+	mtx_assert(&Giant, MA_NOTOWNED);
+}
+
+static int
+vps_restore_modevent(module_t mod, int type, void *data)
+{
+	int error;
+
+	error = 0;
+
+	switch (type) {
+	case MOD_LOAD:
+	   vps_restore_mod_refcnt = 0;
+	   vps_func->vps_restore = vps_restore;
+	   vps_func->vps_restore_ucred = vps_restore_ucred;
+	   vps_func->vps_restore_ucred_lookup = vps_restore_ucred_lookup;
+	   vps_func->vps_restore_return = vps_restore_return;
+	   break;
+	case MOD_UNLOAD:
+	   if (vps_restore_mod_refcnt > 0)
+		return (EBUSY);
+	   vps_func->vps_restore = NULL;
+	   vps_func->vps_restore_ucred = NULL;
+	   vps_func->vps_restore_ucred_lookup = NULL;
+	   vps_func->vps_restore_return = NULL;
+	   break;
+	default:
+	   error = EOPNOTSUPP;
+	   break;
+	}
+	return (error);
+}
+
+static moduledata_t vps_restore_mod = {
+	"vps_restore",
+	vps_restore_modevent,
+	0
+};
+
+DECLARE_MODULE(vps_restore, vps_restore_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_snapst.c head/sys/vps/vps_snapst.c
--- clean-head/sys/vps/vps_snapst.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_snapst.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,3610 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: vps_snapst.c 180 2013-06-14 16:52:13Z klaus $";
+
+#include <sys/cdefs.h>
+
+#include "opt_ddb.h"
+#include "opt_global.h"
+#include "opt_compat.h"
+
+#ifdef VPS
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/refcount.h>
+#include <sys/sched.h>
+#include <sys/sockio.h>
+#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/ttycom.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/uio.h>
+#include <sys/resourcevar.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/namei.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/reboot.h>
+#include <sys/conf.h>
+#include <sys/syscallsubr.h>
+#include <sys/mman.h>
+#include <sys/sleepqueue.h>
+#include <sys/filedesc.h>
+#include <sys/mount.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/pipe.h>
+#include <sys/tty.h>
+#include <sys/syscall.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
+#include <sys/sem.h>
+#include <sys/ktrace.h>
+#include <sys/buf.h>
+#include <sys/jail.h>
+#include <sys/event.h>
+#include <sys/eventvar.h>
+#include <sys/umtx.h>
+
+#include <machine/pcb.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_pageout.h>
+
+#include <machine/pcb.h>
+
+#ifdef DDB
+#include <ddb/ddb.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_clone.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <net/radix.h>
+#include <net/route.h>
+#include <net/vnet.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include "vps_account.h"
+#include "vps_user.h"
+#include "vps.h"
+#include "vps2.h"
+#include <machine/vps_md.h>
+
+#define _VPS_SNAPST_H_ALL
+#include "vps_snapst.h"
+
+#include "vps_libdump.h"
+
+#define ERRMSG vps_snapst_pusherrormsg
+
+#ifdef DIAGNOSTIC
+
+#define DBGS if (debug_snapst) printf
+//#define DBGS if (debug_snapst) vps_printf
+
+static int debug_snapst = 1;
+SYSCTL_INT(_debug, OID_AUTO, vps_snapst_debug, CTLFLAG_RW,
+    &debug_snapst, 0, "");
+
+#else
+
+#define DBGS(x, ...)
+
+#endif /* DIAGNOSTIC */
+
+MALLOC_DEFINE(M_VPS_SNAPST, "vps_snapst",
+    "Virtual Private Systems Snapshot memory");
+
+static int vps_snapshot_sysinfo(struct vps_snapst_ctx *ctx,
+    struct vps *vps);
+static int vps_snapshot_vps(struct vps_snapst_ctx *ctx,
+    struct vps *vps);
+static int vps_snapshot_arg(struct vps_snapst_ctx *ctx,
+    struct vps *vps);
+static int vps_snapshot_mounts(struct vps_snapst_ctx *ctx,
+    struct vps *vps);
+static int vps_snapshot_prison(struct vps_snapst_ctx *ctx,
+    struct vps *vps);
+static int vps_snapshot_proc(struct vps_snapst_ctx *ctx,
+    struct vps *vps);
+static int vps_snapshot_proc_one(struct vps_snapst_ctx *ctx,
+    struct vps *vps, struct proc *p);
+static int vps_snapshot_vnet(struct vps_snapst_ctx *ctx,
+    struct vps *vps, struct vnet *vnet);
+static int vps_snapshot_vnet_route_table(struct vps_snapst_ctx *ctx,
+    struct vps *vps, struct vnet *vnet, int fibnum, int af);
+static int vps_snapshot_ucred(struct vps_snapst_ctx *ctx,
+    struct vps *vps, struct ucred *cr, int how);
+
+static int vps_snapst_mod_refcnt;
+
+/*
+ * * * * * Support functions. * * * *
+ */
+
+/*
+ * * * * * Snapshot memory functions. * * * *
+ *
+ * Since the required amount of memory for storing the snapshot is unkown
+ * in the beginning and can't be determined in advance (as soon as locks
+ * are released objects may change) memory has to be allocated dynamically.
+ * Working with memory chunks or reallocating and copying everything,
+ * including change of memory adresses, lots of times, is slow and tedious.
+ * So we reserve a virtual adress space big enough to hold the whole kernel
+ * part of the snapshot. On 32bit architectures it *could* be a problem
+ * because in default configuration the kernel address space is only 1 GB,
+ * but is still the best solution, IMHO. On 64bit architectures there is
+ * enough address space to feed pigs with.
+ * The base of the snapshot memory (ctx->data) never changes. Before copying
+ * data vps_ctx_extend() must be called. This function allocates and wires
+ * physical pages, if called with M_NOWAIT only what is absolutely
+ * necessary, if called with M_WAITOK some extra pages get allocated,
+ * so the next couple of runs don't need to actually allocate memory.
+ */
+__attribute__((noinline))
+static int
+vps_ctx_alloc(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	vm_offset_t kvaddr;
+	int npages;
+	int error;
+
+	/*
+	 * This space must be big enough to hold the whole kernel part
+	 * of the snapshot.
+	 * On 64bit systems we can set it to something like 1 GB.
+	 *
+	 * npages --> 10240 --> 40 mbyte (assuming PAGE_SIZE == 4K)
+	 */
+	npages = VPS_MD_SNAPCTX_NPAGES;
+
+	ctx->maxsize = npages << PAGE_SHIFT;
+	ctx->dsize2 = 0;
+
+	ctx->vmobj = vm_object_allocate(OBJT_DEFAULT, npages);
+	if (ctx->vmobj == NULL) {
+		error = ENOMEM;
+		ERRMSG(ctx, "%s: vm_object_allocate failed\n", __func__);
+		return (error);
+	}
+
+	vm_map_lock(kernel_map);
+	/* Find free space in kernel virtual address space. */
+	if (vm_map_findspace(kernel_map, vm_map_min (kernel_map),
+		npages << PAGE_SHIFT, &kvaddr) != KERN_SUCCESS) {
+		error = ENOMEM;
+		vm_map_unlock(kernel_map);
+		vm_object_deallocate(ctx->vmobj);
+		ERRMSG(ctx, "%s: vm_map_findspace failed\n", __func__);
+		return (error);
+	}
+
+	/*
+	 * Reserve it by mapping the object.
+	 * Note that if an address in this space gets accessed
+	 * prior to calling vps_ctx_extend() a page fault gets
+	 * triggered and kernel panics !
+	 */
+	if (vm_map_insert(kernel_map, ctx->vmobj,
+	    kvaddr - VM_MIN_KERNEL_ADDRESS, kvaddr,
+	    kvaddr + (npages << PAGE_SHIFT),
+	    VM_PROT_ALL, VM_PROT_ALL, 0) != KERN_SUCCESS) {
+		error = ENOMEM;
+		vm_map_unlock(kernel_map);
+		vm_object_deallocate(ctx->vmobj);
+		ERRMSG(ctx, "%s: vm_map_insert failed\n", __func__);
+		return (error);
+	}
+
+	vm_map_unlock(kernel_map);
+
+	ctx->data = ctx->cpos = (void *)kvaddr;
+
+	ctx->syspagelist = malloc(npages * sizeof(struct vm_page *),
+		M_VPS_SNAPST, M_WAITOK | M_ZERO);
+
+#if 0
+// delete
+	/* XXX get memory range by vm_map_findspace() */
+	ctx->user_map = &curthread->td_proc->p_vmspace->vm_map;
+	ctx->user_map_start = 0x2000000;
+	ctx->user_map_offset = ctx->user_map_start;
+#endif
+
+	vps_snapst_mod_refcnt++;
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_ctx_free(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	vm_offset_t kvaddr;
+	vm_page_t m;
+	int npages, maxpages;
+
+	kvaddr = (vm_offset_t)ctx->data;
+	maxpages = ctx->maxsize >> PAGE_SHIFT;
+	npages = ctx->dsize2 >> PAGE_SHIFT;
+
+	pmap_qremove(kvaddr, npages);
+
+	VM_OBJECT_WLOCK(ctx->vmobj);
+
+	while (npages) {
+		npages--;
+		m = TAILQ_LAST(&ctx->vmobj->memq, pglist);
+		vm_page_lock(m);
+		vm_page_unwire(m, 0);
+		vm_page_free(m);
+		vm_page_unlock(m);
+	}
+
+	VM_OBJECT_WUNLOCK(ctx->vmobj);
+
+	(void)vm_map_unwire(kernel_map, kvaddr, kvaddr +
+	    (maxpages << PAGE_SHIFT), 0);
+
+	/* This also destroys the vm object. */
+	(void)vm_map_remove(kernel_map, kvaddr, kvaddr +
+	    (maxpages << PAGE_SHIFT));
+
+	free(ctx->syspagelist, M_VPS_SNAPST);
+
+	vps_snapst_mod_refcnt--;
+
+	return (0);
+}
+
+/*
+ * If called with M_NOWAIT the return value must be checked !
+ */
+/*
+ * Inline the code that gets executed on every single call.
+ */
+
+/*
+ * We actually have to allocate.
+ */
+__attribute__((noinline))
+static int
+vps_ctx_extend_hard(struct vps_snapst_ctx *ctx, struct vps *vps,
+    size_t size, int how)
+{
+	int npages;
+	int pagenum;
+	int i;
+	int flags;
+	vm_offset_t new;
+	vm_page_t m;
+
+#if 0
+	/* XXX Can't sleep here because of vmobject lock :-( */
+	KASSERT(how == M_WAITOK, ("%s: how != M_WAITOK\n", __func__));
+#endif
+
+	if (how == M_WAITOK)
+		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+				"%s: size=%d", __func__, size);
+
+	npages = round_page(size) >> PAGE_SHIFT;
+	if (how == M_WAITOK) {
+		/* Allocate more here since we can sleep now. */
+		npages += 10;
+	}
+
+	flags = VM_ALLOC_NORMAL|VM_ALLOC_WIRED;
+
+	VM_OBJECT_WLOCK(ctx->vmobj);
+	new = (vm_offset_t)((caddr_t)ctx->data + ctx->dsize2);
+	m = TAILQ_LAST(&ctx->vmobj->memq, pglist);
+	pagenum = (m != NULL) ? m->pindex + 1 : 0;
+	for (i = 0; i < npages; i++) {
+		do {
+			m = vm_page_alloc(ctx->vmobj, pagenum + i, flags);
+			if (m == NULL) {
+				/* Assume that object will not be
+				   modified. */
+				VM_OBJECT_WUNLOCK(ctx->vmobj);
+				vm_waitpfault();
+				VM_OBJECT_WLOCK(ctx->vmobj);
+			}
+		} while (m == NULL && how == M_WAITOK);
+
+		if (m == NULL) {
+			ERRMSG(ctx, "%s: ENOMEM (size=%zu)\n",
+			    __func__, size);
+			/* XXX undo what we've done so far */
+			return (ENOMEM);
+		}
+		pmap_qenter(new + (i << PAGE_SHIFT), &m, 1);
+		bzero((void *)(new + (i << PAGE_SHIFT)), PAGE_SIZE);
+		ctx->syspagelist[pagenum + i] = m;
+	}
+	VM_OBJECT_WUNLOCK(ctx->vmobj);
+
+	ctx->dsize2 += npages << PAGE_SHIFT;
+
+	DBGS("%s: extended by %d pages, total now %d\n",
+	    __func__, npages, pagenum + npages);
+
+	return (0);
+}
+
+/*
+ * * * * * Snapshot functions. * * * *
+ */
+
+/*
+ * This function does the actual snapshot and prepares the dump.
+ */
+
+__attribute__((noinline))
+int
+vps_snapshot(struct vps_dev_ctx *dev_ctx, struct vps *vps,
+    struct vps_arg_snapst *va)
+{
+	struct vps_snapst_ctx *ctx;
+	struct vps_dumpheader *dumphdr;
+	time_t starttime;
+	int error = 0;
+
+#ifdef DIAGNOSTIC
+	vps_snapst_print_errormsgs = debug_snapst;
+#endif
+
+	starttime = time_second;
+
+	sx_assert(&vps->vps_lock, SX_XLOCKED);
+
+	dev_ctx->snapst = NULL;
+
+	ctx = malloc(sizeof (*ctx), M_VPS_SNAPST, M_WAITOK | M_ZERO);
+	LIST_INIT(&ctx->errormsgs);
+	dev_ctx->snapst = ctx;
+
+	if (vps_func->vps_dumpobj_create == NULL) {
+		ERRMSG(ctx, "%s: vps_libdump module not loaded\n",
+		   __func__);
+		error = EOPNOTSUPP;
+		goto out;
+	}
+
+	if (vps->vps_status != VPS_ST_SUSPENDED) {
+		ERRMSG(ctx, "%s: vps is not VPS_ST_SUSPENDED\n",
+		    __func__);
+		error = EBUSY;
+		goto out;
+	}
+
+	dev_ctx->cmd = VPS_IOC_SNAPST;
+	ctx->vps = vps;
+	ctx->pagesread = 0;
+	vps->vps_status = VPS_ST_SNAPSHOOTING;
+
+	if (vps_ctx_alloc(ctx, vps)) {
+		error = ENOMEM;
+		goto out;
+	}
+
+	vps_ctx_extend(ctx, vps, 10 << PAGE_SHIFT, M_WAITOK);
+
+	ctx->dumpobj_list = NULL;
+	dumphdr = (struct vps_dumpheader *)ctx->data;
+	memset(dumphdr, 0, sizeof(*dumphdr));
+	ctx->cpos = (caddr_t)ctx->data + sizeof(*dumphdr);
+	ctx->dsize = sizeof(*dumphdr);
+
+	ctx->nuserpages = 0;
+	/* Gets extended dynamically on demand. */
+	ctx->userpagelistlength = 1024; /* 1024 items */
+	ctx->userpagelist = malloc(ctx->userpagelistlength *
+	    sizeof(void *), M_VPS_SNAPST, M_WAITOK|M_ZERO);
+
+	ctx->nuserpages = 0;
+	/* Gets extended dynamically on demand. */
+	ctx->page_ref_size = 1024; /* 1024 items */
+	ctx->page_ref = malloc(ctx->page_ref_size *
+	    sizeof(struct vps_page_ref), M_VPS_SNAPST, M_WAITOK|M_ZERO);
+
+	SLIST_INIT(&ctx->obj_list);
+
+	ctx->rootobj = vdo_create(ctx, VPS_DUMPOBJT_ROOT, M_WAITOK);
+
+	if ((error = vps_snapshot_sysinfo(ctx, vps)))
+		goto out;
+
+	/* Leaves the vps dump object open */
+	if ((error = vps_snapshot_vps(ctx, vps)))
+		goto out;
+
+	if ((error = vps_snapshot_mounts(ctx, vps)))
+		goto out;
+
+	if ((error = vps_snapshot_arg(ctx, vps)))
+		goto out;
+
+	if ((error = vps_snapshot_vnet(ctx, vps, vps->vnet)))
+		goto out;
+
+	if ((error = vps_snapshot_prison(ctx, vps)))
+		goto out;
+
+	if (vps_func->sem_snapshot_vps &&
+	    (error = vps_func->sem_snapshot_vps(ctx, vps)))
+		goto out;
+
+	if (vps_func->shm_snapshot_vps &&
+	    (error = vps_func->shm_snapshot_vps(ctx, vps)))
+		goto out;
+
+	if (vps_func->msg_snapshot_vps &&
+	    (error = vps_func->msg_snapshot_vps(ctx, vps)))
+		goto out;
+
+	if ((error = vps_snapshot_proc(ctx, vps)))
+		goto out;
+
+	/* Close the vps object. */
+	vdo_close(ctx);
+
+	/* Close the root object. */
+	vdo_close(ctx);
+
+	ctx->nsyspages = (((caddr_t)ctx->cpos - (caddr_t)ctx->data)
+	    >> PAGE_SHIFT);
+	/* If not exactly a multiple of PAGE_SIZE, add one page. */
+	if (ctx->nsyspages << PAGE_SHIFT != (caddr_t)ctx->cpos -
+	    (caddr_t)ctx->data)
+		ctx->nsyspages += 1;
+	va->datalen = (ctx->nsyspages + ctx->nuserpages) << PAGE_SHIFT;
+	va->database = NULL;
+
+	dumphdr->byteorder = VPS_MD_DUMPHDR_BYTEORDER;
+	dumphdr->ptrsize = VPS_MD_DUMPHDR_PTRSIZE;
+	dumphdr->pageshift = PAGE_SHIFT;
+	dumphdr->version = VPS_DUMPH_VERSION;
+	dumphdr->magic = VPS_DUMPH_MAGIC;
+	dumphdr->time = time_second;
+
+	dumphdr->nsyspages = ctx->nsyspages;
+	dumphdr->nuserpages = ctx->nuserpages;
+
+	/* The userspace utility relies on this value. */
+	dumphdr->size = va->datalen;
+
+	if (vdo_checktree(ctx)) {
+		ERRMSG(ctx, "%s: dump tree is invalid !\n", __func__);
+		/*
+		vdo_printtree(ctx);
+		*/
+		return (EINVAL);
+	}
+	vdo_makerelative(ctx);
+	DBGS("%s: dump tree is valid and contains %d elements\n",
+		__func__, ctx->elements);
+
+	/* This has to be the last write access to syspages
+	   dump *grr* !!! */
+	dumphdr->checksum = 0;
+	dumphdr->checksum = vps_cksum((char *)ctx->data,
+	    dumphdr->nsyspages << PAGE_SHIFT);
+
+	DBGS("%s: snapshot dev_ctx=%p dev_ctx->snapst=%p vps=%p "
+	    "syspages=%d cksum=%08llx userpages=%d PREPARED\n",
+		__func__, dev_ctx, dev_ctx->snapst, vps,
+		dumphdr->nsyspages,
+		(long long unsigned int)dumphdr->checksum,
+		dumphdr->nuserpages);
+
+	/* allocate userspace pages vm object and map it */
+	if ((ctx->vps_vmobject = vps_pager_ops.pgo_alloc(ctx,
+			ctx->nsyspages + ctx->nuserpages,
+			VM_PROT_READ, 0,
+			curthread->td_proc->p_ucred)) == NULL) {
+		ERRMSG(ctx, "%s: vm_object_allocate: %d\n",
+		    __func__, error);
+		/* XXX */
+		return (error);
+	}
+
+	ctx->user_map = &curthread->td_proc->p_vmspace->vm_map;
+	vm_map_lock(ctx->user_map);
+	if (vm_map_findspace(ctx->user_map, vm_map_min(ctx->user_map),
+	                     (ctx->nsyspages + ctx->nuserpages) <<
+			     PAGE_SHIFT,
+	                     &ctx->user_map_start) != KERN_SUCCESS) {
+		error = ENOMEM;
+		vm_map_unlock(ctx->user_map);
+		ERRMSG(ctx, "%s: vm_map_findspace: %d\n", __func__, error);
+		/* XXX */
+		return (error);
+	}
+	error = vm_map_insert(ctx->user_map, ctx->vps_vmobject, 0,
+		ctx->user_map_start,
+		ctx->user_map_start +
+		((ctx->nsyspages + ctx->nuserpages) << PAGE_SHIFT),
+		VM_PROT_READ, VM_PROT_READ, 0);
+	if (error != KERN_SUCCESS)
+		panic("%s: vm_map_insert: error=%d\n", __func__, error);
+	vm_map_unlock(ctx->user_map);
+
+	DBGS("%s: snapshot at %zx - %zx\n", __func__,
+	    (size_t)ctx->user_map_start,
+	    (size_t)(ctx->user_map_start +
+	    ((ctx->nsyspages + ctx->nuserpages) << PAGE_SHIFT)));
+
+	va->database = (void *)ctx->user_map_start;
+
+	/*
+ 	 * Resources are freed in vps_snapshot_finish().
+	 */
+
+  out:
+	if (error) {
+		ERRMSG(ctx, "%s: error=%d\n", __func__, error);
+	}
+
+	{
+		struct vps_snapst_errmsg *msg;
+		char *buf, *bufpos;
+		size_t buflen;
+		int error2;
+
+		buflen = 0;
+
+		LIST_FOREACH(msg, &ctx->errormsgs, list) {
+			printf("%s\n", msg->str);
+			buflen += strlen(msg->str);
+		}
+
+		buf = bufpos = malloc(buflen + 1, M_TEMP, M_WAITOK);
+		LIST_FOREACH(msg, &ctx->errormsgs, list) {
+			memcpy(bufpos, msg->str, strlen(msg->str));
+			bufpos += strlen(msg->str);
+		}
+		*(bufpos) = '\0';
+		bufpos += 1;
+
+		DBGS("%s: va->msgbase=%p va->msglen=%zu\n",
+			__func__, va->msgbase, va->msglen);
+		if (va->msgbase != NULL && va->msglen > 0) {
+			if (va->msglen < (bufpos - buf))
+				printf("%s: warning: user-supplied buffer "
+				    "too small for error messages\n",
+				    __func__);
+			if ((error2 = copyout(buf, va->msgbase,
+			    min(va->msglen, (bufpos - buf)))))
+				printf("%s: error messages copyout=%d\n",
+				    __func__, error2);
+		}
+		free(buf, M_TEMP);
+
+		while (!LIST_EMPTY(&ctx->errormsgs)) {
+			msg = LIST_FIRST(&ctx->errormsgs);
+			LIST_REMOVE(msg, list);
+			free(msg, M_TEMP);
+		}
+	}
+
+	DBGS("%s: total time: %lld seconds\n",
+		__func__, (long long int)(time_second - starttime));
+
+	return (error);
+}
+
+/*
+ * Create FILE_PATH dump object for vnode vp at ctx->cpos.
+ */
+__attribute__((noinline))
+static int
+vps_snapshot_vnodepath(struct vps_snapst_ctx *ctx, struct vps *vps,
+		struct vnode *vp, int howalloc)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_filepath *vdfp;
+	char *retbuf, *buf;
+	int error;
+
+	if (vp == NULL)
+		return (0);
+
+	vref(vp);
+	howalloc &= (M_WAITOK|M_NOWAIT);
+	if (howalloc == 0)
+		return (EINVAL);
+	buf = malloc(MAXPATHLEN, M_TEMP, howalloc|M_ZERO);
+	if (buf == NULL) {
+		vrele(vp);
+		return (ENOMEM);
+	}
+	retbuf = "-";
+	error = vn_fullpath1(curthread, vp, vps->_rootvnode,
+				buf, &retbuf, MAXPATHLEN);
+	if (error != 0) {
+		free(buf, M_TEMP);
+		vrele(vp);
+		return (error);
+	}
+
+	DBGS("%s: vnode=%p path=[%s] error=%d\n",
+	    __func__, vp, retbuf, error);
+
+	o1 = vdo_create(ctx, VPS_DUMPOBJT_FILE_PATH, howalloc);
+	if (o1 == NULL) {
+		free(buf, M_TEMP);
+		vrele(vp);
+		return (ENOMEM);
+	}
+	if ((vdfp = vdo_space(ctx, sizeof(*vdfp) +
+	    roundup(strlen(retbuf) + 1, 8), howalloc)) == NULL) {
+		vdo_discard(ctx, o1);
+		free(buf, M_TEMP);
+		vrele(vp);
+		return (ENOMEM);
+	}
+
+	vdfp->fp_size = strlen(retbuf);
+	strlcpy(vdfp->fp_path, retbuf, vdfp->fp_size + 1);
+
+	vdo_close(ctx);
+	free(buf, M_TEMP);
+	vrele(vp);
+
+	return (0);
+}
+
+/*
+ * Pseudo teletype device.
+ */
+__attribute__((noinline))
+static int
+vps_snapshot_pts(struct vps_snapst_ctx *ctx, struct vps *vps,
+		struct tty *tp)
+{
+	struct vps_dump_pts *vdp;
+	struct vps_dump_filepath *vdf;
+	struct pts_softc *psc;
+	int i;
+
+	if (tp == NULL)
+		return (0);
+
+	vdo_create(ctx, VPS_DUMPOBJT_PTS, M_WAITOK);
+
+	vdp = vdo_space(ctx, sizeof(*vdp), M_WAITOK);
+
+	psc = tty_softc(tp);
+	vdp->pt_index = psc->pts_unit;
+	if (tp->t_pgrp != NULL)
+		vdp->pt_pgrp_id = tp->t_pgrp->pg_id;
+	else
+		vdp->pt_pgrp_id = 0;
+	vdp->pt_flags = psc->pts_flags;
+	vdp->pt_cred = psc->pts_cred;
+	vdp->pt_termios.c_iflag = tp->t_termios.c_iflag;
+	vdp->pt_termios.c_oflag = tp->t_termios.c_oflag;
+	vdp->pt_termios.c_cflag = tp->t_termios.c_cflag;
+	vdp->pt_termios.c_lflag = tp->t_termios.c_lflag;
+	vdp->pt_termios.c_ispeed = tp->t_termios.c_ispeed;
+	vdp->pt_termios.c_ospeed = tp->t_termios.c_ospeed;
+	KASSERT(NCCS <= (sizeof(vdp->pt_termios.c_cc) /
+	    sizeof(vdp->pt_termios.c_cc[0])),
+	    ("%s: vdp->pt_termios.c_cc smaller than NCCS\n", __func__));
+	memset(vdp->pt_termios.c_cc, 0, sizeof(vdp->pt_termios.c_cc));
+	for (i = 0; i < NCCS; i++)
+		vdp->pt_termios.c_cc[i] = tp->t_termios.c_cc[i];
+
+	vps_snapshot_ucred(ctx, vps, psc->pts_cred, M_WAITOK);
+
+	vdo_create(ctx, VPS_DUMPOBJT_FILE_PATH, M_WAITOK);
+
+	vdf = vdo_space(ctx, sizeof(*vdf), M_WAITOK);
+	vdf->fp_size = strlen(tty_devname(tp));
+	vdo_space(ctx, roundup(vdf->fp_size + 1, 8), M_WAITOK);
+	memcpy(vdf->fp_path, tty_devname(tp), vdf->fp_size);
+
+	DBGS("%s: data=%p path=[%s]\n", __func__, tp, vdf->fp_path);
+
+	vdo_close(ctx);		/* VPS_DUMPOBJT_FILE_PATH */
+
+	vdo_close(ctx);		/* VPS_DUMPOBJT_PTS */
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_sysinfo(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dump_sysinfo *vds;
+
+	vdo_create(ctx, VPS_DUMPOBJT_SYSINFO, M_WAITOK);
+
+	vds = vdo_space(ctx, sizeof(*vds), M_WAITOK);
+
+	strncpy(vds->kernel, version, MAXHOSTNAMELEN);
+	strncpy(vds->hostname, VPS_VPS(vps, hostname), MAXHOSTNAMELEN);
+
+	vds->shared_page_obj = shared_page_obj;
+
+	DBGS("%s: shared_page_obj = %p\n", __func__, shared_page_obj);
+
+	vdo_close(ctx);
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_vps(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dump_vps *vdi;
+
+	/* Dump vps specific data. */
+	vdo_create(ctx, VPS_DUMPOBJT_VPS, M_WAITOK);
+
+	vdi = vdo_space(ctx, sizeof(*vdi), M_WAITOK);
+	strlcpy(vdi->hostname, VPS_VPS(vps, hostname),
+	    sizeof(vdi->hostname));
+	vdi->boottime.tv_sec = VPS_VPS(vps, boottime).tv_sec;
+	vdi->boottime.tv_usec = VPS_VPS(vps, boottime).tv_usec;
+	vdi->lastpid = VPS_VPS(vps, lastpid);
+
+	vdi->restore_count = vps->restore_count;
+	vdi->initpgrp_id = (VPS_VPS(vps, initpgrp) != NULL) ?
+	    VPS_VPS(vps, initpgrp)->pg_id : 0;
+	vdi->initproc_id = (VPS_VPS(vps, initproc) != NULL) ?
+	    VPS_VPS(vps, initproc)->p_pid : 0;
+	strlcpy(vdi->vps_name, vps->vps_name, sizeof(vdi->vps_name));
+	strlcpy(vdi->rootpath, vps->_rootpath, sizeof(vdi->rootpath));
+
+	/* Object is closed in calling function. */
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_arg(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_dump_arg *vda;
+	struct vps_dump_arg_ip4 *vda4;
+	struct vps_dump_arg_ip6 *vda6;
+	struct vps_dump_accounting *vdacc;
+	size_t privsetsize_round;
+	caddr_t cpos;
+	int error = 0;
+	int i;
+
+	/* XXX locking */
+
+	/* If we ran out of memory previously, we try again.
+ again:
+ */
+	vdo_create(ctx, VPS_DUMPOBJT_ARG, M_WAITOK);
+
+	vda = vdo_space(ctx, sizeof(*vda), M_WAITOK);
+
+	vda->privset_size = PRIV_SET_SIZE;
+	vda->ip4net_cnt = vps->vps_ip4_cnt;
+	vda->ip6net_cnt = vps->vps_ip6_cnt;
+	vda->have_accounting = (vps->vps_acc != NULL) ? 1 : 0;
+
+	privsetsize_round = roundup(vda->privset_size, 8);
+
+	cpos = vdo_space(ctx, privsetsize_round, M_WAITOK);
+	memcpy(cpos, vps->priv_allow_set, vda->privset_size);
+
+	cpos = vdo_space(ctx, privsetsize_round, M_WAITOK);
+	memcpy(cpos, vps->priv_impl_set, vda->privset_size);
+
+	if (vps->vps_ip4_cnt > 0) {
+		cpos = vdo_space(ctx, vps->vps_ip4_cnt *
+			sizeof(struct vps_dump_arg_ip4), M_WAITOK);
+		for (i = 0; i < vps->vps_ip4_cnt; i++) {
+			vda4 = (struct vps_dump_arg_ip4 *)cpos;
+			memcpy(vda4->a4_addr, &vps->vps_ip4[i].addr, 0x4);
+			memcpy(vda4->a4_mask, &vps->vps_ip4[i].mask, 0x4);
+			cpos = (caddr_t)(vda4 + 1);
+		}
+	}
+
+	if (vps->vps_ip6_cnt > 0) {
+		cpos = vdo_space(ctx, vps->vps_ip6_cnt *
+			sizeof(struct vps_dump_arg_ip6), M_WAITOK);
+		for (i = 0; i < vps->vps_ip6_cnt; i++) {
+			vda6 = (struct vps_dump_arg_ip6 *)cpos;
+			memcpy(vda6->a6_addr, &vps->vps_ip6[i].addr, 0x10);
+			vda6->a6_plen = vps->vps_ip6[i].plen;
+			cpos = (caddr_t)(vda6 + 1);
+		}
+	}
+
+	if (vda->have_accounting) {
+		vdacc = vdo_space(ctx, sizeof(*vdacc), M_WAITOK);
+
+#define FILL_ACCVAL(x)						\
+	vdacc->x.cur = vps->vps_acc->x.cur;			\
+	vdacc->x.soft = vps->vps_acc->x.soft;			\
+	vdacc->x.hard = vps->vps_acc->x.hard;			\
+	vdacc->x.hits_soft = vps->vps_acc->x.hits_soft;		\
+	vdacc->x.hits_hard = vps->vps_acc->x.hits_hard
+
+		FILL_ACCVAL(virt);
+		FILL_ACCVAL(phys);
+		FILL_ACCVAL(kmem);
+		FILL_ACCVAL(kernel);
+		FILL_ACCVAL(buffer);
+		FILL_ACCVAL(pctcpu);
+		FILL_ACCVAL(blockio);
+		FILL_ACCVAL(threads);
+		FILL_ACCVAL(procs);
+
+#undef FILL_ACCVAL
+	}
+
+	vdo_close(ctx);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_mounts(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	int error = 0;
+	struct vps_dumpobj *o1;
+	struct vps_dump_mount *vdm;
+	struct mount *mp;
+	char *mntfrom, *mnton, *fstype, *vpsroot;
+	int len;
+
+	/*
+	 * Find all mountpoints that are in the vps's root directory
+	 * (this includes the root directory itself, if a mountpoint).
+	 *
+	 * Assume that the mountlist is in correct order regarding
+	 * dependencies.
+	 *
+	 * XXX If vps's rootdir is '/', things will be odd.
+	 */
+
+	DBGS("%s: vps's rootpath=[%s] vnode=%p\n",
+			__func__, vps->_rootpath, vps->_rootvnode);
+
+	vpsroot = strdup(vps->_rootpath, M_TEMP);
+	if (vpsroot[strlen(vpsroot) - 1] == '/')
+		vpsroot[strlen(vpsroot) - 1] = '\0';
+	len = strlen(vpsroot);
+
+	/* If we ran out of memory previously, we try again. */
+ again:
+
+	mtx_lock(&mountlist_mtx);
+	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
+		mntfrom = mp->mnt_stat.f_mntfromname;
+		mnton = mp->mnt_stat.f_mntonname;
+		fstype = mp->mnt_stat.f_fstypename;
+		DBGS("%s: mp=%p: flag=%zx type=[%s] from=[%s] on=[%s]\n",
+		    __func__, mp, (size_t)mp->mnt_flag, fstype, mntfrom,
+		    mnton);
+
+		if (!(strncmp(vpsroot, mnton, len) == 0 &&
+		    (mnton[len] == '\0' || mnton[len] == '/')))
+			continue;
+
+#if 0
+		/* Mounts performed by jails are not yet supported. */
+		if (mp->mnt_cred->cr_prison != VPS_VPS(vps, prison0)) {
+			ERRMSG(ctx, "%s: unsupported mount by jail: "
+			    "mp=%p\n", __func__, mp);
+			mtx_unlock(&mountlist_mtx);
+			ctx->cpos = (caddr_t)o1;
+			free(vpsroot, M_TEMP);
+			return (EINVAL);
+		}
+#endif
+		o1 = vdo_create(ctx, VPS_DUMPOBJT_MOUNT, M_WAITOK);
+
+		vdm = vdo_space(ctx, sizeof(*vdm), M_NOWAIT);
+
+		if (vdm == NULL) {
+			vdo_discard(ctx, o1);
+			goto again;
+		}
+		strlcpy(vdm->mntfrom, mntfrom, sizeof(vdm->mntfrom));
+		strlcpy(vdm->mnton, mnton, sizeof(vdm->mnton));
+		strlcpy(vdm->fstype, fstype, sizeof(vdm->fstype));
+		vdm->flags = mp->mnt_flag;
+		/* Mounted from inside vps ? */
+		if (mp->mnt_cred->cr_vps == vps)
+			vdm->vpsmount = 1;
+		else
+			vdm->vpsmount = 0;
+
+		if (vdm->vpsmount) {
+			vdm->mnt_cred = mp->mnt_cred;
+
+			if (vps_snapshot_ucred(ctx, vps, mp->mnt_cred,
+			    M_NOWAIT)) {
+				mtx_unlock(&mountlist_mtx);
+				vdo_discard(ctx, o1);
+				goto again;
+			}
+		} else {
+			vdm->mnt_cred = NULL;
+		}
+
+		DBGS("%s: [%s] is in [%s]; vpsmount=%d vdm->mnt_cred=%p\n",
+		    __func__, mnton, vpsroot, vdm->vpsmount, vdm->mnt_cred);
+
+		/* Next. */
+		vdo_close(ctx);
+	}
+	mtx_unlock(&mountlist_mtx);
+
+	free(vpsroot, M_TEMP);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_vnet_route(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vnet *vnet)
+{
+	int error = 0;
+
+	vps_snapshot_vnet_route_table(ctx, vps, vnet, 0, AF_INET);
+	vps_snapshot_vnet_route_table(ctx, vps, vnet, 0, AF_INET6);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_vnet_route_one(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vnet *vnet, struct radix_node *rn)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_route *vdr;
+	struct vps_dump_vnet_sockaddr *vds;
+	struct rtentry *rt;
+
+	if ((o1 = vdo_create(ctx, VPS_DUMPOBJT_VNET_ROUTE, M_NOWAIT)) ==
+	    NULL)
+		return (ENOMEM);
+
+	if ((vdr = vdo_space(ctx, sizeof(*vdr), M_NOWAIT)) == NULL) {
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+
+	rt = (struct rtentry *)rn;
+
+	vdr->rt_have_mask = 0;
+	vdr->rt_have_gateway = 0;
+	vdr->rt_have_ifp = 0;
+	vdr->rt_have_ifa = 0;
+	vdr->rt_flags = rt->rt_flags;
+	vdr->rt_fibnum = rt->rt_fibnum;
+	vdr->rt_rmx.rmx_mtu = rt->rt_rmx.rmx_mtu;
+	vdr->rt_rmx.rmx_expire = rt->rt_rmx.rmx_expire;
+	vdr->rt_rmx.rmx_pksent = rt->rt_rmx.rmx_pksent;
+	vdr->rt_rmx.rmx_weight = rt->rt_rmx.rmx_weight;
+
+	if (1) {
+		if ((vds = vdo_space(ctx, sizeof(*vds), M_NOWAIT)) ==
+		    NULL) {
+			vdo_discard(ctx, o1);
+			return (ENOMEM);
+		}
+		vds->sa_len = rt_key(rt)->sa_len;
+		vds->sa_family = rt_key(rt)->sa_family;
+		memcpy(vds->sa_data, rt_key(rt)->sa_data, vds->sa_len);
+	}
+
+	if (rt_mask(rt) != NULL) {
+		if ((vds = vdo_space(ctx, sizeof(*vds), M_NOWAIT)) ==
+		    NULL) {
+			vdo_discard(ctx, o1);
+			return (ENOMEM);
+		}
+		vds->sa_len = rt_mask(rt)->sa_len;
+		vds->sa_family = rt_mask(rt)->sa_family;
+		memcpy(vds->sa_data, rt_mask(rt)->sa_data, vds->sa_len);
+		vdr->rt_have_mask = 1;
+	}
+
+	if (rt->rt_gateway != NULL) {
+		if ((vds = vdo_space(ctx, sizeof(*vds), M_NOWAIT)) ==
+		    NULL) {
+			vdo_discard(ctx, o1);
+			return (ENOMEM);
+		}
+		vds->sa_len = rt->rt_gateway->sa_len;
+		vds->sa_family = rt->rt_gateway->sa_family;
+		memcpy(vds->sa_data, rt->rt_gateway->sa_data, vds->sa_len);
+		vdr->rt_have_gateway = 1;
+	}
+
+	if (rt->rt_ifa != NULL) {
+		if ((vds = vdo_space(ctx, sizeof(*vds), M_NOWAIT)) ==
+		    NULL) {
+			vdo_discard(ctx, o1);
+			return (ENOMEM);
+		}
+		vds->sa_len = rt->rt_ifa->ifa_addr->sa_len;
+		vds->sa_family = rt->rt_ifa->ifa_addr->sa_family;
+		memcpy(vds->sa_data, rt->rt_ifa->ifa_addr->sa_data,
+		    vds->sa_len);
+		vdr->rt_have_ifa = 1;
+	}
+
+	DBGS("%s: rt=%p rt_flags=%p rt_refcnt=%d rt_fibnum=%d\n",
+	    __func__, rt, (void*)(intptr_t)rt->rt_flags,
+	    rt->rt_refcnt, rt->rt_fibnum);
+
+	vdo_close(ctx);
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_vnet_route_table(struct vps_snapst_ctx *ctx, struct vps *vps,
+	struct vnet *vnet, int fibnum, int af)
+{
+	struct radix_node_head *rnh;
+	struct radix_node **stack;
+	struct radix_node **sp;
+	struct radix_node *rn;
+	struct vps_dumpobj *o1;
+	int error = 0;
+
+	/*
+	 * Because of the small kernel stack we can't just use a recursive
+	 * function for dumping the routing tree.
+	 */
+	/*
+	 * I don't remember what I did but now I'm wondering why I
+	 * didn't use rn_walktree(), but there propably was a problem
+	 * involved.
+	 */
+
+	/* XXX determine required size or extend stack dynamically */
+	stack = malloc(sizeof(struct radix_node) * 0x100, M_TEMP, M_WAITOK);
+
+	/* If we couldn't allocate memory we start over from here. */
+ again:
+	memset(stack, 0, sizeof(struct radix_node) * 0x100);
+
+	o1 = vdo_create(ctx, VPS_DUMPOBJT_VNET_ROUTETABLE, M_WAITOK);
+
+	vdo_append(ctx, &fibnum, sizeof(fibnum), M_WAITOK);
+	vdo_append(ctx, &af, sizeof(af), M_WAITOK);
+
+	CURVNET_SET_QUIET(vnet);
+
+	rnh = rt_tables_get_rnh(fibnum, af);
+
+	DBGS("%s: fibnum=%d af=%d rnh=%p\n", __func__, fibnum, af, rnh);
+
+	RADIX_NODE_HEAD_RLOCK(rnh);
+
+	sp = &stack[0xff];
+	*sp = rnh->rnh_treetop;
+
+	while (sp <= &stack[0xff] && *sp) {
+
+		if (sp < &stack[0x02]) {
+			/* Stack is full. */
+			ERRMSG(ctx, "%s: stack is full, skipping remaining "
+			    "routing table entries !\n", __func__);
+			/* XXX raise error or better restart with a
+			   bigger stack ! */
+			break;
+		}
+
+		/* pop */
+		rn = *sp;
+		*sp = NULL;
+		sp++;
+
+		if (!(rn->rn_flags & RNF_ACTIVE))
+			continue;
+
+		if (rn->rn_bit < 0) {
+
+			if ((rn->rn_flags & RNF_ROOT) == 0) {
+				/* leaf */
+				error = vps_snapshot_vnet_route_one(ctx,
+				    vps, vnet, rn);
+				if (error == ENOMEM) {
+					vdo_discard(ctx, o1);
+					RADIX_NODE_HEAD_RUNLOCK(rnh);
+					goto again;
+				} else if (error != 0) {
+					goto out;
+				}
+			}
+			if ((rn = rn->rn_dupedkey)) {
+				/* push */
+				sp--;
+				*sp = rn;
+			}
+
+		} else {
+			/* tree forks */
+
+			/* push */
+			sp--;
+			*sp = rn->rn_right;
+
+			/* push */
+			sp--;
+			*sp = rn->rn_left;
+		}
+
+		/*
+		DBGS("stack: %p %p %p %p %p %p\n",
+		    stack[0xff], stack[0xfe], stack[0xfd],
+		    stack[0xfc], stack[0xfb], stack[0xfa]);
+		DBGS("stack position: %d\n", &stack[0xff] - sp);
+		*/
+	}
+
+ out:
+	RADIX_NODE_HEAD_RUNLOCK(rnh);
+
+	free(stack, M_TEMP);
+
+	CURVNET_RESTORE();
+
+	if (error)
+		vdo_discard(ctx, o1);
+	else
+		vdo_close(ctx);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_vnet_iface_ifaddr(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct ifaddr *ifa)
+{
+	struct vps_dump_vnet_ifaddr *vdifaddr;
+	struct vps_dump_vnet_sockaddr *vdsaddr;
+	struct vps_dump_vnet_inet6_lifetime *vdia6lt;
+	struct in6_ifaddr *ifaddr6p;
+
+	DBGS("%s: ifa=%p: \n", __func__, ifa);
+
+	vdo_create(ctx, VPS_DUMPOBJT_VNET_ADDR, M_WAITOK);
+
+	vdifaddr = vdo_space(ctx, sizeof(*vdifaddr), M_WAITOK);
+	memset(vdifaddr, 0, sizeof(*vdifaddr));
+
+	if (ifa->ifa_addr) {
+		DBGS ("%s: ifa->ifa_addr = %p\n",
+			__func__, ifa->ifa_addr);
+
+		vdifaddr->have_addr = 1;
+		vdsaddr = vdo_space(ctx, sizeof(*vdsaddr), M_WAITOK);
+		vdsaddr->sa_len = ifa->ifa_addr->sa_len;
+		vdsaddr->sa_family = ifa->ifa_addr->sa_family;
+		KASSERT(vdsaddr->sa_len <= sizeof(vdsaddr->sa_data),
+			("%s: sa_len too big\n", __func__));
+		memcpy(vdsaddr->sa_data, ifa->ifa_addr->sa_data,
+			vdsaddr->sa_len);
+	}
+	if (ifa->ifa_dstaddr) {
+		DBGS("%s: ifa->ifa_dstaddr = %p\n",
+			__func__, ifa->ifa_dstaddr);
+
+		vdifaddr->have_dstaddr = 1;
+		vdsaddr = vdo_space(ctx, sizeof(*vdsaddr), M_WAITOK);
+		vdsaddr->sa_len = ifa->ifa_dstaddr->sa_len;
+		vdsaddr->sa_family = ifa->ifa_dstaddr->sa_family;
+		KASSERT(vdsaddr->sa_len <= sizeof(vdsaddr->sa_data),
+			("%s: sa_len too big\n", __func__));
+		memcpy(vdsaddr->sa_data, ifa->ifa_dstaddr->sa_data,
+			vdsaddr->sa_len);
+	}
+	if (ifa->ifa_netmask) {
+		DBGS("%s: ifa->ifa_netmask = %p\n",
+			__func__, ifa->ifa_netmask);
+
+		vdifaddr->have_netmask = 1;
+		vdsaddr = vdo_space(ctx, sizeof(*vdsaddr), M_WAITOK);
+		vdsaddr->sa_len = ifa->ifa_netmask->sa_len;
+		vdsaddr->sa_family = ifa->ifa_netmask->sa_family;
+		KASSERT(vdsaddr->sa_len <= sizeof(vdsaddr->sa_data),
+			("%s: sa_len too big\n", __func__));
+		memcpy(vdsaddr->sa_data, ifa->ifa_netmask->sa_data,
+			vdsaddr->sa_len);
+
+	}
+
+	if (ifa->ifa_addr->sa_family == AF_INET6) {
+		ifaddr6p = ifatoia6(ifa);
+
+		vdia6lt = vdo_space(ctx, sizeof(*vdia6lt), M_WAITOK);
+		vdia6lt->ia6t_expire = ifaddr6p->ia6_lifetime.ia6t_expire;
+		vdia6lt->ia6t_preferred =
+		    ifaddr6p->ia6_lifetime.ia6t_preferred;
+		vdia6lt->ia6t_vltime = ifaddr6p->ia6_lifetime.ia6t_vltime;
+		vdia6lt->ia6t_pltime = ifaddr6p->ia6_lifetime.ia6t_pltime;
+	}
+
+	/* XXX - metric, ifa_flags, ... */
+
+	vdo_close(ctx);
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_vnet_iface(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vnet *vnet)
+{
+	struct ifnet *ifnetp;
+	struct ifaddr *ifaddrp;
+	struct vps_dump_vnet_ifnet *vdifnet;
+	int last_was_epair = 0;
+	int error = 0;
+
+	/* XXX locking */
+
+	CURVNET_SET_QUIET(vnet);
+	DBGS("%s: curvnet=%p\n", __func__, curvnet);
+
+	TAILQ_FOREACH(ifnetp, &V_ifnet, if_link) {
+
+  again:
+		vdo_create(ctx, VPS_DUMPOBJT_VNET_IFACE, M_WAITOK);
+
+		DBGS("%s: ifnetp=%p: if_xname=[%s]\n",
+				__func__, ifnetp, ifnetp->if_xname);
+
+		vdifnet = vdo_space(ctx, sizeof(*vdifnet), M_WAITOK);
+
+		strlcpy(vdifnet->if_dname, ifnetp->if_dname,
+		    sizeof(vdifnet->if_dname));
+		strlcpy(vdifnet->if_xname, ifnetp->if_xname,
+		    sizeof(vdifnet->if_xname));
+		vdifnet->if_dunit = ifnetp->if_dunit;
+		vdifnet->if_flags = ifnetp->if_flags;
+
+		TAILQ_FOREACH(ifaddrp, &ifnetp->if_addrhead, ifa_link) {
+			error = vps_snapshot_vnet_iface_ifaddr(ctx, vps,
+			    ifaddrp);
+			if (error != 0)
+				goto out;
+		}
+
+		if (last_was_epair == 0 &&
+		    strcmp(ifnetp->if_dname, "epair") == 0) {
+			/* The outside interface of the epair
+			   needs to be dumped too. */
+			ifnetp = ((struct epair_softc *)
+			    (ifnetp->if_softc))->oifp;
+			last_was_epair = 1;
+			vdo_close(ctx);
+			goto again;
+		} else
+			last_was_epair = 0;
+
+		vdo_close(ctx);
+	}
+
+  out:
+	CURVNET_RESTORE();
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_vnet(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vnet *vnet)
+{
+	struct vps_dump_vnet *vdvnet;
+	struct vps_dumpobj *o1;
+	int error = 0;
+
+	o1 = vdo_create(ctx, VPS_DUMPOBJT_VNET, M_WAITOK);
+
+	vdvnet = vdo_space(ctx, sizeof(*vdvnet), M_WAITOK);
+
+	vdvnet->orig_ptr = vnet;
+
+	if ((error = vps_snapshot_vnet_iface(ctx, vps, vnet)))
+		goto out;
+
+	if ((error = vps_snapshot_vnet_route(ctx, vps, vnet)))
+		goto out;
+
+  out:
+	if (error)
+		vdo_discard(ctx, o1);
+	else
+		vdo_close(ctx);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_ucred(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct ucred *cr, int how)
+{
+	struct vps_restore_obj *vbo;
+	struct vps_dumpobj *o1;
+	struct vps_dump_ucred *vdcr;
+	int size;
+	int i;
+
+	DBGS("%s: cr=%p\n", __func__, cr);
+
+	if (cr == NULL)
+		return (0);
+
+	SLIST_FOREACH(vbo, &ctx->obj_list, list)
+		if (vbo->type == VPS_DUMPOBJT_UCRED &&
+		    vbo->orig_ptr == cr)
+			return (0);
+
+	o1 = vdo_create(ctx, VPS_DUMPOBJT_UCRED, how);
+	if (o1 == NULL)
+		return (ENOMEM);
+
+	size = sizeof(*vdcr) + sizeof(vdcr->cr_groups[0]) * cr->cr_ngroups;
+	if ((vdcr = vdo_space(ctx, size, how)) == NULL) {
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+
+	vdcr->cr_uid = cr->cr_uid;
+	vdcr->cr_ruid = cr->cr_ruid;
+	vdcr->cr_svuid = cr->cr_svuid;
+	vdcr->cr_rgid = cr->cr_rgid;
+	vdcr->cr_svgid = cr->cr_svgid;
+	vdcr->cr_flags = cr->cr_flags;
+	vdcr->cr_ngroups = cr->cr_ngroups;
+	vdcr->cr_origptr = cr;
+	/*
+	if (cr->cr_prison == VPS_VPS(vps, prison0))
+		vdcr->cr_prison = NULL;
+	else
+	*/
+		vdcr->cr_prison = cr->cr_prison;
+	KASSERT(cr->cr_prison != VPS_VPS(vps0, prison0),
+		("%s: ucred=%p cr_prison == VPS_VPS(vps0, prison0)\n",
+		__func__, cr));
+	vdcr->cr_vps = cr->cr_vps;
+	vdcr->cr_ref = cr->cr_ref;
+
+	for (i = 0; i < cr->cr_ngroups; i++)
+		vdcr->cr_groups[i] = cr->cr_groups[i];
+
+	vdo_close(ctx);
+
+	/* Insert into list of dumped objects. */
+	vbo = malloc(sizeof(*vbo), M_TEMP, how);
+	if (vbo == NULL) {
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+	vbo->type = VPS_DUMPOBJT_UCRED;
+	vbo->orig_ptr = crhold(cr);
+	vbo->new_ptr = NULL;
+	SLIST_INSERT_HEAD(&ctx->obj_list, vbo, list);
+
+	DBGS("%s: cr=%p not seen before --> dumped\n", __func__, cr);
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_prison_one(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct prison *pr)
+{
+	struct vps_dump_prison *vdpr;
+	struct vps_dumpobj *o1;
+	struct vnode *rootvp;
+	caddr_t cpos;
+	int error = 0;
+	int i;
+
+	DBGS("%s: prison=%p pr_id=%d pr_name=[%s]\n",
+		__func__, pr, pr->pr_id, pr->pr_name);
+
+	mtx_assert(&pr->pr_mtx, MA_OWNED);
+
+	pr->pr_ref++;
+	prison_unlock(pr);
+
+	o1 = vdo_create(ctx, VPS_DUMPOBJT_PRISON, M_WAITOK);
+	vdpr = vdo_space(ctx, sizeof(*vdpr), M_WAITOK);
+
+	prison_lock(pr);
+	pr->pr_ref--;
+
+	vdpr->pr_origptr = pr;
+	if (pr == VPS_VPS(vps, prison0))
+		vdpr->pr_parent = NULL;
+	else
+		vdpr->pr_parent = pr->pr_parent;
+
+	vdpr->pr_id = pr->pr_id;
+	vdpr->pr_securelevel = pr->pr_securelevel;
+	vdpr->pr_enforce_statfs = pr->pr_enforce_statfs;
+	vdpr->pr_childmax = pr->pr_childmax;
+	vdpr->pr_ip4s = pr->pr_ip4s;
+	vdpr->pr_ip6s = pr->pr_ip6s;
+	vdpr->pr_flags = pr->pr_flags;
+	vdpr->pr_allow = pr->pr_allow;
+	strlcpy(vdpr->pr_name, pr->pr_name, sizeof(vdpr->pr_name));
+	strlcpy(vdpr->pr_path, pr->pr_path, sizeof(vdpr->pr_path));
+	vdpr->pr_root = NULL;
+
+	vdo_space(ctx, roundup(vdpr->pr_ip4s * 0x4, 8) +
+	    vdpr->pr_ip6s * 0x10, M_WAITOK);
+
+	cpos = vdpr->pr_ipdata;
+
+	for (i = 0; i < vdpr->pr_ip4s; i++) {
+		memcpy(cpos, &pr->pr_ip4[i], 0x4);
+		cpos += 0x4;
+	}
+	/*
+	if (((size_t)cpos % 8) != 0)
+		cpos += 4;
+	*/
+	cpos = (caddr_t)roundup((size_t)cpos, 8);
+
+	for (i = 0; i < vdpr->pr_ip6s; i++) {
+		memcpy(cpos, &pr->pr_ip6[i], 0x10);
+		cpos += 0x10;
+	}
+
+	/*
+	vps_print_ascii(vdpr->pr_ipdata, roundup(vdpr->pr_ip4s * 0x4, 8)
+		+ vdpr->pr_ip6s * 0x10);
+	*/
+
+	rootvp = pr->pr_root;
+	vref(rootvp);
+
+	pr->pr_ref++;
+	prison_unlock(pr);
+
+	if ((error = vps_snapshot_vnodepath(ctx, vps, rootvp, M_WAITOK))) {
+		vrele(rootvp);
+		DBGS("%s: vps_snapshot_vnodepath: %d\n", __func__, error);
+		goto out;
+	}
+	vrele(rootvp);
+
+	if (pr != VPS_VPS(vps, prison0) && pr->pr_flags & PR_VNET) {
+		KASSERT(pr->pr_vnet != vps->vnet,
+		    ("%s: prison=%p has PR_VNET but pr->pr_vnet == "
+		    "vps->vnet\n", __func__, pr));
+		if ((error = vps_snapshot_vnet(ctx, vps, pr->pr_vnet)))
+			goto out;
+	}
+
+ out:
+	prison_lock(pr);
+	pr->pr_ref--;
+ //out_locked:
+	if (error)
+		vdo_discard(ctx, o1);
+	else
+		vdo_close(ctx);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_prison(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct prison *ppr, *cpr;
+	int level, descend;
+	int error = 0;
+
+	sx_slock(&allprison_lock);
+
+	ppr = VPS_VPS(vps, prison0);
+
+	prison_lock(ppr);
+	error = vps_snapshot_prison_one(ctx, vps, ppr);
+	prison_unlock(ppr);
+
+	FOREACH_PRISON_DESCENDANT_LOCKED_LEVEL(ppr, cpr, descend, level) {
+		DBGS("%s: ppr=%p cpr=%p descend=%d level=%d\n",
+			__func__, ppr, cpr, descend, level);
+
+		/*
+		 * In case of error continue looping in order
+		 * to unlock prisons,
+		 * but don't dump anything anymore.
+		 */
+		if (error == 0)
+			error = vps_snapshot_prison_one(ctx, vps, cpr);
+	}
+
+	sx_sunlock(&allprison_lock);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_proc(struct vps_snapst_ctx *ctx, struct vps *vps)
+{
+	struct vps_restore_obj *vbo;
+	struct vps_dumpobj *o1;
+	struct vps_dump_pgrp *vdpg;
+	struct vps_dump_session *vdsess;
+	struct session *sess;
+	struct pgrp *pg;
+	struct proc *p, *p2;
+	int found;
+	int i;
+	int error = 0;
+
+	sx_slock(&VPS_VPS(vps, proctree_lock));
+
+	/* Dump all process groups (pgrp), and all sessions. */
+	for (i = 0; i <= VPS_VPS(vps, pgrphash); i++)
+		LIST_FOREACH(pg, &VPS_VPS(vps, pgrphashtbl)[i], pg_hash) {
+			DBGS("%s: pgrp=%p pg_id=%d pg_session=%p\n",
+			    __func__, pg, pg->pg_id, pg->pg_session);
+
+			o1 = vdo_create(ctx, VPS_DUMPOBJT_PGRP, M_WAITOK);
+
+			vdpg = vdo_space(ctx, sizeof(*vdpg), M_WAITOK);
+			vdpg->pg_id = pg->pg_id;
+			vdpg->pg_jobc = pg->pg_jobc;
+			vdpg->pg_session_id = pg->pg_session->s_sid;
+
+			/* XXX necessary ?
+			SLIST_INSERT_HEAD(ctx->dumpobj_list, o1, list);
+			*/
+
+			found = 0;
+			SLIST_FOREACH(vbo, &ctx->obj_list, list)
+				if (vbo->type == VPS_DUMPOBJT_SESSION &&
+				    vbo->orig_ptr == pg->pg_session)
+					found = 1;
+
+			if (found == 1) {
+				vdo_close(ctx); /* pgrp */
+				continue;
+			}
+
+			/* Dump session. */
+			vdo_create(ctx, VPS_DUMPOBJT_SESSION, M_WAITOK);
+
+			sess = pg->pg_session;
+			vdsess = vdo_space(ctx, sizeof(*vdsess), M_WAITOK);
+			vdsess->s_sid = sess->s_sid;
+			vdsess->s_count = sess->s_count;
+			vdsess->s_leader_id = (sess->s_leader != NULL) ?
+				sess->s_leader->p_pid : 0;
+			vdsess->s_have_ttyvp = (sess->s_ttyvp != NULL) ?
+			    1 : 0;
+			KASSERT(sizeof(sess->s_login) <= 
+			    sizeof(vdsess->s_login),
+			    ("%s: sess->s_login too big\n", __func__));
+			memcpy(vdsess->s_login, sess->s_login,
+			    sizeof(sess->s_login));
+
+			if (sess->s_ttyvp)
+				vps_snapshot_vnodepath(ctx, vps,
+				    sess->s_ttyvp, M_WAITOK);
+
+			vdo_close(ctx);
+
+			/* Insert into list of dumped objects. */
+			vbo = malloc(sizeof(*vbo), M_TEMP, M_WAITOK);
+			vbo->type = VPS_DUMPOBJT_SESSION;
+			vbo->orig_ptr = pg->pg_session;
+			vbo->new_ptr = NULL;
+			SLIST_INSERT_HEAD(&ctx->obj_list, vbo, list);
+
+			DBGS("%s: dump session %p/%d: s_ttyvp=%p s_ttyp=%p"
+			    "\n", __func__, pg->pg_session, sess->s_sid,
+			    sess->s_ttyvp, sess->s_ttyp);
+
+			vdo_close(ctx); /* pgrp */
+		}
+
+	sx_sunlock(&VPS_VPS(vps, proctree_lock));
+
+	sx_slock(&VPS_VPS(vps, allproc_lock));
+
+	LIST_FOREACH_SAFE(p, &VPS_VPS(vps, allproc), p_list, p2) {
+		if ((error = vps_snapshot_proc_one(ctx, vps, p))) {
+			ERRMSG(ctx, "%s: vps_snapshot_proc_one(p=%p) "
+			    "returned error\n", __func__, p);
+			goto out;
+		}
+	}
+
+ out:
+	sx_sunlock(&VPS_VPS(vps, allproc_lock));
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_sysentvec(struct vps_snapst_ctx *ctx, struct vps *vps,
+		struct proc *p)
+{
+	struct vps_dump_sysentvec *vds;
+	struct sysentvec *sv;
+	long svtype;
+
+	sv = p->p_sysent;
+
+        if (vps_md_snapshot_sysentvec(sv, &svtype) != 0) {
+		ERRMSG(ctx, "%s: proc=%p/%u unknown sysentvec %p\n",
+		    __func__, p, p->p_pid, sv);
+		return (EINVAL);
+        }
+
+	vdo_create(ctx, VPS_DUMPOBJT_SYSENTVEC, M_WAITOK);
+
+	vds = vdo_space(ctx, sizeof(*vds), M_WAITOK);
+	vds->sv_type = svtype;
+
+	vdo_close(ctx);
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_pipe(struct vps_snapst_ctx *ctx, struct vps *vps,
+		struct pipe *pi)
+{
+	struct vps_restore_obj *vbo;
+	struct vps_dump_pipe *vdp;
+	struct pipepair *pp;
+	int error = 0;
+	char f_dump;
+
+	vdo_create(ctx, VPS_DUMPOBJT_PIPE, M_WAITOK);
+
+	pp = pi->pipe_pair;
+
+	DBGS("%s: pipe=%p pipepair=%p\n", __func__, pi, pp);
+
+	/* Check in list of dumped objects, if already dumped. */
+	f_dump = 1;
+	SLIST_FOREACH(vbo, &ctx->obj_list, list)
+		if (vbo->type == VPS_DUMPOBJT_PIPE &&
+		    vbo->spare[0] == pp)
+			f_dump = 0;
+
+#if 0
+//delete
+	/* Save the pointers. */
+	vdp.have_dumped_pipe = f_dump;
+	vdp.thisend = pi;
+	vdp.pair = pp;
+	vdp.rpipe = &pp->pp_rpipe;
+	vdp.wpipe = &pp->pp_wpipe;
+
+	vdo_append(ctx, &vdp, sizeof(vdp), M_WAITOK);
+#endif
+
+	vdp = vdo_space(ctx, sizeof(*vdp), M_WAITOK);
+
+	vdp->pi_have_dumped_pipe = f_dump;
+	vdp->pi_localend = pi;
+	vdp->pi_pair = pp;
+	vdp->pi_rpipe = &pp->pp_rpipe;
+	vdp->pi_wpipe = &pp->pp_wpipe;
+
+	if (f_dump) {
+		DBGS("%s: dumping ... \n", __func__);
+
+		/* not used by restore function
+		vdo_append(ctx, pp, sizeof(*pp), M_WAITOK);
+		*/
+
+		/* XXX dump buffered data if any */
+
+		if (pp->pp_rpipe.pipe_buffer.cnt > 0)
+			DBGS("%s: has data: rpipe->pipe_buffer.cnt=%u\n",
+			    __func__, pp->pp_rpipe.pipe_buffer.cnt);
+		if (pp->pp_rpipe.pipe_map.cnt > 0)
+			DBGS("%s: has data: rpipe->pipe_map.cnt=%zu\n",
+			    __func__, pp->pp_rpipe.pipe_map.cnt);
+		if (pp->pp_wpipe.pipe_buffer.cnt > 0)
+			DBGS("%s: has data: wpipe->pipe_buffer.cnt=%u\n",
+			    __func__, pp->pp_wpipe.pipe_buffer.cnt);
+		if (pp->pp_wpipe.pipe_map.cnt > 0)
+			DBGS("%s: has data: wpipe->pipe_map.cnt=%zu\n",
+			    __func__, pp->pp_wpipe.pipe_map.cnt);
+
+		/* Insert into list of dumped objects. */
+		vbo = malloc(sizeof(*vbo), M_TEMP, M_WAITOK);
+		vbo->type = VPS_DUMPOBJT_PIPE;
+		vbo->orig_ptr = pi;
+		vbo->new_ptr = NULL;
+		vbo->spare[0] = pp;
+		SLIST_INSERT_HEAD(&ctx->obj_list, vbo, list);
+	}
+
+	vdo_close(ctx);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_mbufchain(struct vps_snapst_ctx *ctx, struct vps *vps,
+		struct mbuf *m)
+{
+	struct vps_dump_mbufchain *vdmc;
+	struct vps_dump_mbuf *vdmb;
+	struct vps_dumpobj *o1;
+	struct mbuf *m2;
+	int error = 0;
+	int i;
+
+	if ((o1 = vdo_create(ctx, VPS_DUMPOBJT_MBUFCHAIN,
+	    M_NOWAIT)) == NULL)
+		return (ENOMEM);
+
+	if ((vdmc = vdo_space(ctx, sizeof(*vdmc), M_NOWAIT)) == NULL) {
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+
+	vdmc->mc_mbcount = 0;
+
+	m2 = m;
+
+	/* Count the chain length. */
+	while (m2) {
+		m2 = m2->m_next;
+		vdmc->mc_mbcount++;
+	}
+
+	/* Actually dump a chain. */
+	m2 = m;
+	for (i = 0; i < vdmc->mc_mbcount; i++) {
+
+		if ((vdmb = vdo_space(ctx, sizeof(*vdmb), M_NOWAIT)) == 
+		    NULL) {
+			vdo_discard(ctx, o1);
+			return (ENOMEM);
+		}
+		vdmb->mb_orig_ptr = m2;
+		vdmb->mb_type = m2->m_type;
+		vdmb->mb_len = m2->m_len;
+		vdmb->mb_flags = m2->m_flags;
+		vdmb->mb_have_dat = 0;
+		vdmb->mb_have_ext = 0;
+		vdmb->mb_have_data = 0;
+		vdmb->mb_payload_size = 0;
+
+		DBGS("%s: m=%p type=%d flags=%d len=%d next=%p "
+		    "nextpkt=%p\n", __func__, m2, m2->m_type,
+		    m2->m_flags, m2->m_len, m2->m_next, m2->m_nextpkt);
+
+		/* Force EXT_PACKET --> EXT_CLUSTER */
+		if (m2->m_flags & M_EXT && m2->m_ext.ext_type == EXT_PACKET)
+			//dm2->m_ext.ext_type = EXT_CLUSTER;
+			;
+
+		if ((m2->m_flags & M_EXT) == 0) {
+
+			//vps_print_ascii(m2->m_dat, MLEN);
+
+			vdmb->mb_have_dat = 1;
+			vdmb->mb_payload_size = MLEN;
+			if (vdo_append(ctx, m2->m_dat, roundup(MLEN, 8),
+			    M_NOWAIT)) {
+				vdo_discard(ctx, o1);
+				return (ENOMEM);
+			}
+			if (m2->m_data != NULL) {
+				vdmb->mb_have_data = 1;
+				vdmb->mb_data_off = m2->m_data - m2->m_dat;
+			}
+
+		} else if (m2->m_flags & M_EXT) {
+
+			DBGS("%s: M_EXT ext_type=%d ext_size=%u\n",
+			    __func__, m2->m_ext.ext_type,
+			    m2->m_ext.ext_size);
+
+			if (m2->m_ext.ext_type != EXT_CLUSTER &&
+				m2->m_ext.ext_type != EXT_JUMBOP &&
+				m2->m_ext.ext_type != EXT_JUMBO9 &&
+				m2->m_ext.ext_type != EXT_JUMBO16 &&
+				m2->m_ext.ext_type != EXT_PACKET) {
+				ERRMSG(ctx, "%s: DON'T KNOW HOW TO HANDLE "
+				    "MBUF M_EXT TYPE!\n", __func__);
+				return (EINVAL);
+			}
+
+			/* checksum */
+			{
+				u_int32_t sum = 0, i;
+
+				for (i = 0; i < m2->m_ext.ext_size; i++)
+					sum += (u_char)m2->m_ext.ext_buf[i];
+				DBGS("%s: checksum=%08x\n", __func__, sum);
+
+				vdmb->mb_checksum = sum;
+			}
+
+			if (vdo_append(ctx, m2->m_ext.ext_buf,
+			    roundup(m2->m_ext.ext_size, 8), M_NOWAIT)) {
+				vdo_discard(ctx, o1);
+				return (ENOMEM);
+			}
+			vdmb->mb_have_ext = 1;
+			vdmb->mb_payload_size = m2->m_ext.ext_size;
+			if (m2->m_data != NULL) {
+				vdmb->mb_have_data = 1;
+				vdmb->mb_data_off = m2->m_data -
+				    m2->m_ext.ext_buf;
+			}
+
+			/*
+			vps_print_ascii(m2->m_ext.ext_buf,
+			    m2->m_ext.ext_size);
+			*/
+
+		} else {
+			ERRMSG(ctx, "%s: DON'T KNOW HOW TO HANDLE MBUF!\n",
+			    __func__);
+			return (EINVAL);
+		}
+		if (m2->m_flags & M_PKTHDR) {
+			DBGS("%s: m2=%p header=%p rcvif=%p \n",
+			    __func__, m2, m2->m_pkthdr.header,
+			    m2->m_pkthdr.rcvif);
+		}
+
+		DBGS("%s: vdmb: mb_have_dat=%d mb_have_ext=%d "
+		    "mb_payload_size=%u\n", __func__, vdmb->mb_have_dat,
+		    vdmb->mb_have_ext, vdmb->mb_payload_size);
+
+		m2 = m2->m_next;
+	}
+
+	vdo_close(ctx);
+
+	DBGS("%s: %d mbufs dumped\n", __func__, vdmc->mc_mbcount);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_sockbuf(struct vps_snapst_ctx *ctx, struct vps *vps,
+		struct sockbuf *sb)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_sockbuf *vdsb;
+	int error = 0;
+
+	if (sb->sb_upcall != NULL) {
+		ERRMSG(ctx, "%s: sb->sb_upcall != NULL\n", __func__);
+		return (EINVAL);
+	}
+
+	if ((o1 = vdo_create(ctx, VPS_DUMPOBJT_SOCKBUF, M_NOWAIT)) == NULL)
+		return (ENOMEM);
+
+	if ((vdsb = vdo_space(ctx, sizeof(*vdsb), M_NOWAIT)) == NULL) {
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+
+	vdsb->sb_mb = sb->sb_mb;
+	vdsb->sb_mbtail = sb->sb_mbtail;
+	vdsb->sb_lastrecord = sb->sb_lastrecord;
+	vdsb->sb_sndptr = sb->sb_sndptr;
+	vdsb->sb_state = sb->sb_state;
+	vdsb->sb_flags = sb->sb_flags;
+	vdsb->sb_sndptroff = sb->sb_sndptroff;
+	vdsb->sb_cc = sb->sb_cc;
+	vdsb->sb_hiwat = sb->sb_hiwat;
+	vdsb->sb_mbcnt = sb->sb_mbcnt;
+	vdsb->sb_mcnt = sb->sb_mcnt;
+	vdsb->sb_ccnt = sb->sb_ccnt;
+	vdsb->sb_mbmax = sb->sb_mbmax;
+	vdsb->sb_ctl = sb->sb_ctl;
+	vdsb->sb_lowat = sb->sb_lowat;
+	vdsb->sb_timeo = sb->sb_timeo;
+
+	if (sb->sb_mb) {
+		if ((error = vps_snapshot_mbufchain(ctx, vps, sb->sb_mb))) {
+			vdo_discard(ctx, o1);
+			return (error);
+		}
+	}
+
+	DBGS("%s: sb=%p sb_mb=%p sb_mbtail=%p sb_lastrecord=%p "
+	    "sb_sndptr=%p\n", __func__, sb, sb->sb_mb, sb->sb_mbtail,
+	    sb->sb_lastrecord, sb->sb_sndptr);
+	DBGS("%s: sb=%p sb->sb_cc=%u sb->sb_mb=%p sb->sb_sndptroff=%u\n",
+	    __func__, sb, sb->sb_cc, sb->sb_mb, sb->sb_sndptroff);
+
+	vdo_close(ctx);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_socket_unix(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct socket *so)
+{
+	struct vps_dump_vnet_sockaddr *vdsaddr;
+	struct vps_dump_unixpcb *vdunpcb;
+	struct unpcb *un_pcb;
+	int error;
+	int i;
+
+	error = 0;
+	un_pcb = (struct unpcb *)so->so_pcb;
+
+	if ((vdunpcb = vdo_space(ctx, sizeof(*vdunpcb),
+	    M_NOWAIT)) == NULL) {
+		error = ENOMEM;
+		goto drop;
+	}
+
+	vdunpcb->unp_have_conn = 0;
+	vdunpcb->unp_have_addr = 0;
+	vdunpcb->unp_have_vnode = 0;
+	vdunpcb->unp_conn_socket = NULL;
+
+	vdunpcb->unp_socket = un_pcb->unp_socket;
+	vdunpcb->unp_flags = un_pcb->unp_flags;
+	vdunpcb->unp_cc = un_pcb->unp_cc;
+	vdunpcb->unp_mbcnt = un_pcb->unp_mbcnt;
+
+	vdunpcb->unp_peercred.cr_uid = un_pcb->unp_peercred.cr_uid;
+	vdunpcb->unp_peercred.cr_ngroups =
+	    min(un_pcb->unp_peercred.cr_ngroups, 16);
+	for (i = 0; i < vdunpcb->unp_peercred.cr_ngroups; i++)
+		vdunpcb->unp_peercred.cr_groups[i] =
+			un_pcb->unp_peercred.cr_groups[i];
+
+	if (un_pcb->unp_conn != NULL) {
+		vdunpcb->unp_have_conn = 1;
+		vdunpcb->unp_conn_socket = un_pcb->unp_conn->unp_socket;
+	}
+
+	if (un_pcb->unp_addr != NULL) {
+		vdunpcb->unp_have_addr = 1;
+		if ((vdsaddr = vdo_space(ctx, sizeof(*vdsaddr),
+		    M_NOWAIT)) == NULL) {
+			error = ENOMEM;
+			goto drop;
+		}
+		vdsaddr->sa_len = un_pcb->unp_addr->sun_len;
+		vdsaddr->sa_family = un_pcb->unp_addr->sun_family;
+		memcpy(vdsaddr->sa_data, un_pcb->unp_addr->sun_path,
+		    vdsaddr->sa_len);
+	}
+
+	if (un_pcb->unp_vnode != NULL) {
+		vdunpcb->unp_have_vnode = 1;
+		/*
+		if ((error = vps_snapshot_vnodepath(ctx, vps,
+		    un_pcb->unp_vnode, M_NOWAIT)))
+			goto drop;
+		*/
+	}
+
+  drop:
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_socket_inet(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct socket *so)
+{
+	struct vps_dump_inetpcb *vdinpcb;
+	struct vps_dump_udppcb *vdudpcb;
+	struct vps_dump_tcppcb *vdtcpcb;
+	struct inpcb *inpcb;
+	struct udpcb *udp_pcb;
+	struct tcpcb *tcp_pcb;
+	int error;
+
+	error = 0;
+	inpcb = (struct inpcb *)so->so_pcb;
+
+	if ((vdinpcb = vdo_space(ctx, sizeof(*vdinpcb),
+	    M_NOWAIT)) == NULL) {
+		error = ENOMEM;
+		goto drop;
+	}
+
+	vdinpcb->inp_vflag = inpcb->inp_vflag;
+	vdinpcb->inp_flags = inpcb->inp_flags;
+	vdinpcb->inp_flags2 = inpcb->inp_flags2;
+	vdinpcb->inp_ip_p = inpcb->inp_ip_p;
+	vdinpcb->inp_have_ppcb = 0;
+
+	vdinpcb->inp_inc.inc_flags = inpcb->inp_inc.inc_flags;
+	vdinpcb->inp_inc.inc_len = inpcb->inp_inc.inc_len;
+	vdinpcb->inp_inc.inc_fibnum = inpcb->inp_inc.inc_fibnum;
+	vdinpcb->inp_inc.ie_fport = inpcb->inp_inc.inc_ie.ie_fport;
+	vdinpcb->inp_inc.ie_lport = inpcb->inp_inc.inc_ie.ie_lport;
+
+	if (vdinpcb->inp_vflag & INP_IPV6) {
+		memcpy(vdinpcb->inp_inc.ie_ufaddr,
+		    &inpcb->inp_inc.inc6_faddr, 0x10);
+		memcpy(vdinpcb->inp_inc.ie_uladdr,
+		    &inpcb->inp_inc.inc6_laddr, 0x10);
+	} else {
+		memcpy(vdinpcb->inp_inc.ie_ufaddr,
+		    &inpcb->inp_inc.inc_faddr, 0x4);
+		memcpy(vdinpcb->inp_inc.ie_uladdr,
+		    &inpcb->inp_inc.inc_laddr, 0x4);
+	}
+
+	if (inpcb->inp_ppcb == NULL)
+		return (0);
+
+	vdinpcb->inp_have_ppcb = 1;
+
+	INP_INFO_RLOCK(inpcb->inp_pcbinfo);
+	INP_RLOCK(inpcb);
+
+	/* inpcb->inp_ip_p seems to be 0 and only used for raw ip
+	   and divert sockets! */
+	switch (so->so_proto->pr_protocol) {
+	case IPPROTO_TCP:
+		DBGS("%s: IPPROTO_TCP\n", __func__);
+		tcp_pcb = (struct tcpcb *)inpcb->inp_ppcb;
+		if ((vdtcpcb = vdo_space(ctx, sizeof(*vdtcpcb),
+		    M_NOWAIT)) == NULL) {
+			INP_RUNLOCK(inpcb);
+			INP_INFO_RUNLOCK(inpcb->inp_pcbinfo);
+			error = ENOMEM;
+			goto drop;
+		}
+		vdtcpcb->t_state = tcp_pcb->t_state;
+		vdtcpcb->t_flags = tcp_pcb->t_flags;
+		vdtcpcb->snd_una = tcp_pcb->snd_una;
+		vdtcpcb->snd_max = tcp_pcb->snd_max;
+		vdtcpcb->snd_nxt = tcp_pcb->snd_nxt;
+		vdtcpcb->snd_up = tcp_pcb->snd_up;
+		vdtcpcb->snd_wl1 = tcp_pcb->snd_wl1;
+		vdtcpcb->snd_wl2 = tcp_pcb->snd_wl2;
+		vdtcpcb->iss = tcp_pcb->iss;
+		vdtcpcb->irs = tcp_pcb->irs;
+		vdtcpcb->rcv_nxt = tcp_pcb->rcv_nxt;
+		vdtcpcb->rcv_adv = tcp_pcb->rcv_adv;
+		vdtcpcb->rcv_wnd = tcp_pcb->rcv_wnd;
+		vdtcpcb->rcv_up = tcp_pcb->rcv_up;
+		vdtcpcb->snd_wnd = tcp_pcb->snd_wnd;
+		vdtcpcb->snd_cwnd = tcp_pcb->snd_cwnd;
+		vdtcpcb->snd_ssthresh = tcp_pcb->snd_ssthresh;
+		break;
+	case IPPROTO_UDP:
+		DBGS("%s: IPPROTO_UDP\n", __func__);
+		udp_pcb = (struct udpcb *)inpcb->inp_ppcb;
+		if (udp_pcb->u_tun_func != NULL) {
+			ERRMSG(ctx, "%s: udp socket with tunneling "
+			    "function set, skipping !\n", __func__);
+			INP_RUNLOCK(inpcb);
+			INP_INFO_RUNLOCK(inpcb->inp_pcbinfo);
+			error = EINVAL;
+			goto drop;
+		}
+		if ((vdudpcb = vdo_space(ctx, sizeof(*vdudpcb),
+		    M_NOWAIT)) == NULL) {
+			INP_RUNLOCK(inpcb);
+			INP_INFO_RUNLOCK(inpcb->inp_pcbinfo);
+			error = ENOMEM;
+			goto drop;
+		}
+		vdudpcb->u_have_tun_func = 0;
+		vdudpcb->u_flags = udp_pcb->u_flags;
+		break;
+	case IPPROTO_ICMP:
+	case IPPROTO_RAW:
+		/* Nothing to do. */
+		break;
+	default:
+		ERRMSG(ctx, "%s: unhandled IPPROTO %d\n",
+			__func__, inpcb->inp_ip_p);
+		error = EINVAL;
+		INP_RUNLOCK(inpcb);
+		INP_INFO_RUNLOCK(inpcb->inp_pcbinfo);
+		goto drop;
+		break;
+	}
+	INP_INFO_RUNLOCK(inpcb->inp_pcbinfo);
+	INP_RUNLOCK(inpcb);
+
+  drop:
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_socket(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct socket *so)
+{
+	struct vps_restore_obj *vbo;
+	struct vps_dumpobj *o1;
+	struct vps_dump_socket *vds;
+	struct socket *so2;
+	int error = 0;
+
+	SLIST_FOREACH(vbo, &ctx->obj_list, list)
+		if (vbo->type == VPS_DUMPOBJT_SOCKET &&
+		    vbo->orig_ptr == so) {
+			DBGS("%s: socket=%p already dumped\n",
+			    __func__, so);
+			return (0);
+	}
+
+	/* If we couldn't allocate memory we try again. */
+  again:
+
+	sblock(&so->so_snd, SBL_WAIT | SBL_NOINTR);
+	sblock(&so->so_rcv, SBL_WAIT | SBL_NOINTR);
+	SOCKBUF_LOCK(&so->so_snd);
+	SOCKBUF_LOCK(&so->so_rcv);
+
+	if ((o1 = vdo_create(ctx, VPS_DUMPOBJT_SOCKET, M_NOWAIT)) == NULL) {
+		error = ENOMEM;
+		goto drop;
+	}
+
+	if ((vds = vdo_space(ctx, sizeof(*vds), M_NOWAIT)) == NULL) {
+		error = ENOMEM;
+		goto drop;
+	}
+
+	vds->so_family = so->so_proto->pr_domain->dom_family;
+	vds->so_protocol = so->so_proto->pr_protocol;
+	vds->so_type = so->so_proto->pr_type;
+
+	vds->so_options = so->so_options;
+	vds->so_state = so->so_state;
+	vds->so_qlimit = so->so_qlimit;
+	vds->so_qstate = so->so_qstate;
+	vds->so_qlen = so->so_qlen;
+	vds->so_incqlen = so->so_incqlen;
+	vds->so_cred = so->so_cred;
+	vds->so_orig_ptr = so;
+
+	DBGS("%s: socket protocol family=%d protocol=%d type=%d\n",
+	    __func__, vds->so_family, vds->so_protocol, vds->so_type);
+
+	switch (vds->so_family) {
+		case PF_UNIX:
+			error = vps_snapshot_socket_unix(ctx, vps, so);
+			if (error != 0)
+				goto drop;
+			break;
+		case PF_INET:
+		case PF_INET6:
+			error = vps_snapshot_socket_inet(ctx, vps, so);
+			if (error != 0)
+				goto drop;
+			break;
+
+		default:
+			ERRMSG(ctx, "%s: unhandled protocol family %d\n",
+			    __func__, vds->so_family);
+			error = EINVAL;
+			goto drop;
+			break;
+	}
+
+	if ((error = vps_snapshot_ucred(ctx, vps, so->so_cred, M_NOWAIT)))
+		goto drop;
+	if ((error = vps_snapshot_sockbuf(ctx, vps, &so->so_rcv)))
+		goto drop;
+	if ((error = vps_snapshot_sockbuf(ctx, vps, &so->so_snd)))
+		goto drop;
+
+
+	SOCKBUF_UNLOCK(&so->so_rcv);
+	SOCKBUF_UNLOCK(&so->so_snd);
+	sbunlock(&so->so_rcv);
+	sbunlock(&so->so_snd);
+
+	vdo_close(ctx);
+
+	/* Sockets that are on the accept queue of this socket. */
+	if (so->so_qlen > 0 || so->so_incqlen > 0) {
+		DBGS("%s: so=%p so_qlen=%d so_incqlen=%d\n",
+			__func__, so, so->so_qlen, so->so_incqlen);
+		TAILQ_FOREACH(so2, &so->so_comp, so_list) {
+			DBGS("%s: so_comp: so2=%p \n", __func__, so2);
+			if ((error = vps_snapshot_socket(ctx, vps, so2)))
+				goto drop;
+		}
+		TAILQ_FOREACH(so2, &so->so_incomp, so_list) {
+			DBGS("%s: so_incomp: so2=%p \n", __func__, so2);
+			if ((error = vps_snapshot_socket(ctx, vps, so2)))
+				goto drop;
+		}
+	}
+
+	/* Insert into list of dumped objects. */
+	vbo = malloc(sizeof(*vbo), M_TEMP, M_WAITOK);
+	vbo->type = VPS_DUMPOBJT_SOCKET;
+	vbo->orig_ptr = so;
+	vbo->new_ptr = NULL;
+	SLIST_INSERT_HEAD(&ctx->obj_list, vbo, list);
+
+	DBGS("%s: socket=%p not seen before --> dumped\n", __func__, so);
+
+	return (0);
+
+  drop:
+	SOCKBUF_UNLOCK(&so->so_rcv);
+	SOCKBUF_UNLOCK(&so->so_snd);
+	sbunlock(&so->so_rcv);
+	sbunlock(&so->so_snd);
+	/* SOCK_UNLOCK(so); */
+
+	DBGS("%s: error = %d\n", __func__, error);
+	if (o1 != NULL)
+		vdo_discard(ctx, o1);
+
+	if (error == ENOMEM)
+		goto again;
+
+	return (error);
+}
+
+#if 0
+/*
+ * Mostly copied from kern_linkat().
+ *
+ * Relink a file that is already unlinked but still in use by some process.
+ */
+__attribute__((noinline, unused))
+static int
+vps_snapshot_vnode_relink(struct vps_snapst_ctx *ctx, struct vps *vps,
+	struct vnode *vp, const char *path, int fd, int wait)
+{
+	struct mount *mp;
+	struct nameidata nd;
+	int lvfslocked;
+	int error;
+
+	bwillwrite();
+	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
+		return (error);
+	}
+	NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE2,
+		UIO_SYSSPACE, path, fd, curthread);
+	if ((error = namei(&nd)) == 0) {
+		lvfslocked = NDHASGIANT(&nd);
+		if (nd.ni_vp != NULL) {
+			if (nd.ni_dvp == nd.ni_vp)
+				vrele(nd.ni_dvp);
+			else
+				vput(nd.ni_dvp);
+			vrele(nd.ni_vp);
+			error = EEXIST;
+		} else if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY))
+		    == 0) {
+			error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
+			VOP_UNLOCK(vp, 0);
+			vput(nd.ni_dvp);
+		}
+		NDFREE(&nd, NDF_ONLY_PNBUF);
+		VFS_UNLOCK_GIANT(lvfslocked);
+	}
+	vn_finished_write(mp);
+
+	if (error)
+		DBGS("%s: error: %d\n", __func__, error);
+
+	return (error);
+}
+#endif
+
+#define KQ_LOCK(kq) do {                                                \
+        mtx_lock(&(kq)->kq_lock);                                       \
+} while (0)
+
+#define KQ_UNLOCK(kq) do {                                                \
+        mtx_unlock(&(kq)->kq_lock);                                       \
+} while (0)
+
+#if 0
+struct kevent {
+        uintptr_t       ident;          /* identifier for this event */
+        short           filter;         /* filter for event */
+        u_short         flags;
+        u_int           fflags;
+        intptr_t        data;
+        void            *udata;         /* opaque user data identifier */
+};
+#endif
+
+__attribute__((noinline, unused))
+static int
+vps_snapshot_kqueue(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct kqueue *kq)
+{
+	struct vps_dump_knote *vdkn;
+	struct kevent *kev;
+	struct knote *kn;
+	int error;
+	int i;
+
+	error = 0;
+
+	vdo_create(ctx, VPS_DUMPOBJT_KQUEUE, M_WAITOK);
+
+	KQ_LOCK(kq);
+	kq->kq_refcnt++;
+
+	for (i = 0; i < kq->kq_knlistsize; i++) {
+		/*DBGS("%s: kqueue=%p i=%d\n", __func__, kq, i);*/
+		SLIST_FOREACH(kn, &kq->kq_knlist[i], kn_link) {
+			DBGS("%s: knote=%p kn_status=%08x\n",
+				__func__, kn, kn->kn_status);
+			if (kn != NULL && (kn->kn_status & KN_INFLUX) ==
+			    KN_INFLUX) {
+				DBGS("%s: kn->kn_status & KN_INFLUX\n",
+				    __func__);
+				/* XXX have to sleep here */
+			}
+			kev = &kn->kn_kevent;
+			DBGS("kevent: ident  = 0x%016zx\n",
+			    (size_t)kev->ident);
+			DBGS("kevent: filter = 0x%04hx\n",
+			    kev->filter);
+			DBGS("kevent: flags  = 0x%04hx\n",
+			    kev->flags);
+			DBGS("kevent: fflags = 0x%08x\n",
+			    kev->fflags);
+			DBGS("kevent: data   = 0x%016zx\n",
+			    (size_t)kev->data);
+			DBGS("kevent: udata  = 0x%016lx\n",
+			    (long unsigned int)kev->udata);
+
+			vdo_create(ctx, VPS_DUMPOBJT_KNOTE, M_WAITOK);
+
+			vdkn = vdo_space(ctx, sizeof(*vdkn), M_WAITOK);
+			vdkn->kn_status = kn->kn_status;
+			vdkn->ke_ident = kev->ident;
+			vdkn->ke_filter = kev->filter;
+			vdkn->ke_flags = kev->flags;
+			vdkn->ke_fflags = kev->fflags;
+			vdkn->ke_data = kev->data;
+			vdkn->ke_udata = kev->udata;
+
+			vdo_close(ctx);
+		}
+	}
+
+        kq->kq_refcnt--;
+	if (kq->kq_refcnt == 1)
+		wakeup(&kq->kq_refcnt);
+	KQ_UNLOCK(kq);
+
+	vdo_close(ctx);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_fdset(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p)
+{
+	struct vps_restore_obj *vbo;
+	struct vps_dump_filedesc *vdfd;
+	struct vps_dump_file *vdf;
+	struct filedesc *fdp;
+	struct file *fp;
+	int error = 0;
+	int found;
+	int i;
+
+	fdp = p->p_fd;
+
+	SLIST_FOREACH(vbo, &ctx->obj_list, list)
+		if (vbo->type == VPS_DUMPOBJT_FDSET &&
+		    vbo->orig_ptr == fdp)
+			break;
+
+	if (vbo != NULL) {
+		DBGS("%s: fdset %p already dumped\n", __func__, fdp);
+		return (0);
+	}
+
+	DBGS("%s: dumping fdset %p\n", __func__, fdp);
+
+	FILEDESC_XLOCK(fdp);
+
+	vdo_create(ctx, VPS_DUMPOBJT_FDSET, M_WAITOK);
+
+	vdfd = vdo_space(ctx, sizeof(*vdfd), M_WAITOK);
+
+	vdfd->fd_orig_ptr = fdp;
+	vdfd->fd_nfiles = fdp->fd_nfiles;
+	vdfd->fd_have_cdir = (fdp->fd_cdir != NULL) ? 1 : 0;
+	vdfd->fd_have_rdir = (fdp->fd_rdir != NULL) ? 1 : 0;
+	vdfd->fd_have_jdir = (fdp->fd_jdir != NULL) ? 1 : 0;
+
+	vdo_space(ctx, sizeof(vdfd->fd_entries[0]) * vdfd->fd_nfiles,
+	    M_WAITOK);
+
+	if ((error = vps_snapshot_vnodepath(ctx, vps, fdp->fd_cdir,
+	    M_WAITOK)))
+		goto out;
+	if ((error = vps_snapshot_vnodepath(ctx, vps, fdp->fd_rdir,
+	    M_WAITOK)))
+		goto out;
+	if ((error = vps_snapshot_vnodepath(ctx, vps, fdp->fd_jdir,
+	    M_WAITOK)))
+		goto out;
+
+	for (i = 0; i < fdp->fd_nfiles; i++) {
+
+		fp = fget_locked(fdp, i);
+		vdfd->fd_entries[i].fp = fp;
+		if (fp == NULL)
+			continue;
+		vdfd->fd_entries[i].flags = fdp->fd_ofiles[i].fde_flags;
+		vdfd->fd_entries[i].rights = fdp->fd_ofiles[i].fde_rights;
+
+		DBGS("%s: idx=%d fp=%p\n", __func__, i, fp);
+
+		found = 0;
+		SLIST_FOREACH(vbo, &ctx->obj_list, list)
+			if (vbo->type == VPS_DUMPOBJT_FILE &&
+			    vbo->orig_ptr == fp)
+				found = 1;
+
+		if (found == 1) {
+			DBGS("%s: fp %p already dumped\n", __func__, fp);
+			continue;
+		}
+
+		vdo_create(ctx, VPS_DUMPOBJT_FILE, M_WAITOK);
+
+		vdf = vdo_space(ctx, sizeof(*vdf), M_WAITOK);
+
+		vdf->orig_ptr = fp;
+		vdf->flags = fdp->fd_ofiles[i].fde_flags;
+		vdf->f_type = fp->f_type;
+		vdf->f_flag = fp->f_flag;
+		vdf->f_offset = fp->f_offset;
+		vdf->f_cred = fp->f_cred;
+
+		DBGS("%s: file=%p flags=%08x offset=%d\n",
+		    __func__, fp, fp->f_flag, (int)fp->f_offset);
+
+		vps_snapshot_ucred(ctx, vps, fp->f_cred, M_WAITOK);
+
+		switch (fp->f_type) {
+		case DTYPE_VNODE:
+			/* XXX e.g. named pipes are not dtype_vnode but
+			       do refer to a vnode ? */
+			if (fp->f_vnode == NULL)
+				break;
+			if ((error = vps_snapshot_vnodepath(ctx, vps,
+			    fp->f_vnode, M_WAITOK))) {
+				ERRMSG(ctx, "%s: vps_snapshot_vnodepath(): "
+				    "%d\n", __func__, error);
+				goto out;
+			}
+			break;
+
+		case DTYPE_PTS:
+			if (fp->f_data == NULL)
+				break;
+			if ((error = vps_snapshot_pts(ctx, vps,
+			    fp->f_data)))
+				goto out;
+			break;
+
+		case DTYPE_SOCKET:
+			if (fp->f_data == NULL)
+				break;
+			if ((error = vps_snapshot_socket(ctx, vps,
+			    fp->f_data)))
+				goto out;
+			break;
+
+		case DTYPE_PIPE:
+			if (fp->f_data == NULL)
+				break;
+			if ((error = vps_snapshot_pipe(ctx, vps,
+			    fp->f_data)))
+				goto out;
+			break;
+
+		case DTYPE_KQUEUE:
+			DBGS("%s: KQUEUE fp=%p f_data=%p\n",
+				__func__, fp, fp->f_data);
+			if (fp->f_data == NULL)
+				break;
+			if ((error = vps_snapshot_kqueue(ctx, vps,
+			    fp->f_data)))
+				goto out;
+			break;
+
+		default:
+			ERRMSG(ctx, "%s: unhandled dtype %d\n",
+			    __func__, fp->f_type);
+			error = EINVAL;
+			goto out;
+			break;
+		}
+
+		vdo_close(ctx);
+
+		/* Insert into list of dumped objects. */
+		vbo = malloc(sizeof(*vbo), M_TEMP, M_WAITOK);
+		vbo->type = VPS_DUMPOBJT_FILE;
+		vbo->orig_ptr = fp;
+		vbo->new_ptr = NULL;
+		SLIST_INSERT_HEAD(&ctx->obj_list, vbo, list);
+	}
+
+	/* Insert into list of dumped objects. */
+	vbo = malloc(sizeof(*vbo), M_TEMP, M_WAITOK);
+	vbo->type = VPS_DUMPOBJT_FDSET;
+	vbo->orig_ptr = fdp;
+	vbo->new_ptr = NULL;
+	SLIST_INSERT_HEAD(&ctx->obj_list, vbo, list);
+
+ out:
+
+	vdo_close(ctx);
+
+	FILEDESC_XUNLOCK(fdp);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_pargs(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p)
+{
+	struct vps_dump_pargs *vdp;
+	struct pargs *pargs;
+	int error = 0;
+	int len2;
+
+	pargs = p->p_args;
+	if (pargs == NULL)
+		return (0);
+
+	len2 = roundup(pargs->ar_length, 8);
+
+	vdo_create(ctx, VPS_DUMPOBJT_PARGS, M_WAITOK);
+
+	vdp = vdo_space(ctx, sizeof(*vdp) + len2, M_WAITOK);
+
+	vdp->ar_length = pargs->ar_length;
+	memcpy(vdp->ar_args, pargs->ar_args, pargs->ar_length);
+
+	vdo_close(ctx);
+
+	DBGS("%s: [%s]\n", __func__, p->p_args->ar_args);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_vmpages(struct vps_snapst_ctx *ctx, struct vps *vps,
+    vm_object_t vmo)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_vmpages *vdvmp;
+	struct vps_dump_vmpageref *vdvmpr;
+	int npages;
+	void *newarr;
+	vm_pindex_t pidx;
+
+	npages = 0;
+
+	if ((o1 = vdo_create(ctx, VPS_DUMPOBJT_VMPAGE, M_NOWAIT)) == NULL) {
+		VM_OBJECT_WUNLOCK(vmo);
+		vps_ctx_extend(ctx, NULL, PAGE_SIZE, M_WAITOK);
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+	if ((vdvmp = vdo_space(ctx, sizeof(*vdvmp), M_NOWAIT)) == NULL) {
+		VM_OBJECT_WUNLOCK(vmo);
+		vps_ctx_extend(ctx, NULL, PAGE_SIZE, M_WAITOK);
+		vdo_discard(ctx, o1);
+		return (ENOMEM);
+	}
+
+	for (pidx = 0; pidx < vmo->size; pidx++) {
+
+		/*
+		 * If there is anything it this address,
+		 * it is either:
+		 * a) a resident page
+		 * b) a swapped out page
+		 * We do not care if resident pages get swapped out
+		 * until vpsctl reads them, because we lookup or swap
+		 * them in again by that time.
+		 */
+
+		if (vm_page_lookup(vmo, pidx) == NULL) {
+			if (vmo->type==OBJT_DEFAULT ||
+			    vmo->type==OBJT_VNODE ||
+			    vmo->type==OBJT_PHYS)
+				// not having it
+				continue;
+			else if (vmo->type==OBJT_SWAP &&
+			    vm_pager_has_page(vmo, pidx, NULL, NULL) ==
+			    FALSE)
+				// not having it
+				continue;
+		}
+
+		if (ctx->nuserpages == ctx->page_ref_size) {
+			/* Extend array by one page. */
+			newarr = malloc(ctx->nuserpages *
+			    sizeof(struct vps_page_ref) + PAGE_SIZE,
+			    M_VPS_SNAPST, M_NOWAIT | M_ZERO);
+			if (newarr == NULL) {
+				VM_OBJECT_WUNLOCK(vmo);
+				vps_ctx_extend(ctx, NULL, PAGE_SIZE,
+				    M_WAITOK);
+				ctx->nuserpages -= npages;
+				vdo_discard(ctx, o1);
+				return (ENOMEM);
+			}
+			memcpy(newarr, ctx->page_ref, ctx->nuserpages *
+				sizeof(struct vps_page_ref));
+			free(ctx->page_ref, M_VPS_SNAPST);
+			ctx->page_ref = newarr;
+			ctx->page_ref_size = (ctx->nuserpages *
+			    sizeof(struct vps_page_ref)+PAGE_SIZE) /
+			    sizeof(struct vps_page_ref);
+		}
+		ctx->page_ref[ctx->nuserpages].obj = vmo;
+		ctx->page_ref[ctx->nuserpages].pidx = pidx;
+		++npages;
+		++ctx->nuserpages;
+
+		if ((vdvmpr = vdo_space(ctx, sizeof(*vdvmpr),
+		    M_NOWAIT)) == NULL) {
+			VM_OBJECT_WUNLOCK(vmo);
+			vps_ctx_extend(ctx, NULL, PAGE_SIZE, M_WAITOK);
+			vdo_discard(ctx, o1);
+			ctx->nuserpages -= npages;
+			return (ENOMEM);
+		}
+		vdvmpr->pr_vmobject = vmo;
+		vdvmpr->pr_pindex = pidx;
+
+	}
+
+	vdvmp->count = npages;
+	DBGS("%s: dumped %d pages\n", __func__, npages);
+
+	vdo_close(ctx);
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_vpsfs_getuppervn(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vnode **vpp)
+{
+	struct vnode *lvp, *uvp;
+	struct mount *mp;
+	int error;
+
+	/*
+	 * If using vpsfs, vmobject only has a reference to the lower
+	 * vnode. So we must try to get the vpsfs alias vnode in order
+	 * to get the correct path.
+	 * XXX Also this only works if the corresponding vpsfs mount
+	 *     is the vps instances' root.
+	 */
+	if (vps_func->vpsfs_tag != NULL &&
+	    vps_func->vpsfs_nodeget != NULL &&
+	    vps->_rootvnode->v_tag == vps_func->vpsfs_tag) {
+
+		lvp = *vpp;
+		mp = vps->_rootvnode->v_mount;
+
+		/* Exclusive lock is required by vpsfs_nodeget(). */
+		error = vn_lock(lvp, LK_EXCLUSIVE);
+
+		if (error != 0) {
+			/* Give up */
+			DBGS("%s: vn_lock(%p, LK_EXCLUSIVE): %d\n",
+				__func__, lvp, error);
+			*vpp = lvp;
+			vput(lvp);
+			return (error);
+		}
+
+		if ((error = vps_func->vpsfs_nodeget(mp,
+		    lvp, &uvp))) {
+			/* Give up */
+			DBGS("%s: lvp=%p nothing found\n",
+				__func__, lvp);
+			*vpp = lvp;
+			vput(lvp);
+			return (error);
+		} else {
+			DBGS("%s: lvp=%p --> uvp=%p\n",
+				__func__, lvp, uvp);
+			*vpp = uvp;
+		}
+
+		vn_lock(lvp, LK_RELEASE);
+
+	}
+
+	return (0);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_vmobject(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vm_object *vmo)
+{
+	struct vps_dump_vmobject *vdvmo;
+	struct vm_object *dumped_backing_obj;
+	struct vps_dumpobj *o1, *save_obj;
+	struct vps_restore_obj *vbo;
+	struct vnode *save_vp;
+	struct vnode *vp;
+	int found;
+	char dump_pages;
+	int error = 0;
+
+	if (vmo == NULL) {
+		/* Nothing to do. */
+		DBGS("%s: NULL object\n", __func__);
+		return (0);
+	}
+
+	/* Look if this object is already dumped (shared memory). */
+	SLIST_FOREACH(vbo, &ctx->obj_list, list)
+		if (vbo->type == VPS_DUMPOBJT_VMOBJECT &&
+		    vbo->orig_ptr == vmo) {
+			/*
+			DBGS("%s: object=%p already dumped, skipping.\n",
+				__func__, vmo);
+			*/
+			return (0);
+		}
+
+	save_obj = ctx->curobj;
+
+	/* Try to have a good size of pre-allocated space. */
+	/* XXX */
+	vps_ctx_extend(ctx, NULL, PAGE_SIZE + sizeof(struct vps_page_ref)
+		* vmo->resident_page_count * 2, M_WAITOK);
+ again1:
+	VM_OBJECT_RLOCK(vmo);
+	dumped_backing_obj = vmo->backing_object;
+	if (vmo->backing_object != NULL) {
+		/* Look if backing object is already dumped. */
+		found = 0;
+		SLIST_FOREACH(vbo, &ctx->obj_list, list) {
+			if (vbo->type == VPS_DUMPOBJT_VMOBJECT &&
+			    vbo->orig_ptr == vmo->backing_object) {
+				found = 1;
+				break;
+			}
+		}
+		if (found == 0) {
+			/* Dump backing object first. */
+			DBGS("%s: obj=%p has backing_object=%p, dumping "
+			    "this first.\n",
+			    __func__, vmo, vmo->backing_object);
+			VM_OBJECT_RUNLOCK(vmo);
+			if ((error = vps_snapshot_vmobject(ctx, vps,
+			    dumped_backing_obj)))
+				return (error);
+			VM_OBJECT_RLOCK(vmo);
+		}
+	}
+	VM_OBJECT_RUNLOCK(vmo);
+
+ again2:
+	/*
+	if (error == ENOMEM)
+		vps_ctx_extend(ctx, NULL, PAGE_SIZE, M_WAITOK);
+	*/
+	error = 0;
+	VM_OBJECT_WLOCK(vmo);
+
+	if (vmo->backing_object != dumped_backing_obj) {
+		VM_OBJECT_WUNLOCK(vmo);
+		DBGS("%s: jumping to again1 because backing object "
+		    "changed\n", __func__);
+		vdo_discard(ctx, save_obj->next);
+		goto again1;
+	}
+
+	if ((o1 = vdo_create(ctx, VPS_DUMPOBJT_VMOBJECT, M_NOWAIT)) ==
+	    NULL) {
+		VM_OBJECT_WUNLOCK(vmo);
+		error = ENOMEM;
+		vps_ctx_extend(ctx, NULL, PAGE_SIZE, M_WAITOK);
+		goto again2;
+	}
+
+	/*
+	DBGS("%s: obj=%p: size=%d ref_count=%d shadow_count=%d flags=%04x "
+	    "type=%02x handle=%p backing_object=%p\n",
+	    __func__, o, (int)o->size, o->ref_count,o->shadow_count,
+	    o->flags, o->type, o->handle, o->backing_object);
+	*/
+
+	if ((vdvmo = vdo_space(ctx, sizeof(*vdvmo), M_NOWAIT)) == NULL) {
+		VM_OBJECT_WUNLOCK(vmo);
+		vps_ctx_extend(ctx, NULL, PAGE_SIZE, M_WAITOK);
+		vdo_discard(ctx, o1);
+		error = ENOMEM;
+		goto again2;
+	}
+
+	vdvmo->orig_ptr = vmo;
+	vdvmo->cred = vmo->cred;
+	vdvmo->backing_object = vmo->backing_object;
+
+	vdvmo->flags = vmo->flags;
+	vdvmo->type = vmo->type;
+	vdvmo->have_vnode = 0;
+	vdvmo->is_sharedpageobj = 0;
+
+	vdvmo->size = vmo->size;
+	vdvmo->charge = vmo->charge;
+	vdvmo->backing_object_offset = vmo->backing_object_offset;
+
+	switch (vmo->type) {
+		case OBJT_DEAD:
+			DBGS("%s: obj=%p OBJT_DEAD\n", __func__, vmo);
+			dump_pages = 0;
+			break;
+
+		case OBJT_VNODE:
+			vp = vmo->handle;
+			vref(vp);
+			save_vp = vp;
+
+			VM_OBJECT_WUNLOCK(vmo);
+#if 1
+			error = vps_snapshot_vpsfs_getuppervn(ctx, vps,
+			    &vp);
+			if (error != 0) {
+				vdo_discard(ctx, o1);
+				vrele(vp);
+				goto out;
+			}
+#endif
+			error = vps_snapshot_vnodepath(ctx, vps, vp,
+			    M_WAITOK);
+			if (error != 0) {
+				vdo_discard(ctx, o1);
+				vrele(vp);
+				goto out;
+			}
+
+			VM_OBJECT_WLOCK(vmo);
+			vrele(vp);
+
+			/* XXX Why ?
+			if (error != 0 && vmo->handle != save_vp) {
+			*/
+			if (vmo->handle != save_vp) {
+				/* Object changed while it was unlocked. */
+				VM_OBJECT_WUNLOCK(vmo);
+				vdo_discard(ctx, o1);
+				goto out;
+			}
+
+			dump_pages = (vmo->flags & OBJ_MIGHTBEDIRTY) ?
+			    1 : 0;
+			vdvmo->have_vnode = 1;
+
+			break;
+
+		case OBJT_PHYS:
+			DBGS("%s: obj=%p OBJT_PHYS %s\n", __func__, vmo,
+			    (vmo == shared_page_obj) ? "shared_page_obj" :
+			    "");
+			if (vmo == shared_page_obj) {
+				dump_pages = 0;
+				vdvmo->is_sharedpageobj = 1;
+			} else {
+				dump_pages = 1;
+			}
+			break;
+
+		case OBJT_DEFAULT:
+		case OBJT_SWAP:
+			dump_pages = 1;
+			break;
+
+		/*
+		case OBJT_DEVICE:
+			break;
+		*/
+
+		default:
+			panic("%s: unsupported object type obj=%p "
+			    "type=%d\n", __func__, vmo, vmo->type);
+			break;
+	}
+
+	if (vmo->cred != NULL) {
+		error = vps_snapshot_ucred(ctx, vps, vmo->cred, M_NOWAIT);
+		if (error == ENOMEM) {
+			VM_OBJECT_WUNLOCK(vmo);
+			vps_ctx_extend(ctx, NULL, PAGE_SIZE, M_WAITOK);
+			vdo_discard(ctx, o1);
+			goto again2;
+		} else if (error != 0) {
+			VM_OBJECT_WUNLOCK(vmo);
+			vdo_discard(ctx, o1);
+			goto out;
+		}
+	}
+
+	/* Dump pages. */
+	if (dump_pages) {
+		error = vps_snapshot_vmpages(ctx, vps, vmo);
+		if (error != 0) {
+			VM_OBJECT_WUNLOCK(vmo);
+			vdo_discard(ctx, o1);
+			goto out;
+		}
+	}
+
+	vm_object_reference_locked(vmo);
+	VM_OBJECT_WUNLOCK(vmo);
+
+	/* Insert in any case. */
+	if (1) {
+		/* Insert into list of dumped backing objects. */
+		vbo = malloc(sizeof(*vbo), M_TEMP, M_WAITOK);
+		vbo->type = VPS_DUMPOBJT_VMOBJECT;
+		vbo->orig_ptr = vmo;
+		vbo->new_ptr = NULL;
+		SLIST_INSERT_HEAD(&ctx->obj_list, vbo, list);
+	}
+
+	vdo_close(ctx);
+
+ out:
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_vmspace(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct vmspace *vmspace)
+{
+	struct vps_restore_obj *vbo;
+	struct vps_dump_vmspace *vdvms;
+	struct vps_dump_vmmapentry *vdvme;
+	struct vm_map_entry *e;
+	int i;
+	int error = 0;
+
+	SLIST_FOREACH(vbo, &ctx->obj_list, list)
+		if (vbo->type == VPS_DUMPOBJT_VMSPACE &&
+		    vbo->orig_ptr == vmspace)
+			break;
+
+	if (vbo != NULL) {
+		DBGS("%s: vmspace %p already dumped\n",
+		    __func__, vmspace);
+		return (0);
+	}
+
+	DBGS("%s: vmspace=%p map=%p\n",
+	    __func__, vmspace, &vmspace->vm_map);
+
+	vdo_create(ctx, VPS_DUMPOBJT_VMSPACE, M_WAITOK);
+
+	vdvms = vdo_space(ctx, sizeof(*vdvms), M_WAITOK);
+
+	vdvms->vm_orig_ptr = vmspace;
+	vdvms->vm_tsize = vmspace->vm_tsize;
+	vdvms->vm_dsize = vmspace->vm_dsize;
+	vdvms->vm_ssize = vmspace->vm_ssize;
+	vdvms->vm_map.minoffset = vmspace->vm_map.min_offset;
+	vdvms->vm_map.maxoffset = vmspace->vm_map.max_offset;
+
+	vm_map_lock(&vmspace->vm_map);
+
+	for (i = 0, e = vmspace->vm_map.header.next;
+		e != &vmspace->vm_map.header;
+		i++, e = e->next) {
+
+		DBGS("%s: entry=%p: start=%016zx end=%016zx prot=%02x "
+		    "max_prot=%02x " "object=%p eflags=%08x (%s)\n",
+		    __func__, e, (size_t)e->start, (size_t)e->end,
+		    e->protection, e->max_protection,
+		    e->object.vm_object, e->eflags,
+		    e->eflags & MAP_ENTRY_IS_SUB_MAP ? "submap" :
+		    "vm object");
+
+		vdo_create(ctx, VPS_DUMPOBJT_VMMAPENTRY, M_WAITOK);
+		vdvme = vdo_space(ctx, sizeof(*vdvme), M_WAITOK);
+
+		vdvme->map_object = e->object.vm_object;
+		vdvme->offset = e->offset;
+		vdvme->start = e->start;
+		vdvme->end = e->end;
+		vdvme->avail_ssize = e->avail_ssize;
+		vdvme->eflags = e->eflags;
+		vdvme->protection = e->protection;
+		vdvme->max_protection = e->max_protection;
+		vdvme->inheritance = e->inheritance;
+
+		if (e->cred != NULL)
+			vps_snapshot_ucred(ctx, vps, e->cred, M_WAITOK);
+
+		vdvme->cred = e->cred;
+
+		if (e->eflags & MAP_ENTRY_IS_SUB_MAP) {
+			ERRMSG(ctx, "%s: WARNING: skipping submap\n",
+			    __func__);
+		} else
+			if ((error = vps_snapshot_vmobject(ctx, vps,
+			    e->object.vm_object)))
+				goto out;
+
+		vdo_close(ctx);
+	}
+
+	/* Insert into list of dumped objects. */
+	vbo = malloc(sizeof(*vbo), M_TEMP, M_WAITOK);
+	vbo->type = VPS_DUMPOBJT_VMSPACE;
+	vbo->orig_ptr = vmspace;
+	vbo->new_ptr = NULL;
+	SLIST_INSERT_HEAD(&ctx->obj_list, vbo, list);
+
+ out:
+	vm_map_unlock(&vmspace->vm_map);
+
+	vdo_close(ctx);
+
+	return (error);
+}
+
+/* XXX --> header */
+int vps_umtx_snapshot(struct thread *td);
+
+__attribute__((noinline, unused))
+static int
+vps_snapshot_umtx(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct thread *td)
+{
+	//struct umtx_q *uq;
+	int error = 0;
+
+	vdo_create(ctx, VPS_DUMPOBJT_UMTX, M_WAITOK);
+
+	vps_umtx_snapshot(td);
+
+	/*
+	DBGS("%s: td->td_umtxq=%p\n", __func__, td->td_umtxq);
+	if (td->td_umtxq == NULL) {
+		error = 0;
+		goto out;
+	}
+
+	mtx_lock_spin(&umtx_lock);
+	mtx_unlock_spin(&umtx_lock);
+	*/
+
+ //out:
+	vdo_close(ctx);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_thread_savefpu(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct thread *td)
+{
+
+	return (vps_md_snapshot_thread_savefpu(ctx, vps, td));
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_thread(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct thread *td)
+{
+	struct vps_dumpobj *o1;
+	struct vps_dump_thread *vdtd;
+	int error = 0;
+	int i;
+
+	/* XXX Has to happen in suspend, because filesystem sync
+	   is finished. */
+	/* Drain pending ktrace records. */
+	ktruserret(td);
+
+	/* pre-alloc some space to avoid re-doing ... */
+	vps_ctx_extend(ctx, NULL, td->td_kstack_pages << PAGE_SHIFT,
+	    M_WAITOK);
+
+  again:
+	o1 = vdo_create(ctx, VPS_DUMPOBJT_THREAD, M_WAITOK);
+
+	thread_lock(td);
+
+	/* Make sure the thread is stopped in ast(). <-- XXX */
+	if ( ! (TD_IS_SUSPENDED(td)) ) {
+		ERRMSG(ctx, "%s: td=%p not suspended !\n", __func__, td);
+		error = EBUSY;
+		thread_unlock(td);
+		vdo_discard(ctx, o1);
+		goto out;
+	}
+
+	if ((vdtd = vdo_space(ctx, sizeof(*vdtd), M_NOWAIT)) == NULL) {
+		thread_unlock(td);
+		vdo_discard(ctx, o1);
+		goto again;
+	}
+
+	vdtd->td_tid = td->td_tid;
+	vdtd->td_xsig = td->td_xsig;
+	vdtd->td_dbgflags = td->td_dbgflags;
+	vdtd->td_sigstk.ss_sp = PTRTO64(td->td_sigstk.ss_sp);
+	vdtd->td_sigstk.ss_size = td->td_sigstk.ss_size;
+	vdtd->td_sigstk.ss_flags = td->td_sigstk.ss_flags;
+	for (i = 0; i < _SIG_WORDS; i++) {
+		vdtd->td_sigmask[i] = td->td_sigmask.__bits[i];
+		vdtd->td_oldsigmask[i] = td->td_oldsigmask.__bits[i];
+	}
+
+	vdtd->td_rqindex = td->td_rqindex;
+	vdtd->td_base_pri = td->td_base_pri;
+	vdtd->td_priority = td->td_priority;
+	vdtd->td_pri_class = td->td_pri_class;
+	vdtd->td_user_pri = td->td_user_pri;
+	vdtd->td_base_user_pri = td->td_base_user_pri;
+
+	vdtd->td_errno = td->td_errno;
+	vdtd->td_retval[0] = td->td_retval[0];
+	vdtd->td_retval[1] = td->td_retval[1];
+
+	vdtd->td_kstack_pages = td->td_kstack_pages;
+
+	/* The kstack includes the PCB. */
+	if (vdo_append(ctx, (void *)td->td_kstack,
+			td->td_kstack_pages << PAGE_SHIFT, M_NOWAIT)) {
+		thread_unlock(td);
+		vdo_discard(ctx, o1);
+		goto again;
+	}
+
+	if (vps_snapshot_thread_savefpu(ctx, vps, td) != 0) {
+		thread_unlock(td);
+		vdo_discard(ctx, o1);
+		goto again;
+	}
+
+	thread_unlock(td);
+
+	vps_md_print_thread(td);
+#ifdef DDB
+	db_trace_thread(td, 16);
+#endif
+
+	/* not yet
+	if ((error = vps_snapshot_umtx(ctx, vps, td)))
+		goto out;
+	*/
+
+ out:
+	vdo_close(ctx);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static int
+vps_snapshot_proc_one(struct vps_snapst_ctx *ctx, struct vps *vps,
+    struct proc *p)
+{
+	struct thread *td;
+	struct vps_dump_proc *vdp;
+	int error = 0;
+	int i;
+
+	DBGS("%s: p=%p pid=%d ctx->cpos=%p delta=%p\n",
+	    __func__, p, p->p_pid, ctx->cpos,
+	    (void *)((caddr_t)ctx->cpos - (caddr_t)ctx->data));
+
+	vdo_create(ctx, VPS_DUMPOBJT_PROC, M_WAITOK);
+
+	PROC_LOCK(p);
+	KASSERT(p->p_state == PRS_NORMAL,
+	    ("%s: p=%p p_state=%d\n", __func__, p, p->p_state));
+	PROC_UNLOCK(p);
+
+	//PROC_LOCK(p);
+
+	/* Dump structures. */
+
+	vdp = vdo_space(ctx, sizeof(*vdp), M_WAITOK);
+	memset(vdp, 0, sizeof(*vdp));
+
+	/* sigacts */
+	KASSERT(_SIG_MAXSIG <= (sizeof(vdp->p_sigacts.ps_sigact) /
+	    sizeof(vdp->p_sigacts.ps_sigact[0])),
+	    ("%s: vdp->p_sigacts.ps_sigact too small\n",
+	    __func__));
+	KASSERT(_SIG_WORDS <= (sizeof(vdp->p_sigacts.ps_sigonstack) /
+	    sizeof(vdp->p_sigacts.ps_sigonstack[0])),
+	    ("%s: vdp->p_sigacts.ps_sigonstack etc. too small\n",
+	    __func__));
+
+	vdp->p_sigacts.ps_maxsig = _SIG_MAXSIG;
+	vdp->p_sigacts.ps_sigwords = _SIG_WORDS;
+
+	vdp->p_sigacts.ps_flag = p->p_sigacts->ps_flag;
+	for (i = 0; i < _SIG_MAXSIG; i++) {
+		vdp->p_sigacts.ps_sigact[i] =
+		    PTRTO64(p->p_sigacts->ps_sigact[i]);
+		vdp->p_sigacts.ps_catchmask[i][0] =
+		    p->p_sigacts->ps_catchmask[i].__bits[0];
+		vdp->p_sigacts.ps_catchmask[i][1] =
+		    p->p_sigacts->ps_catchmask[i].__bits[1];
+		vdp->p_sigacts.ps_catchmask[i][2] =
+		   p->p_sigacts->ps_catchmask[i].__bits[2];
+		vdp->p_sigacts.ps_catchmask[i][3] =
+		   p->p_sigacts->ps_catchmask[i].__bits[3];
+	}
+	for (i = 0; i < _SIG_WORDS; i++) {
+		vdp->p_sigacts.ps_sigonstack[i] =
+		    p->p_sigacts->ps_sigonstack.__bits[i];
+		vdp->p_sigacts.ps_sigintr[i] =
+		    p->p_sigacts->ps_sigintr.__bits[i];
+		vdp->p_sigacts.ps_sigreset[i] =
+		    p->p_sigacts->ps_sigreset.__bits[i];
+		vdp->p_sigacts.ps_signodefer[i] =
+		    p->p_sigacts->ps_signodefer.__bits[i];
+		vdp->p_sigacts.ps_siginfo[i] =
+		    p->p_sigacts->ps_siginfo.__bits[i];
+		vdp->p_sigacts.ps_sigignore[i] =
+		    p->p_sigacts->ps_sigignore.__bits[i];
+		vdp->p_sigacts.ps_sigcatch[i] =
+		    p->p_sigacts->ps_sigcatch.__bits[i];
+		vdp->p_sigacts.ps_freebsd4[i] =
+		    p->p_sigacts->ps_freebsd4.__bits[i];
+		vdp->p_sigacts.ps_osigset[i] =
+		    p->p_sigacts->ps_osigset.__bits[i];
+		vdp->p_sigacts.ps_usertramp[i] =
+		    p->p_sigacts->ps_usertramp.__bits[i];
+	}
+
+	/* plimit */
+	/* XXX this is COW ... */
+
+	KASSERT(RLIM_NLIMITS < (sizeof(vdp->p_limit.pl_rlimit) /
+		sizeof(vdp->p_limit.pl_rlimit[0])),
+		("%s: vdp->p_limit.pl_rlimit too small\n",
+		__func__));
+
+	vdp->p_limit.pl_nlimits = RLIM_NLIMITS;
+
+	for (i = 0; i < RLIM_NLIMITS; i++) {
+		vdp->p_limit.pl_rlimit[i].rlim_cur =
+		    p->p_limit->pl_rlimit[i].rlim_cur;
+		vdp->p_limit.pl_rlimit[i].rlim_max =
+		    p->p_limit->pl_rlimit[i].rlim_max;
+	}
+
+	/* proc */
+	vdp->p_pptr_id = (p->p_pptr) ? p->p_pptr->p_pid : 0;
+	vdp->p_peers_id = (p->p_peers) ? p->p_peers->p_pid : 0;
+	vdp->p_leader_id = (p->p_leader) ? p->p_leader->p_pid : 0;
+	vdp->p_pgrp_id = (p->p_pgrp) ? p->p_pgrp->pg_id : 0;
+	vdp->p_xthread_id = (p->p_xthread) ? p->p_xthread->td_tid : 0;
+
+	vdp->p_pid = p->p_pid;
+	vdp->p_swtick = p->p_swtick;
+	vdp->p_cpulimit = p->p_cpulimit;
+	vdp->p_flag = p->p_flag;
+	vdp->p_state = p->p_state;
+	vdp->p_stops = p->p_stops;
+	vdp->p_oppid = p->p_oppid;
+	vdp->p_xstat = p->p_xstat;
+	vdp->p_stype = p->p_stype;
+	vdp->p_step = p->p_step;
+	vdp->p_sigparent = p->p_sigparent;
+	vdp->p_ucred = p->p_ucred;
+	vdp->p_tracecred = p->p_tracecred;
+	vdp->p_traceflag = p->p_traceflag;
+	vdp->p_vmspace = p->p_vmspace;
+	vdp->p_fd = p->p_fd;
+	strlcpy(vdp->p_comm, p->p_comm, min(sizeof(vdp->p_comm),
+	    sizeof(p->p_comm)));
+
+	/* credentials */
+	vps_snapshot_ucred(ctx, vps, p->p_ucred, M_WAITOK);
+
+	/* sysentvec */
+	if ((error = vps_snapshot_sysentvec(ctx, vps, p)))
+		goto out;
+
+	/* ktrace */
+	if (p->p_tracevp != NULL) {
+		if ((error = vps_snapshot_vnodepath(ctx, vps, p->p_tracevp,
+		    M_WAITOK)))
+			goto out;
+		vdp->p_have_tracevp = 1;
+	}
+
+	/* Executable vnode. */
+	if (p->p_textvp != NULL) {
+		if ((error = vps_snapshot_vnodepath(ctx, vps, p->p_textvp,
+		    M_WAITOK)))
+			goto out;
+		vdp->p_have_textvp = 1;
+	}
+
+	/* Dump vmspace. */
+	if ((error = vps_snapshot_vmspace(ctx, vps, p->p_vmspace)))
+		goto out;
+
+	/* Dump threads. */
+	TAILQ_FOREACH(td, &p->p_threads, td_plist)
+		if ((error = vps_snapshot_thread(ctx, vps, td)))
+			goto out;
+
+	/* Dump file set. */
+	if ((error = vps_snapshot_fdset(ctx, vps, p)))
+		goto out;
+
+	/* Dump process argument list. */
+	if ((error = vps_snapshot_pargs(ctx, vps, p)))
+		goto out;
+
+	if (vps_func->sem_snapshot_proc &&
+	    (error = vps_func->sem_snapshot_proc(ctx, vps, p)))
+		goto out;
+
+	if (vps_func->shm_snapshot_proc &&
+	    (error = vps_func->shm_snapshot_proc(ctx, vps, p)))
+		goto out;
+
+	if (vps_func->msg_snapshot_proc &&
+	    (error = vps_func->msg_snapshot_proc(ctx, vps, p)))
+		goto out;
+
+  out:
+	//PROC_UNLOCK(p);
+
+	vdo_close(ctx);
+
+	return (error);
+}
+
+/* * * * * * * * * * * * * * * * * * */
+
+__attribute__((noinline))
+int
+vps_snapshot_finish(struct vps_dev_ctx *dev_ctx, struct vps *vps)
+{
+	struct vps_snapst_ctx *ctx;
+
+	ctx = dev_ctx->snapst;
+
+	DBGS("%s: dev_ctx=%p\n", __func__, dev_ctx);
+
+	if (ctx == NULL)
+		return (0);
+
+	if (vps == NULL)
+	   vps = ctx->vps;
+
+	if (vps != NULL && vps->vps_status != VPS_ST_SNAPSHOOTING )
+		return (EINVAL);
+
+	ctx->cmd = 0;
+	ctx->vps = NULL;
+
+	if (ctx->vps_vmobject) {
+	        (void)vm_object_reference(ctx->vps_vmobject);
+		/* Frees one reference. */
+		(void)vm_map_remove(ctx->user_map, ctx->user_map_start,
+			ctx->user_map_start +
+			((ctx->nsyspages + ctx->nuserpages)
+			<< PAGE_SHIFT));
+
+		VM_OBJECT_WLOCK(ctx->vps_vmobject);
+		vps_pager_ops.pgo_dealloc(ctx->vps_vmobject);
+		VM_OBJECT_WUNLOCK(ctx->vps_vmobject);
+		ctx->vps_vmobject = NULL;
+	}
+
+	while ( ! SLIST_EMPTY(&ctx->obj_list)) {
+		struct vps_restore_obj *vbo;
+
+		vbo = SLIST_FIRST(&ctx->obj_list);
+		SLIST_REMOVE_HEAD(&ctx->obj_list, list);
+
+		switch (vbo->type) {
+		case VPS_DUMPOBJT_VMOBJECT:
+			vm_object_deallocate(vbo->orig_ptr);
+			break;
+		case VPS_DUMPOBJT_UCRED:
+			crfree(vbo->orig_ptr);
+			break;
+		default:
+			break;
+		}
+		free(vbo, M_TEMP);
+	}
+
+	/*
+	 * Clean up the memory mess.
+	 */
+	if (ctx->userpagelist)
+		free(ctx->userpagelist, M_VPS_SNAPST);
+
+	if (ctx->page_ref)
+		free(ctx->page_ref, M_VPS_SNAPST);
+
+	if (ctx->data)
+		vps_ctx_free(ctx, vps);
+
+	if (vps != NULL) {
+		vps->vps_status = VPS_ST_SUSPENDED;
+		/* XXX unlock vps */
+	}
+
+	free(dev_ctx->snapst, M_VPS_SNAPST);
+	dev_ctx->snapst = NULL;
+	dev_ctx->cmd = 0;
+
+	DBGS("%s: finished snapshot\n", __func__);
+
+	return (0);
+}
+
+static int
+vps_snapst_modevent(module_t mod, int type, void *data)
+{
+	int error;
+
+	error = 0;
+
+	switch (type) {
+	case MOD_LOAD:
+	   vps_snapst_mod_refcnt = 0;
+	   vps_func->vps_snapshot = vps_snapshot;
+	   vps_func->vps_snapshot_finish = vps_snapshot_finish;
+	   vps_func->vps_ctx_extend_hard = vps_ctx_extend_hard;
+	   vps_func->vps_snapshot_ucred = vps_snapshot_ucred;
+	   break;
+	case MOD_UNLOAD:
+	   if (vps_snapst_mod_refcnt > 0)
+		return (EBUSY);
+	   vps_func->vps_snapshot = NULL;
+	   vps_func->vps_snapshot_finish = NULL;
+	   vps_func->vps_ctx_extend_hard = NULL;
+	   vps_func->vps_snapshot_ucred = NULL;
+	   break;
+	default:
+	   error = EOPNOTSUPP;
+	   break;
+	}
+	return (error);
+}
+
+static moduledata_t vps_snapst_mod = {
+	"vps_snapst",
+	vps_snapst_modevent,
+	0
+};
+
+DECLARE_MODULE(vps_snapst, vps_snapst_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_snapst.h head/sys/vps/vps_snapst.h
--- clean-head/sys/vps/vps_snapst.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_snapst.h	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,371 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: vps_snapst.h 162 2013-06-06 18:17:55Z klaus $ */
+
+#ifndef _VPS_SNAPST_H
+#define _VPS_SNAPST_H
+
+#ifdef VPS
+
+#include <sys/cdefs.h>
+
+/* XXX for vps_printf() */
+#include <machine/stdarg.h>
+
+extern struct vm_object *shared_page_obj;
+
+MALLOC_DECLARE(M_VPS_CORE);
+
+struct vps_snapst_ctx;
+struct vps_arg_snapst;
+struct vps_dev_ctx;
+
+int getsock(struct filedesc *fdp, int fd, struct file **fpp, u_int *fflagp);
+void fdgrowtable(struct filedesc *fdp, int nfd);
+void fdused(struct filedesc *fdp, int fd);
+void fdunused(struct filedesc *fdp, int fd);
+int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
+    char *buf, char **retbuf, u_int buflen);
+void vnet_route_init(const void *);
+void vnet_route_uninit(const void *);
+
+static int vps_ctx_extend(struct vps_snapst_ctx *ctx, struct vps *vps,
+    size_t size, int how);
+
+int vps_snapshot(struct vps_dev_ctx *ctx, struct vps *vps,
+    struct vps_arg_snapst *va);
+int vps_snapshot_getpage(struct vps_dev_ctx *ctx, vm_offset_t offset,
+    vm_paddr_t *paddr);
+int vps_snapshot_finish(struct vps_dev_ctx *ctx, struct vps *vps);
+
+int vps_restore(struct vps_dev_ctx *ctx, struct vps_arg_snapst *va);
+
+SLIST_HEAD(_vps_dumpobj_list, vps_dumpobj);
+
+struct vm_object;
+struct vps_page_ref;
+struct vps_dumpinfo;
+struct vps_snapst_errmsg;
+
+struct vps_snapst_ctx {
+	struct vps_snapst_ctx *dev;	/* Owner */
+	struct vps *vps;		/* Working on this instance */
+	struct ucred *vps_ucred;	/* Ucred for various restore
+					   functions */
+	int cmd;			/* Last/Pending ioctl */
+	void *data;			/* Base of private data */
+	size_t dsize;			/* Used size of private data
+					   in bytes */
+	size_t dsize2;			/* Allocated size of private
+					   data in bytes */
+	size_t maxsize;			/* Maximum size in bytes */
+	void *cpos;			/* Current position */
+	int pagesread;			/* Count of pages requested */
+	int nsyspages;			/* Count of pages from
+					   kernel memory */
+	int nuserpages;			/* Count of pages from
+					   userspace memory */
+	int userpagelistlength;
+	/* dump */
+	struct vm_object *vmobj;	/* VM Object for dump */
+	struct vm_page **userpagelist;	/* Array of pointers to pages */
+	struct vm_page **syspagelist;	/* Array of pointers to pages */
+	/* restore */
+	int userpagesidx;		/* ... */
+	caddr_t userpagesaddr;		/* ... */
+	SLIST_HEAD(_vps_restore_obj_list, vps_restore_obj) obj_list;
+	struct _vps_dumpobj_list *dumpobj_list;
+
+	struct vm_map *user_map;
+	vm_offset_t user_map_start;
+	vm_offset_t user_map_offset;
+
+	size_t page_ref_size;
+	struct vps_page_ref *page_ref;
+
+	int pager_npages_res;
+	int pager_npages_swap;
+	int pager_npages_miss;
+
+	struct vps_dumpheader *dumphdr;
+
+	struct vm_object *vps_vmobject;
+
+	struct vps_dumpobj *rootobj;
+	struct vps_dumpobj *lastobj;
+	struct vps_dumpobj *curobj;
+	int level;
+	int elements;
+	char relative;
+
+	int extend_failcount;
+
+	struct vps_dump_sysinfo *old_sysinfo;
+
+	LIST_HEAD(_vps_snapst_errmsg_list, vps_snapst_errmsg) errormsgs;
+};
+
+struct vps_dumpobj;
+
+struct vps_page_ref {
+	struct vm_object *obj;
+	vm_pindex_t pidx;
+	enum { UNKNOWN = 0, RESIDENT, PAGER } origin;
+};
+
+struct vps_snapst_errmsg {
+	LIST_ENTRY (vps_snapst_errmsg) list;
+	char str[0];
+};
+
+static int vps_snapst_print_errormsgs;
+
+/* inlining not possible */
+__attribute__((unused))
+static void
+vps_snapst_pusherrormsg(struct vps_snapst_ctx *ctx, char *fmt, ...)
+{
+	struct vps_snapst_errmsg *entry;
+	va_list ap;
+	char *buf;
+
+	buf = malloc(0x1000, M_TEMP, M_WAITOK);
+
+	va_start(ap, fmt);
+	vsnprintf(buf, 0x1000, fmt, ap);
+	va_end(ap);
+
+	if (vps_snapst_print_errormsgs != 0)
+		printf("%s", buf);
+
+	entry = malloc(sizeof(*entry) + strlen(buf) + 1, M_TEMP, M_WAITOK);
+	memcpy(entry->str, buf, strlen(buf) + 1);
+
+	LIST_INSERT_HEAD(&ctx->errormsgs, entry, list);
+
+	free(buf, M_TEMP);
+}
+
+#if defined(_VPS_SNAPST_H_ALL) || defined(_VPS_SNAPST_H_RESTORE_OBJ)
+struct vps_restore_obj {
+	SLIST_ENTRY (vps_restore_obj) list;
+	int type;
+	struct vps_dumpobj *dumpobj;
+	void * orig_ptr;
+	void * new_ptr;
+	int orig_id;
+	void * spare[4];
+};
+#endif
+
+#ifdef _VPS_SNAPST_H_ALL
+
+extern uma_zone_t vmspace_zone;
+//extern struct fileops pipeops;
+
+#if 0
+static
+void nullprintf(char *fmt, ...)
+{
+}
+#define printf nullprintf
+#endif
+
+/* XXXXXXXXXXXXXXXX duplicated file scope declarations XXXXXXXXXXXXXXX */
+
+/* XXX from net/if_epair.c */
+struct epair_softc {
+        struct ifnet    *ifp;
+        struct ifnet    *oifp;
+        u_int           refcount;
+        void            (*if_qflush)(struct ifnet *);
+};
+
+/* kern/tty_pts.c */
+
+/*
+ * Per-PTS structure.
+ *
+ * List of locks
+ * (t)  locked by tty_lock()
+ * (c)  const until freeing
+ */
+struct pts_softc {
+        int             pts_unit;       /* (c) Device unit number. */
+        unsigned int    pts_flags;      /* (t) Device flags. */
+#define PTS_PKT         0x1     /* Packet mode. */
+#define PTS_FINISHED    0x2     /* Return errors on read()/write(). */
+        char            pts_pkt;        /* (t) Unread packet mode data. */
+
+        struct cv       pts_inwait;     /* (t) Blocking write() on master. */
+        struct selinfo  pts_inpoll;     /* (t) Select queue for write(). */
+        struct cv       pts_outwait;    /* (t) Blocking read() on master. */
+        struct selinfo  pts_outpoll;    /* (t) Select queue for read(). */
+
+#ifdef PTS_EXTERNAL
+        struct cdev     *pts_cdev;      /* (c) Master device node. */
+#endif /* PTS_EXTERNAL */
+
+        struct uidinfo  *pts_uidinfo;   /* (c) Resource limit. */
+#ifdef VPS
+        struct ucred    *pts_cred;      /* (c) */
+#endif
+};
+
+#endif /* _VPS_SNAPST_H_ALL */
+
+#define VPS_SYSENTVEC_NULL	0x0
+#define VPS_SYSENTVEC_ELF32	0x1
+#define VPS_SYSENTVEC_ELF64	0x2
+
+/*
+ * * * * * Support functions. * * * *
+ */
+__attribute__((noinline, unused))
+static u_int
+vps_cksum(char *ptr, int size)
+{
+        u_int i, sum;
+
+        sum = 0;
+        for (i = 0; i < size; i++)
+                sum += (u_char)ptr[i];
+        return (sum);
+}
+
+
+/* BEGIN DEBUG */
+
+#define DBG_CTX_POS(t)					\
+do {							\
+	printf("%s: ctx->cpos=%p rel=%p (%s)\n",	\
+		__func__, ctx->cpos,			\
+		(void *)(ctx->cpos - ctx->data), (t));	\
+} while (0)
+
+__attribute__((unused))
+static int
+vps_printf(const char *fmt, ...)
+{
+        va_list ap;
+        int retval;
+
+	printf("%lld.%d ", (long long int)time_second, ticks);
+
+        va_start(ap, fmt);
+        retval = vprintf(fmt, ap);
+        va_end(ap);
+
+        return (retval);
+}
+
+__attribute__((unused))
+static void
+vps_print_ascii(const char *data, int len)
+{
+        const char *p;
+        char line[61];
+        int j;
+
+        p = data;
+        j = 0;
+	memset(line, 0, 61);
+
+        while (p < data + len) {
+                if (*p > 0x20)
+                        line[j] = *p;
+                else
+                        line[j] = '.';
+                j++;
+                p++;
+                if (j > 60) {
+                        printf("[%s]\n", line);
+			memset(line, 0, 61);
+                        j = 0;
+                }
+        }
+        if (j > 0)
+                printf("[%s]\n", line);
+}
+
+/* END DEBUG */
+
+static inline
+int
+vps_ctx_extend(struct vps_snapst_ctx *ctx, struct vps *vps, size_t size,
+    int how)
+{
+	int error;
+
+	if (vps_func->vps_ctx_extend_hard == NULL)
+		return (ENOSYS);
+
+	if (how == M_WAITOK)
+		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
+		    "%s: size=%d", __func__, size);
+
+	/*
+	 * On M_WAITOK allocations we always keep at least one page
+	 * room to cover M_NOWAIT calls (usually tiny sizes).
+	 */
+	if ((caddr_t)ctx->data + ctx->dsize2 > (caddr_t)ctx->cpos + size +
+	    (how==M_WAITOK ? PAGE_SIZE : 0)) {
+		/*
+		DBGS("%s: ctx->data + ctx->dsize2 = %08x     "
+		    "ctx->cpos + size = %08x\n",
+		    __func__, (u_int)(ctx->data + ctx->dsize2),
+		    (u_int)(ctx->cpos + size));
+                */
+		/* Nothing to do. */
+		return (0);
+
+	} else {
+
+		/* Actually allocate space. */
+		error = vps_func->vps_ctx_extend_hard(ctx, vps, size, how);
+
+		if (error != 0) {
+			if (ctx->extend_failcount++ > 10)
+				panic("%s: ctx=%p failcount=%d\n",
+				    __func__, ctx, ctx->extend_failcount);
+		} else {
+			ctx->extend_failcount = 0;
+		}
+
+		return (error);
+	}
+}
+
+
+#endif /* VPS */
+
+#endif /* _VPS_SNAPST_H */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_suspend.c head/sys/vps/vps_suspend.c
--- clean-head/sys/vps/vps_suspend.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_suspend.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,1100 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: vps_suspend.c 162 2013-06-06 18:17:55Z klaus $";
+
+#include "opt_global.h"
+#include "opt_ddb.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_compat.h"
+
+#ifdef VPS
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/limits.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/libkern.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/ucred.h>
+#include <sys/ioccom.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/fcntl.h>
+#include <sys/namei.h>
+#include <sys/syscallsubr.h>
+#include <sys/resourcevar.h>
+#include <sys/sysproto.h>
+#include <sys/reboot.h>
+#include <sys/sysent.h>
+#include <sys/sleepqueue.h>
+#include <sys/syscall.h>
+#include <sys/systm.h>
+#include <sys/filedesc.h>
+#include <sys/buf.h>
+#include <sys/imgact.h>
+#include <sys/vmmeter.h>
+#include <sys/dirent.h>
+#include <sys/jail.h>
+#include <sys/stat.h>
+#include <sys/rwlock.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_kern.h>
+
+#include <machine/pcb.h>
+
+#include <net/if.h>
+#include <net/if_clone.h>
+#include <netinet/in.h>
+
+#include <security/mac/mac_framework.h>
+
+#ifdef DDB
+#include <ddb/ddb.h>
+#else
+#define db_trace_thread(x,y)
+#endif
+
+#include "vps_account.h"
+#include "vps_user.h"
+#include "vps.h"
+#include "vps2.h"
+#include <machine/vps_md.h>
+
+MALLOC_DECLARE(M_VPS_CORE);
+
+int vps_suspend(struct vps *vps, int flags);
+int vps_resume(struct vps *vps, int flags);
+int vps_abort(struct vps *vps, int flags);
+
+static int vps_syscall_fixup(struct vps *vps, struct thread *td);
+static int vps_access_vmspace(struct vmspace *vm, vm_offset_t vaddr,
+	size_t len, void *buf, int prot);
+
+static int vps_resume_relinkvnodes(struct vps *vps);
+static int get_next_dirent(struct vnode *vp, struct dirent **dpp,
+    char *dirbuf, int dirbuflen, off_t *off, char **cpos,
+    int *len, int *eofflag, struct thread *td);
+static int vps_suspend_relink_delete(struct vnode *vp);
+
+static int vps_suspend_mod_refcnt;
+
+/*
+ * This is mostly kern_linkat().
+ *
+ * Relinks a unlinked vnode to a temporary name so it can be migrated.
+ */
+static int
+vps_suspend_relinkvnodes_one(struct vps *vps, struct vnode *vp,
+	const char *path, int fd)
+{
+        struct nameidata nd;
+        struct mount *mp;
+	struct stat *statp;
+	char *path2;
+        int error;
+
+        bwillwrite();
+        if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
+                return (error);
+        }
+        NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | AUDITVNODE2,
+                UIO_SYSSPACE, path, fd, curthread);
+        if ((error = namei(&nd)) == 0) {
+                if (nd.ni_vp != NULL) {
+                        if (nd.ni_dvp == nd.ni_vp)
+                                vrele(nd.ni_dvp);
+                        else
+                                vput(nd.ni_dvp);
+                        vrele(nd.ni_vp);
+                        error = EEXIST;
+                } else if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY))
+		    == 0) {
+                        error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
+                        VOP_UNLOCK(vp, 0);
+                        vput(nd.ni_dvp);
+                }
+                NDFREE(&nd, NDF_ONLY_PNBUF);
+        }
+        vn_finished_write(mp);
+
+	/* Get the name into the cache for reverse lookup later. */
+	statp = malloc(sizeof(*statp), M_TEMP, M_WAITOK);
+	path2 = malloc(strlen(path) + 1, M_TEMP, M_WAITOK);
+	strlcpy(path2, path, strlen(path) + 1);
+
+	kern_stat(curthread, path2, UIO_SYSSPACE, statp);
+
+	free(path2, M_TEMP);
+	free(statp, M_TEMP);
+
+        return (error);
+}
+
+static int
+vps_suspend_relinkvnodes(struct vps *vps)
+{
+	struct filedesc *fdp;
+	struct file *fp;
+	struct proc *p;
+	char *freebuf;
+	char *retbuf;
+	char *path;
+	int error;
+	int i;
+
+	sx_assert(&vps->vps_lock, SA_XLOCKED);
+
+	if (vps->vps_status != VPS_ST_SUSPENDED)
+		return (EBUSY);
+
+	error = 0;
+
+	/* Delete all '/VPSRELINKED_*' entries first. */
+	vps_resume_relinkvnodes(vps);
+
+	sx_slock(&VPS_VPS(vps, allproc_lock));
+	LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list) {
+		//PROC_LOCK(p);
+		fdp = p->p_fd;
+		FILEDESC_SLOCK(fdp);
+
+		for (i = 0; i < fdp->fd_nfiles; i++) {
+
+			fp = fget_locked(fdp, i);
+			if (fp == NULL || fp->f_type != DTYPE_VNODE)
+				continue;
+
+			fhold(fp);
+			error = vn_fullpath(curthread, fp->f_vnode,
+			    &retbuf, &freebuf);
+			if (error == 0)
+				free(freebuf, M_TEMP);
+
+			if (error != 0 && error != ENOENT) {
+				DBGCORE("%s: error: %d\n", __func__, error);
+				fdrop(fp, curthread);
+		   		FILEDESC_SUNLOCK(fdp);
+		   		//PROC_SUNLOCK(p);
+				sx_sunlock(&VPS_VPS(vps, allproc_lock));
+				return (error);
+
+			} else if (error == ENOENT) {
+				path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+				snprintf(path, MAXPATHLEN,
+				    "%s/VPSRELINKED_%p",
+				    vps->_rootpath, fp->f_vnode);
+				DBGCORE("%s: proc=%p/%d/[%s] fp=%p "
+				    "fd_idx=%d\n", __func__, p, p->p_pid,
+				    p->p_comm, fp, i);
+				DBGCORE("%s: relinking vnode %p at [%s]\n",
+				    __func__, fp->f_vnode, path);
+				error = vps_suspend_relinkvnodes_one(vps,
+				    fp->f_vnode, path, AT_FDCWD);
+				free(path, M_TEMP);
+				if (error != 0 && error != EEXIST) {
+					DBGCORE("%s: error: %d\n",
+					    __func__, error);
+					fdrop(fp, curthread);
+		   			FILEDESC_SUNLOCK(fdp);
+		   			//PROC_SUNLOCK(p);
+					sx_sunlock(&VPS_VPS(vps,
+					    allproc_lock));
+					return (error);
+				}
+			}
+			fdrop(fp, curthread);
+		}
+		FILEDESC_SUNLOCK(fdp);
+		//PROC_UNLOCK(p);
+	}
+	sx_sunlock(&VPS_VPS(vps, allproc_lock));
+
+	return (error);
+}
+
+/*
+ * In case vnodes have been relinked in suspend,
+ * just delete those links now.
+ */
+static int
+vps_resume_relinkvnodes(struct vps *vps)
+{
+	int error = 0;
+
+	error = vps_suspend_relink_delete(vps->_rootvnode);
+
+	return (error);
+}
+
+/*
+ * Suspend VPS instance:
+ * Suspend all threads,
+ * keep all sockets and other FDs from receiving data,
+ * --> done for tcp !
+ *
+ * Come in with vps exclusively locked.
+ */
+int
+vps_suspend(struct vps *vps, int flags)
+{
+	struct prison *ppr, *cpr;
+	struct thread *td;
+	struct proc *p;
+	struct vnet *vnet;
+	int running_threads;
+	int descend;
+	int error = 0;
+
+	sx_assert(&vps->vps_lock, SA_XLOCKED);
+
+	if (vps->vps_status != VPS_ST_RUNNING)
+		return (EBUSY);
+
+	vps_suspend_mod_refcnt++;
+
+	DBGCORE("%s: suspend vps=%p BEGIN\n", __func__, vps);
+
+	vps->vps_status = VPS_ST_SUSPENDED;
+
+	/* ''main'' vnet of vps */
+	vnet = vps->vnet;
+	DBGCORE("%s: vnet=%p setting VPS_VNET_SUSPENDED\n", __func__, vnet);
+	vnet->vnet_vps_flags |= VPS_VNET_SUSPENDED;
+
+	/* vnets of jails, if any */
+	sx_slock(&allprison_lock);
+	ppr = VPS_VPS(vps, prison0);
+	FOREACH_PRISON_DESCENDANT_LOCKED(ppr, cpr, descend) {
+		if ((cpr->pr_flags & PR_VNET)==0)
+			continue;
+		vnet = cpr->pr_vnet;
+		DBGCORE("%s: vnet=%p setting VPS_VNET_SUSPENDED\n",
+		    __func__, vnet);
+		vnet->vnet_vps_flags |= VPS_VNET_SUSPENDED;
+	}
+	sx_sunlock(&allprison_lock);
+
+	vps->suspend_time = time_second;
+
+	sx_xlock(&VPS_VPS(vps, allproc_lock));
+	LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list) {
+		DBGCORE("p=%p pid=%d comm=[%s]\n", p, p->p_pid, p->p_comm);
+		PROC_LOCK(p);
+		p->p_flag |= P_STOPPED_TRACE; /* XXX good ?! */
+	
+		/* Keep proc from being swapped out (kernel stacks). */
+		p->p_lock++;
+	
+		if ((p->p_flag & P_INMEM) == 0) {
+			DBGCORE("%s: p=%p NOT P_INMEM, swapping in\n",
+			    __func__, p);
+			faultin(p);
+		}
+		TAILQ_FOREACH(td, &p->p_threads, td_plist) {
+			thread_lock(td);
+			DBGCORE("td=%u/%p td->td_flags=%08x\n",
+			    td->td_tid, td, td->td_flags);
+			//db_trace_thread(td, 16);
+			td->td_flags |= TDF_NEEDSUSPCHK | TDF_VPSSUSPEND;
+			if (TD_ON_SLEEPQ(td)) {
+				if (td->td_flags & TDF_SINTR)
+					sleepq_abort(td, ERESTART);
+				else
+					DBGCORE("%s: td=%p/%d on sleepqueue"
+					    " but not TDF_SINTR!\n",
+					    __func__, td, td->td_tid);
+	
+			} else if (TD_IS_SWAPPED(td)) {
+				panic("%s: td=%p TD_IS_SWAPPED\n",
+				    __func__, td);
+	
+			} else if (TD_IS_RUNNING(td) || TD_ON_RUNQ(td) ||
+			    TD_ON_RUNQ(td)) {
+				DBGCORE("%s: thread=%p is "
+				    "running/runq/can_run\n", __func__, td);
+				/* thread will be suspended at some
+				   point ... */
+	
+			} else if (TD_ON_LOCK(td) || TD_AWAITING_INTR(td)) {
+				DBGCORE("%s: thread=%p inhibited: "
+				    "TD_ON_LOCK / TD_AWAITING_INTR\n",
+				    __func__, td);
+				/* thread will be suspended at some
+				   point ... */
+	
+			} else {
+				DBGCORE("%s: thread=%p UNHANDLED STATE !\n",
+				    __func__, td);
+			}
+	
+#if 0
+#if defined(CPU_X86)
+			DBGCORE("td->td_frame=%p tf_rax=%p tf_rsp=%p\n",
+			    td->td_frame, (void*)td->td_frame->tf_rax,
+			    (void*)td->td_frame->tf_rsp);
+#elif defined(CPU_386)
+			DBGCORE("td->td_frame=%p tf_eax=%p tf_esp=%p\n",
+			    td->td_frame, (void*)td->td_frame->tf_eax,
+			    (void*)td->td_frame->tf_esp);
+#else
+#error "unsupported architecture"
+#endif
+#endif /* 0 */
+
+			thread_unlock(td);
+		}
+		PROC_UNLOCK(p);
+	}
+	sx_xunlock(&VPS_VPS(vps, allproc_lock));
+
+	/*
+	 * XXX If we get stuck here, keep system in a safe state and return.
+	 */
+
+	/* Block until all threads are suspended. */
+	do {
+		pause("vpsssp", hz / 10);
+		running_threads = 0;
+
+		sx_xlock(&VPS_VPS(vps, allproc_lock));
+		LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list) {
+			PROC_LOCK(p);
+
+			/* vfork */
+			if (p->p_flag & P_PPWAIT) {
+				cv_broadcast(&p->p_pwait);
+
+				DBGCORE("%s: cv_broadcast(%p) p=%p/%d\n",
+				    __func__, &p->p_pwait, p, p->p_pid);
+			}
+
+			TAILQ_FOREACH(td, &p->p_threads, td_plist)
+				if ( ! TD_IS_SUSPENDED(td))
+					++running_threads;
+
+			PROC_UNLOCK(p);
+		}
+		sx_xunlock(&VPS_VPS(vps, allproc_lock));
+
+	} while (running_threads > 0);
+
+	if (flags & VPS_SUSPEND_RELINKFILES)
+		error = vps_suspend_relinkvnodes(vps);
+
+	DBGCORE("%s: suspend vps=%p FINISHED\n", __func__, vps);
+
+	vps_suspend_mod_refcnt--;
+
+	return (error);
+}
+
+/*
+ * Resume vps instance previously suspended by vps_suspend().
+ *
+ * Come in with vps exclusively locked.
+ */
+int
+vps_resume(struct vps *vps, int flags)
+{
+	struct prison *ppr, *cpr;
+	struct vnet *vnet;
+	struct thread *td;
+	struct proc *p;
+	int wakeup_swapper;
+	int descend;
+#ifdef DISABLED_INVARIANTS
+	struct vps_ref *ref;
+#endif
+
+	sx_assert(&vps->vps_lock, SA_XLOCKED);
+
+	if (vps->vps_status != VPS_ST_SUSPENDED)
+		return (EBUSY);
+
+	vps_suspend_mod_refcnt++;
+
+	vps_resume_relinkvnodes(vps);
+
+	DBGCORE("%s: resume vps=%p BEGIN\n", __func__, vps);
+
+#ifdef DISABLED_INVARIANTS
+	DBGCORE("references: \n");
+	TAILQ_FOREACH(ref, &vps->vps_ref_head, list) {
+		DBGCORE("    ref=%p arg=%p ticks=%zu ",
+			ref, ref->arg, (size_t)ref->ticks);
+		if (ref->arg != (void*)0 && ref->arg != (void*)0xdead0010 &&
+		    ref->arg != (void*)0xbeefc0de) {
+			DBGCORE("cr_ref=%d\n",
+			    ((struct ucred *)(ref->arg))->cr_ref);
+		} else {
+			DBGCORE("\n");
+		}
+	}
+#endif
+
+	/*
+	 * XXX
+	 * cannot lock here because of vps_syscall_fixup().
+	 */
+	sx_xlock(&VPS_VPS(vps, allproc_lock));
+	LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list)
+		TAILQ_FOREACH(td, &p->p_threads, td_plist) {
+			//db_trace_thread(td, 16);
+			if ((vps_syscall_fixup(vps, td))) {
+				DBGCORE("%s: vps_syscall_fixup(vps=%p, "
+				    "td=%p) failed\n", __func__, vps, td);
+			}
+		}
+
+#ifdef DISABLED_INVARIANTS
+	DBGCORE("references: \n");
+	TAILQ_FOREACH(ref, &vps->vps_ref_head, list) {
+		DBGCORE("    ref=%p arg=%p ticks=%zu ",
+			ref, ref->arg, (size_t)ref->ticks);
+		if (ref->arg != (void*)0 && ref->arg != (void*)0xdead0010 &&
+		    ref->arg != (void*)0xbeefc0de) {
+			DBGCORE("cr_ref=%d\n",
+			    ((struct ucred *)(ref->arg))->cr_ref);
+		} else {
+			DBGCORE("\n");
+		}
+	}
+#endif
+
+	LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list) {
+		DBGCORE("p=%p pid=%d\n", p, p->p_pid);
+
+		PROC_LOCK(p);
+		p->p_flag &= ~P_STOPPED_TRACE;
+
+		/* Allow proc being swapped out again (kernel stacks). */
+		p->p_lock--;
+
+		PROC_UNLOCK(p);
+		PROC_SLOCK(p);
+
+		if ((p->p_flag & P_STOPPED_SIG) == 0) {
+			TAILQ_FOREACH(td, &p->p_threads, td_plist) {
+				DBGCORE("td=%p\n", td);
+				wakeup_swapper = 0;
+				thread_lock(td);
+				if (TD_IS_SUSPENDED(td))
+					wakeup_swapper =
+					    thread_unsuspend_one(td);
+				else
+					DBGCORE("%s: thread %p not "
+					    "suspended ---> MUST NOT "
+					    "HAPPEN !\n", __func__, td);
+				thread_unlock(td);
+				if (wakeup_swapper) {
+					DBGCORE("%s: wakeup_swapper()\n",
+					    __func__);
+					kick_proc0();
+				}
+			}
+		} else {
+			DBGCORE("%s: P_STOPPED_SIG, not resuming\n",
+			    __func__);
+		}
+		PROC_SUNLOCK(p);
+	}
+	sx_xunlock(&VPS_VPS(vps, allproc_lock));
+
+	vps->suspend_time = 0;
+
+	/* vnets of jails, if any */
+	sx_slock(&allprison_lock);
+	ppr = VPS_VPS(vps, prison0);
+	FOREACH_PRISON_DESCENDANT_LOCKED(ppr, cpr, descend) {
+		if ((cpr->pr_flags & PR_VNET)==0)
+			continue;
+		vnet = cpr->pr_vnet;
+		DBGCORE("%s: vnet=%p clearing VPS_VNET_SUSPENDED\n",
+		    __func__, vnet);
+		vnet->vnet_vps_flags &= ~VPS_VNET_SUSPENDED;
+	}
+	sx_sunlock(&allprison_lock);
+
+	/* ''main'' vnet of vps */
+	vnet = vps->vnet;
+	DBGCORE("%s: vnet=%p clearing VPS_VNET_SUSPENDED\n",
+	    __func__, vnet);
+	vnet->vnet_vps_flags &= ~VPS_VNET_SUSPENDED;
+
+	vps->vps_status = VPS_ST_RUNNING;
+
+	DBGCORE("%s: resume vps=%p FINISHED\n", __func__, vps);
+
+	vps_suspend_mod_refcnt--;
+
+	return (0);
+}
+
+int
+vps_abort(struct vps *vps, int flags)
+{
+	struct prison *ppr, *cpr;
+	struct vnet *vnet;
+	struct proc *p;
+	int descend;
+
+	sx_assert(&vps->vps_lock, SA_XLOCKED);
+
+	if (vps->vps_status != VPS_ST_SUSPENDED)
+		return (EBUSY);
+
+	DBGCORE("%s: abort vps=%p BEGIN\n", __func__, vps);
+
+	/* ''main'' vnet of vps */
+	vnet = vps->vnet;
+	DBGCORE("%s: vnet=%p setting VPS_VNET_ABORT\n", __func__, vnet);
+	vnet->vnet_vps_flags |= VPS_VNET_ABORT;
+
+	/* vnets of jails, if any */
+	sx_slock(&allprison_lock);
+	ppr = VPS_VPS(vps, prison0);
+	FOREACH_PRISON_DESCENDANT_LOCKED(ppr, cpr, descend) {
+		if ((cpr->pr_flags & PR_VNET)==0)
+			continue;
+		vnet = cpr->pr_vnet;
+		DBGCORE("%s: vnet=%p setting VPS_VNET_ABORT\n",
+		    __func__, vnet);
+		vnet->vnet_vps_flags |= VPS_VNET_ABORT;
+	}
+	sx_sunlock(&allprison_lock);
+
+	sx_xlock(&VPS_VPS(vps, allproc_lock));
+	LIST_FOREACH(p, &VPS_VPS(vps, allproc), p_list) {
+		DBGCORE("p=%p pid=%d\n", p, p->p_pid);
+		PROC_LOCK(p);
+		kern_psignal(p, SIGKILL);
+		PROC_UNLOCK(p);
+	}
+	sx_xunlock(&VPS_VPS(vps, allproc_lock));
+
+	vps_resume(vps, 0);
+
+	return (0);
+}
+
+/*
+ *  Access pages of a different vmspace.
+ */
+
+__attribute__((noinline))
+static int
+vps_access_vmspace(struct vmspace *vm, vm_offset_t vaddr, size_t len,
+    void *buf, int prot)
+{
+	vm_map_t map;
+	vm_page_t m;
+	vm_page_t *marr;
+	vm_map_entry_t entry;
+	vm_object_t object;
+	vm_pindex_t pindex;
+	vm_prot_t prot2;
+	vm_offset_t vaddr2;
+	vm_offset_t kvaddr;
+	boolean_t wired;
+	int npages;
+	int error;
+
+	DBGCORE("%s: vmspace=%p vaddr=%p len=%zu buf=%p prot=%x\n",
+		__func__, vm, (void*)vaddr, len, buf, prot);
+
+	prot &= (VM_PROT_READ|VM_PROT_WRITE);
+
+	marr = malloc(sizeof(vm_page_t) * ((len >> PAGE_SHIFT) + 1),
+	   M_VPS_CORE, M_WAITOK | M_ZERO);
+
+	map = &vm->vm_map;
+	npages = 0;
+	error = 0;
+	vaddr2 = vaddr;
+
+	if (vm_map_wire(map, trunc_page(vaddr), trunc_page(vaddr + len) +
+	    PAGE_SIZE, VM_MAP_WIRE_USER)) {
+		DBGCORE("%s: vm_map_wire: error\n", __func__);
+		return (EINVAL);
+	}
+
+	vm_map_lock_read(map);
+
+	do {
+
+		if ((error = vm_map_lookup_locked(&map, trunc_page(vaddr2),
+		    prot, &entry, &object, &pindex, &prot2, &wired))) {
+			DBGCORE("%s: vm_map_lookup failed: %d\n",
+			    __func__, error);
+			error = EFAULT;
+			goto unlock;
+		}
+
+		VM_OBJECT_WLOCK(object);
+
+		DBGCORE("%s: vaddr=%p len=%zu map=%p entry=%p object=%p "
+		    "pindex=%u\n", __func__, (void*)vaddr, len, map,
+		    entry, object, (unsigned int)pindex);
+
+		if ((m = vm_page_lookup(object, pindex)) == NULL) {
+			DBGCORE("%s: error vm_page_lookup\n", __func__);
+			error = EINVAL;
+			goto unlock;
+		}
+
+		VM_OBJECT_WUNLOCK(object);
+		if (error)
+			goto unwire;
+
+		marr[npages] = m;
+
+		++npages;
+		vaddr2 += PAGE_SIZE;
+
+	} while (trunc_page(vaddr2) < vaddr + len);
+
+	vm_map_lock(kernel_map);
+
+	if (vm_map_findspace(kernel_map, vm_map_min(kernel_map),
+	    npages << PAGE_SHIFT, &kvaddr) != KERN_SUCCESS) {
+		error = EINVAL;
+		DBGCORE("%s: error findspace\n", __func__);
+		goto unlock_kern;
+	}
+
+	/* actually map */
+	pmap_qenter(kvaddr, marr, npages);
+
+	switch (prot) {
+	case VM_PROT_READ:
+		memcpy(buf, (void *)(kvaddr + (vaddr - trunc_page(vaddr))),
+		    len);
+		break;
+	case VM_PROT_WRITE:
+		memcpy((void *)(kvaddr + (vaddr - trunc_page(vaddr))),
+		    buf, len);
+		break;
+	default:
+		break;
+	}
+
+	/* actually unmap */
+	pmap_qremove(kvaddr, npages);
+
+	free(marr, M_VPS_CORE);
+
+  unlock_kern:
+	vm_map_unlock(kernel_map);
+
+  unlock:
+	vm_map_unlock_read(map);
+
+  unwire:
+	vm_map_unwire(map, trunc_page(vaddr),
+	    trunc_page(vaddr + len) + PAGE_SIZE, VM_MAP_WIRE_USER);
+
+	return (error);
+}
+
+__attribute__((noinline))
+static void
+vps_syscall_fixup_inthread(register_t code, struct trapframe *frame)
+{
+	//struct syscall_args sa;
+	struct thread *td = curthread;
+	int error;
+
+	error = 0;
+
+	DBGCORE("%s: ####################### curthread=%p/%u code=%zu\n",
+		__func__, td, td->td_tid, (size_t)code);
+	KASSERT(frame == td->td_frame, ("%s: frame == td->td_frame\n",
+	    __func__));
+
+	switch(code) {
+	case SYS_vfork: {
+		/*
+		 * XXX: assuming single-threaded parent and
+		 *      only one child proc with P_PPWAIT set.
+		 */
+		struct proc *p2;
+		struct proc *p = td->td_proc;
+
+		LIST_FOREACH(p2, &p->p_children, p_sibling) {
+			if (p2->p_flag & P_PPWAIT)
+				break;
+		}
+		/*
+		KASSERT(p2 != NULL,
+		    ("%s: no child proc with p_flag & P_PPWAIT, p=%p\n",
+		    __func__, p));
+		*/
+		/* happens when vps is aborted --> no problem */
+		if (p2 == NULL) {
+			DBGCORE("%s: WARNING no child proc with p_flag "
+			    "& P_PPWAIT, p=%p\n", __func__, p);
+			break;
+		}
+		PROC_LOCK(p2);
+		error = 0;
+		while (p2->p_flag & P_PPWAIT) {
+			cv_wait(&p2->p_pwait, &p2->p_mtx);
+			if (td->td_flags & TDF_VPSSUSPEND) {
+				DBGCORE("%s: aborted cv_wait(), td=%p/%u\n",
+					__func__, td, td->td_tid);
+				error = EINTR;
+				break;
+			}
+		}
+		PROC_UNLOCK(p2);
+		if (error) {
+			td->td_retval[0] = 0;
+			td->td_retval[1] = 0;
+			td->td_errno = error;
+		} else {
+		   	td->td_retval[0] = p2->p_pid;
+		   	td->td_retval[1] = 0;
+		   	td->td_errno = 0;
+		}
+		/*
+		if ((td->td_flags & TDF_VPSSUSPEND) == 0)
+		   	cpu_set_syscall_retval(td, td->td_errno);
+		*/
+		break;
+	}
+	case SYS_nanosleep: {
+		/*
+		struct timespec ts1, ts2;
+
+		if ((error = cpu_fetch_syscall_args(td, &sa))) {
+			printf("%s: cpu_fetch_syscall_args() error: %d\n",
+				__func__, error);
+			error = EINTR;
+			break;
+		}
+		KASSERT(sa.code == code,
+		    ("%s: sa.code != code\n", __func__));
+
+		if (sa.args[0] == 0)
+			break;
+
+		if ((vps_access_vmspace(td->td_proc->p_vmspace, sa.args[0],
+		    sizeof(struct timespec), &ts1, VM_PROT_READ)))
+			break;
+		DBGCORE("%s: SYS_nanosleep: suspended at %lu\n",
+		    __func__, vps->suspend_time);
+		DBGCORE("%s: SYS_nanosleep: ts: sec=%lu nsec=%lu\n",
+		    __func__, ts1.tv_sec, ts1.tv_nsec);
+		*/
+		break;
+	}
+	default: {
+		break;
+	}
+	}
+
+        if (td->td_flags & TDF_VPSSUSPEND) {
+                DBGCORE("%s: td=%p suspending\n", __func__, td);
+                td->td_errno = error;
+                if (td->td_flags & TDF_NEEDSUSPCHK) {
+                        PROC_LOCK(td->td_proc);
+                        thread_suspend_check(0);
+                        /*
+                         * Threads created by vps_restore() never
+                         * reach this point.
+                         */
+                        PROC_UNLOCK(td->td_proc);
+                }
+                td->td_flags &= ~TDF_VPSSUSPEND;
+                error = td->td_errno;
+        }
+
+	cpu_set_syscall_retval(td, td->td_errno);
+
+        userret(td, frame);
+
+#ifdef KTRACE
+        if (KTRPOINT(td, KTR_STRUCT))
+                ktrstruct("VPS", "VPS RESTORED", 13);
+#endif
+        mtx_assert(&Giant, MA_NOTOWNED);
+}
+
+static int
+vps_syscall_fixup_need_inthread(struct vps *vps, struct thread *td,
+    register_t code, register_t *args, int narg)
+{
+	int need_inthread = 0;
+
+	switch (code) {
+	case SYS_nanosleep: {
+		struct timespec ts;
+		if (args[0] == 0)
+			break;
+		if ((vps_access_vmspace(td->td_proc->p_vmspace, args[0],
+		    sizeof(struct timespec), &ts, VM_PROT_READ)))
+			break;
+		if (1) {
+			DBGCORE("%s: SYS_nanosleep: suspended at %zu\n",
+			    __func__, (size_t)vps->suspend_time);
+			DBGCORE("%s: SYS_nanosleep: ts: sec=%zu nsec=%zu\n",
+			    __func__, (size_t)ts.tv_sec,
+			    (size_t)ts.tv_nsec);
+			//need_inthread = 1;
+		}
+		td->td_errno = ERESTART;
+		break;
+	}
+	case SYS_vfork: {
+		DBGCORE("########################## SYS_VFORK: td=%p "
+		    "tid=%u\n", td, td->td_tid);
+		if (td->td_errno != EINTR)
+			break;
+		need_inthread = 1;
+		break;
+	}
+	default: {
+		break;
+	}
+	}
+
+	return (need_inthread);
+}
+
+__attribute__((noinline))
+static int
+vps_syscall_fixup(struct vps *vps, struct thread *td)
+{
+	register_t code;
+	register_t args[8];
+	int narg = 8;
+	int error = 0;
+
+	error = vps_md_syscall_fixup(vps, td, &code, (register_t **)&args, &narg);
+	if (error != 0)
+		goto out;
+
+	if (vps_syscall_fixup_need_inthread(vps, td, code, args, narg) != 0) {
+		error = vps_md_syscall_fixup_setup_inthread(vps, td, code);
+		if (error != 0)
+			goto out;
+	}
+
+  out:
+	return (error);
+}
+
+static int
+vps_suspend_modevent(module_t mod, int type, void *data)
+{
+        int error;
+
+        error = 0;
+
+        switch (type) {
+        case MOD_LOAD:
+		vps_suspend_mod_refcnt = 0;
+		vps_func->vps_suspend = vps_suspend;
+		vps_func->vps_resume = vps_resume;
+		vps_func->vps_abort = vps_abort;
+		vps_func->vps_access_vmspace = vps_access_vmspace;
+		vps_func->vps_syscall_fixup_inthread =
+		    vps_syscall_fixup_inthread;
+		break;
+        case MOD_UNLOAD:
+		if (vps_suspend_mod_refcnt > 0)
+			return (EBUSY);
+		vps_func->vps_suspend = NULL;
+		vps_func->vps_resume = NULL;
+		vps_func->vps_abort = NULL;
+		vps_func->vps_access_vmspace = NULL;
+		vps_func->vps_syscall_fixup_inthread = NULL;
+		break;
+        default:
+		error = EOPNOTSUPP;
+		break;
+        }
+
+        return (error);
+}
+
+static moduledata_t vps_suspend_mod = {
+        "vps_suspend",
+        vps_suspend_modevent,
+        0
+};
+
+DECLARE_MODULE(vps_suspend, vps_suspend_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+
+static int
+vps_suspend_relink_delete(struct vnode *vp)
+{
+	struct vnode *save_cdir;
+	struct dirent *dp;
+	struct thread *td;
+	char *dirbuf;
+	char *cpos = NULL;
+	off_t off;
+	int dirbuflen;
+	int eofflag;
+	int len;
+	int error = 0;
+
+	dirbuflen = PATH_MAX;
+	td = curthread;
+
+        dirbuf = (char *)malloc(dirbuflen, M_TEMP, M_WAITOK);
+
+	save_cdir = td->td_proc->p_fd->fd_cdir;
+	td->td_proc->p_fd->fd_cdir = vp;
+
+	VOP_LOCK(vp, LK_SHARED | LK_RETRY);
+
+	off = 0;
+	len = 0;
+	do {
+		error = get_next_dirent(vp, &dp, dirbuf, dirbuflen, &off,
+					&cpos, &len, &eofflag, td);
+		if (error) {
+			printf("%s: get_next_dirent() error=%d\n",
+				__func__, error);
+			goto out;
+		}
+
+		/*
+		DEBUG("%s: dp=%p dp->d_type=%d dp->d_name=[%s]\n",
+			__func__, dp, dp->d_type, dp->d_name);
+		*/
+
+		if (dp->d_type != DT_REG)
+			goto next;
+		if (strcmp(dp->d_name, "VPSRELINKED_"))
+			goto next;
+
+		error = kern_unlinkat(td, AT_FDCWD, dp->d_name,
+		    UIO_SYSSPACE, 0);
+		printf("%s: unlinked [%s]: error=%d\n",
+			__func__, dp->d_name, error);
+
+	  next:
+		;
+
+	} while (len > 0 || !eofflag);
+
+
+ out:
+	VOP_UNLOCK(vp, 0);
+	td->td_proc->p_fd->fd_cdir = save_cdir;
+	free(dirbuf, M_TEMP);
+	return (error);
+}
+
+#define DIRENT_MINSIZE (sizeof(struct dirent) - (MAXNAMLEN+1) + 4)
+
+/* copied from kern/vfs_default.c */
+static int
+get_next_dirent(struct vnode *vp, struct dirent **dpp, char *dirbuf,
+                int dirbuflen, off_t *off, char **cpos, int *len,
+                int *eofflag, struct thread *td)
+{
+        int error, reclen;
+        struct uio uio;
+        struct iovec iov;
+        struct dirent *dp;
+
+        KASSERT(VOP_ISLOCKED(vp), ("vp %p is not locked", vp));
+        KASSERT(vp->v_type == VDIR, ("vp %p is not a directory", vp));
+
+        if (*len == 0) {
+                iov.iov_base = dirbuf;
+                iov.iov_len = dirbuflen;
+
+                uio.uio_iov = &iov;
+                uio.uio_iovcnt = 1;
+                uio.uio_offset = *off;
+                uio.uio_resid = dirbuflen;
+                uio.uio_segflg = UIO_SYSSPACE;
+                uio.uio_rw = UIO_READ;
+                uio.uio_td = td;
+
+                *eofflag = 0;
+
+#ifdef MAC
+                error = mac_vnode_check_readdir(td->td_ucred, vp);
+                if (error == 0)
+#endif
+                        error = VOP_READDIR(vp, &uio, td->td_ucred, eofflag,
+                                NULL, NULL);
+                if (error)
+                        return (error);
+
+                *off = uio.uio_offset;
+
+                *cpos = dirbuf;
+                *len = (dirbuflen - uio.uio_resid);
+        }
+
+        dp = (struct dirent *)(*cpos);
+        reclen = dp->d_reclen;
+        *dpp = dp;
+
+        /* check for malformed directory.. */
+        if (reclen < DIRENT_MINSIZE)
+                return (EINVAL);
+
+        *cpos += reclen;
+        *len -= reclen;
+
+        return (0);
+}
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_user.c head/sys/vps/vps_user.c
--- clean-head/sys/vps/vps_user.c	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_user.c	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,711 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char vpsid[] =
+    "$Id: vps_user.c 155 2013-06-04 09:15:51Z klaus $";
+
+#include <sys/cdefs.h>
+
+#include "opt_ddb.h"
+#include "opt_global.h"
+
+#ifdef VPS
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/limits.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/libkern.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <sys/ucred.h>
+#include <sys/ioccom.h>
+#include <sys/socket.h>
+#include <sys/jail.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include "vps_user.h"
+#include "vps_account.h"
+#include "vps.h"
+#include "vps2.h"
+
+#ifdef DIAGNOSTIC
+
+#define DBGUSER	if (debug_user) printf
+
+static int debug_user = 1;
+
+SYSCTL_INT(_debug, OID_AUTO, vps_user_debug, CTLFLAG_RW,
+    &debug_user, 0, "");
+
+#else
+
+#define DBGUSER(x, ...)
+
+#endif /* DIAGNOSTIC */
+
+MALLOC_DECLARE(M_VPS_DEV);
+
+/* ----------------------- */
+
+//#define INCLUDE_CURVPS 1
+
+int
+vps_ioc_list(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	struct vps_info *info;
+	int vpscnt;
+
+	sx_slock(&vps_all_lock);
+
+	vpscnt = 0;
+
+#ifdef INCLUDE_CURVPS
+	/* Include own vps. */
+	++vpscnt;
+#endif
+	/* Calculate data size to allocate. */
+	LIST_FOREACH(vps2, &vps->vps_child_head, vps_sibling)
+		++vpscnt;
+
+	ctx->length = sizeof(*info) * vpscnt;
+	/*
+	 * Always round up to pages, otherwise mmap produces rubbish.
+	 */
+	ctx->length = ((ctx->length >> PAGE_SHIFT) + 1 ) << PAGE_SHIFT;
+	ctx->data = malloc(ctx->length, M_VPS_DEV, M_WAITOK | M_ZERO);
+
+	info = (struct vps_info *)ctx->data;
+
+#ifdef INCLUDE_CURVPS
+	if (1) {
+		/* Include own vps. */
+		vps2 = vps;
+		strncpy(info->name, vps2->vps_name, sizeof(info->name));
+		strncpy(info->fsroot, vps2->_rootpath,
+		    sizeof(info->fsroot));
+		info->status = vps2->vps_status;
+		info->nprocs = VPS_VPS(vps2, nprocs);
+		info->nsocks = vps2->vnet->vnet_sockcnt;
+		info->nifaces = vps2->vnet->vnet_ifcnt;
+		info->restore_count = vps2->restore_count;
+		info->acc.virt = vps2->vps_acc->virt.cur;
+		info->acc.phys = vps2->vps_acc->phys.cur;
+		info->acc.pctcpu = vps2->vps_acc->pctcpu.cur;
+		++info;
+	}
+#endif
+	LIST_FOREACH(vps2, &vps->vps_child_head, vps_sibling) {
+		strncpy(info->name, vps2->vps_name, sizeof(info->name));
+		strncpy(info->fsroot, vps2->_rootpath,
+		    sizeof(info->fsroot));
+		info->status = vps2->vps_status;
+		info->nprocs = VPS_VPS(vps2, nprocs);
+		info->nsocks = vps2->vnet->vnet_sockcnt;
+		info->nifaces = vps2->vnet->vnet_ifcnt;
+		info->restore_count = vps2->restore_count;
+		info->acc.virt = vps2->vps_acc->virt.cur;
+		info->acc.phys = vps2->vps_acc->phys.cur;
+		info->acc.pctcpu = vps2->vps_acc->pctcpu.cur;
+		++info;
+	}
+	sx_sunlock(&vps_all_lock);
+
+	/* Return count of vps info structures to user. */
+	*((int *)data) = vpscnt;
+
+	return (0);
+}
+
+int
+vps_ioc_create(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	struct vps_param *vps_pr;
+	int error;
+
+	error = 0;
+	vps_pr = (struct vps_param *)data;
+	vps_pr->name[sizeof(vps_pr->name) -1] = '\0';
+	vps_pr->fsroot[sizeof(vps_pr->fsroot) -1] = '\0';
+	if (strlen(vps_pr->name) == 0)
+		return (EINVAL);
+
+	sx_xlock(&vps_all_lock);
+	vps2 = vps_by_name(vps, vps_pr->name);
+	if (vps2) {
+		sx_xunlock(&vps_all_lock);
+		return (EADDRINUSE);
+	}
+
+	vps2 = vps_alloc(vps, vps_pr, vps_pr->name, &error);
+
+	sx_xunlock(&vps_all_lock);
+
+	return (error);
+}
+
+int
+vps_ioc_destroy(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	char *vps_name;
+	int error;
+
+	vps_name = (char *)data;
+	vps_name[MAXHOSTNAMELEN-1] = '\0';
+	if (strlen(vps_name) == 0)
+		return (EINVAL);
+
+	sx_xlock(&vps_all_lock);
+	vps2 = vps_by_name(vps, vps_name);
+	if (vps2)
+		error = vps_free(vps2);
+	else
+		error = ESRCH;
+	sx_xunlock(&vps_all_lock);
+
+	return (error);
+}
+
+int
+vps_ioc_switch(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	char *vps_name;
+	int error;
+
+	vps_name = (char *)data;
+	vps_name[MAXHOSTNAMELEN-1] = '\0';
+	if (strlen(vps_name) == 0)
+		return (EINVAL);
+
+	sx_slock(&vps_all_lock);
+	vps2 = vps_by_name(vps, vps_name);
+	if (vps2)
+		error = vps_switch_proc(td, vps2, 0);
+	else
+		error = ESRCH;
+	sx_sunlock(&vps_all_lock);
+
+	return (error);
+}
+
+/*
+ * We don't support this anymore.
+ * Instead the userspace tool uses a pts to wait for the switched process.
+ */
+int
+vps_ioc_switchwait(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+
+	return (EOPNOTSUPP);
+}
+
+int
+vps_ioc_ifmove(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps_arg_ifmove *va_ifmove;
+	struct vps *vps2;
+	int error;
+
+	va_ifmove = (struct vps_arg_ifmove *) data;
+	va_ifmove->vps_name[sizeof(va_ifmove->vps_name) -1] = '\0';
+	va_ifmove->if_name[sizeof(va_ifmove->if_name) -1] = '\0';
+	va_ifmove->if_newname[sizeof(va_ifmove->if_newname) -1] = '\0';
+	if (strlen(va_ifmove->vps_name) == 0)
+		return (EINVAL);
+	if (strlen(va_ifmove->if_name) == 0)
+		return (EINVAL);
+	if (strlen(va_ifmove->if_newname) == 0)
+		return (EINVAL);
+
+	sx_slock(&vps_all_lock);
+	vps2 = vps_by_name(vps, va_ifmove->vps_name);
+	if (vps2) {
+		DBGUSER("%s: if_name=[%s] if_newname=[%s]\n",
+		    __func__, va_ifmove->if_name, va_ifmove->if_newname);
+		CURVNET_SET_QUIET(TD_TO_VNET(td));
+		error = if_vmove_vps(td, va_ifmove->if_name,
+		    sizeof(va_ifmove->if_name), vps2,
+		    va_ifmove->if_newname);
+		CURVNET_RESTORE();
+	} else
+		error = ESRCH;
+	sx_sunlock(&vps_all_lock);
+
+	return (error);
+}
+
+int
+vps_ioc_suspend(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	struct vps_arg_flags *va;
+	int error;
+
+	va = (struct vps_arg_flags *)data;
+	va->vps_name[MAXHOSTNAMELEN-1] = '\0';
+	if (strlen(va->vps_name) == 0)
+		return (EINVAL);
+	if (va->flags & ~(VPS_SUSPEND_RELINKFILES))
+		return (EINVAL);
+
+	if (vps_func->vps_suspend == NULL)
+		return (EOPNOTSUPP);
+
+	sx_slock(&vps_all_lock);
+	vps2 = vps_by_name(vps, va->vps_name);
+	if (vps2) {
+		sx_xlock(&vps2->vps_lock);
+		error = vps_func->vps_suspend(vps2, va->flags);
+		sx_xunlock(&vps2->vps_lock);
+	} else
+		error = ESRCH;
+	sx_sunlock(&vps_all_lock);
+
+	return (error);
+}
+
+int
+vps_ioc_resume(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	struct vps_arg_flags *va;
+	int error;
+
+	va = (struct vps_arg_flags *)data;
+	va->vps_name[MAXHOSTNAMELEN-1] = '\0';
+	if (strlen(va->vps_name) == 0)
+		return (EINVAL);
+	if (va->flags & 1)
+		return (EINVAL);
+
+	if (vps_func->vps_resume == NULL)
+		return (EOPNOTSUPP);
+
+	sx_slock(&vps_all_lock);
+	vps2 = vps_by_name(vps, va->vps_name);
+	if (vps2) {
+		if (vps2->vps_status == VPS_ST_SNAPSHOOTING &&
+		    vps_func->vps_snapshot_finish)
+			vps_func->vps_snapshot_finish(ctx, vps2);
+		sx_xlock(&vps2->vps_lock);
+		error = vps_func->vps_resume(vps2, va->flags);
+		sx_xunlock(&vps2->vps_lock);
+	} else
+		error = ESRCH;
+	sx_sunlock(&vps_all_lock);
+
+	return (error);
+}
+
+int
+vps_ioc_abort(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	struct vps_arg_flags *va;
+	int error;
+
+	va = (struct vps_arg_flags *)data;
+	va->vps_name[MAXHOSTNAMELEN-1] = '\0';
+	if (strlen(va->vps_name) == 0)
+		return (EINVAL);
+	if (va->flags & 1)
+		return (EINVAL);
+
+	if (vps_func->vps_abort == NULL)
+		return (EOPNOTSUPP);
+
+	sx_slock(&vps_all_lock);
+	vps2 = vps_by_name(vps, va->vps_name);
+	if (vps2) {
+		if (vps2->vps_status == VPS_ST_SNAPSHOOTING &&
+		    vps_func->vps_snapshot_finish)
+			vps_func->vps_snapshot_finish(ctx, vps2);
+		sx_xlock(&vps2->vps_lock);
+		error = vps_func->vps_abort(vps2, va->flags);
+		sx_xunlock(&vps2->vps_lock);
+	} else
+		error = ESRCH;
+	sx_sunlock(&vps_all_lock);
+
+	return (error);
+}
+
+int
+vps_ioc_snapshot(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	struct vps_arg_snapst *va_snapst;
+	int error;
+
+	va_snapst = (struct vps_arg_snapst *)data;
+	/*va_snapst->vps_name[sizeof(va_snapst->vps_name) - 1] = '\0';*/
+	va_snapst->vps_name[MAXHOSTNAMELEN-1] = '\0';
+	if (strlen(va_snapst->vps_name) == 0)
+		return (EINVAL);
+
+	sx_slock(&vps_all_lock);
+	vps2 = vps_by_name(vps, va_snapst->vps_name);
+	if (vps2) {
+		if (vps_func->vps_snapshot == NULL)
+			error = EOPNOTSUPP;
+		else {
+			sx_xlock(&vps2->vps_lock);
+			error = vps_func->vps_snapshot(ctx, vps2,
+			    va_snapst);
+			sx_xunlock(&vps2->vps_lock);
+		}
+	} else
+		error = ESRCH;
+	sx_sunlock(&vps_all_lock);
+
+	return (error);
+}
+
+int
+vps_ioc_snapshot_finish(struct vps *vps, struct vps_dev_ctx *ctx,
+    u_long cmd, caddr_t data, int flags, struct thread *td)
+{
+	int error;
+
+	if (vps_func->vps_snapshot_finish == NULL)
+		error = EOPNOTSUPP;
+	else
+		error = vps_func->vps_snapshot_finish(ctx, NULL);
+
+	return (error);
+}
+
+int
+vps_ioc_restore(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	struct vps_arg_snapst *va_snapst;
+	int error;
+
+	va_snapst = (struct vps_arg_snapst *)data;
+	/*va_snapst->vps_name[sizeof(va_snapst->vps_name) - 1] = '\0';*/
+	va_snapst->vps_name[MAXHOSTNAMELEN-1] = '\0';
+	if (strlen(va_snapst->vps_name) == 0)
+		return (EINVAL);
+
+	sx_xlock(&vps_all_lock);
+	vps2 = vps_by_name(vps, va_snapst->vps_name);
+	if (vps2 == NULL) {
+		if (vps_func->vps_restore == NULL)
+			error = EOPNOTSUPP;
+		else
+			error = vps_func->vps_restore(ctx, va_snapst);
+	} else
+		error = EADDRINUSE;
+	sx_xunlock(&vps_all_lock);
+
+	return (error);
+}
+
+int
+vps_ioc_argset(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	struct vps_arg_set *va;
+	struct vps_arg_item *item;
+	caddr_t kdata;
+	size_t kdatalen;
+	int error;
+
+	va = (struct vps_arg_set *)data;
+	va->vps_name[sizeof(va->vps_name) - 1] = '\0';
+	if (strlen(va->vps_name) == 0)
+		return (EINVAL);
+
+	sx_xlock(&vps_all_lock);
+	vps2 = vps_by_name(vps, va->vps_name);
+	if (vps2 == NULL)
+		error = ENOENT;
+	else {
+		kdatalen = va->datalen;
+		DBGUSER("%s: kdatalen=%zu\n", __func__, kdatalen);
+		kdata = malloc(kdatalen, M_TEMP, M_WAITOK);
+		if ((error = copyin(va->data, kdata, kdatalen)))
+			goto fail;
+		for (item = (struct vps_arg_item *)kdata;
+		    (caddr_t)item < kdata + kdatalen;
+		    item++) {
+			DBGUSER("%s: item=%p type=%u revoke=%u\n",
+			    __func__, item, item->type, item->revoke);
+			switch (item->type) {
+			case VPS_ARG_ITEM_PRIV:
+				error = vps_priv_setitem(vps, vps2, item);
+				break;
+			case VPS_ARG_ITEM_IP4:
+			case VPS_ARG_ITEM_IP6:
+				error = vps_ip_setitem(vps, vps2, item);
+				break;
+			case VPS_ARG_ITEM_LIMIT:
+				error = vps_limit_setitem(vps, vps2, item);
+				break;
+			default:
+				error = EINVAL;
+				break;
+			}
+			if (error != 0)
+				break;
+		}
+  fail:
+		free(kdata, M_TEMP);
+	}
+	sx_xunlock(&vps_all_lock);
+
+	return (error);
+}
+
+int
+vps_ioc_argget(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	struct vps_arg_get *va;
+	size_t kdatalen, len, klenused;
+	caddr_t kdata;
+	int error;
+
+	va = (struct vps_arg_get *)data;
+	va->vps_name[sizeof(va->vps_name) - 1] = '\0';
+	if (strlen(va->vps_name) == 0)
+		return (EINVAL);
+
+	sx_xlock(&vps_all_lock);
+	vps2 = vps_by_name(vps, va->vps_name);
+	if (vps2 == NULL)
+		error = ENOENT;
+	else {
+		error = 0;
+		kdatalen = va->datalen;
+		klenused = 0;
+		kdata = malloc(kdatalen, M_TEMP, M_WAITOK | M_ZERO);
+
+		len = kdatalen - klenused;
+		if ((error = vps_priv_getitemall(vps, vps2, kdata +
+		    klenused, &len)))
+			goto fail;
+		klenused += len;
+
+		len = kdatalen - klenused;
+		if ((error = vps_ip_getitemall(vps, vps2, kdata + klenused,
+		    &len)))
+			goto fail;
+		klenused += len;
+
+		len = kdatalen - klenused;
+		error = vps_limit_getitemall(vps, vps2, kdata + klenused,
+		    &len);
+		if (error != 0 && error != EOPNOTSUPP)
+			goto fail;
+		klenused += len;
+
+		KASSERT(klenused <= kdatalen,
+		    ("%s: klenused=%zu > kdatalen=%zu !!!\n",
+		    __func__, klenused, kdatalen));
+
+		if ((error = copyout(kdata, va->data, klenused)))
+			goto fail;
+  fail:
+		va->datalen = klenused;
+		free(kdata, M_TEMP);
+	}
+	sx_xunlock(&vps_all_lock);
+
+	/* XXX
+	if (vps2)
+		vps_account_print_pctcpu(vps2);
+	*/
+
+	return (error);
+}
+
+int
+vps_ioc_getextinfo(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+    caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	struct vps_getextinfo *vx;
+	struct vps_extinfo *xinfo;
+	size_t kdatalen, klenused;
+	caddr_t kdata;
+	int error;
+
+	vx = (struct vps_getextinfo *)data;
+	vx->vps_name[sizeof(vx->vps_name) - 1] = '\0';
+	if (strlen(vx->vps_name) == 0)
+		return (EINVAL);
+
+	if (vx->datalen < sizeof(*xinfo))
+		return (EINVAL);
+
+	sx_xlock(&vps_all_lock);
+	vps2 = vps_by_name(vps, vx->vps_name);
+	if (vps2 == NULL)
+		error = ENOENT;
+	else {
+		error = 0;
+		kdatalen = vx->datalen;
+		klenused = 0;
+		kdata = malloc(kdatalen, M_TEMP, M_WAITOK | M_ZERO);
+
+		xinfo = (struct vps_extinfo *)(kdata + klenused);
+
+		strncpy(xinfo->name, vps2->vps_name, sizeof(xinfo->name));
+		strncpy(xinfo->fsroot, vps2->_rootpath,
+		    sizeof(xinfo->fsroot));
+		xinfo->status = vps2->vps_status;
+		xinfo->nprocs = VPS_VPS(vps2, nprocs);
+		xinfo->nsocks = vps2->vnet->vnet_sockcnt;
+		xinfo->nifaces = vps2->vnet->vnet_ifcnt;
+		xinfo->restore_count = vps2->restore_count;
+
+		klenused += sizeof(*xinfo);
+
+		KASSERT(klenused <= kdatalen,
+		    ("%s: klenused=%zu > kdatalen=%zu !!!\n",
+		    __func__, klenused, kdatalen));
+
+		if ((error = copyout(kdata, vx->data, klenused)))
+		    goto fail;
+  fail:
+		vx->datalen = klenused;
+		free(kdata, M_TEMP);
+	}
+	sx_xunlock(&vps_all_lock);
+
+	/* XXX
+	if (vps2)
+		vps_account_print_pctcpu(vps2);
+	*/
+
+	return (error);
+}
+
+int
+vps_ioc_fscalc(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+	caddr_t data, int flags, struct thread *td)
+{
+
+	return (EOPNOTSUPP);
+}
+
+int
+vps_ioc_fscalcpath(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+	caddr_t data, int flags, struct thread *td)
+{
+	struct vps_arg_get *va;
+	struct vps_arg_item *item;
+	size_t kdatalen;
+	caddr_t kdata;
+	int error;
+
+	va = (struct vps_arg_get *)data;
+	va->vps_name[sizeof (va->vps_name) - 1] = '\0';
+	if (strlen (va->vps_name) == 0)
+	   return (EINVAL);
+
+	if (va->datalen < sizeof(*item) * 2)
+	   return (EINVAL);
+
+	error = 0;
+	kdatalen = va->datalen;
+	kdata = malloc(kdatalen, M_TEMP, M_WAITOK | M_ZERO);
+
+	/* XXX
+	if ((error = vps_account_vpsfs_calc_path(vps, va->vps_name,
+	    kdata, &kdatalen)))
+		goto fail;
+	*/
+	error = EOPNOTSUPP;
+	goto fail;
+
+	if ((error = copyout(kdata, va->data, kdatalen)))
+	   goto fail;
+
+ fail:
+	va->datalen = kdatalen;
+	free(kdata, M_TEMP);
+
+	return (error);
+}
+
+int
+vps_ioc_getconsfd(struct vps *vps, struct vps_dev_ctx *ctx, u_long cmd,
+	caddr_t data, int flags, struct thread *td)
+{
+	struct vps *vps2;
+	struct vps_arg_getconsfd *va;
+	int error;
+
+	va = (struct vps_arg_getconsfd *)data;
+	va->vps_name[MAXHOSTNAMELEN-1] = '\0';
+	if (strlen(va->vps_name) == 0)
+	   return (EINVAL);
+
+	sx_xlock(&vps_all_lock);
+	vps2 = vps_by_name(vps, va->vps_name);
+	if (vps2)
+	   error = vps_console_getfd(vps2, td, &va->consfd);
+	else
+	   error = ESRCH;
+	sx_xunlock(&vps_all_lock);
+
+	return (error);
+}
+
+#endif /* VPS */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/sys/vps/vps_user.h head/sys/vps/vps_user.h
--- clean-head/sys/vps/vps_user.h	1970-01-01 01:00:00.000000000 +0100
+++ head/sys/vps/vps_user.h	2013-06-24 14:20:40.000000000 +0200
@@ -0,0 +1,274 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: vps_user.h 153 2013-06-03 16:18:17Z klaus $ */
+
+#ifndef _VPS_USER_H
+#define _VPS_USER_H
+
+#include <sys/cdefs.h>
+
+#define DEFAULTLEN      0x40
+
+/*
+ * Possible vps status values
+ */
+//#define VPS_ST_INITISDYING               0x01
+#define VPS_ST_CREATING                  0x02
+#define VPS_ST_RUNNING                   0x04
+#define VPS_ST_SUSPENDED                 0x08
+#define VPS_ST_SNAPSHOOTING              0x10
+#define VPS_ST_RESTORING                 0x20
+#define VPS_ST_DYING                     0x40
+#define VPS_ST_DEAD                      0x80
+
+/*
+ * Various flags
+ */
+#define VPS_SUSPEND_RELINKFILES 	0x1000
+
+#ifndef _VPS_USER_H__ONLY_FLAGS
+/*
+ * This structure is used for the LIST ioctl,
+ * where only basic information about each vps
+ * instance is needed.
+ * Therefore this structure is small and can be filled
+ * in quickly.
+ */
+struct vps_info {
+        char name[MAXHOSTNAMELEN];
+        char fsroot[MAXPATHLEN];
+
+        int status;
+        int nprocs;
+        int nsocks;
+        int nifaces;
+	int restore_count;
+
+	/*struct vps_acc account;*/
+	struct {
+		unsigned long virt;
+		unsigned long phys;
+		unsigned long pctcpu;
+	} acc;
+};
+
+/*
+ * Extended info, used for the ''show'' command.
+ */
+struct vps_extinfo {
+        char name[MAXHOSTNAMELEN];
+        char fsroot[MAXPATHLEN];
+
+        int status;
+        int nprocs;
+        int nsocks;
+        int nifaces;
+	int restore_count;
+};
+
+struct vps_getextinfo {
+        char vps_name[MAXHOSTNAMELEN];
+	void *data;
+	size_t datalen;
+};
+
+/*
+ * This is the extended structure for creating, modifying
+ * or detailed viewing of a single vps instance.
+ * It contains all parameters and information available.
+ */
+struct vps_param {
+        char name[MAXHOSTNAMELEN];
+        char fsroot[MAXPATHLEN];
+};
+
+struct vps_arg_ifmove {
+        char vps_name[MAXHOSTNAMELEN];
+        char if_name[IFNAMSIZ];
+        char if_newname[IFNAMSIZ];
+};
+
+struct vps_arg_snapst {
+        char vps_name[MAXHOSTNAMELEN];
+        caddr_t database;
+        size_t datalen;
+        char errmsg[DEFAULTLEN];
+	caddr_t msgbase;
+	size_t msglen;
+};
+
+/* --- */
+
+#define VPS_ARG_PRIV_ALLOW	0x2
+#define VPS_ARG_PRIV_DENY	0x4
+#define VPS_ARG_PRIV_NOSYS	0x8
+
+#define VPS_ARG_ITEM_PRIV	0x2
+#define VPS_ARG_ITEM_IP4	0x4
+#define VPS_ARG_ITEM_IP6	0x8
+#define VPS_ARG_ITEM_LIMIT	0x10
+
+struct vps_arg_priv {
+	u_int priv;
+	u_int value;
+};
+
+struct vps_arg_ip4 {
+	struct in_addr addr;
+	struct in_addr mask;
+};
+
+struct vps_arg_ip6 {
+	struct in6_addr addr;
+	u_int8_t	plen;
+};
+
+struct vps_arg_limit {
+	u_int resource;
+	size_t cur;
+	size_t soft;
+	size_t hard;
+	u_int16_t hits_soft;
+	u_int16_t hits_hard;
+};
+
+struct vps_arg_item {
+	u_int16_t type;
+	u_int8_t revoke;
+	u_int8_t _pad0;
+	u_int16_t _pad1;
+	u_int16_t _pad2;
+	union {
+		struct vps_arg_priv  priv;
+		struct vps_arg_ip4   ip4;
+		struct vps_arg_ip6   ip6;
+		struct vps_arg_limit limit;
+	} u;
+};
+
+struct vps_arg_get {
+        char vps_name[MAXHOSTNAMELEN];
+	void *data;
+	size_t datalen;
+};
+
+struct vps_arg_set {
+        char vps_name[MAXHOSTNAMELEN];
+	void *data;
+	size_t datalen;
+        char errmsg[DEFAULTLEN];
+};
+
+struct vps_arg_flags {
+	char vps_name[MAXHOSTNAMELEN];
+	int flags;
+};
+
+struct vps_arg_getconsfd {
+	char vps_name[MAXHOSTNAMELEN];
+	int consfd;
+};
+
+/* --- */
+
+/*
+ * arg is the count of info structs which can be read (mmap).
+ */
+#define VPS_IOC_LIST     _IOR('v', 0x0101, int)
+
+/*
+ * see 'struct vps_getextinfo' definition.
+ */
+#define VPS_IOC_GETXINFO _IOWR('v', 0x0102, struct vps_getextinfo)
+
+/*
+ * arg is a pointer to a char string providing information
+ * if an error occured.
+ */
+#define VPS_IOC_SET      _IOR('v', 0x0103, caddr_t *)
+
+/* arg is a filled in vps_param struct. */
+#define VPS_IOC_CREAT    _IOW('v', 0x0104, struct vps_param)
+
+/* arg is name of vps instance. */
+#define VPS_IOC_DESTR    _IOW('v', 0x0105, char[MAXHOSTNAMELEN])
+
+/* arg is name of vps instance. */
+#define VPS_IOC_SWITCH   _IOW('v', 0x0106, char[MAXHOSTNAMELEN])
+
+/* arg is name of vps instance. */
+#define VPS_IOC_SWITWT   _IOW('v', 0x0107, char[MAXHOSTNAMELEN])
+
+/* arg is filled in vps_arg_ifmove struct. interface name
+   is returned in ->if_name. */
+#define VPS_IOC_IFMOVE   _IOWR('v', 0x0109, struct vps_arg_ifmove)
+
+/* arg is name of vps instance. */
+#define VPS_IOC_SUSPND   _IOW('v', 0x0110, struct vps_arg_flags)
+
+/* arg is name of vps instance. */
+#define VPS_IOC_RESUME   _IOW('v', 0x0111, struct vps_arg_flags)
+
+/* arg is filled in vps_arg_snapst struct.
+   length of data for mmaping is returned. */
+#define VPS_IOC_SNAPST   _IOWR('v', 0x0112, struct vps_arg_snapst)
+
+/* arg is filled in vps_arg_snapst struct.
+   length of data for mmaping is given.
+   name of vps instance is optional. */
+#define VPS_IOC_RESTOR   _IOWR('v', 0x0113, struct vps_arg_snapst)
+
+/* arg is size in bytes to allocate. */
+#define VPS_IOC_ALLOC    _IOW('v', 0x0114, int)
+
+/* arg is name of vps instance. */
+#define VPS_IOC_ABORT    _IOW('v', 0x0115, struct vps_arg_flags)
+
+/* arg is ignored. */
+#define VPS_IOC_SNAPSTFIN     _IOW('v', 0x0119, void *)
+
+#define VPS_IOC_ARGGET   _IOWR('v', 0x0120, struct vps_arg_get)
+#define VPS_IOC_ARGSET   _IOWR('v', 0x0121, struct vps_arg_set)
+
+/* vps_name is the mountpoint of the filesystem in question. */
+#define VPS_IOC_FSCALCPATH    _IOWR('v', 0x0130, struct vps_arg_get)
+
+/* vps_name is the vps which has the filesystem in question mounted
+   as its root. */
+#define VPS_IOC_FSCALC        _IOWR('v', 0x0131, struct vps_arg_get)
+
+/* arg is name of vps instance. */
+#define VPS_IOC_GETCONSFD     _IOWR('v', 0x0140, struct vps_arg_getconsfd)
+
+#endif /* ! _VPS_USER_H__ONLY_FLAGS */
+
+#endif /* _VPS_USER_H */
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/autobuild/Makefile head/tools/vps/autobuild/Makefile
--- clean-head/tools/vps/autobuild/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/autobuild/Makefile	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,246 @@
+#
+# Klaus P. Ohrhallinger <k@7he.at>, 2012-2013
+# 
+# $Id: Makefile 128 2013-04-09 18:07:32Z klaus $
+#
+
+FREEBSD_VERSION=91
+ORIGSRCURL=ftp://ftp.at.freebsd.org/pub/FreeBSD/releases/amd64/9.1-RELEASE/src.txz
+SVNURL='svn+ssh://klaus@svn.7he.at/svn/vps/trunk'
+
+BUILDER32_HOST=builder32.7he.at
+BUILDER32_USER=root
+
+SOURCES=usr/src/sys usr/src/sbin/mount usr/src/include
+
+DIFF_EXCLUDE=".svn\nrsync_vps.amd64\nrsync_vps.i386\nautobuild\n\*nodiff\n"
+
+#
+#
+#
+
+# debug
+COPTFLAGS= -pipe
+CFLAGS= -fno-strict-aliasing -pipe
+
+# prod
+#COPTFLAGS= -pipe -O2
+#CFLAGS= -fno-strict-aliasing -pipe -O2
+
+
+all:	fetch extract diff patch build summary
+#all:	build summary
+
+build:	build_amd64_dbg build_amd64_prod build_i386_dbg build_i386_prod
+#build:	build_amd64_dbg build_i386_dbg
+#build:	build_amd64_prod build_i386_prod
+#build:	build_amd64_dbg
+#build:	build_i386_dbg
+
+clean:
+	rm -rf work
+
+fetch: fetch_orig fetch_vps
+
+extract: extract_pre extract_orig extract_vps
+
+fetch_orig:
+	if [ ! -s "src.txz" ] \
+	; then \
+		fetch -4 ${ORIGSRCURL} \
+	; else \
+		echo "source already downloaded" \
+	; fi
+
+fetch_vps:
+	if [ ! -d "trunk" ] \
+	; then \
+		svn co ${SVNURL} \
+	; else \
+		echo "svn already checked out" \
+	; fi
+
+extract_pre:
+	mkdir work
+
+extract_orig:
+	mkdir work/orig
+	tar xJpf src.txz -C work/orig ${SOURCES}
+	mv work/orig/usr/src/* work/orig/
+	rm -r work/orig/usr
+
+extract_vps:
+	cp -a trunk work
+	rm -rf work/trunk/web
+
+diff:
+	svn info trunk | grep Revision | awk '{print $$2}' > ./work/svnversion
+	[ -e "vps.diff" ] && rm vps.diff || true
+	printf ${DIFF_EXCLUDE} > ./work/diffexclude
+	# diff: 0 -> equal; 1 -> different; 2 -> trouble
+	(cd work; diff -Naupr -X ./diffexclude -I '$$Id.*$$' -I '$$FreeBSD.*$$' -w orig trunk \
+		> ../vps-fbsd${FREEBSD_VERSION}-r`cat ./svnversion`.diff) || true
+	ls -lh vps-fbsd${FREEBSD_VERSION}-r`cat ./work/svnversion`.diff
+	ln -s vps-fbsd${FREEBSD_VERSION}-r`cat ./work/svnversion`.diff vps.diff
+	rm ./work/diffexclude
+
+patch:
+	[ -d "work/build" ] && rm -rf work/build || true
+	cp -a work/orig work/build
+	(cd work/build/; patch -p1 < ../../vps.diff)
+	cp -v work/trunk/tools/vps/rsync/rsync_vps.amd64 \
+		work/build/tools/vps/rsync/rsync_vps.amd64
+	cp -v work/trunk/tools/vps/rsync/rsync_vps.i386 \
+		work/build/tools/vps/rsync/rsync_vps.i386
+
+summary:
+	ls -lh vps*.diff
+	ls -lh work/build/vps*.tbz
+
+build_amd64_dbg:
+	printf "COPTFLAGS= -pipe\nCFLAGS= -fno-strict-aliasing -pipe\n" > \
+		/tmp/make-dbg.conf
+	(cd work/build/sys/amd64/conf && \
+		config VPS_DBG)
+	(cd work/build/sys/amd64/compile/VPS_DBG && \
+		make cleandepend __MAKE_CONF=/tmp/make-dbg.conf && \
+		make depend __MAKE_CONF=/tmp/make-dbg.conf && \
+		make kernel __MAKE_CONF=/tmp/make-dbg.conf && \
+		make modules __MAKE_CONF=/tmp/make-dbg.conf)
+	make do-package \
+		COMPILEDIR=work/build/sys/amd64/compile/VPS_DBG \
+		ARCH2=amd64 \
+		TYPE2=dbg \
+		MAKE_CONF=/tmp/make-dbg.conf
+	
+build_amd64_prod:
+	printf "COPTFLAGS= -pipe -O2\nCFLAGS= -fno-strict-aliasing -pipe -O2 -Wuninitialized\n" > \
+		./work/make-prod.conf
+	(cd work/build/sys/amd64/conf && \
+		config VPS_PROD)
+	(cd work/build/sys/amd64/compile/VPS_PROD && \
+		make cleandepend __MAKE_CONF=./work/make-prod.conf && \
+		make depend __MAKE_CONF=./work/make-prod.conf && \
+		make kernel __MAKE_CONF=./work/make-prod.conf && \
+		make modules __MAKE_CONF=./work/make-prod.conf)
+	make do-package \
+		COMPILEDIR=work/build/sys/amd64/compile/VPS_PROD \
+		ARCH2=amd64 \
+		TYPE2=prod \
+		MAKE_CONF=/tmp/make-prod.conf
+
+build_i386_dbg:
+	#[ ! -d "${BUILDER32}/tmp/work" ]
+	cp Makefile ./work/Makefile
+	rm -rf ./work/pkg-files
+	cp -a pkg-files ./work/pkg-files
+	rsync -av --delete -e "ssh -4 -l ${BUILDER32_USER}" work ${BUILDER32_HOST}:/tmp/${BUILDER32_USER}/
+	ssh -4 -l ${BUILDER32_USER} ${BUILDER32_HOST} "cd /tmp/${BUILDER32_USER} && make -f work/Makefile __build_i386_dbg"
+	rsync -av --delete -e "ssh -4 -l ${BUILDER32_USER}" ${BUILDER32_HOST}:/tmp/${BUILDER32_USER}/work ./
+
+
+__build_i386_dbg:
+	printf "COPTFLAGS= -pipe\nCFLAGS= -fno-strict-aliasing -pipe\n" > \
+		/tmp/${BUILDER32_USER}/make-dbg.conf
+	(cd work/build/sys/i386/conf && \
+		config VPS_DBG)
+	(cd work/build/sys/i386/compile/VPS_DBG && \
+		make cleandepend __MAKE_CONF=/tmp/make-dbg.conf && \
+		make depend __MAKE_CONF=/tmp/make-dbg.conf && \
+		make kernel __MAKE_CONF=/tmp/make-dbg.conf && \
+		make modules __MAKE_CONF=/tmp/make-dbg.conf )
+	rm -rf ./pkg-files
+	mv work/pkg-files ./pkg-files
+	make -f work/Makefile do-package \
+		COMPILEDIR=work/build/sys/i386/compile/VPS_DBG \
+		ARCH2=i386 \
+		TYPE2=dbg \
+		MAKE_CONF=/tmp/${BUILDER32_USER}/make-dbg.conf
+	rm -rf ./pkg-files
+	
+build_i386_prod:
+	#[ ! -d "${BUILDER32}/tmp/work" ]
+	cp Makefile ./work/Makefile
+	rm -rf ./work/pkg-files
+	cp -a pkg-files ./work/pkg-files
+	rsync -av --delete -e "ssh -4 -l ${BUILDER32_USER}" work ${BUILDER32_HOST}:/tmp/${BUILDER32_USER}/
+	ssh -4 -l ${BUILDER32_USER} ${BUILDER32_HOST} "cd /tmp/${BUILDER32_USER} && make -f work/Makefile __build_i386_prod"
+	rsync -av --delete -e "ssh -4 -l ${BUILDER32_USER}" ${BUILDER32_HOST}:/tmp/${BUILDER32_USER}/work ./
+
+
+__build_i386_prod:
+	printf "COPTFLAGS= -pipe -O2\nCFLAGS= -fno-strict-aliasing -pipe -O2 -Wuninitialized\n" > \
+		/tmp/make-prod.conf
+	(cd work/build/sys/i386/conf && \
+		config VPS_PROD)
+	(cd work/build/sys/i386/compile/VPS_PROD && \
+		make cleandepend __MAKE_CONF=/tmp/make-prod.conf && \
+		make depend __MAKE_CONF=/tmp/make-prod.conf && \
+		make kernel __MAKE_CONF=/tmp/make-prod.conf && \
+		make modules __MAKE_CONF=/tmp/make-prod.conf )
+	rm -rf ./pkg-files
+	mv work/pkg-files ./pkg-files
+	make -f work/Makefile do-package \
+		COMPILEDIR=work/build/sys/i386/compile/VPS_PROD \
+		ARCH2=i386 \
+		TYPE2=prod \
+		MAKE_CONF=/tmp/make-prod.conf
+	rm -rf ./pkg-files
+
+do-package:
+	mkdir "${COMPILEDIR}/dist"
+	(cd ${COMPILEDIR} && make install DESTDIR=`pwd`/dist)
+	mkdir -p ${COMPILEDIR}/dist/sbin
+	mkdir -p ${COMPILEDIR}/dist/usr/sbin
+	mkdir -p ${COMPILEDIR}/dist/usr/share/man/man4
+	mkdir -p ${COMPILEDIR}/dist/usr/share/man/man5
+	mkdir -p ${COMPILEDIR}/dist/usr/share/man/man8
+	mkdir -p ${COMPILEDIR}/dist/usr/share/man/man9
+	mkdir -p ${COMPILEDIR}/dist/etc/vps
+	(DIR=`realpath ${COMPILEDIR}`; \
+		cd ${COMPILEDIR}/../../../../usr.sbin/vpsctl && \
+		make clean __MAKE_CONF=${MAKE_CONF} && \
+		make __MAKE_CONF=${MAKE_CONF} && \
+		make install DESTDIR=$${DIR}/dist __MAKE_CONF=${MAKE_CONF} && \
+		make clean __MAKE_CONF=${MAKE_CONF} )
+	(DIR=`realpath ${COMPILEDIR}`; \
+		cd ${COMPILEDIR}/../../../../sbin/mount_vpsfs && \
+		make clean __MAKE_CONF=${MAKE_CONF} && \
+		make __MAKE_CONF=${MAKE_CONF} && \
+		make install DESTDIR=$${DIR}/dist __MAKE_CONF=${MAKE_CONF} && \
+		make clean __MAKE_CONF=${MAKE_CONF} )
+	install -o root -g wheel -m 0555 \
+		${COMPILEDIR}/../../../../tools/vps/rsync/rsync_vps.${ARCH2} \
+		${COMPILEDIR}/dist/usr/sbin/rsync_vps
+	# various other files that go into package
+	install -o root -g wheel -m 0644 \
+		pkg-files/dist/etc_vps_example.conf \
+		${COMPILEDIR}/dist/etc/vps/vps_example.conf
+	install -o root -g wheel -m 0755 \
+		pkg-files/dist/vpssetup.sh \
+		${COMPILEDIR}/dist/etc/rc.vpssetup.sh
+	# all installed now
+	echo "@cwd /" > ${COMPILEDIR}/pkg-plist
+	echo "@comment ORIGIN:misc/vps" >> ${COMPILEDIR}/pkg-plist
+	echo "@srcdir `realpath ${COMPILEDIR}/dist`" >> ${COMPILEDIR}/pkg-plist
+	echo "@exec mkdir -p /etc/vps" >> ${COMPILEDIR}/pkg-plist
+	echo "@exec mkdir -p /usr/vps" >> ${COMPILEDIR}/pkg-plist
+	(cd ${COMPILEDIR}/dist && find . -type f >> ../pkg-plist)
+	echo "@dirrm /etc/vps" >> ${COMPILEDIR}/pkg-plist
+	echo "@dirrm /usr/vps" >> ${COMPILEDIR}/pkg-plist
+	pkg_create -v \
+		-D pkg-files/pkg-message \
+		-c pkg-files/pkg-comment \
+		-d pkg-files/pkg-descr \
+		-i pkg-files/pkg_install_pre.sh \
+		-I pkg-files/pkg_install_post.sh \
+		-k pkg-files/pkg_remove_pre.sh \
+		-K pkg-files/pkg_remove_post.sh \
+		-f ${COMPILEDIR}/pkg-plist \
+		work/build/vps-fbsd${FREEBSD_VERSION}-r`cat ./work/svnversion`-${ARCH2}-${TYPE2}.tbz
+
+	# clean up
+	rm -rf "${COMPILEDIR}/dist"
+	rm -f ${COMPILEDIR}/pkg-plist
+
+# EOF
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/autobuild/pkg-files/dist/etc_vps_example.conf head/tools/vps/autobuild/pkg-files/dist/etc_vps_example.conf
--- clean-head/tools/vps/autobuild/pkg-files/dist/etc_vps_example.conf	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/autobuild/pkg-files/dist/etc_vps_example.conf	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,8 @@
+NAME = 'example'
+FSROOT = '/usr/vps/example_mp'
+FSROOT_PRIV = '/usr/vps/example'
+NETIF_0_ADDRESS = '10.0.0.190, 2001:10:20::190'
+ROOT_MOUNT = 'mount_vpsfs /usr/vps/example /usr/vps/example_mp'
+ROOT_UNMOUNT = 'umount /usr/vps/example_mp'
+INIT = '/sbin/init'
+LIMITS = 'phys:6000000:8000000,virt:100000000:160000000:pctcpu:100:200'
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/autobuild/pkg-files/dist/vpssetup.sh head/tools/vps/autobuild/pkg-files/dist/vpssetup.sh
--- clean-head/tools/vps/autobuild/pkg-files/dist/vpssetup.sh	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/autobuild/pkg-files/dist/vpssetup.sh	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,32 @@
+#!/bin/sh -x
+
+kldload if_vps
+kldload vps_dev
+kldload vps_ddb
+kldload vps_libdump
+kldload vps_snapst
+kldload vps_restore
+kldload vps_suspend
+kldload vps_account
+kldload vpsfs
+kldload sysvmsg
+kldload sysvsem
+kldload sysvshm
+
+ifconfig vps0 create
+ifconfig vps0 up
+
+sysctl -w net.inet.ip.forwarding=1
+sysctl -w net.inet6.ip6.forwarding=1
+
+sysctl -w debug.vps_core_debug=0
+sysctl -w debug.vps_if_debug=0
+sysctl -w debug.vps_dev_debug=0
+sysctl -w debug.vps_user_debug=0
+sysctl -w debug.vps_snapst_debug=0
+sysctl -w debug.vps_restore_debug=0
+sysctl -w debug.vps_restore_ktrace=0
+sysctl -w debug.vps_account_debug=0
+sysctl -w debug.vps_vpsfs_debug=0
+
+exit 0
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/autobuild/pkg-files/pkg-comment head/tools/vps/autobuild/pkg-files/pkg-comment
--- clean-head/tools/vps/autobuild/pkg-files/pkg-comment	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/autobuild/pkg-files/pkg-comment	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1 @@
+VPS - OS Level Virtualization
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/autobuild/pkg-files/pkg-descr head/tools/vps/autobuild/pkg-files/pkg-descr
--- clean-head/tools/vps/autobuild/pkg-files/pkg-descr	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/autobuild/pkg-files/pkg-descr	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,7 @@
+OS Level Virtualization
+See vps(4) for more information.
+
+This package will backup your previously installed
+kernel to /boot/kernel.GENERIC upon install.
+
+WWW: http://www.7he.at/freebsd/vps/
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/autobuild/pkg-files/pkg-message head/tools/vps/autobuild/pkg-files/pkg-message
--- clean-head/tools/vps/autobuild/pkg-files/pkg-message	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/autobuild/pkg-files/pkg-message	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,16 @@
+* * * * * * * * * * * * * * * * * * * * * * * * * *
+Your previously installed kernel has been moved to
+/boot/kernel.GENERIC
+
+Type:
+boot /boot/kernel.GENERIC/kernel
+at the boot loader prompt to use it.
+
+There is an example config file at 
+/etc/vps/vps_example.conf
+
+A script that loads the kernel modules is at
+/etc/rc.vpssetup.sh
+
+See vpsctl(8) how to get started. 
+* * * * * * * * * * * * * * * * * * * * * * * * * *
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/autobuild/pkg-files/pkg_install_post.sh head/tools/vps/autobuild/pkg-files/pkg_install_post.sh
--- clean-head/tools/vps/autobuild/pkg-files/pkg_install_post.sh	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/autobuild/pkg-files/pkg_install_post.sh	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exit 0
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/autobuild/pkg-files/pkg_install_pre.sh head/tools/vps/autobuild/pkg-files/pkg_install_pre.sh
--- clean-head/tools/vps/autobuild/pkg-files/pkg_install_pre.sh	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/autobuild/pkg-files/pkg_install_pre.sh	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+if [ ! -d /boot/kernel.GENERIC ]
+then
+        mv /boot/kernel /boot/kernel.GENERIC
+        echo "Moved currently installed kernel to /boot/kernel.GENERIC"
+fi
+
+exit 0
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/autobuild/pkg-files/pkg_remove_post.sh head/tools/vps/autobuild/pkg-files/pkg_remove_post.sh
--- clean-head/tools/vps/autobuild/pkg-files/pkg_remove_post.sh	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/autobuild/pkg-files/pkg_remove_post.sh	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+if [ -d /boot/kernel.GENERIC ]
+then
+        rmdir /boot/kernel
+        mv /boot/kernel.GENERIC /boot/kernel
+fi
+
+exit 0
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/autobuild/pkg-files/pkg_remove_pre.sh head/tools/vps/autobuild/pkg-files/pkg_remove_pre.sh
--- clean-head/tools/vps/autobuild/pkg-files/pkg_remove_pre.sh	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/autobuild/pkg-files/pkg_remove_pre.sh	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exit 0
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/autoinstalldist.sh head/tools/vps/autoinstalldist.sh
--- clean-head/tools/vps/autoinstalldist.sh	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/autoinstalldist.sh	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+fail() {
+        echo "FAILURE"
+        exit 1
+}
+
+tar xzpf dist.tgz || fail
+rm -rf /boot/kernel || fail
+mv boot/kernel /boot/ || fail
+mv usr/sbin/vpsctl /usr/sbin/vpsctl || fail
+mv sbin/mount_vpsfs /sbin/mount_vpsfs || fail
+
+echo "SUCCESS"
+exit 0
+
+# EOF
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/builddist.sh head/tools/vps/builddist.sh
--- clean-head/tools/vps/builddist.sh	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/builddist.sh	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,31 @@
+#!/bin/sh -x
+
+# to be run in kernel compile directory
+
+dist="$(pwd)/dist"
+
+rsync_bin="rsync_vps.$(uname -m)"
+
+rm -r ${dist}
+make install DESTDIR=${dist}
+mkdir -p ${dist}/sbin
+mkdir -p ${dist}/usr/sbin
+mkdir -p ${dist}/usr/share/man
+mkdir -p ${dist}/usr/share/man/man4
+mkdir -p ${dist}/usr/share/man/man5
+mkdir -p ${dist}/usr/share/man/man8
+mkdir -p ${dist}/usr/share/man/man9
+cd ../../../../usr.sbin/vpsctl && make clean && make && make install DESTDIR=${dist} && make clean && cd - || exit 1
+cd ../../../../sbin/mount_vpsfs && make clean && make && make install DESTDIR=${dist} && make clean && cd - || exit 1
+cp ../../../../tools/vps/rsync/${rsync_bin} ${dist}/usr/sbin/rsync_vps
+cp ../../../../tools/vps/dist-README ${dist}/README
+
+cd dist
+tar czpvf ../dist.tgz *
+cd ..
+ls -lh dist.tgz
+rm -r ${dist}
+
+exit 0
+
+# EOF
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/check_linelength.pl head/tools/vps/check_linelength.pl
--- clean-head/tools/vps/check_linelength.pl	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/check_linelength.pl	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,59 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+exit(main(\@ARGV));
+
+sub main {
+	my $line;
+	my $length;
+	my $cpos;
+	my $lpos;
+	my $spacescnt;
+	my $spacesstr;
+	my $argv = shift;
+	my $linenum = 0;
+
+	#print("argv[0]=@$argv[0] argv[1]=@$argv[1]\n");
+
+	open(FILE, "<", @$argv[0]) or die "cannot open [@$argv[0]]";
+
+	while (<FILE>) {
+		$line = $_;
+
+		$linenum += 1;
+
+		# Convert '\t' to '        '.
+		#$line =~ s/\t/        /g;
+		$lpos = 0;
+		while ($line =~ m/\t/) {
+			$cpos = index($line, "\t", $lpos);
+			$spacescnt = 8 - ($cpos % 8);
+			#print("cpos=$cpos spacescnt=$spacescnt\n");
+			$spacesstr = "";
+			while ($spacescnt > 0) {
+				$spacesstr .= " ";
+				$spacescnt -= 1;
+			}
+			$line =~ s/\t/$spacesstr/;
+			$lpos = $cpos;
+		}
+
+		# Remove '\n'.
+		$line =~ s/\n//;
+
+		#print("$line\n");
+
+		$length = length($line);
+
+		if ($length > 76) {
+			print("line $linenum length $length [$line]\n");
+		}
+	}
+
+	close(FILE);
+
+	return (0);
+}
+
+# EOF
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/dist-README head/tools/vps/dist-README
--- clean-head/tools/vps/dist-README	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/dist-README	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,8 @@
+
+* * * * * * * * * * * * * * * * * * * * * * * * * *
+*       Virtual Private Systems for FreeBSD       *
+* * * * * * * * * * * * * * * * * * * * * * * * * *
+
+Please visit http://www.7he.at/freebsd/vps/
+for further and up to date information.
+
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/installdist.sh head/tools/vps/installdist.sh
--- clean-head/tools/vps/installdist.sh	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/installdist.sh	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,10 @@
+#!/bin/sh -x
+
+tar xzpvf dist.tgz
+rm -rf /boot/kernel
+mv boot/kernel /boot/
+mv usr/sbin/vpsctl /usr/sbin/vpsctl
+mv sbin/mount_vpsfs /sbin/mount_vpsfs
+mv usr/sbin/rsync_vps /usr/sbin/rsync_vps
+
+
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/makepublicdiff.sh head/tools/vps/makepublicdiff.sh
--- clean-head/tools/vps/makepublicdiff.sh	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/makepublicdiff.sh	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+ORIGDIR=clean-head
+WORKDIR=head
+
+DIFFFILENAME=$(date '+vps-%Y%m%d_%s.diff')
+
+diff -Naupr -x .svn -x rsync_vps.\* -I '$Id.*$' -I '$FreeBSD.*$' ${ORIGDIR} ${WORKDIR} > ${DIFFFILENAME} 
+
+ls -lh ${DIFFFILENAME}
+
+# EOF
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/merge.sh head/tools/vps/merge.sh
--- clean-head/tools/vps/merge.sh	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/merge.sh	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+SRCDIR=trunk
+DSTDIR=head
+
+DIRS=$(cd ${SRCDIR} && find . -type d | grep -v '\.svn')
+FILES=$(cd ${SRCDIR} && find . -type f | grep -v '\.svn')
+
+
+for DIR in ${DIRS}
+do
+	if [ ! -e "${DSTDIR}/${DIR}" ]
+	then
+		mkdir -p "${DSTDIR}/${DIR}"
+	fi
+done
+
+for FILE in ${FILES}
+do
+	cp -av "${SRCDIR}/${FILE}" "${DSTDIR}/${FILE}"
+done 
+
+exit 0
+
+# EOF
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/rsync/README head/tools/vps/rsync/README
--- clean-head/tools/vps/rsync/README	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/rsync/README	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,4 @@
+
+Binaries are available at:
+XXX
+
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/rsync/rsync-20100417.diff head/tools/vps/rsync/rsync-20100417.diff
--- clean-head/tools/vps/rsync/rsync-20100417.diff	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/rsync/rsync-20100417.diff	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,59 @@
+Only in rsync-3.0.5-koh/: Makefile
+Only in rsync-3.0.5-koh/: config.h
+Only in rsync-3.0.5-koh/: config.log
+Only in rsync-3.0.5-koh/: config.status
+Only in rsync-3.0.5-koh/lib: dummy
+diff -aur rsync-3.0.5/log.c rsync-3.0.5-koh/log.c
+--- rsync-3.0.5/log.c	2008-09-27 04:19:51.000000000 +0000
++++ rsync-3.0.5-koh/log.c	2010-03-29 06:58:37.000000000 +0000
+@@ -319,7 +319,10 @@
+ 		f = stderr;
+ 		break;
+ 	case FINFO:
++		/*
+ 		f = am_server ? stderr : stdout;
++		*/
++		f = stderr;
+ 		break;
+ 	default:
+ 		exit_cleanup(RERR_MESSAGEIO);
+@@ -444,7 +447,10 @@
+ 		return;
+ 
+ 	if (code == FINFO && !am_server)
++		/*
+ 		f = stdout;
++		*/
++		f = stderr;
+ 	else
+ 		f = stderr;
+ 
+diff -aur rsync-3.0.5/main.c rsync-3.0.5-koh/main.c
+--- rsync-3.0.5/main.c	2008-10-11 18:14:43.000000000 +0000
++++ rsync-3.0.5-koh/main.c	2010-03-29 07:02:40.000000000 +0000
+@@ -1260,8 +1260,20 @@
+ 			remote_argv ? NS(remote_argv[0]) : "");
+ 	}
+ 
+-	pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc,
+-		     &f_in, &f_out);
++	if (!strcmp(shell_cmd, "-")) {
++		server_options(remote_argv,&remote_argc);
++		f_in = 0;
++		f_out = 1;
++		pid = -1;
++		/*
++		rprintf(FINFO,"remote_argc=%d remote_argv: [%s] [%s] [%s] [%s]\n",
++			remote_argc, remote_argv[0], remote_argv[1], remote_argv[2],
++			remote_argv[3]);
++		*/
++	} else {
++		pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc,
++			     &f_in, &f_out);
++	}
+ 
+ 	/* if we're running an rsync server on the remote host over a
+ 	 * remote shell command, we need to do the RSYNCD protocol first */
+Only in rsync-3.0.5-koh/popt: dummy
+Only in rsync-3.0.5-koh/: shconfig
+Only in rsync-3.0.5-koh/zlib: dummy
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/rsync/rsync-20120604.diff head/tools/vps/rsync/rsync-20120604.diff
--- clean-head/tools/vps/rsync/rsync-20120604.diff	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/rsync/rsync-20120604.diff	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,123 @@
+Only in rsync-3.0.9-koh: Makefile
+Only in rsync-3.0.9-koh: access.o
+Only in rsync-3.0.9-koh: acls.o
+Only in rsync-3.0.9-koh: authenticate.o
+Only in rsync-3.0.9-koh: backup.o
+Only in rsync-3.0.9-koh: batch.o
+Only in rsync-3.0.9-koh: checksum.o
+Only in rsync-3.0.9-koh: chmod.o
+Only in rsync-3.0.9-koh: cleanup.o
+Only in rsync-3.0.9-koh: clientname.o
+Only in rsync-3.0.9-koh: clientserver.o
+Only in rsync-3.0.9-koh: compat.o
+Only in rsync-3.0.9-koh: config.h
+Only in rsync-3.0.9-koh: config.log
+Only in rsync-3.0.9-koh: config.status
+Only in rsync-3.0.9-koh: connection.o
+Only in rsync-3.0.9-koh: exclude.o
+Only in rsync-3.0.9-koh: fileio.o
+Only in rsync-3.0.9-koh: flist.o
+Only in rsync-3.0.9-koh: generator.o
+Only in rsync-3.0.9-koh: hashtable.o
+Only in rsync-3.0.9-koh: hlink.o
+Only in rsync-3.0.9-koh: io.o
+Only in rsync-3.0.9-koh/lib: compat.o
+Only in rsync-3.0.9-koh/lib: dummy
+Only in rsync-3.0.9-koh/lib: md5.o
+Only in rsync-3.0.9-koh/lib: mdfour.o
+Only in rsync-3.0.9-koh/lib: permstring.o
+Only in rsync-3.0.9-koh/lib: pool_alloc.o
+Only in rsync-3.0.9-koh/lib: snprintf.o
+Only in rsync-3.0.9-koh/lib: sysacls.o
+Only in rsync-3.0.9-koh/lib: sysxattrs.o
+Only in rsync-3.0.9-koh/lib: wildmatch.o
+Only in rsync-3.0.9-koh: loadparm.o
+diff -aupr rsync-3.0.9/log.c rsync-3.0.9-koh/log.c
+--- rsync-3.0.9/log.c	2011-01-30 03:25:53.000000000 +0000
++++ rsync-3.0.9-koh/log.c	2012-06-04 10:59:45.000000000 +0000
+@@ -317,7 +317,10 @@ void rwrite(enum logcode code, const cha
+ 		f = stderr;
+ 		break;
+ 	case FINFO:
++		/*
+ 		f = am_server ? stderr : stdout;
++		*/
++		f = stderr;
+ 		break;
+ 	default:
+ 		exit_cleanup(RERR_MESSAGEIO);
+@@ -442,7 +445,10 @@ void rflush(enum logcode code)
+ 		return;
+ 
+ 	if (code == FINFO && !am_server)
++		/*
+ 		f = stdout;
++		*/
++		f = stderr;
+ 	else
+ 		f = stderr;
+ 
+Only in rsync-3.0.9-koh: log.c.orig
+Only in rsync-3.0.9-koh: log.o
+diff -aupr rsync-3.0.9/main.c rsync-3.0.9-koh/main.c
+--- rsync-3.0.9/main.c	2011-06-18 19:44:47.000000000 +0000
++++ rsync-3.0.9-koh/main.c	2012-06-04 13:30:32.000000000 +0000
+@@ -1272,8 +1272,21 @@ static int start_client(int argc, char *
+ 			remote_argv ? NS(remote_argv[0]) : "");
+ 	}
+ 
+-	pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc,
+-		     &f_in, &f_out);
++	if (!strcmp(shell_cmd, "-")) {
++		server_options(remote_argv,&remote_argc);
++		f_in = 0;
++		f_out = 1;
++		pid = -1;
++		local_server = 0;
++		/*
++		rprintf(FINFO,"remote_argc=%d remote_argv: [%s] [%s] [%s] [%s]\n",
++			remote_argc, remote_argv[0], remote_argv[1], remote_argv[2],
++			remote_argv[3]);
++		*/
++	} else {
++		pid = do_cmd(shell_cmd, shell_machine, shell_user, remote_argv, remote_argc,
++			     &f_in, &f_out);
++	}
+ 
+ 	/* if we're running an rsync server on the remote host over a
+ 	 * remote shell command, we need to do the RSYNCD protocol first */
+Only in rsync-3.0.9-koh: main.c.orig
+Only in rsync-3.0.9-koh: main.o
+Only in rsync-3.0.9-koh: match.o
+Only in rsync-3.0.9-koh: options.o
+Only in rsync-3.0.9-koh: params.o
+Only in rsync-3.0.9-koh: pipe.o
+Only in rsync-3.0.9-koh/popt: dummy
+Only in rsync-3.0.9-koh/popt: findme.o
+Only in rsync-3.0.9-koh/popt: popt.o
+Only in rsync-3.0.9-koh/popt: poptconfig.o
+Only in rsync-3.0.9-koh/popt: popthelp.o
+Only in rsync-3.0.9-koh/popt: poptparse.o
+Only in rsync-3.0.9-koh: progress.o
+Only in rsync-3.0.9-koh: receiver.o
+Only in rsync-3.0.9-koh: rounding.h
+Only in rsync-3.0.9-koh: rsync
+Only in rsync-3.0.9-koh: rsync.o
+Only in rsync-3.0.9-koh: sender.o
+Only in rsync-3.0.9-koh: shconfig
+Only in rsync-3.0.9-koh: socket.o
+Only in rsync-3.0.9-koh: syscall.o
+Only in rsync-3.0.9-koh: token.o
+Only in rsync-3.0.9-koh: uidlist.o
+Only in rsync-3.0.9-koh: util.o
+Only in rsync-3.0.9-koh: xattrs.o
+Only in rsync-3.0.9-koh/zlib: adler32.o
+Only in rsync-3.0.9-koh/zlib: compress.o
+Only in rsync-3.0.9-koh/zlib: crc32.o
+Only in rsync-3.0.9-koh/zlib: deflate.o
+Only in rsync-3.0.9-koh/zlib: dummy
+Only in rsync-3.0.9-koh/zlib: inffast.o
+Only in rsync-3.0.9-koh/zlib: inflate.o
+Only in rsync-3.0.9-koh/zlib: inftrees.o
+Only in rsync-3.0.9-koh/zlib: trees.o
+Only in rsync-3.0.9-koh/zlib: zutil.o
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/setup.sh head/tools/vps/setup.sh
--- clean-head/tools/vps/setup.sh	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/setup.sh	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,32 @@
+#!/bin/sh -x
+
+kldload if_vps 
+kldload vps_dev
+kldload vps_ddb
+kldload vps_libdump
+kldload vps_snapst
+kldload vps_restore
+kldload vps_suspend
+kldload vps_account
+kldload vpsfs
+kldload sysvmsg
+kldload sysvsem
+kldload sysvshm
+
+ifconfig vps0 create
+ifconfig vps0 up
+
+sysctl -w net.inet.ip.forwarding=1
+sysctl -w net.inet6.ip6.forwarding=1
+
+sysctl -w debug.vps_core_debug=0
+sysctl -w debug.vps_if_debug=0
+sysctl -w debug.vps_dev_debug=0 
+sysctl -w debug.vps_user_debug=0 
+sysctl -w debug.vps_snapst_debug=0 
+sysctl -w debug.vps_restore_debug=0 
+sysctl -w debug.vps_restore_ktrace=0 
+sysctl -w debug.vps_account_debug=0 
+sysctl -w debug.vps_vpsfs_debug=0
+
+# EOF
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/tools/vps/splitdiff.pl head/tools/vps/splitdiff.pl
--- clean-head/tools/vps/splitdiff.pl	1970-01-01 01:00:00.000000000 +0100
+++ head/tools/vps/splitdiff.pl	2013-06-24 14:20:19.000000000 +0200
@@ -0,0 +1,33 @@
+#!/usr/bin/perl
+
+use strict;
+
+my $rv = main($ARGV[0], $ARGV[1]);
+
+exit($rv);
+
+sub main
+{
+	my $infile = shift;
+	my $outdir = shift;
+	my $filename;
+
+	open(IN, "<$infile") or die "open error";
+
+	while (<IN>) {
+		if (/^diff (.*) (.*) (.*)/) {
+			close(OUT);
+			$filename = $2;
+			$filename =~ s{/}{_}g;
+			open(OUT, ">$outdir/$filename") or die "open error";
+		}
+		print OUT $_;
+	}
+	close(OUT);
+
+	close(IN);
+
+	return (0);
+}
+
+# EOF
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/usr.sbin/Makefile head/usr.sbin/Makefile
--- clean-head/usr.sbin/Makefile	2013-06-26 09:47:24.000000000 +0200
+++ head/usr.sbin/Makefile	2013-06-24 14:20:21.000000000 +0200
@@ -90,6 +90,7 @@ SUBDIR=	adduser \
 	tzsetup \
 	ugidfw \
 	vipw \
+	vpsctl \
 	wake \
 	watch \
 	watchdogd \
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/usr.sbin/vpsctl/Makefile head/usr.sbin/vpsctl/Makefile
--- clean-head/usr.sbin/vpsctl/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ head/usr.sbin/vpsctl/Makefile	2013-06-24 14:20:21.000000000 +0200
@@ -0,0 +1,51 @@
+# $Id: Makefile 162 2013-06-06 18:17:55Z klaus $
+
+PROG=	vpsctl
+MAN=	vpsctl.8 vps.4 vps.9 vps.conf.5
+WARNS?=	6
+BINDIR=	/usr/sbin
+
+CFLAGS+= -I${.CURDIR}/../../sys/ -g
+
+clean:
+	rm -f vpsctl.o priv_ston.o priv_ntos.o vps_libdump.o \
+		vpsctl mkprivlist \
+		priv_ston.c priv_ntos.c \
+		vpsctl.8.gz vps.4.gz vps.9.gz vps.conf.5.gz \
+		vpsctl.8.html vps.conf.5.html vps.4.html vps.9.html mount_vpsfs.8.html \
+		vpsctl.8.ps vps.conf.5.ps vps.4.ps vps.9.ps mount_vpsfs.8.ps \
+		vpsctl.8.pdf vps.conf.5.pdf vps.4.pdf vps.9.pdf mount_vpsfs.8.pdf
+
+mkprivlist:
+	cc -Wall -g -o ./mkprivlist ${.CURDIR}/mkprivlist.c
+
+priv_ston.c priv_ntos.c: mkprivlist
+	./mkprivlist ${.CURDIR}/../../sys/sys/priv.h
+
+vpsctl: priv_ston.c priv_ntos.c
+	cc -Wall -g -I../../sys -I/usr/include -o vpsctl \
+		${.CURDIR}/vpsctl.c \
+		./priv_ston.c \
+		./priv_ntos.c \
+		${.CURDIR}/../../sys/vps/vps_libdump.c
+
+man2:
+	groff -mdoc -Thtml vpsctl.8 > vpsctl.8.html
+	groff -mdoc -Thtml vps.conf.5 > vps.conf.5.html
+	groff -mdoc -Thtml vps.4 > vps.4.html
+	groff -mdoc -Thtml vps.9 > vps.9.html
+	groff -mdoc -Thtml ../../sbin/mount_vpsfs/mount_vpsfs.8 > mount_vpsfs.8.html
+	groff -mdoc -Tps vpsctl.8 > vpsctl.8.ps
+	groff -mdoc -Tps vps.conf.5 > vps.conf.5.ps
+	groff -mdoc -Tps vps.4 > vps.4.ps
+	groff -mdoc -Tps vps.9 > vps.9.ps
+	groff -mdoc -Tps ../../sbin/mount_vpsfs/mount_vpsfs.8 > mount_vpsfs.8.ps
+	ps2pdf vpsctl.8.ps vpsctl.8.pdf
+	ps2pdf vps.conf.5.ps vps.conf.5.pdf
+	ps2pdf vps.4.ps vps.4.pdf
+	ps2pdf vps.9.ps vps.9.pdf
+	ps2pdf mount_vpsfs.8.ps mount_vpsfs.8.pdf
+
+.include <bsd.prog.mk>
+
+# EOF
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/usr.sbin/vpsctl/mkprivlist.c head/usr.sbin/vpsctl/mkprivlist.c
--- clean-head/usr.sbin/vpsctl/mkprivlist.c	1970-01-01 01:00:00.000000000 +0100
+++ head/usr.sbin/vpsctl/mkprivlist.c	2013-06-24 14:20:21.000000000 +0200
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: mkprivlist.c 133 2013-04-20 17:06:57Z klaus $
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#define _WITH_GETLINE
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <regex.h>
+
+int main(int argc, char **argv, char **envp)
+{
+	FILE *fp, *out1, *out2;
+	char *line = NULL;
+	size_t linecap = 0;
+	ssize_t linelen;
+	regex_t expr;
+	regmatch_t results[4];
+	char name[0x100], val[0x100];
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: %s path/to/sys/priv.h\n", argv[0]);
+		return (-1);
+	}
+
+	if ((out1 = fopen("priv_ntos.c", "w")) == NULL) {
+		fprintf(stderr, "fopen(): %s\n", strerror(errno));
+		return (-1);
+	}
+
+	if ((out2 = fopen("priv_ston.c", "w")) == NULL) {
+		fprintf(stderr, "fopen(): %s\n", strerror(errno));
+		return (-1);
+	}
+
+	if ((fp = fopen(argv[1], "r")) == NULL) {
+		fprintf(stderr, "fopen([%s]): %s\n",
+			argv[1], strerror(errno));
+		return (-1);
+	}
+
+	if (regcomp(&expr, "^#define[ \t]+(PRIV_[^ \t]+)[ \t]+([0-9]+)", REG_EXTENDED)) {
+		fprintf(stderr, "regcomp error\n");
+		return (-1);
+	}
+
+	fprintf(out1,
+		"/* AUTOMATICALLY GENERATED FILE */\n"
+		"\n"
+		"#include <sys/priv.h>\n"
+		"\n"
+		"const char * priv_ntos(int priv);\n"
+		"\n"
+		"const char *\n"
+		"priv_ntos(int priv)\n"
+		"{\n"
+		"\n"
+		"    switch (priv) {\n"
+		);
+
+	fprintf(out2,
+		"/* AUTOMATICALLY GENERATED FILE */\n"
+		"\n"
+		"#include <sys/priv.h>\n"
+		"#include <string.h>\n"
+		"\n"
+		"int priv_ston(const char *str);\n"
+		"\n"
+		"int\n"
+		"priv_ston(const char *str)\n"
+		"{\n"
+		"\n"
+		);
+
+	while ((linelen = getline(&line, &linecap, fp)) > 0) {
+		//fwrite(line, linelen, 1, stdout);
+
+		if (regexec(&expr, line, 3, results, 0))
+			continue;
+
+		/*
+		printf("results: [%d/%d] [%d/%d] [%d/%d]\n",
+			results[0].rm_so, results[0].rm_eo,
+			results[1].rm_so, results[1].rm_eo,
+			results[2].rm_so, results[2].rm_eo);
+		*/
+
+		memcpy(name, line + results[1].rm_so, results[1].rm_eo - results[1].rm_so);
+		name[results[1].rm_eo - results[1].rm_so] = '\0';
+
+		memcpy(val, line + results[2].rm_so, results[2].rm_eo - results[2].rm_so);
+		val[results[2].rm_eo - results[2].rm_so] = '\0';
+
+		//printf("name=[%s] val=[%s]\n", name, val);
+
+		fprintf(out1, "    case %s: return (\"%s\");\n",
+			val, name);
+		fprintf(out2, "    if (strcmp(str, \"%s\") == 0) return (%s);\n",
+			name, val);
+	}
+
+	fclose(fp);
+	regfree(&expr);
+
+	fprintf(out2,
+		"    return (0);\n"
+		"}\n"
+		);
+
+	fprintf(out1,
+		"    default: return (\"unknown\");\n"
+		"    }\n"
+		"}\n"
+		);
+
+	fclose(out2);
+	fclose(out1);
+
+	return (0);
+}
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/usr.sbin/vpsctl/vps.4 head/usr.sbin/vpsctl/vps.4
--- clean-head/usr.sbin/vpsctl/vps.4	1970-01-01 01:00:00.000000000 +0100
+++ head/usr.sbin/vpsctl/vps.4	2013-06-24 14:20:21.000000000 +0200
@@ -0,0 +1,224 @@
+.\"
+.\" $Id: vps.4 120 2012-08-30 11:14:36Z klaus $
+.\"
+.\" The following commands are required for all man pages.
+.Dd August 29, 2012
+.Os
+.Dt VPS 4
+.Sh NAME
+.Nm vps
+.Nd "Virtual Private Systems"
+.\" 
+.\" 
+.Sh SYNOPSIS
+To compile VPS into the kernel,
+place following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "option VPS"
+.Cd "option VIMAGE"
+.Ed
+.Pp
+The core code will be statically linked into the kernel,
+and some additional modules will be built:
+.Bd -ragged -offset indent
+.\" XXX which macro can be used here ?
+.Cd vps_dev.ko
+.Cd vps_account.ko
+.Cd vps_suspend.ko
+.Cd vps_libdump.ko
+.Cd vps_snapst.ko
+.Cd vps_restore.ko
+.Cd vps_ddb.ko
+.Cd vpsfs.ko
+.Cd if_vps.ko
+.Ed
+.Pp
+In order to have the all the code linked into the kernel
+rather than having several loadable modules, add:
+.Bd -ragged -offset indent
+.Cd "option VPS_STATIC"
+.Ed
+.\" 
+.\" 
+.Sh DESCRIPTION
+Virtual Private Systems (short VPS) is an operating system level
+virtualization implementation.
+.Pp
+Virtualization solutions like XEN divide the host's resources into
+several, often fixed-sized, parts, and runs several instances
+of the same or different operating systems.
+This implies a big performance impact, since loads of translation work
+for hardware access is necessary.
+Furthermore, resources can't be shared and overcommitted very well.
+.Pp
+In VPS, in comparison, the virtualization takes place one level
+higher, in the actual operating system.
+The drawback is that you can't provide different operating systems
+or versions, but there is only very little performance impact compared
+to a native environment.
+Resource sharing, like diskspace and memory overcommittment work much
+better, too.
+.Pp
+For network stack virtualization
+.Xr vimage/vnet
+is used.
+.Pp
+VPS is capable of migrating a running instance to another physical host
+without closing any process, TCP session or any other resource.
+.Pp
+Currently, since VPS is still experimental, not all resources
+or system setups are supported yet for live migration.
+.\"
+.Pp
+Description of the kernel modules:
+.Bl -tag -width indent
+.\"
+.\"
+.It Cd vps_dev.ko
+This module provides the
+.Ar /dev/vps
+interface and all the procedures required for
+.Xr vpsctl 8
+to work.
+.\"
+.\"
+.It Cd vps_account.ko
+This module provides the resource accounting and limiting functionality.
+.\"
+.\"
+.It Cd vps_suspend.ko
+This module provides the suspend and resume commands described in
+.Xr vpsctl 8
+under
+.Cm suspend
+and
+.Cm resume .
+.\"
+.\"
+.It Cd vps_libdump.ko
+This module provides common routines for both the snapshot and restore modules.
+.\"
+.\"
+.It Cd vps_snapst.ko
+This module provides the snapshot functionality described in
+.Xr vpsctl 8
+under
+.Cm snapshot .
+.\"
+.\"
+.It Cd vps_restore.ko
+This module provides the functionality to restore a VPS instance
+from a snapshot file or in live host to host migration.
+See
+.Xr vpsctl 8
+under
+.Cm restore
+and
+.Cm migrate .
+.\"
+.\"
+.It Cd vps_ddb.ko
+If compiled with
+.Cd option DDB
+this modules provides debugging routines.
+.\"
+.\"
+.It Cd vpsfs.ko
+This module provides a virtual filesystem, that allows VPS to account
+and restrict diskspace usage per instance.
+Also see
+.Xr mount_vpsfs 8 .
+.\"
+.\"
+.It Cd if_vps.ko
+This module provides virtual network interfaces named
+.Ar vpsN .
+Each VPS instance can have zero, one or more interfaces.
+Whenever a packet is input to a vps interface, it is output
+on the vps interface that has the destination address of the packet
+configured on it AND is allowed to have this address by means of
+VPS instance configuration.
+.Pp
+Interfaces can be created using the 'ifconfig create' command,
+but usually
+.Xr vpsctl 8
+will create and destroy them as needed.
+.\".Pp
+.\"On load of the module
+.\".Ar vps0
+.\"is automatically created and later used as the default output interface.
+The first interface created is used as the default output interface,
+so after loading the module
+.Ar vps0 ,
+should be created, set to UP and kept on the main vps instance.
+.El
+.Pp
+If you don't want a certain functionality simply don't load the
+respective module.
+.Pp
+.\" 
+.\" 
+.\" .Sh IMPLEMENTATION NOTES
+.\" 
+.\" 
+.Sh DIAGNOSTICS
+.\" 
+.Pp
+If compiled with option
+.Cd DIAGNOSTIC
+following sysctls are available:
+.Pp
+.Dl debug.vps_core_debug
+.Dl debug.vps_if_debug
+.Dl debug.vps_dev_debug
+.Dl debug.vps_user_debug
+.Dl debug.vps_snapst_debug
+.Dl debug.vps_restore_debug
+.Dl debug.vps_account_debug
+.Dl debug.vps_vpsfs_debug
+.Pp
+Each of them enables/disables debug output to the
+kernel message buffer for the corresponding module.
+.Pp
+.\" 
+.\" .Sh COMPATIBILITY
+.\" 
+.\" 
+.Sh SEE ALSO
+.Xr vps 9 ,
+.Xr vpsctl 8 ,
+.Xr vps.conf 5 ,
+.Xr mount_vpsfs 8 ,
+.Ad http://www.7he.at/freebsd/vps/
+.\" 
+.\" 
+.\" .Sh STANDARDS
+.\" 
+.\" 
+.Sh HISTORY
+Work on VPS was started in February 2009.
+.\" 
+.\" 
+.Sh AUTHORS
+.Pp
+Virtual Private Systems for FreeBSD and this manual page as well,
+were written by
+.An "Klaus P. Ohrhallinger" .
+.Pp
+Development of this software was partly funded by:
+.Pp
+TransIP.nl <http://www.transip.nl/>
+.\"
+.\"
+.Sh BUGS
+VPS is in an early stage of development and has to be considered as
+experimental.
+This means many bugs have to be expected.
+.Pp
+Please submit bug reports to
+.Ad freebsd-vps@7he.at .
+.\"
+.\"
+.Sh VERSION
+$Id: vps.4 120 2012-08-30 11:14:36Z klaus $
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/usr.sbin/vpsctl/vps.9 head/usr.sbin/vpsctl/vps.9
--- clean-head/usr.sbin/vpsctl/vps.9	1970-01-01 01:00:00.000000000 +0100
+++ head/usr.sbin/vpsctl/vps.9	2013-06-24 14:20:21.000000000 +0200
@@ -0,0 +1,255 @@
+.\"
+.\" $Id: vps.9 120 2012-08-30 11:14:36Z klaus $
+.\"
+.\" The following commands are required for all man pages.
+.Dd August 29, 2012
+.Os
+.Dt VPS 9
+.Sh NAME
+.Nm vps
+.Nd Virtual Private Systems internals
+.\" 
+.\" 
+.\" .Sh SYNOPSIS
+.\" 
+.\" 
+.Sh DESCRIPTION
+This manual page is supposed to give an overview of how Virtual Private
+Systems (short VPS) works and how it is implemented.
+.\" 
+.\" 
+.Sh IMPLEMENTATION NOTES
+As much as possible (which is almost all) of the code resides in the
+.Ar sys/vps
+directory.
+.Pp
+It can be roughly split up into several components:
+.Bl -tag -width indent
+.\"
+.\"
+.It Cm core
+All that absolutely has to be statically linked into the kernel.
+Very early in the boot process the kernel has to be able to allocate
+the
+.Ar vps0
+instance, which is the instance reflecting the physical host.
+.Pp
+The smaller this part is, the better, as it is even there when VPS
+is not used.
+.Pp
+Files:
+.Ar vps/vps_core.c ,
+.Ar vps/vps_priv.c ,
+.Ar vps/vps_console.c ,
+.Ar vps/vps_pager.c ,
+.Ar vps/vps_devfsruleset.h ,
+.Ar vps/vps_int.h ,
+.Ar vps/vps.h
+.\"
+.\"
+.It Cm device
+Provides the
+.Ar /dev/vps
+interface and all functions for managing VPS from userspace.
+.Pp
+Files:
+.Ar vps/vps_dev.c ,
+.Ar vps/vps_user.c ,
+.Ar vps/vps_user.h
+.\"
+.\"
+.It Cm network interface
+The
+.Ar vpsN
+network device.
+Acts like a virtual layer 3 switch, is the easiest way of connecting
+up VPS instances to a physical network.
+.Pp
+Files:
+.Ar vps/if_vps.c
+.\"
+.\"
+.It Cm suspend
+Suspending and resuming a vps instance.
+.Pp
+Files:
+.Ar vps/vps_suspend.c
+.\"
+.\"
+.It Cm libdump
+Common routines for the snapshot and restore modules and
+userspace programs.
+Provides functions for reading and manipulating snapshot
+files and definitions of all involved data structures.
+.Pp
+Files:
+.Ar vps/vps_libdump.c ,
+.Ar vps/vps_libdump.h
+.\"
+.\"
+.It Cm snapshot
+All the snapshot functionality.
+.Pp
+Files:
+.Ar vps/vps_snapst.c ,
+.Ar vps/vps_snapst.h
+.\"
+.\"
+.It Cm restore
+All the restore functionality.
+.Pp
+Files:
+.Ar vps/vps_restore.c
+.\"
+.\"
+.It Cm accounting
+All the resource accounting and limiting functionality.
+.Pp
+Files:
+.Ar vps/vps_account.c ,
+.Ar vps/vps_account.h
+.\"
+.\"
+.It Cm debug
+Debugging routines,
+.Ar DDB
+integration.
+.Pp
+Files:
+.Ar vps/vps_ddb.c
+.El
+.Pp
+.\"
+.\"
+Overview how things work:
+.\"
+.Bl -tag -width indent
+.It Cm Taking snapshots
+This procedure is quite simple. First all threads have to be suspended,
+which happens at the end of the
+.Ar syscall()
+function.
+A flag in the respective vnet instance is set, causing
+.Ar tcp_input()
+and
+.Ar tcp_output()
+to drop incoming data and not sending outgoing data.
+This is important for live migration.
+.Pp
+Then general information about the vps instance is dumped,
+after that each mount that belongs in the vps context.
+Next is networking related information like interfaces,
+routing tables.
+.Pp
+Each process gets dumped, including proc structure,
+user credentials, signal handlers, vmspace, fdset,
+and threads.
+Note that the userspace pages (vmspace) are not copied
+but wired and directly mapped in the vmspace of vpsctl.
+.Pp
+When the /dev/vps filehandle on which snapshot was requested
+is closed again, the snapshot information is deleted and
+the vps instance remains suspended and can be resumed again.
+.Pp
+The resulting snapshot or dump is of a well-defined format.
+This format is defined in vps/vps_libdump.h and has a version
+number.
+.Pp
+This allows live migration between different kernel versions
+and kernels compiled with different options that result
+in different data structures.
+.Pp
+.It Cm Restoring snapshots
+This applies for restoring from a file and in live migration
+as well.
+.Pp
+First sanity checks on the restore file have to be performed.
+First of all a magic pattern in the header, a checksum
+and the snapshot format version are compared.
+The dumped objects are serialized using length encoding, so
+it is necessary to check nothing runs out of bounds.
+.Pp
+If the snapshot file is found to be valid, or the user forced it,
+the actual restore process is started.
+A new vps instance is allocated, general vps information, mounts,
+network interfaces, including their flags and addresses, and
+routing tables are restored.
+Then sessions (for process groups) are restored,
+and then each process including all its information.
+Threads which were interrupted in certain syscalls get fixed up.
+For instance nanosleep is restarted for sleeping the remaining time.
+Afterwards the process tree (child/parent relationship, process groups, ...)
+is fixed up.
+At the end leftovers are cleaned up and the restored vps instance remains in
+state suspended, ready for being resumed.
+.It Cm Virtualization of globals
+Currently for storing and accessing virtualized global variables
+.Ar vnet
+is used. This can be changed easily by replacing a few macros.
+.Pp
+The 
+.Cm process tree ,
+i.e. the proctree, allproc and zombproc list and locks,
+are private to each vps instance.
+This allows each vps instance to run its init task as pid 1,
+and using the right pids when restoring a vps instance.
+.Pp
+.Cm Devfs 
+keeps a reference in each mount to the respective vps instance, and can
+therefore provide virtualized namespace for devices like pseudo ttys.
+The pts code already uses ucred references, so the only extension is
+support for restoring pts instances with certain unit numbers.
+The unit number allocator (kern/subr_unit.c) was extended by unr_alloc_unit().
+.Pp
+.\"
+.\"
+.It Cm Privilege checking / Security
+By default a reasonable set of
+.Xr priv 9
+privileges is given to a vps instance, but it is possible to give any
+privilege to a vps instance by configuration.
+.Pp
+.\"
+.\"
+.It Cm Resource accounting and limiting
+Currently might not always work as expected.
+.El
+.\" 
+.\" 
+.Sh SEE ALSO
+.Xr vps 4 ,
+.Xr vpsctl 8 ,
+.Xr vps.conf 5 ,
+.Xr mount_vpsfs 8 ,
+.Ad http://www.7he.at/freebsd/vps/
+.\" 
+.\" 
+.\" .Sh STANDARDS
+.\" 
+.\" 
+.Sh HISTORY
+Work on VPS was started in February 2009.
+.\" 
+.\" 
+.Sh AUTHORS
+.Pp
+Virtual Private Systems for FreeBSD and this manual page as well,
+were written by
+.An "Klaus P. Ohrhallinger" .
+.Pp
+Development of this software was partly funded by:
+.Pp
+TransIP.nl <http://www.transip.nl/>
+.\"
+.\"
+.Sh BUGS
+VPS is in an early stage of development and has to be considered as
+experimental.
+This means many bugs have to be expected.
+.Pp
+Please submit bug reports to
+.Ad freebsd-vps@7he.at .
+.\"
+.\"
+.Sh VERSION
+$Id: vps.9 120 2012-08-30 11:14:36Z klaus $
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/usr.sbin/vpsctl/vps.conf.5 head/usr.sbin/vpsctl/vps.conf.5
--- clean-head/usr.sbin/vpsctl/vps.conf.5	1970-01-01 01:00:00.000000000 +0100
+++ head/usr.sbin/vpsctl/vps.conf.5	2013-06-24 14:20:21.000000000 +0200
@@ -0,0 +1,215 @@
+.\"
+.\" $Id: vps.conf.5 120 2012-08-30 11:14:36Z klaus $
+.\"
+.\" The following commands are required for all man pages.
+.Dd August 29, 2012
+.Os
+.Dt VPS.CONF 5
+.Sh NAME
+.Nm vps.conf
+.Nd configuration file for a Virtual Private Systems instance
+.\" 
+.\" 
+.Sh DESCRIPTION
+Options are set with
+.Dq Ar name Li = Ar value
+assignments, one per line.
+.Ar name
+is case insensetive.
+.Ar value
+needs quoting if it contains whitespace.
+Comments start with #.
+.Pp
+The following list provides a name and short description for each
+variable that can be set in the
+.Nm
+file:
+.Bl -tag -width indent-two
+.\" 
+.\" 
+.It Va NAME
+The desired name for the vps instance.
+.\" 
+.\" 
+.It Va FSROOT
+The filesystem root of the vps instance.
+.\" 
+.\" 
+.It Op Va FSROOT_PRIV
+If some sort of virtal file system (like
+.Xr mount_vpsfs 8
+is used), this lets you specify the underlying path
+that will be synced on migration instead of the virtual
+mount.
+.\" 
+.\" 
+.It Op Va INIT
+Command line to execute in vps instance after starting.
+If not specified, no processes are started in the vps instance.
+.\"
+.\"
+.It Op Va ROOT_MOUNT
+Command line for mounting root filesystem of vps instance,
+if necessary.
+.\"
+.\"
+.It Op Va ROOT_MOUNT
+Command line for unmounting root filesystem of vps instance,
+if necessary.
+.\" 
+.\" 
+.It Op Va NETWORK_ANNOUNCE
+Command line for announcing vps instance on the network.
+E.g. setting routes somewhere.
+.\" 
+.\" 
+.It Op Va NETWORK_REVOKE
+Command line for revoking vps instance from the network.
+E.g. deleting routes somewhere.
+.\" 
+.\" 
+.It Op Va IP_NETWORKS
+List of IPv4 and IPv6 networks the VPS
+instance is allowed to use on its interfaces.
+.Pp
+Following formats are valid:
+.Dl 192.168.123.231
+.Dl 192.168.213.0/255.255.255.0
+.Dl fc00::200:20
+.Dl fc00::100:0/112
+.Pp
+Multiple networks can be specified on at once,
+separated by ','.
+.\" 
+.\" 
+.It Op Va LIMITS
+Resource limits for the vps instance, specified as
+.Va resource:softlimit:hardlimit .
+Following resources are valid:
+.Bl -tag -width indent-two
+.It Ar phys
+Physical memory.
+.It Ar virt
+Virtual memory.
+.It Ar pctcpu
+CPU utilization in percent.
+.It Ar blockio
+Block I/O Operations per second.
+.It Ar threads
+Number of threads allowed.
+.It Ar procs
+Number of processes allowed.
+.El
+.Pp
+Separate multiple resource limit specifications by ','.
+.\" 
+.\" 
+.It Op Va PRIV_ALLOW
+List of 
+.Xr priv 9
+privileges that are allowed for the vps instance.
+This is used in addition to the quite reasonable
+default set.
+Specifiy either numeric value or name, separate by ','.
+See 
+.Va /usr/include/sys/priv.h
+for a list of valid privileges.
+.\" 
+.\" 
+.It Op Va PRIV_NOSYS
+List of
+.Xr priv 9
+privileges that are forbidden for the vps instance,
+but instead of EPERM error ENOSYS error is returned.
+This is necessary for some applications.
+.\" 
+.\" 
+.It Op Va NETIF_<index>_ADDRESS
+A list of IPv4 and/or IPv6 addresses that the vps instance
+may use on the network interface vps<index>.
+.Pp
+For every
+.Va NETIF_<index>_ADDRESS
+specification a if_vps interface with the name vps<index>
+is created in the vps instance.
+.Pp
+The difference to specifing the addresses in
+.Va IP_NETWORKS
+is that for each address an ARP entry and a routing entry is
+automatically created.
+.\" 
+.\" 
+.El
+.\"
+.\"
+.\" This next command is for sections 1, 6, 7, 8 and 9 only
+.\"     (command return values (to shell) and
+.\"     fprintf/stderr type diagnostics).
+.\" 
+.\" 
+.\" .Sh DIAGNOSTICS
+.\" 
+.\" 
+.\" .Sh COMPATIBILITY
+.\"
+.\"
+.Sh FILES
+.Bl -tag -width /etc/vps/vps_<ID>.conf
+.It Pa /etc/vps/vps_<ID>.conf
+for each VPS instance with id <ID>.
+.El
+.\" 
+.\" 
+.Sh EXAMPLES
+.Pp
+Example of a vps instance configuration file:
+.Pp
+.Dl # This is a comment.
+.Dl NAME = 'vps190'
+.Dl FSROOT = '/usr/vps/vps190'
+.Dl FSROOT_PRIV = '/usr/vps/vps190_priv'
+.Dl NETIF_0_ADDRESS = '10.142.178.190, 2001:10:10::beef:190'
+.Dl ROOT_MOUNT = 'mount_vpsfs /usr/vps/vps190_priv /usr/vps/vps190'
+.Dl ROOT_UNMOUNT = 'umount /usr/vps/vps190'
+.Dl INIT = '/sbin/init'
+.Dl LIMITS = 'phys:0:0,virt:100000000:160000000,pctcpu:100:200,threads:12:12'
+.Pp
+.\"
+.\"
+.Sh SEE ALSO
+.Xr vps 4 ,
+.Xr vps 9 ,
+.Xr vpsctl 8 ,
+.Xr mount_vpsfs 8 ,
+.Ad http://www.7he.at/freebsd/vps/
+.\" 
+.\" 
+.\" .Sh STANDARDS
+.\" 
+.\" 
+.Sh HISTORY
+Work on VPS was started in February 2009.
+.\" 
+.\" 
+.Sh AUTHORS
+.Pp
+Virtual Private Systems for FreeBSD and this manual page as well,
+were written by
+.An "Klaus P. Ohrhallinger" .
+.Pp
+Development of this software was partly funded by:
+.Pp
+TransIP.nl <http://www.transip.nl/>
+.\"
+.\"
+.Sh BUGS
+VPS is in an early stage of development and has to be considered as
+experimental.
+This means many bugs have to be expected.
+.Pp
+Please submit bug reports to
+.Ad freebsd-vps@7he.at .
+.\"
+.\"
+.Sh VERSION
+$Id: vps.conf.5 120 2012-08-30 11:14:36Z klaus $
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/usr.sbin/vpsctl/vpsctl.8 head/usr.sbin/vpsctl/vpsctl.8
--- clean-head/usr.sbin/vpsctl/vpsctl.8	1970-01-01 01:00:00.000000000 +0100
+++ head/usr.sbin/vpsctl/vpsctl.8	2013-06-24 14:20:21.000000000 +0200
@@ -0,0 +1,566 @@
+.\"
+.\" $Id: vpsctl.8 130 2013-04-10 09:32:39Z klaus $
+.\"
+.\" The following commands are required for all man pages.
+.Dd April 10, 2013
+.Os
+.Dt VPSCTL 8
+.Sh NAME
+.Nm vpsctl
+.Nd manage Virtual Private Systems instances
+.\" 
+.\" 
+.Sh SYNOPSIS
+.Nm
+.\" .Op Fl X 
+.Cm start
+.Ar id
+.Op Ar config-file
+.Nm
+.Cm stop
+.Ar id
+.Op Ar config-file
+.Nm
+.Cm list
+.Nm
+.Cm show
+.Ar id
+.Nm
+.Cm shell
+.Ar id
+.Nm
+.Cm console
+.Ar id
+.Nm
+.Cm ifmove
+.Ar id
+.Ar ifname
+.Op Ar ifnewname
+.Nm
+.Cm execin
+.Ar id
+.Ar command
+.Op Ar arguments ...
+.Nm
+.Cm execwt
+.Ar id
+.Ar command
+.Op Ar arguments ...
+.Nm
+.Cm suspend
+.Ar id
+.Nm
+.Cm resume
+.Ar id
+.Nm
+.Cm snapshot
+.Ar id
+.Ar output-file
+.Nm
+.Cm abort
+.Ar id
+.Nm
+.Cm restore
+.Ar id
+.Ar input-file
+.Nm
+.Cm migrate
+.Ar id
+.Ar remote-host
+.Op Ar norsync|onersync
+.\"
+.\"
+.\"
+.Nm
+.Cm argshow
+.Ar id
+.\"
+.Cm ipnet
+.Ar id
+.Cm add
+.Ar adress/network, ...
+.\" 
+.Nm
+.Cm ipnet
+.Ar id
+.Cm rem
+.Ar adress/network, ...
+.\"
+.Nm
+.Cm priv
+.Ar id
+.Cm allow
+.Ar privilege-number, ...
+.\"
+.Nm
+.Cm priv
+.Ar id
+.Cm deny
+.Ar privilege-number, ...
+.\"
+.Nm
+.Cm priv
+.Ar id
+.Cm nosys
+.Ar privilege-number, ...
+.\"
+.Nm
+.Cm limit
+.Ar id
+.Ar resource:softlimit:hardlimit, ...
+.\" 
+.Nm
+.Cm showdump
+.Ar file
+.\" 
+.\" 
+.Sh DESCRIPTION
+.\" The following commands should be uncommented and
+.\" used where appropriate.
+The
+.Nm
+utility is used to manage Virtual Private System (VPS) instances,
+e.g. starting, stopping, migrating and reading status information.
+.Pp
+Basically VPS works in a hierarchical way, so you can use the
+.Nm
+utility on the main host system (which in turn is a VPS instance too)
+and inside child VPS instances as well. You can only see and manage
+instances that are children of the current instance.
+.Pp
+For a general description of what VPS is, see
+.Xr vps 4 .
+.Pp
+The following commands are available:
+.Bl -tag -width indent
+.\" 
+.\" START
+.It Cm start Ar id Op Ar config-file
+Creates and runs a new VPS instance named
+.Ar id
+using settings from
+.Ar config-file .
+.Pp
+If no
+.Ar config-file
+is given,
+.Nm
+tries to read settings from /etc/vps/vps_<ID>.conf.
+.Pp
+See the
+.Sx FILES
+sections for the config file syntax.
+.\" 
+.\" STOP
+.It Cm stop Ar id Op Ar config-file
+Stops and destroys VPS instance
+.Ar id .
+.Pp
+If no
+.Ar config-file
+is given,
+.Nm
+tries to read settings from /etc/vps/vps_<ID>.conf.
+.Pp
+If you perform 'shutdown -h ...' from inside a VPS instance,
+you still have to run
+.Cm stop Ar id
+to free it entirely.
+.\" 
+.\" LIST
+.It Cm list
+Prints a listing of all currently existing VPS instances.
+Status is one of running, suspended or dead.
+After stopping an instance, it may reside for a while as dead
+instance in the system. A typical cause is TCP sockets in TIME_WAIT state.
+After all references are gone, it will be automatically deleted.
+.\".Pp
+.\"Restore count tells you how often one instance was restored either from a
+.\"snapshot file or in a live migration from another host.
+.\"
+.\" SHOW
+.It Cm show Ar id
+Shows some details about the VPS instance given by
+.Ar id .
+For a more detailed listing including all run-time properties about
+a VPS instance see
+.Cm argshow
+.Ar id .
+.\" 
+.\" SHELL
+.It Cm shell Ar id
+Allocates a pseudo tty and starts an interactive shell in the given VPS instance.
+This command is equally to 'vpsctl execwt /bin/sh'.
+.\" 
+.\" CONSOLE
+.It Cm console Ar id
+Opens the system console of the given VPS instance.
+.\" 
+.\" IFMOVE
+.It Cm ifmove Ar id Ar ifname Op Ar ifnewname
+Moves network interface
+.Ar ifname
+into vps instance
+.Ar id
+and optionally renames it to
+.Op Ar ifnewname .
+.\" 
+.\" EXECIN
+.It Cm execin Ar id Ar command Op Ar arguments ...
+Starts the given
+.Ar command
+using
+.Ar arguments
+if given in the context of VPS instance
+.Ar id .
+The
+.Nm
+utility does not wait on exit of
+.Ar command
+but exits immediately.
+.\" 
+.\" EXECWT
+.It Cm execwt Ar id Ar command Op Ar arguments ...
+Same syntax as for the
+.Cm execin
+command, but a pseudo tty is allocated for
+.Ar command
+in order to have interactive input/output
+and the
+.Nm
+utility waits until exit of
+.Ar command .
+.\" 
+.\" EXECWT
+.It Cm suspend Ar id
+Suspends all processes in VPS instance
+.Ar id ,
+all TCP sockets are set to drop incoming data, every other activity is suspended.
+May be used for creating consistent backups of one VPS instances' filesystem space.
+.\" 
+.\" RESUME
+.It Cm resume Ar id
+Resumes previously suspended vps instance
+.Ar id .
+.\" 
+.\" SNAPSHOT
+.It Cm snapshot Ar id Ar output-file
+Writes a snapshot of
+.Ar id
+to
+.Ar output-file ,
+including the state of all processes, sockets, network attributes etc.
+The VPS instance
+.Ar id
+has to be suspended by
+.Cm suspend
+first.
+.\" 
+.\" ABORT
+.It Cm abort Ar id
+Ungracefully kill all processes in VPS instance
+.Ar id .
+You still have to run
+.Cm stop Ar id
+to get rid of it.
+If
+.Ar id
+is currently suspended, run
+.Cm resume Ar id
+afterwards in order to have effect.
+.\" 
+.\" RESTORE
+.It Cm restore Ar id Ar input-file
+Restores a VPS instance from a snapshot file previously created by
+.Cm snapshot
+to a suspended state. Use
+.Cm resume Ar id
+to get it running again.
+.Pp
+The snapshot file can originate from a different host, but care has
+to be taken to have compatible or better, the same kernel, on both
+systems. Before the actual restore process starts, sanity and compatibility
+checks against the snapshot file are performed, but in case of mismatches
+a kernel crash could still happen.
+.Pp
+Instead of
+.Ar id
+an empty string ('') can be given. The
+.Ar id
+the instance had when its snapshot was created is used then.
+.Pp
+The right instance config file has to exist.
+.\" 
+.\" MIGRATE
+.It Cm migrate Ar id Ar remote-host Op Ar norsync|onersync
+Performs a live migration of VPS instance
+.Ar id
+to host
+.Ar remote-host .
+All processes, open files, pipes, sockets, TCP session etc. are preserved.
+.Pp
+Specify
+.Ar norsync
+if you don't want the filesystem tree to be synced.
+Do not use this option unless you are sure nothing was modified
+or the filesystem is mounted readonly.
+Specify
+.Ar onersync
+if you only need one sync pass (faster than two-pass but vps is suspended
+longer).
+.Pp
+If the migration process fails or is aborted, the instance is left in
+suspended state.
+Use 
+.Cm resume Ar id
+to get it running again. You might have to set some network settings
+in the parent system manually, like published arp entries and routes.
+.Pp
+SSH is used as transport to
+.Ar remote-host .
+If no ssh key is loaded/available, you will be prompted for a password.
+.\"
+.\" ARGSHOW
+.It Cm argshow Ar id
+Shows arguments of VPS instance
+.Ar id .
+.Pp
+The output show IPv4 and IPv6 networks the instance is allowed to use
+on its interfaces, as well as a list of privileges 
+.Xr priv 9.
+For
+.Ar NOSYS
+privileges, a 'No such system call' error is returned instead 
+of 'Permission denied'. Some applications wouldn't run otherwise.
+.Pp
+Resource limits are shown as: resource type, current utilization,
+preconfigured soft limit (may be exceeded if resources are still
+available), hard limit (will never be exceeded) and counters how
+often the soft or hard limits have been hit.
+.\"
+.\" IPNET ADD
+.It Cm ipnet Ar id Cm add Ar address/network, ...
+Adds an IP address or network to the list of networks the VPS
+instance is allowed to use on its interfaces.
+.Pp
+Following formats are valid:
+.Dl 192.168.123.231
+.Dl 192.168.213.0/255.255.255.0
+.Dl fc00::200:20
+.Dl fc00::100:0/112
+.Pp
+Multiple networks can be specified on the command line at once,
+separated by ',' but without whitespace.
+.Pp
+To specify networks in a configuration file, use 
+.Ar IP_NETWORKS.
+.\"
+.\" IPNET REM
+.It Cm ipnet Ar id Cm rem Ar address/network, ...
+Removes a previously added IP address or network from the list.
+See the description of
+.Cm ipnet Ar id Cm add
+for more information.
+.\"
+.\" PRIV ALLOW
+.It Cm priv Ar id Cm allow Ar privilege-number, ...
+Adds one or more privileges, specified by name (e.g. PRIV_KLD_LOAD)
+or its numeric value, to the list of allowed privileges.
+Separate multiple privileges by ',' without whitespace.
+.Pp
+See 
+.Xr priv 9
+for more information about privileges, and
+.Ar sys/priv.h
+for a list of defined privileges.
+.Pp
+To specify privileges in a configuration file, use
+.Ar PRIV_ALLOW.
+.\"
+.\" PRIV DENY
+.It Cm priv Ar id Cm deny Ar privilege-number, ...
+Removes one or more privileges, specified by name (e.g. PRIV_KLD_LOAD)
+or its numeric value, from the list of allowed or 'nosys' privileges.
+.Pp
+System calls or other operations that depend on the privilege in
+question, return to userspace with a 'Permission denied' error.
+.\"
+.\" PRIV NOSYS
+.It Cm priv Ar id Cm nosys privilege-number, ...
+Adds one ore more privileges, specified by name (e.g. PRIV_KLD_LOAD)
+or its numeric value, to the list of
+privileges, that are not allowed, but supposed to return ''No such
+system call'' instead of ''Permission denied'', to satisfy some
+applications.
+.Pp
+To specify privileges in a configuration file, use
+.Ar PRIV_NOSYS.
+.\"
+.\" LIMIT
+.It Cm limit Ar id Ar resource:softlimit:hardlimit, ....
+Configures a limit on one or more given resources (like virtual memory,
+ cpu utilization, ...).
+.Pp
+The command
+.Cm argshow
+.Ar id
+shows you which resources are known.
+.Pp
+The
+.Ar softlimit
+is a treshold that will be exceeded in case the current
+utilization of the given resource allows to do so without affecting
+other VPS instances' performance.
+.Pp
+The
+.Ar hardlimit
+will never be exceeded.
+.Pp
+For CPU utilization 'sysctl kern.fscale' equals 100% of one cpu
+(To allow a VPS instance to use 25% of one CPU set the limit to
+(sysctl kern.fscale) * 0.25).
+.Pp
+To specify resource limits in a configuration file, use
+.Ar LIMITS .
+.Pp
+.\"
+.\" SHOWDUMP
+.It Cm showdump Ar file
+Shows information about the snapshot contained in
+.Ar file .
+It generates a lot of output.
+.Pp
+.El
+.\" 
+.\" 
+.\" .Sh IMPLEMENTATION NOTES
+.\" This next command is for sections 1, 6, 7 and 8 only.
+.\" 
+.\" 
+.\" .Sh ENVIRONMENT
+.\" 
+.\" 
+.Sh EXIT STATUS
+The
+.Nm
+utility exits 0 on success and -1 if an error occurs.  
+.\"
+.\"
+.Sh FILES
+.Bl -tag -width /etc/vps/vps_<ID>.conf
+.It Pa /etc/vps/vps_<ID>.conf
+for each VPS instance with id <ID>.
+.El
+.\" 
+.\" 
+.Sh EXAMPLES
+Example of a rc script (e.g. put these lines in /etc/rc.local):
+.Pp
+.Dl kldload vps_ddb
+.Dl kldload vps_dev
+.Dl kldload if_vps
+.Dl kldload vpsfs
+.Dl kldload vps_account
+.Dl kldload vps_suspend
+.Dl kldload vps_libdump
+.Dl kldload vps_snapst
+.Dl kldload vps_restore
+.Pp
+.Dl ifconfig vps0 create
+.Dl ifconfig vps0 up
+.Pp
+.Dl sysctl -w net.inet.ip.forwarding=1
+.Dl sysctl -w net.inet6.ip6.forwarding=1
+.Pp
+.Pp
+.\"
+.\"
+Example of a minimal VPS instance config file (/etc/vps/vps_testvps.conf):
+.Pp
+.Dl NAME = testvps
+.Dl FSROOT = /vps/testvps
+.Dl NETIF_0_ADDRESS = '1.2.3.4, 2001:2002::2003'
+.Dl ROOT_MOUNT = 'true'
+.Dl ROOT_UMOUNT = 'true'
+.Dl INIT = '/sbin/init'
+.Pp
+See
+.Xr vps.conf 5
+for a complete description of config file options.
+.Pp
+The /vps/testvps directory contains a full FreeBSD userland installation.
+See
+.Xr jail 8
+for examples how to install into a directory.
+.Pp
+The only crucial configuration bits are setting all terminals to
+.Ar off
+in
+.Ar /etc/ttys ,
+as well as putting
+.Ar root_rw_mount=NO
+into
+.Ar /etc/rc.conf .
+.Pp
+Don't use nullfs, there are some issues with snapshot/restore.
+.Pp
+The IP addresses given are assumed to belong to a subnet on a physically attached
+ethernet network. The
+.Nm
+utility
+creates a published ARP entry and a local route for each address.
+.Pp
+Start the vps instance:
+.Pp
+.Dl vpsctl start testvps
+.Dl vpsctl list
+.\"
+.\"
+.\" This next command is for sections 1, 6, 7, 8 and 9 only
+.\"     (command return values (to shell) and
+.\"     fprintf/stderr type diagnostics).
+.\" 
+.\" 
+.\" .Sh DIAGNOSTICS
+.\" 
+.\" 
+.\" .Sh COMPATIBILITY
+.\" 
+.\" 
+.Sh SEE ALSO
+.Xr vps 4 ,
+.Xr vps 9 ,
+.Xr vps.conf 5 ,
+.Xr mount_vpsfs 8 ,
+.Ad http://www.7he.at/freebsd/vps/
+.\" 
+.\" 
+.\" .Sh STANDARDS
+.\" 
+.\" 
+.Sh HISTORY
+Work on VPS was started in February 2009.
+.\" 
+.\" 
+.Sh AUTHORS
+.Pp
+Virtual Private Systems for FreeBSD and this manual page as well,
+were written by
+.An "Klaus P. Ohrhallinger" .
+.Pp
+Development of this software was partly funded by:
+.Pp
+TransIP.nl <http://www.transip.nl/>
+.\"
+.\"
+.Sh BUGS
+VPS is in an early stage of development and has to be considered as
+experimental.
+This means many bugs have to be expected.
+.Pp
+Please submit bug reports to
+.Ad freebsd-vps@7he.at .
+.\"
+.\"
+.Sh VERSION
+$Id: vpsctl.8 130 2013-04-10 09:32:39Z klaus $
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/usr.sbin/vpsctl/vpsctl.c head/usr.sbin/vpsctl/vpsctl.c
--- clean-head/usr.sbin/vpsctl/vpsctl.c	1970-01-01 01:00:00.000000000 +0100
+++ head/usr.sbin/vpsctl/vpsctl.c	2013-06-24 14:20:21.000000000 +0200
@@ -0,0 +1,3042 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: vpsctl.c 171 2013-06-11 16:35:58Z klaus $
+ *
+ */
+
+/*
+ * cc -g -Wall -Werror -o vpsctl vpsctl.c -I/usr/src/sys
+ */
+
+#include <machine/cputypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/ioccom.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/ttycom.h>
+#include <sys/sockio.h>
+#include <sys/priv.h>
+#include <sys/sysctl.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <termios.h>
+#include <assert.h>
+
+#ifndef VIMAGE
+#define VIMAGE	1
+#endif
+#ifndef VPS
+#define VPS	1
+#endif
+
+#include <vps/vps_user.h>
+#include <vps/vps_account.h>
+
+#include <vps/vps_libdump.h>
+
+#include "vpsctl.h"
+
+#define s6_addr8  __u6_addr.__u6_addr8
+#define s6_addr16 __u6_addr.__u6_addr16
+#define s6_addr32 __u6_addr.__u6_addr32
+
+#define LINE_MAXLEN	0x400
+
+#define DEFAULT_VPSIF	"vps0"
+
+#define RSYNC_MODE_CLIENT 1
+#define RSYNC_MODE_SERVER 2
+
+#ifdef DEBUG
+#define DBGfprintf	fprintf
+#else
+#define	DBGfprintf	nofprintf	
+int nofprintf(FILE __unused *fp, const char __unused *fmt, ...);
+int nofprintf(FILE __unused *fp, const char __unused *fmt, ...)
+{
+	return (0);
+}
+#endif
+
+/* Default TTY escape pattern. */
+static const char def_escape_pattern[] = 
+    { 0x0D, 0x23, 0x2E, 0x00, };
+static const char def_escape_message[] =
+    "Escape sequence: <enter>#.\n";
+
+int vpsfd;
+char **vc_envv;
+int fscale;
+
+int mig_did_suspend;
+int mig_did_revoke;
+char *mig_vps;
+struct vps_conf mig_vc;
+
+int vc_read_config(char *file_n, struct vps_conf *vc);
+char *vc_trim_whitespace(char *s);
+int vc_exec_cmd(char *cmd, int quiet);
+int vc_usage(FILE *);
+int vc_list(int, char **argv);
+int vc_shell(int, char **argv);
+int vc_show(int, char **);
+int vc_start(int, char **);
+int vc_stop(int, char **);
+int vc_exec(int, char **, char **);
+int vc_ifmove(int, char **);
+int vc_suspend(int, char **);
+int vc_snapshot(int, char **, int, int);
+int vc_restore(int, char **);
+int vc_abort(int, char **);
+int vc_migrate(int argc, char **argv);
+int vc_sshtest(int argc, char **argv);
+int vc_get_ssh_transport(char *host, int *pid, int *rfd, int *wfd);
+int vc_close_ssh_transport(int pid);
+const char *vc_statusstr(int status);
+int vc_net_publish(struct vps_conf *cf);
+int vc_net_revoke(struct vps_conf *cf);
+int vc_rsync(int, int, int, char *);
+int vc_argtest(int, char **);
+int vc_arg_show(int, char **);
+int vc_allow_ip4net(const char *, in_addr_t, in_addr_t);
+int vc_allow_ip6net(const char *, struct in6_addr *, u_int8_t *);
+int vc_arg_ipnet(int, char **);
+int vc_arg_priv(int, char **);
+int vc_arg_limit(int, char **);
+int vc_quota_recalc(int, char **);
+int vc_showdump(int, char **);
+int vc_console(int, char **);
+static int vc_ttyloop(int ptsmfd, const char *esc_pattern);
+
+int
+main(int argc, char **argv, char **envv)
+{
+	size_t sysctl_len;
+	int rc;
+
+	if (argc < 2)
+		return (vc_usage(stdout));
+
+	vc_envv = envv;
+
+	sysctl_len = sizeof(fscale);
+	if ((rc = sysctlbyname("kern.fscale", &fscale, &sysctl_len, NULL, 0)) == -1) {
+		fprintf(stderr, "sysctlbyname(\"kern.fscale\", ...): %s\n",
+			strerror(errno));
+		return (-1);
+	}
+
+	if ((vpsfd = open(_PATH_VPSDEV, O_RDWR)) == -1) {
+		fprintf(stderr, "open(%s): %s\n",
+				_PATH_VPSDEV, strerror(errno));
+		return (-1);
+	}
+
+	if (strcmp(argv[1], "start") == 0) {
+		rc = vc_start(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "stop") == 0) {
+		rc = vc_stop(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "execin") == 0) {
+		rc = vc_exec(argc-1, &argv[1], NULL);
+	} else
+	if (strcmp(argv[1], "execwt") == 0) {
+		rc = vc_exec(argc-1, &argv[1], NULL);
+	} else
+	if (strcmp(argv[1], "shell") == 0) {
+		rc = vc_shell(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "ifmove") == 0) {
+		rc = vc_ifmove(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "list") == 0) {
+		rc = vc_list(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "show") == 0) {
+		rc = vc_show(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "suspend") == 0) {
+		rc = vc_suspend(argc-1, &argv[1]);
+	} else
+	if (strcmp(argv[1], "resume") == 0) {
+		rc = vc_suspend(argc-1, &argv[1]);
+	} else
+	if (strcmp(argv[1], "snapshot") == 0) {
+		rc = vc_snapshot(argc-2, &argv[2], -1, 0);
+	} else
+	if (strcmp(argv[1], "restore") == 0) {
+		rc = vc_restore(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "abort") == 0) {
+		rc = vc_abort(argc-1, &argv[1]);
+	} else
+	if (strcmp(argv[1], "migrate") == 0) {
+		rc = vc_migrate(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "rsyncserver") == 0) {
+		if (argc < 2)
+			return (-1);
+		rc = vc_rsync(RSYNC_MODE_SERVER, 0, 1, argv[2]);
+	} else
+	if (strcmp(argv[1], "argshow") == 0) {
+		rc = vc_arg_show(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "ipnet") == 0) {
+		rc = vc_arg_ipnet(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "priv") == 0) {
+		rc = vc_arg_priv(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "limit") == 0) {
+		rc = vc_arg_limit(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "quotarecalc") == 0) {
+		rc = vc_quota_recalc(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "showdump") == 0) {
+		rc = vc_showdump(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "console") == 0) {
+		rc = vc_console(argc-2, &argv[2]);
+	} else
+#if 0
+	// debug / test code, move or delete at some point
+	if (strcmp(argv[1], "sshtest") == 0) {
+		rc = vc_sshtest(argc-2, &argv[2]);
+	} else
+	if (strcmp(argv[1], "rsync") == 0) {
+		int pid, rfd, wfd, len;
+		char cmd[0x100];
+
+		if (argc < 3)
+			return (-1);
+		if ((vc_get_ssh_transport(argv[2], &pid, &rfd, &wfd)))
+			return (-1);
+
+		snprintf(cmd, sizeof(cmd), "vpsctl rsyncserver %s\n",
+			argv[3]);
+		write(wfd, cmd, strlen(cmd));
+		rc = vc_rsync(RSYNC_MODE_CLIENT, rfd, wfd, argv[3]);
+
+		/* See if our remote shell still works. */
+		snprintf(cmd, sizeof(cmd), "uptime\n");
+		write(wfd, cmd, strlen(cmd));
+		len = read(rfd, cmd, sizeof(cmd));
+		if (len == -1)
+			fprintf(stderr, "read error: %s\n", strerror(errno));
+		cmd[len] = '\0';
+		fprintf(stderr, "len=%d cmd=[%s]\n", len, cmd);
+
+		vc_close_ssh_transport(pid);
+	} else
+	if (strcmp(argv[1], "argtest") == 0) {
+		rc = vc_argtest(argc-2, &argv[2]);
+	} else
+#endif /* 0 */
+	{
+		rc = vc_usage(stdout);
+	}
+
+	if (close(vpsfd) == -1) {
+		fprintf(stderr, "%s: close: %s\n",
+			__func__, strerror(errno));
+	}
+
+	return (rc);
+}
+
+int
+vc_usage(FILE *out)
+{
+	fprintf(out, 
+		"usage: \n"
+		"\n"
+		"vpsctl \n"
+		"      start    <id> <file>                 \n"
+		"      stop     <id> <file>                 \n"
+		"      list                                 \n"
+		"      show     <id>                        \n"
+		/*"      update   <id> <file>                 \n"*/
+		"      execin   <id> <cmd> [args ...]       \n"
+		"      execwt   <id> <cmd> [args ...]       \n"
+		"      shell    <id>                        \n"
+		"      console  <id>                        \n"
+		"      ifmove   <id> <ifname> [ifnewname]   \n"
+		"      suspend  <id>                        \n"
+		"      resume   <id>                        \n"
+		"      snapshot <id> <file>                 \n"
+		"      abort    <id>                        \n"
+		"      restore  <id> <file>                 \n"
+		"      migrate  <id> <remote-host> [norsync|onersync]\n"
+		"                                           \n"
+		"      argshow  <id>                        \n"
+		"      ipnet    <id> add <address/network, ...> \n"
+		"      ipnet    <id> rem <address/network, ...> \n"
+		"      priv     <id> allow <privilege number, ...> \n"
+		"      priv     <id> deny  <privilege number, ...> \n"
+		"      priv     <id> nosys <privilege number, ...> \n"
+		"      limit    <id> <resource:soft:hard,...> \n"
+		"                                           \n"
+		"      showdump <file> (attention: loads of output !)\n"
+		"\n"
+	);
+	return (out == stdout ? 0 : -1);
+}
+
+const char *
+vc_statusstr(int status)
+{
+    switch (status) {
+		case VPS_ST_CREATING:
+			return ("creating");
+		case VPS_ST_RUNNING:
+			return ("running");
+		case VPS_ST_SUSPENDED:
+			return ("suspended");
+		case VPS_ST_SNAPSHOOTING:
+			return ("snapshooting");
+		case VPS_ST_RESTORING:
+			return ("restoring");
+		case VPS_ST_DYING:
+			return ("dying");
+		case VPS_ST_DEAD:
+			return ("dead");
+		default:
+			return ("unknown");
+	}
+}
+
+int
+vc_shell(int argc, char **argv)
+{
+	char *argv2[4];
+	char *envv2[4];
+	char *s;
+	char str1[] = "execwt";
+	char str2[] = "/bin/sh";
+	char str3[] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:"
+		"/usr/local/sbin:/usr/local/bin:/root/bin";
+	char str4[0x400];
+	char str5[0x400];
+	int rc;
+
+	if (argc < 1)
+		return (vc_usage(stderr));
+
+	envv2[0] = str3;
+	envv2[3] = NULL;
+
+	if ((s = getenv("TERM")) != 0) {
+		snprintf(str4, sizeof(str4), "TERM=%s", s);
+		envv2[1] = str4;
+	} else
+		envv2[1] = NULL;
+
+	if ((s = getenv("TERMCAP")) != 0) {
+		snprintf(str5, sizeof(str5), "TERM=%s", s);
+		envv2[2] = str5;
+	} else
+		envv2[2] = NULL;
+
+	argv2[0] = str1;
+	argv2[1] = argv[0];
+	if ((argv2[2] = getenv("SHELL")) == NULL)
+		argv2[2] = str2;
+	argv2[3] = NULL;
+	
+	rc = vc_exec(3, argv2, envv2);
+
+	return (rc);
+}
+
+int
+vc_console(int argc, char **argv)
+{
+	struct vps_arg_getconsfd va;
+	int consfd;
+	int rc;
+
+	if (argc < 1)
+		return (vc_usage(stderr));
+
+	memset(&va, 0, sizeof(va));
+	snprintf(va.vps_name, sizeof(va.vps_name), "%s", argv[0]);
+	if ((rc = ioctl(vpsfd, VPS_IOC_GETCONSFD, &va)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_GETCONSFD: %s\n",
+			strerror(errno));
+		return (-1);
+	}
+	consfd = va.consfd;
+
+	fprintf(stdout, def_escape_message);
+	vc_ttyloop(consfd, def_escape_pattern);
+
+	return (rc);
+}
+	
+int
+vc_list(int argc __attribute__((unused)), char **argv __attribute__((unused)))
+{
+	struct vps_info *info, *info0;
+	int rc, cnt, i;
+
+	if ((rc = ioctl(vpsfd, VPS_IOC_LIST, &cnt)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_LIST: %s\n",
+			strerror(errno));
+		return (-1);
+	}
+	
+	if (cnt <= 0)
+		return (rc);
+
+	if ((info0 = mmap(NULL, cnt * sizeof(struct vps_info), 
+		PROT_READ, 0, vpsfd, 0)) == MAP_FAILED) {
+		fprintf(stderr, "mmap: %s\n", strerror(errno));
+		return (rc);
+	}
+
+	fprintf(stdout, "%-20s %-8s %-28s %4s %14s\n",
+		"Name", "State", "VFS Root", "%CPU", "Virtual Size");
+
+	for (i = 0; i < cnt; i++) {
+		info = info0 + i;
+
+		fprintf(stdout, "%-20s %-8s %-28s %4lu %14lu\n",
+			info->name,
+			vc_statusstr(info->status),
+			info->fsroot,
+			info->acc.pctcpu / (fscale / 100),
+			info->acc.virt);
+	}
+
+	munmap(info0, cnt * sizeof(struct vps_info));
+
+	return (rc);
+}
+
+int
+vc_suspend(int argc, char **argv)
+{
+	struct vps_arg_flags va;
+	u_long cmd;
+
+	if (argc < 2)
+		return (vc_usage(stderr));
+
+	if (strcmp(argv[0], "suspend") == 0)
+		cmd = VPS_IOC_SUSPND;
+	else if (strcmp (argv[0], "resume") == 0)
+		cmd = VPS_IOC_RESUME;
+	else
+		return (vc_usage(stderr));
+
+	snprintf(va.vps_name, sizeof(va.vps_name), "%s", argv[1]);
+	va.flags = 0;
+	va.flags |= VPS_SUSPEND_RELINKFILES;
+	if (argc > 2 && strcmp(argv[2], "norelinkfiles")==0)
+		va.flags &= ~VPS_SUSPEND_RELINKFILES;
+
+	if ((ioctl(vpsfd, cmd, &va)) == -1) {
+		fprintf(stderr, "ioctl %s: %s\n",
+			cmd == VPS_IOC_SUSPND ? "VPS_IOC_SUSPND" : "VPS_IOC_RESUME",
+			strerror(errno));
+		return (errno);
+	}
+
+	if (argc > 2 && strcmp(argv[2], "remote") == 0)
+		fprintf(stdout, "SUCCESS\n");
+
+	return (0);
+}
+
+int
+vc_abort(int argc, char **argv)
+{
+	struct vps_arg_flags va;
+	long cmd;
+
+	if (argc < 2)
+		return (vc_usage(stderr));
+
+	cmd = VPS_IOC_ABORT;
+
+	snprintf(va.vps_name, sizeof(va.vps_name), "%s", argv[1]);
+	va.flags = 0;
+
+	if ((ioctl(vpsfd, cmd, &va)) == -1) {
+		fprintf(stderr, "ioctl %s: %s\n", "VPS_IOC_ABORT", strerror(errno));
+		return (errno);
+	}
+
+	return (0);
+}
+
+int
+vc_snapshot(int argc, char **argv, int outfd, int verbose)
+{
+	struct vps_arg_snapst va;
+	int out, len, rv, wlen, one, i;
+	int *base;
+	char str2[0x100];
+	//char tmpc, *tmpp;
+	char *errbuf;
+
+	if (argc < 2)
+		return (vc_usage(stderr));
+
+	if (outfd > -1)
+		out = outfd;
+	else if (strcmp(argv[1], "-") == 0)
+		out = 1; /* stdout */
+	else
+		if ((out = open(argv[1], O_CREAT|O_WRONLY)) == -1) {
+			fprintf(stderr, "open([%s]): %s\n",
+				argv[1], strerror(errno));
+			return (-1);
+		}
+
+	if (verbose) {
+		fprintf(stderr, "Taking snapshot ... ");
+		fflush(stdout);
+	}
+
+
+	memset(&va, 0, sizeof (va));
+	va.msglen = 0x10000;
+	errbuf = malloc(va.msglen);
+	va.msgbase = errbuf;
+	strncpy(va.vps_name, argv[0], sizeof(va.vps_name));
+
+	if ((ioctl(vpsfd, VPS_IOC_SNAPST, &va)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_SNAPST: %s\n",
+			strerror(errno));
+		fprintf(stderr,
+			"Kernel error messages:\n"
+			"------------------------\n"
+			"%s"
+			"------------------------\n",
+			errbuf);
+		free(errbuf);
+		close(out);
+		return (errno);
+	}
+	base = (void*)va.database;
+	len = va.datalen;
+	DBGfprintf(stderr, "base = %p, len = %d\n", base, len);
+
+	if (verbose) {
+		fprintf(stderr, "done\n");
+		fflush(stderr);
+	}
+
+	//fprintf(stderr, "errbuf: [%s]\n", errbuf);
+	free(errbuf);
+
+	/*
+	 * XXX
+	 * Since 9.0 on i386, writing out the mmaped area to a pipe
+	 * to ssh, produces random data.
+	 * A pipe to cat always reproduces the correct data.
+	 * For now touch every single page as a workaround before write().
+	 */
+#if defined(CPU_386)
+#if 0
+	for (tmpp = (char *)base; tmpp < (char *)base + len; tmpp += PAGE_SIZE)
+		tmpc = *tmpp;
+#else
+	{
+	int *base2;
+	base2 = malloc(len);
+	memcpy(base2, base, len);
+	base = base2;
+	}
+#endif
+#endif /* CPU_386 */
+
+	if (verbose) {
+		fprintf(stderr, "Transferring dump (%d MB) ", len/1024/1024);
+		fflush(stderr);
+	}
+
+	one = roundup(len / 100, 8);
+	
+	i = 0;
+	wlen = 0;
+	while (wlen < len) {
+		if ((rv = write(out, ((char *)base)+wlen, MIN(len-wlen, one))) == -1) {
+			fprintf(stderr, "write: %s\n", strerror(errno));
+			return (-1);
+		}
+		wlen += rv;
+		if (verbose) {
+			if (i != 0 && i != 100 && (i % 10) == 0)
+				snprintf(str2, sizeof(str2), "(%d%%)", i);
+			else
+				str2[0] = '\0';
+			fprintf(stderr, ".%s", str2);
+			fflush(stderr);
+		}
+		i++;
+	}
+
+	if (verbose) {
+		fprintf(stderr, "(100%%) done\n");
+		fflush(stderr);
+	}
+
+	if ( ! (out == 1 || outfd > -1) )
+		close(out);
+
+	return (0);
+}
+
+int
+vc_restore(int argc, char **argv)
+{
+	struct vps_arg_snapst va;
+	struct vps_dumpheader *dumphdr;
+	//struct stat statbuf;
+	int in, len, rv;
+	int have_header;
+	unsigned int rlen;
+	/* int *base; */
+	void *buf;
+	struct vps_conf vc;
+	char file_n[MAXPATHLEN];
+	char *errbuf;
+
+	if (argc < 2)
+		return (vc_usage(stderr));
+
+	snprintf(file_n, MAXPATHLEN, "%s/vps_%s.conf",
+			_PATH_CONFDIR, argv[0]);
+	memset(&vc, 0, sizeof(struct vps_conf));
+	if (vc_read_config(file_n, &vc)) {
+		fprintf(stderr, "config not found\n");
+		return (1);
+	}
+
+	if (strcmp(argv[1], "-") == 0)
+		in = 0; /* stdin */
+	else
+		if ((in = open(argv[1], O_RDONLY)) == -1) {
+			fprintf(stderr, "open([%s]): %s\n",
+				argv[1], strerror(errno));
+			return (-1);
+		}
+
+	/*
+	if ((fstat(in, &statbuf)) == -1) {
+		fprintf(stderr, "fstat(): %s\n", strerror(errno));
+		close(in);
+		return (-1);
+	}
+	len = statbuf.st_size;
+	*/
+
+	len = 0x100;
+	buf = malloc(len);
+	rlen = 0;
+	have_header = 0;
+	while ((rv = read(in, ((char*)buf)+rlen, len-rlen)) > 0) {
+		if (rv == -1) {
+			fprintf(stderr, "read: %s\n", strerror(errno));
+			return (-1);
+		}
+		rlen += rv;
+		if (have_header == 0 && rlen >= sizeof (*dumphdr)) {
+			dumphdr = (struct vps_dumpheader *)buf;
+			len = dumphdr->size;
+			DBGfprintf(stderr, "size=%lu\n", dumphdr->size);
+			buf = realloc(buf, len);
+			have_header = 1;
+		}
+	}
+
+	DBGfprintf(stdout, "rlen = %d\n", rlen);
+
+	memset(&va, 0, sizeof(va));
+	va.msglen = 0x10000;
+	errbuf = malloc(va.msglen);
+	va.msgbase = errbuf;
+	strncpy(va.vps_name, argv[0], sizeof(va.vps_name));
+	va.database = buf;
+	va.datalen = rlen;
+
+	if ((ioctl(vpsfd, VPS_IOC_RESTOR, &va)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_RESTOR: %s [%s]\n",
+			strerror(errno), va.errmsg);
+		fprintf(stderr,
+			"Kernel error messages:\n"
+			"------------------------\n"
+			"%s"
+			"------------------------\n",
+			errbuf);
+		free(errbuf);
+		close(in);
+		return (errno);
+	}
+
+	//fprintf(stderr, "errbuf: [%s]\n", errbuf);
+	free(errbuf);
+
+	if (in != 0)
+		close(in);
+
+	vc_net_publish(&vc);
+
+	if (argc > 2 && strcmp(argv[2], "remote") == 0)
+		fprintf(stdout, "SUCCESS\n");
+
+	return (0);
+}
+
+int
+vc_start(int argc, char **argv)
+{
+	struct vps_param vp;
+	struct vps_conf vc;
+	char file_n[MAXPATHLEN];
+
+	memset(&vp, 0, sizeof(struct vps_param));
+
+	switch (argc) {
+		case 1:
+			/* <name> */
+			snprintf(file_n, MAXPATHLEN, "%s/vps_%s.conf",
+				_PATH_CONFDIR, argv[0]);
+			/* FALLTHROUGH */
+		case 2:
+			/* <name> <conffile> */
+			if (vc_read_config(argc == 2 ? argv[1] : file_n, &vc))
+				return (-1);
+			/* Override vps name. */
+			strncpy(vp.name, argv[0][0] ? argv[0] : vc.name,
+				MAXHOSTNAMELEN);
+			break;
+		default:
+			return (vc_usage(stderr));
+			break;
+	}
+
+	if (vc.epair) {
+		struct epair_cf *epp;
+
+		epp = vc.epair;
+		do {
+			/*
+			printf("epp->idx = %d\nepp->ifidx = %d\nepp->ifconfig = [%s]\n",
+					epp->idx, epp->ifidx, epp->ifconfig);
+			*/
+		} while ((epp = epp->next));
+	}
+
+	/* Fill in vps_param structure. */
+	strncpy(vp.fsroot, vc.fsroot, MAXPATHLEN);
+
+	/* If given, execute the command to mount the root filesystem. */
+	if (vc.cmd_mountroot[0]) {
+		if (vc_exec_cmd(vc.cmd_mountroot, 0))
+			goto startfail;
+	}
+
+	/* 
+	 * Actually create the vps instance.
+	 */
+	if (ioctl(vpsfd, VPS_IOC_CREAT, &vp) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_CREAT: %s\n",
+			strerror(errno));
+		goto startfail;
+	}
+
+	/*
+	 * Set allowed privileges and ip4/ip6 networks.
+	 */
+	{
+		struct ip_network *netp;
+		char *argv2[4];
+		int error;
+		int i;
+
+		for (i = 0; i < vc.ip_networks_cnt; i++) {
+			netp = vc.ip_networks[i];
+
+			switch (netp->af) {
+			case AF_INET:
+				vc_allow_ip4net(vp.name, netp->addr.in.s_addr,
+				     netp->mask.in.s_addr);
+				break;
+			case AF_INET6:
+				vc_allow_ip6net(vp.name, &netp->addr.in6, &netp->mask.in6);
+				break;
+			default:
+				break;
+			}
+		}
+
+		argv2[0] = vp.name;
+		argv2[3] = NULL;
+
+		if (vc.priv_allow != NULL) {
+			argv2[1] = strdup("allow");
+			argv2[2] = vc.priv_allow;
+			error = vc_arg_priv(3, argv2);
+			free(argv2[1]);
+			if (error != 0)
+				goto startfail;
+		}
+
+		if (vc.priv_nosys != NULL) {
+			argv2[1] = strdup("nosys");
+			argv2[2] = vc.priv_nosys;
+			error = vc_arg_priv(3, argv2);
+			free(argv2[1]);
+			if (error != 0)
+				goto startfail;
+		}
+
+		if (vc.limits != NULL) {
+			argv2[1] = vc.limits;
+			argv2[2] = NULL;
+			error = vc_arg_limit(2, argv2);
+			/*
+			if (error != 0)
+				goto startfail;
+			Ignore error and only warn if module is not loaded.
+			*/
+			if (error != 0 && error != EOPNOTSUPP)
+				goto startfail;
+		}
+
+	}
+
+	/*
+	 * Clone the epair network interfaces, and move the b-side(s)
+	 * into the newly created vps instance.
+	 * Also issue the epair_<idx>_ifconfig commands.
+	 */
+	if (vc.epair) {
+		struct vps_arg_ifmove va;
+		char cmd[0x100];
+		struct epair_cf *epp;
+
+		epp = vc.epair;
+		do {
+			/* XXX check if interface does not exist before creating ! */
+
+			snprintf(cmd, 0x100, "ifconfig epair%d create\n", epp->ifidx);
+			if (vc_exec_cmd(cmd, 0))
+				goto startfail;
+
+			snprintf(cmd, 0x100, "ifconfig epair%da %s\n",
+					epp->ifidx, epp->ifconfig);
+			if (vc_exec_cmd(cmd, 0))
+				goto startfail;
+
+			/* Move b-side into vps instance. */
+			strncpy(va.vps_name, vp.name, sizeof(va.vps_name));
+			snprintf(va.if_name, sizeof(va.if_name), "epair%db", epp->ifidx);
+			if ((ioctl(vpsfd, VPS_IOC_IFMOVE, &va)) == -1) {
+				fprintf(stderr, "ioctl VPS_IOC_IFMOVE: %s\n",
+					strerror(errno));
+				goto startfail;
+			}
+
+		} while ((epp = epp->next));
+	}
+
+	/*
+	 * Clone the vps network interfaces, set adresses on interface and
+	 * (XXX) set in vps instance for filtering and lookup;
+	 * then move interface into vps.
+	 */
+	if (vc.netif) {
+		struct vps_arg_ifmove va;
+		struct netif_cf *netifp;
+		struct netif_addr *ifaddrp;
+		struct ifreq ifr;
+		struct in6_addr addr6;
+		u_int8_t plen;
+		/* char cmd[0x100]; */
+		int sockfd;
+		int i;
+
+		if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+			fprintf(stderr, "socket failed: %s\n", strerror(errno));
+			goto startfail;
+		}
+
+		netifp = vc.netif;
+		do {
+			/*
+			fprintf(stderr, "netifp=%p idx=%d addrcnt=%d\n",
+					netifp, netifp->idx, netifp->ifaddr_cnt);
+			snprintf(cmd, 0x100, "ifconfig vps%d create", netifp->ifidx);
+			if (vc_exec_cmd(cmd, 0))
+				goto startfail;
+			*/
+			memset(&ifr, 0, sizeof(ifr));
+			strncpy(ifr.ifr_name, "vps", 4);
+			if (ioctl(sockfd, SIOCIFCREATE2, &ifr) == -1) {
+				fprintf(stderr, "ioctl SIOCIFCREATE2: %s\n", strerror(errno));
+				goto startfail;
+			}
+			strncpy(va.if_name, ifr.ifr_name, sizeof(va.if_name));
+
+			for (i = 0; i < netifp->ifaddr_cnt; i++) {
+				ifaddrp = netifp->ifaddr[i];
+
+				/*
+				if (ifaddrp->af == AF_INET)
+					snprintf(cmd, 0x100,
+					    "ifconfig vps%d inet %s netmask 0xffffffff",
+					    netifp->ifidx, ifaddrp->str);
+				else if (ifaddrp->af == AF_INET6)
+					snprintf(cmd, 0x100,
+					    "ifconfig vps%d inet6 %s prefixlen 128",
+					    netifp->ifidx, ifaddrp->str);
+				else
+					continue;
+
+				if (vc_exec_cmd(cmd, 0))
+					goto startfail;
+				*/
+
+				switch (ifaddrp->af) {
+				case AF_INET:
+					vc_allow_ip4net(vp.name, inet_addr(ifaddrp->str), 0xffffffff);
+					break;
+
+				case AF_INET6:
+					if (inet_pton(AF_INET6, ifaddrp->str, &addr6) == -1) {
+						fprintf(stderr, "couldn't parse [%s] as AF_INET6\n", ifaddrp->str);
+						goto startfail;
+					} else {
+						plen = 128;
+						vc_allow_ip6net(vp.name, &addr6, &plen);
+					}
+					break;
+
+				default:
+					break;
+				}
+			}
+
+			strncpy(va.vps_name, vp.name, sizeof(va.vps_name));
+			/* snprintf(va.if_name, sizeof(va.if_name), "vps%d", netifp->ifidx); */
+			snprintf(va.if_newname, sizeof(va.if_newname), "vps%d", netifp->ifidx);
+			if ((ioctl(vpsfd, VPS_IOC_IFMOVE, &va)) == -1) {
+				fprintf(stderr, "ioctl VPS_IOC_IFMOVE: %s\n",
+					strerror(errno));
+				goto startfail;
+			}
+
+		} while ((netifp = netifp->next));
+
+		close(sockfd);
+	}
+
+	vc_net_publish(&vc);
+
+	/* Start the init process if given. 
+	   XXX support parameters. */
+	if (vc.initproc[0]) {
+		int argc2 = 3;
+		char str1[] = "execin";
+		char *argv2[] = { str1, NULL, NULL, NULL };
+
+		argv2[1] = vp.name;
+		argv2[2] = vc.initproc;
+
+		if (vc_exec(argc2, argv2, NULL)) {
+			goto startfail;
+		}
+	}
+	return (0);
+
+  startfail:
+	fprintf(stderr, "not started due to failure(s) !\n");
+
+	/* XXX undo everything */
+
+	return (-1);
+}
+
+int
+vc_stop(int argc, char **argv)
+{
+	struct vps_conf vc;
+	char file_n[MAXPATHLEN];
+	char *vps_name;
+	int vps_status;
+
+	switch (argc) {
+		case 1:
+			/* <name> */
+			snprintf(file_n, MAXPATHLEN, "%s/vps_%s.conf",
+				_PATH_CONFDIR, argv[0]);
+			/* FALLTHROUGH */
+		case 2:
+			/* <name> <conffile> */
+			memset(&vc, 0, sizeof (struct vps_conf));
+			if (vc_read_config(argc==2 ? argv[1] : file_n, &vc) 
+				&& argv[0][0] == 0) {
+				fprintf(stderr, "must specify at least <name> or <config>\n");
+				return (-1);
+			}
+			/* Override vps name. */
+			vps_name = argv[0][0] ? argv[0] : vc.name;
+			break;
+		default:
+			return (vc_usage(stderr));
+			break;
+	}
+
+	/* 
+	 * If we do not have config values, just return because
+	 * we do not know what to unmount etc..
+	 */
+	if (vps_name[0] == 0)
+		return (0);
+
+	/*
+	 * First get info about the vps instance.
+	 */
+	{
+		struct vps_getextinfo vgx;
+		struct vps_extinfo *xinfo;
+
+		memset(&vgx, 0, sizeof(vgx));
+		vgx.datalen = sizeof(*xinfo);
+		vgx.data = malloc(vgx.datalen);
+		xinfo = (struct vps_extinfo *)vgx.data;
+
+		snprintf(vgx.vps_name, sizeof(vgx.vps_name), "%s", vps_name);
+
+		if ((ioctl(vpsfd, VPS_IOC_GETXINFO, &vgx)) == -1) {
+			fprintf(stderr, "ioctl VPS_IOC_GETXINFO: %s\n",
+				strerror(errno));
+			free(xinfo);
+			return (-1);
+		}
+
+		vps_status = xinfo->status;
+
+		free(xinfo);
+	}
+
+	vc_net_revoke(&vc);
+
+	/*
+	 * Issue DESTROY IOCTL and specify 60 seconds grace time
+	 * between SIGTERM and SIGKILL.
+	 */
+	if ((ioctl(vpsfd, VPS_IOC_DESTR, vps_name)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_DESTR: %s\n",
+			strerror(errno));
+		return (-1);
+	}
+
+	/* Take epair interfaces down and destroy them */
+	if (vc.epair) {
+		char cmd[0x100];
+		struct epair_cf *epp;
+
+		epp = vc.epair;
+		do {
+			snprintf(cmd, 0x100, "ifconfig epair%da down\n", epp->ifidx);
+			vc_exec_cmd(cmd, 0);
+
+			snprintf(cmd, 0x100, "ifconfig epair%db down\n", epp->ifidx);
+			vc_exec_cmd(cmd, 0);
+
+			/* disabled - epair destroy panics
+			snprintf(cmd, 0x100, "ifconfig epair%da destroy\n", epp->ifidx);
+			vc_exec_cmd(cmd, 0);
+			*/
+
+		} while ((epp = epp->next));
+	}
+
+	if (vc.cmd_unmountroot[0])
+		vc_exec_cmd(vc.cmd_unmountroot, 0);
+
+	return (0);
+}
+
+int
+vc_exec(int argc, char **argv, char **envv)
+{
+	int rc, pid;
+	int ptsmfd, ptssfd;
+	int f_pts;
+	int i;
+	u_long cmd;
+
+	if (argc < 3)
+		return (vc_usage(stderr));
+	
+	if (strcmp (argv[0], "execin") == 0)
+		cmd = VPS_IOC_SWITCH;
+	else
+	if (strcmp (argv[0], "execwt") == 0)
+		cmd = VPS_IOC_SWITWT;
+	else
+		return (vc_usage(stderr));
+
+	if (cmd == VPS_IOC_SWITWT) {
+		f_pts = 1;
+		if ((ptsmfd = posix_openpt(O_RDWR)) == -1) {
+			fprintf(stderr, "posix_openpt(): %s\n", strerror(errno));
+			return (-1);
+		}
+		cmd = VPS_IOC_SWITCH;
+	} else {
+		f_pts = 0;
+		ptssfd = ptsmfd = -1;
+	}
+
+	if ((pid = fork()) == -1) {
+		fprintf(stderr, "fork: %s\n", strerror(errno));
+		return (-1);
+	}
+
+	if (pid == 0) {
+
+		if (f_pts) {
+			/* Get rid of any open file descriptors except vpsfd and ptsmfd. */
+			closefrom(MAX(vpsfd, ptsmfd) + 1);
+			for (i = 0; i < MAX(vpsfd, ptsmfd); i++)
+				if (i != vpsfd && i != ptsmfd)
+					close(i);
+
+			if ((ptssfd = open(ptsname(ptsmfd), O_RDWR)) == -1) {
+				fprintf(stderr, "open(%s): %s\n", ptsname(ptsmfd),
+					strerror(errno));
+				close(ptsmfd);
+				exit(-1);
+			}
+			close(ptsmfd);
+			dup2(ptssfd, 0);
+			dup2(ptssfd, 1);
+			dup2(ptssfd, 2);
+
+		} else {
+			/* Get rid of any open file descriptors except vpsfd. */
+			closefrom(vpsfd + 1);
+			for (i = 0; i < vpsfd; i++)
+				close(i);
+
+		}
+
+		if ((rc = ioctl(vpsfd, cmd, argv[1])) == -1) {
+			fprintf(stderr, "ioctl %lx: %s\n",
+				cmd, strerror(errno));
+			close(vpsfd);
+			exit(-1);
+		}
+		if (close(vpsfd) == -1) {
+			fprintf(stderr, "%s: close: %s\n",
+				__func__, strerror(errno));
+		}
+
+		if (f_pts) {
+			/*
+			if (setpgid(0, 0) == -1) {
+				fprintf(stderr, "setpgid(): %s\n", strerror(errno));
+				exit(-1);
+			}
+			*/
+			if (setsid() == -1) {
+				fprintf(stderr, "setsid(): %s\n", strerror(errno));
+				/*
+				 * If this is the only process in the vps instance
+				 * it's process group has the same number the process,
+				 * which implies setsid() is not permitted.
+				 * Report error on screen but continue anyway
+				 * to allow opening an emergency shell or whatever.
+				 *
+				exit(-1);
+				*/
+			}
+			if (ioctl(ptssfd, TIOCSCTTY, NULL) == -1) {
+				fprintf(stderr, "ioctl(TIOCSCTTY): %s\n", strerror(errno));
+				exit(-1);
+			}
+		}
+
+		if (execve(argv[2], &argv[2], envv) == -1) {
+			fprintf(stderr, "execve([%s], ...): %s\n",
+				argv[2], strerror(errno));
+			exit(-1);
+		}
+		/* NOTREACHED */
+
+	} else {
+		if (f_pts) {
+			fprintf(stdout, def_escape_message);
+			vc_ttyloop(ptsmfd, def_escape_pattern);
+		}
+		rc = 0;
+	}
+
+	return (rc);
+}
+
+int
+vc_ifmove(int argc, char **argv)
+{
+	struct vps_arg_ifmove va;
+
+	if (argc < 2)
+		return (vc_usage(stderr));
+
+	strncpy(va.vps_name, argv[0], sizeof(va.vps_name));
+	strncpy(va.if_name, argv[1], sizeof(va.if_name));
+	if (argc > 2)
+		strncpy(va.if_newname, argv[2], sizeof(va.if_newname));
+
+	if ((ioctl(vpsfd, VPS_IOC_IFMOVE, &va)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_IFMOVE: %s\n",
+			strerror(errno));
+		return (-1);
+	}
+
+	DBGfprintf(stdout, "%s@%s\n", va.if_name, va.vps_name);
+	return (0);
+}
+
+static void
+vc_migrate_sighandler(int sig)
+{
+	char str_resume[] = "resume";
+	char *str[3];
+	int error = 0;
+
+	fprintf(stderr, "%s: signal=%d received\n", __func__, sig);
+
+	if (sig == SIGSEGV || sig == SIGBUS || sig == SIGABRT) {
+		signal(sig, SIG_DFL);
+		return;
+	}
+
+	fprintf(stderr, "Aborted. \n");
+	if (mig_did_suspend) {
+		fprintf(stderr, "Trying to resume vps ... ");
+		str[0] = str_resume;
+		str[1] = mig_vps;
+		str[2] = NULL;
+		if ((error = vc_suspend(2, str))) {
+			fprintf(stderr, "failed (%s)\n", strerror(errno));
+		} else {
+			fprintf(stderr, "done\n");
+		}
+		
+	}
+	if (error == 0 && mig_did_revoke) {
+		fprintf(stderr, "Trying to re-announce vps on networks ... ");
+		if ((error = vc_net_publish(&mig_vc))) {
+			fprintf(stderr, "failed (%s)\n", strerror(errno));
+		} else {
+			fprintf(stderr, "done\n");
+		}
+	}
+
+	signal(sig, SIG_DFL);
+	kill(getpid(), sig);
+	return;
+}
+
+int
+vc_migrate(int argc, char **argv)
+{
+	struct vps_conf vc;
+	char *argv2[5];
+	char *host, *vps;
+	char *fsroot;
+	char cmd[0x100];
+	char file_n[MAXPATHLEN];
+	char f_norsync = 0;
+	char f_onersync = 0;
+	char str_suspend[] = "suspend";
+	char str_abort[] = "abort";
+	int pid, rfd, wfd;
+	int argc2;
+	int error;
+	int len;
+	
+	if (argc < 2)
+		return (vc_usage(stderr));
+
+	if (argc > 2 && strcmp(argv[2], "norsync") == 0)
+		f_norsync = 1;
+
+	if (argc > 2 && strcmp(argv[2], "onersync") == 0)
+		f_onersync = 1;
+
+	mig_did_suspend = 0;
+	mig_did_revoke = 0;
+	signal(SIGINT, vc_migrate_sighandler);
+	signal(SIGQUIT, vc_migrate_sighandler);
+	signal(SIGTERM, vc_migrate_sighandler);
+	signal(SIGPIPE, vc_migrate_sighandler);
+
+	snprintf(file_n, MAXPATHLEN, "%s/vps_%s.conf",
+			_PATH_CONFDIR, argv[0]);
+	memset(&vc, 0, sizeof(struct vps_conf));
+	if (vc_read_config(file_n, &vc)) {
+		fprintf(stderr, "config not found\n");
+		return (1);
+	}
+
+	vps = argv[0];
+	host = argv[1];
+
+	mig_vps = vps;
+	mig_vc = vc;
+
+	if (vc.fsroot_priv[0] != '\0')
+		fsroot = vc.fsroot_priv;
+	else
+		fsroot = vc.fsroot;
+
+	fprintf(stderr, "Opening ssh transport ... ");
+
+	if ((error = vc_get_ssh_transport(host, &pid, &rfd, &wfd)))
+		return (error);
+
+	fprintf(stderr, "done\n");
+
+	if (f_norsync == 0) {
+
+		fprintf(stderr, "Copying config file ... ");
+		snprintf(cmd, sizeof(cmd), "vpsctl rsyncserver %s/\n", _PATH_CONFDIR); 
+		write(wfd, cmd, strlen(cmd));
+		if ((error = vc_rsync(RSYNC_MODE_CLIENT, rfd, wfd, file_n)))
+			goto resume;
+	
+		fprintf(stderr, "done\n");
+
+		if (f_onersync == 0) {
+
+			fprintf(stderr, "Performing first filesystem sync ... ");
+
+			/* Start a first filesystem sync while vps is still running. */
+			if (vc.fsroot_priv[0] != '\0') {
+				/* Create vps' private root directory. */
+				snprintf(cmd, sizeof(cmd), "mkdir -p %s\n", vc.fsroot_priv);
+				write(wfd, cmd, strlen(cmd));
+				//len = read(rfd, cmd, sizeof(cmd));
+			}
+			/* Create vps' mountpoint directory. */
+			snprintf(cmd, sizeof(cmd), "mkdir -p %s\n", vc.fsroot);
+			write(wfd, cmd, strlen(cmd));
+			//len = read(rfd, cmd, sizeof(cmd));
+
+			snprintf(cmd, sizeof(cmd), "vpsctl rsyncserver %s/\n", fsroot);
+			write(wfd, cmd, strlen(cmd));
+			snprintf(cmd, sizeof(cmd), "%s/", fsroot);
+			if ((error = vc_rsync(RSYNC_MODE_CLIENT, rfd, wfd, cmd)))
+				goto resume;
+
+			fprintf(stderr, "done\n");
+
+		}
+
+	}
+
+	fprintf(stderr, "Suspending vps ... ");
+
+	argv2[0] = str_suspend;
+	argv2[1] = vps;
+	argv2[2] = NULL;
+	argc2 = 2;
+	if ((error = vc_suspend(argc2, argv2))) {
+		return (error);
+	}
+	mig_did_suspend = 1;
+
+	fprintf(stderr, "done\n");
+
+	if (f_norsync == 0) {
+
+	fprintf(stderr, "Performing final filesystem sync ... ");
+
+	/* After suspending do the final filesystem sync. */
+	snprintf(cmd, sizeof(cmd), "vpsctl rsyncserver %s/\n", fsroot);
+	write(wfd, cmd, strlen(cmd));
+	snprintf(cmd, sizeof(cmd), "%s/", fsroot);
+	if ((error = vc_rsync(RSYNC_MODE_CLIENT, rfd, wfd, cmd)))
+		goto resume;
+
+	fprintf(stderr, "done\n");
+
+	}
+
+	/* Take offline. */
+	vc_net_revoke(&vc);
+	mig_did_revoke = 1;
+
+	//fprintf(stderr, "Starting snapshot and remote restore ... ");
+
+	/* Start restore on other side ... */
+	snprintf(cmd, sizeof(cmd), "vpsctl restore %s - remote\n", vps);
+	write(wfd, cmd, strlen(cmd));
+
+	/* ... and send snapshot data. */
+	argv2[0] = vps;
+	//argv2[1] = (char *)filename;
+	argv2[1] = NULL;
+	argv2[2] = NULL;
+	argc2 = 2;
+	if ((error = vc_snapshot(argc2, argv2, wfd, 1)))
+		goto resume;
+
+	fprintf(stderr, "Restoring on remote host ... ");
+
+	/* Get status of remote restore. */
+	len = read(rfd, cmd, sizeof(cmd));
+	cmd[len] = '\0';
+	DBGfprintf(stdout, "%s: remote restore: [%s]\n", __func__, cmd);
+	if (strncmp(cmd, "SUCCESS", 7)) {
+		fprintf(stderr, "%s: restore on remote host failed\n", __func__);
+		goto resume;
+	}
+
+	fprintf(stderr, "done\n");
+
+	/* remote vps_resume */
+	snprintf(cmd, sizeof(cmd), "vpsctl resume %s remote\n", vps);
+	write(wfd, cmd, strlen(cmd));
+	len = read(rfd, cmd, sizeof(cmd));
+	cmd[len] = '\0';
+	DBGfprintf(stderr, "%s: remote resume: [%s]\n", __func__, cmd);
+	if (strncmp(cmd, "SUCCESS", 7) != 0) {
+		fprintf(stderr, "%s: resume on remote host failed: [%s]\n",
+			__func__, cmd);
+		goto resume;
+	}
+
+	fprintf(stderr, "Aborting local instance ... ");
+
+	/* Migration was successful so abort local instance. */
+	argv2[0] = str_abort;
+	argv2[1] = vps;
+	argv2[2] = NULL;
+	argc2 = 2;
+	vc_abort(argc2, argv2);
+
+	fprintf(stderr, "done\n");
+
+	fprintf(stderr, "Stopping local instance ... ");
+
+	argv2[0] = vps;
+	argv2[1] = NULL;
+	argc2 = 1;
+	vc_stop(argc2, argv2);
+
+	fprintf(stderr, "done\n");
+
+	vc_close_ssh_transport(pid);	
+
+	return (0);
+
+  resume:
+	/*
+	 * XXX does not work like this currently because snapshot context in
+	 *     kernel exists until mappings are removed and (?) dev fd closed.
+	 */
+	/*
+	argv2[0] = str_resume;
+	argv2[1] = vps;
+	argv2[2] = NULL;
+	argc2 = 2;
+	vc_suspend(argc2, argv2);
+
+	//vc_net_publish(&vc);
+	*/
+
+	kill(getpid(), SIGTERM);
+
+	return (error);
+}
+
+/* open ssh session to remote host and return a set of
+   file descriptors */
+int
+vc_get_ssh_transport(char *host, int *pid, int *rfd, int *wfd)
+{
+	char str_ssh[] = "/usr/bin/ssh";
+	char str_q[] = "-q";
+	char str_l[] = "-l";
+	char str_root[] = "root";
+	char *argv[] = { str_ssh, str_q, str_l, str_root, NULL, NULL };
+	int sshrfd, sshwfd;
+	int fds[2];
+	int error;
+
+	argv[4] = host;
+
+	if ((error = pipe(fds))) {
+		fprintf(stderr, "%s: pipe: %s\n",
+			__func__, strerror(errno));
+	}
+	*rfd = fds[0]; 
+	sshwfd = fds[1];
+
+	if ((error = pipe(fds))) {
+		fprintf(stderr, "%s: pipe: %s\n",
+			__func__, strerror(errno));
+	}
+	*wfd = fds[1]; 
+	sshrfd = fds[0];
+
+	if ((*pid = fork()) == -1) {
+		fprintf(stderr, "%s: fork: %s\n",
+			__func__, strerror(errno));
+		return (-1);
+	}
+
+	if (*pid == 0) {
+
+		close(1);
+		close(0);
+		dup2(sshrfd, 0);
+		dup2(sshwfd, 1);
+
+		if ((execve(argv[0], argv, vc_envv)) == -1) {
+			fprintf(stderr, "%s: execve: %s\n",
+				__func__, strerror(errno));
+			exit(-1);
+		}
+		/* NOTREACHED */
+
+	} else {
+		char buf[0x100];
+		int rlen = 0;
+
+		/* Get rid of warning message. */
+		/* XXX dirty */
+		while (rlen < 80)
+		   rlen += read(*rfd, buf, sizeof(buf));
+	}
+
+	return (0);
+}
+
+int
+vc_close_ssh_transport(int pid)
+{
+	int status = 0;
+
+	if (pid > 0) {
+		kill(pid, SIGTERM);
+		wait4(pid, &status, 0, NULL);
+	}
+	return (WIFEXITED(status) ? WEXITSTATUS(status) : -1);
+}
+
+int
+vc_sshtest(int argc, char **argv)
+{
+	char buf[0x100];
+	int pid, rfd, wfd;
+	int len;
+
+	if (argc < 2) {
+		return (-1);
+	}
+
+	if ((vc_get_ssh_transport(argv[0], &pid, &rfd, &wfd)))
+		return (-1);
+
+	write(wfd, argv[1], strlen(argv[1]));
+	write(wfd, "\n", 1);
+	len = read(rfd, buf, sizeof(buf));
+	buf[len] = 0;
+	printf("buf=[%s]\n", buf);
+
+	vc_close_ssh_transport(pid);
+
+	return (0);
+}
+
+#define RSYNC_DELETE 1
+
+/*
+ * The rsync program that is used here is slightly adapted to allow
+ * write/read from/to its stdin/stdout.
+ */
+int
+vc_rsync(int mode, int rfd, int wfd, char *path)
+{
+	char *argv[7];
+	char str_rsync[] = "/usr/sbin/rsync_vps";
+	char str_flagscl[] = "-xae";
+	char str_dash[] = "-";
+	char str_server[] = "--server";
+	char str_flagssv[] = "-logDtprxe.iLf";
+	char str_delete[] = "--delete";
+	char str_dot[] = ".";
+	int oflags_rfd;
+	int oflags_wfd;
+	int status;
+	int pid;
+
+	/* 
+	 * XXX Make sure directory actually exists.
+	 * On server side create it if necessary.
+	 *
+	 * --> happens in vc_migrate().
+	 */
+
+	oflags_rfd = fcntl(rfd, F_GETFL);
+	oflags_wfd = fcntl(wfd, F_GETFL);
+
+	pid = fork();
+
+	if (pid == -1) {
+		fprintf(stderr, "fork failed: %s\n", strerror(errno));
+		return (-1);
+
+	} else if (pid == 0) {
+		
+		if (rfd != 0 && wfd != 1) {
+			close(1);
+			close(0);
+			dup2(rfd, 0);
+			dup2(wfd, 1);
+		}
+
+		if (mode == RSYNC_MODE_CLIENT) {
+
+			argv[0] = str_rsync;
+			argv[1] = str_delete;
+			argv[2] = str_flagscl;
+			argv[3] = str_dash;
+			argv[4] = path;
+			argv[5] = NULL;
+
+		} else if (mode == RSYNC_MODE_SERVER) {
+
+			argv[0] = str_rsync;
+			argv[1] = str_server;
+			argv[2] = str_flagssv;
+			argv[3] = str_delete;
+			argv[4] = str_dot;
+			argv[5] = path;
+			argv[6] = NULL;
+
+		} else {
+			fprintf(stderr, "invalid rsync mode: %d\n", mode);
+			exit(-1);
+		}
+
+		DBGfprintf(stderr, "%s: cmdline=[%s] [%s] [%s] [%s] [%s] [%s] [%s]\n",
+			__func__, argv[0], argv[1], argv[2], argv[3], argv[4],
+			argv[5], argv[6]);
+
+		if (mode == RSYNC_MODE_CLIENT) {
+			/* XXX protocol setup blocks if we don't wait ... */
+			sleep(1);
+		}
+
+		if ((execve(argv[0], argv, NULL))) {
+			fprintf(stderr, "execve(%s, ...) failed: %s\n",
+				argv[0], strerror(errno));
+			exit(-1);
+		}
+		/* Not reached. */
+		
+	} else {
+		const char *str;
+		char buf[0x100];
+		char found;
+		char *p;
+		int slen;
+		int rc;
+
+		str = "RSYNC FINISHED\n";
+		slen = strlen(str);
+		found = 0;
+
+		wait4(pid, &status, 0, NULL);
+
+		/*
+		 * There might be data left to read of the server side rsync,
+		 * like debug messages, so read everything until we have the
+		 * shell again.
+		 *
+		 * On the server side we send the message held in ''str''
+		 * to inform the client side that rsync is done.
+		 *
+		 * I know this isn't what can be considered as good style.
+		 */
+		if (mode == RSYNC_MODE_CLIENT) {
+			memset(buf, 0, sizeof(buf));
+			while (found == 0) {
+				/* I/O is still blocking here. */
+				rc = read(rfd, buf, sizeof(buf));
+				if (rc == -1 && errno != EAGAIN && errno != EINTR) {
+					fprintf(stderr, "%s: read error: %s\n",
+						__func__, strerror(errno));
+					return (-1);
+				}
+
+				for (p = buf; p < buf + sizeof(buf) - slen; p++) {
+					if (memcmp(p, str, slen) == 0) {
+						found = 1;
+						break;
+					}
+				}
+				usleep(10);
+			}
+
+		} else {
+			snprintf(buf, sizeof(buf), "%s", str);
+			write(wfd, buf, slen);
+		}
+
+		/* 
+		 * Rsync sets i/o channels to non blocking;
+		 * so revert to blocking mode.
+		 */
+		fcntl(rfd, F_SETFL, oflags_rfd);
+		fcntl(wfd, F_SETFL, oflags_wfd);
+
+		return (WIFEXITED(status) ? WEXITSTATUS(status) : -1);
+	}
+
+	/* Not reached. */
+	return (0);
+}
+
+/*
+ * If using vps interface, set routes and arp entries
+ * for each of clients addresses.
+ * XXX Do custom net_publish command if specified.
+ */
+int
+vc_net_publish(struct vps_conf *cf)
+{
+	struct netif_addr *ifaddrp;
+	struct netif_cf *netifp;
+	char cmd[0x100];
+	int i;
+
+	if (cf->netif == NULL)
+		return (0);
+
+	netifp = cf->netif;
+	do {
+		for (i = 0; i < netifp->ifaddr_cnt; i++) {
+			ifaddrp = netifp->ifaddr[i];
+
+			if (ifaddrp->af == AF_INET) {
+				snprintf(cmd, 0x100, "arp -s %s auto pub",
+						ifaddrp->str);
+				vc_exec_cmd(cmd, 1);
+				snprintf(cmd, 0x100, "route add -inet %s -iface %s",
+						ifaddrp->str, DEFAULT_VPSIF);
+				vc_exec_cmd(cmd, 1);
+			} else if (ifaddrp->af == AF_INET6) {
+				snprintf(cmd, 0x100, "route add -inet6 %s -iface %s -proto1",
+						ifaddrp->str, DEFAULT_VPSIF);
+				vc_exec_cmd(cmd, 1);
+			}
+		}
+	} while ((netifp = netifp->next));
+
+	return (0);
+}
+
+int
+vc_net_revoke(struct vps_conf *cf)
+{
+	struct netif_addr *ifaddrp;
+	struct netif_cf *netifp;
+	char cmd[0x100];
+	int i;
+
+	if (cf->netif == NULL)
+		return (0);
+
+	netifp = cf->netif;
+	do {
+		for (i = 0; i < netifp->ifaddr_cnt; i++) {
+			ifaddrp = netifp->ifaddr[i];
+
+			if (ifaddrp->af == AF_INET) {
+				snprintf(cmd, 0x100, "route del -inet %s -iface %s",
+						ifaddrp->str, DEFAULT_VPSIF);
+				vc_exec_cmd(cmd, 1);
+				snprintf(cmd, 0x100, "arp -d %s pub",
+						ifaddrp->str);
+				vc_exec_cmd(cmd, 1);
+			} else if (ifaddrp->af == AF_INET6) {
+				snprintf(cmd, 0x100, "route del -inet6 %s -iface %s -proto1",
+						ifaddrp->str, DEFAULT_VPSIF);
+				vc_exec_cmd(cmd, 1);
+			}
+		}
+	} while ((netifp = netifp->next));
+
+	return (0);
+}
+
+int
+vc_exec_cmd(char *cmd, int quiet)
+{
+	char str_sh[] = "/bin/sh";
+	char str_opt[] = "-c";
+	char *argv[] = { str_sh, str_opt, NULL, NULL };
+	int status = 0;
+	int pid;
+
+	if ( !quiet)
+		DBGfprintf(stdout, "%s: cmd: [%s]\n", __func__, cmd);
+
+	argv[2] = cmd;
+
+	if ((pid = fork()) == -1) {
+		fprintf(stderr, "%s: fork: %s\n",
+			__func__, strerror(errno));
+		return (-1);
+	}
+
+	if (pid == 0) {
+		if (quiet) {
+			int fd;
+
+			close(1);
+			close(2);
+			fd = open("/dev/null", O_RDWR);
+			if (fd != 1)
+			 	dup2(fd, 1);
+			if (fd != 2)
+				dup2(fd, 2);
+		}
+		if ((execve("/bin/sh", argv, vc_envv)) == -1) {
+			fprintf(stderr, "%s: execve: %s\n",
+				__func__, strerror(errno));
+			exit(-1);
+		}
+		/* NOTREACHED */
+	} else {
+		wait4(pid, &status, 0, NULL);
+	}
+	return (WIFEXITED(status) ? WEXITSTATUS(status) : -1);
+}
+
+int
+vc_read_config(char *file_n, struct vps_conf *vc)
+{
+	char linebuf[LINE_MAXLEN];
+	FILE *file_s;
+
+	memset(vc, 0, sizeof(struct vps_conf));
+	/* Set defaults where available. */
+	//strncpy(vc->initproc, "/sbin/init", MAXPATHLEN);
+
+	if ((file_s = fopen(file_n, "r")) == NULL) {
+		fprintf(stderr, "open file [%s]: %s\n",
+			file_n, strerror(errno));
+		return (-1);
+	}
+	while (fgets(linebuf, LINE_MAXLEN, file_s)) {
+		char *key, *val, *pos;
+
+		/* [whitespace]KEY[whitespace]=[whitespace]VALUE[whitespace]\n */
+		pos = linebuf;
+		key = strsep(&pos, "=");
+		val = strsep(&pos, "\n");
+		if ( ! (key && val && strlen(key) > 0 && strlen(val) > 0) )
+			continue;
+		key = vc_trim_whitespace(key);
+		val = vc_trim_whitespace(val);
+
+		if (key[0] == '#')
+			continue;
+
+		/* Fill in structure. */
+		if      (strcasecmp (key, "name") == 0)
+			strncpy(vc->name, val, MAXHOSTNAMELEN);
+
+		else if (strcasecmp(key, "fsroot") == 0)
+			strncpy(vc->fsroot, val, MAXPATHLEN);
+
+		else if (strcasecmp(key, "fsroot_priv") == 0)
+			strncpy(vc->fsroot_priv, val, MAXPATHLEN);
+
+		else if (strcasecmp(key, "init") == 0)
+			strncpy(vc->initproc, val, MAXPATHLEN);
+
+		else if (strcasecmp(key, "root_mount") == 0)
+			strncpy(vc->cmd_mountroot, val, MAXPATHLEN);
+
+		else if (strcasecmp(key, "root_unmount") == 0)
+			strncpy(vc->cmd_unmountroot, val, MAXPATHLEN);
+
+		else if (strcasecmp(key, "devfs_ruleset") == 0)
+			strncpy(vc->devfs_ruleset, val, DEFAULTLEN);
+
+		else if (strcasecmp(key, "network_announce") == 0)
+			strncpy(vc->network_announce, val, DEFAULTLEN);
+
+		else if (strcasecmp(key, "network_revoke") == 0)
+			strncpy(vc->network_revoke, val, DEFAULTLEN);
+
+		else if (strncasecmp(key, "netif_", 6) == 0) {
+			struct netif_cf *netifp, *netifp2;
+			char cmd[11];
+			char *c;
+			int idx;
+
+			c = key;
+			while (*c) {
+				*c = tolower(*c);
+				++c;
+			}
+
+			netifp = NULL;
+			if (sscanf(key, "netif_%d_%10s", &idx, cmd) == 2) {
+			
+				if ((netifp2 = vc->netif)) {
+					do {
+						if (netifp2->idx == idx)
+							netifp = netifp2;
+					} while ((netifp2 = netifp2->next));
+				}
+			} else
+				continue;
+
+			if (netifp == NULL) {
+				if ((netifp = malloc(sizeof(struct netif_cf))) == NULL) {
+					fprintf(stderr, "no memory !\n");
+					return (-1);
+				}
+				memset(netifp, 0, sizeof(*netifp));
+				netifp2 = vc->netif;
+				if (netifp2) {
+					while (netifp2->next)
+						netifp2 = netifp2->next;
+					netifp2->next = netifp;
+				} else
+					vc->netif = netifp;	
+				netifp->idx = idx;
+				netifp->ifidx = idx;
+
+			}
+
+			if (strcmp(cmd, "ifidx") == 0)
+				netifp->ifidx = atoi(val);
+
+			else if (strcmp(cmd, "address") == 0) {
+				char **ap, *argv[10], *addrstr, *input;
+				struct netif_addr *addrp;
+
+				addrstr = strdup(val);
+				input = addrstr;
+				for (ap = argv; (*ap = strsep(&input, " ,")) != NULL;) {
+
+					if (**ap == '\0')
+						continue;
+
+					//fprintf(stderr, "address=[%s]\n", *ap);
+
+					addrp = calloc(1, sizeof(*addrp));
+
+					addrp->str = strdup(*ap);
+					netifp->ifaddr[netifp->ifaddr_cnt] = addrp;
+					netifp->ifaddr_cnt++;
+
+					if ((inet_pton(AF_INET, *ap, &addrp->addr.in)) == 1) {
+						/*
+						fprintf(stderr, "in.s_addr=0x%08x\n",
+						    addrp->addr.in.s_addr);
+						*/
+						addrp->af = AF_INET;
+
+					} else if ((inet_pton(AF_INET6, *ap, &addrp->addr.in6))
+					    == 1) {
+						/*
+						fprintf(stderr, "in6.s6_addr: "
+						    "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
+						    "%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
+						    in6.s6_addr[0], in6.s6_addr[1], in6.s6_addr[2],
+						    in6.s6_addr[3], in6.s6_addr[4], in6.s6_addr[5],
+						    in6.s6_addr[6], in6.s6_addr[7], in6.s6_addr[8],
+						    in6.s6_addr[9], in6.s6_addr[10],
+						    in6.s6_addr[11], in6.s6_addr[12],
+						    in6.s6_addr[13], in6.s6_addr[14],
+						    in6.s6_addr[15]);
+						*/
+						addrp->af = AF_INET6;
+
+					} else {
+						fprintf(stderr, "could not parse address [%s]\n",
+						    *ap);
+						netifp->ifaddr[netifp->ifaddr_cnt] = NULL;
+						netifp->ifaddr_cnt--;
+						free(addrp);
+					}
+
+					if (++ap >= &argv[10])
+						break;
+				}
+				
+				free(addrstr);
+			}
+
+		}
+
+		else if (strncasecmp(key, "epair_", 6) == 0) {
+			struct epair_cf *epp, *epp2;
+			char cmd[11];
+			char *c;
+			int idx;
+
+			c = key;
+			while (*c) {
+				*c = tolower(*c);
+				++c;
+			}
+
+			epp = NULL;
+			if (sscanf(key, "epair_%d_%10s", &idx, cmd) == 2) {
+				if ((epp2 = vc->epair)) {
+					do {
+						if (epp2->idx == idx)
+							epp = epp2;
+					} while ((epp2 = epp2->next));
+				}
+			} else
+				continue;
+
+			if (epp == NULL) {
+				if ((epp = malloc(sizeof(struct epair_cf))) == NULL) {
+					fprintf(stderr, "no memory !\n");
+					return (-1);
+				}
+				memset(epp, 0, sizeof(struct epair_cf));
+				epp2 = vc->epair;
+				if (epp2) {
+					while (epp2->next)
+						epp2 = epp2->next;
+					epp2->next = epp;
+				} else
+					vc->epair = epp;
+				epp->idx = idx;
+			}
+			if (strcmp(cmd, "ifidx") == 0)
+				epp->ifidx = atoi(val);
+			else if (strcmp(cmd, "ifconfig") == 0)
+				epp->ifconfig = strdup(val);
+		}
+
+		else if (strncasecmp(key, "ip_networks", 13) == 0) {
+			/*
+			 * XXX redundant, share with vc_arg_ipnet()
+			 */
+			char **ap, *argv[10], *addrstr, *input, *straddr, *strmask, *strtmp, *sep;
+			struct ip_network *netp;
+
+			addrstr = strdup(val);
+			input = addrstr;
+			for (ap = argv; (*ap = strsep(&input, " ,")) != NULL;) {
+
+				if (**ap == '\0')
+					continue;
+
+				strtmp = strdup(*ap);
+				sep = strstr(strtmp, "/");
+				if (sep == NULL) {
+					free(strtmp);
+					break;
+				}
+				straddr = strtmp;
+				*sep = '\0';
+				strmask = sep+1;
+
+				netp = calloc(1, sizeof(*netp));
+
+				netp->str = strdup(*ap);
+				vc->ip_networks[vc->ip_networks_cnt++] = netp;
+
+				if ( (inet_pton(AF_INET, straddr, &netp->addr.in) == 1) &&
+				     (inet_pton(AF_INET, strmask, &netp->mask.in) == 1) ) {
+					/*
+					fprintf(stderr, "in.s_addr=0x%08x\n",
+					    netp->addr.in.s_addr);
+					*/
+					netp->af = AF_INET;
+
+				} else if ( (inet_pton(AF_INET6, straddr, &netp->addr.in6) == 1) &&
+		 		    (sscanf(strmask, "%hhu", &netp->mask.in6) == 1) ) {
+					/*
+					fprintf(stderr, "in6.s6_addr: %02x%02x:%02x%02x:%02x%02x:"
+						"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
+						in6.s6_addr[0], in6.s6_addr[1], in6.s6_addr[2],
+						in6.s6_addr[3], in6.s6_addr[4], in6.s6_addr[5],
+						in6.s6_addr[6], in6.s6_addr[7], in6.s6_addr[8],
+						in6.s6_addr[9], in6.s6_addr[10], in6.s6_addr[11],
+						in6.s6_addr[12], in6.s6_addr[13], in6.s6_addr[14],
+						in6.s6_addr[15]);
+					*/
+					netp->af = AF_INET6;
+
+				} else {
+					fprintf(stderr, "could not parse address [%s]\n", *ap);
+					vc->ip_networks[--vc->ip_networks_cnt] = NULL;
+					free(netp);
+				}
+
+				free(strtmp);
+
+				if (++ap >= &argv[10])
+					break;
+			}
+				
+			free(addrstr);
+		}
+
+		else if (strncasecmp(key, "priv_allow", 11) == 0) {
+			if (vc->priv_allow != NULL) {
+				fprintf(stderr, "redundant PRIV_ALLOW line, ignoring.\n");
+				break;
+			}
+			vc->priv_allow = strdup(val);
+		}
+
+		else if (strncasecmp(key, "priv_nosys", 11) == 0) {
+			if (vc->priv_nosys != NULL) {
+				fprintf(stderr, "redundant PRIV_NOSYS line, ignoring.\n");
+				break;
+			}
+			vc->priv_nosys = strdup(val);
+		}
+
+		else if (strncasecmp(key, "limits", 7) == 0) {
+			if (vc->limits != NULL) {
+				fprintf(stderr, "redundant LIMITS line, ignoring.\n");
+				break;
+			}
+			vc->limits = strdup(val);
+		}
+		else {
+			fprintf(stderr, "unknown key [%s], ignoring.\n", key);
+		}
+
+		/* fprintf(stdout, "conf: key=[%s] val=[%s]\n", key, val); */
+	}
+	fclose(file_s);
+
+	/* Check if config is complete. */
+	if (vc->name[0] == '\0') {
+		fprintf(stderr, "missing parameter NAME in config\n");
+		return (-1);
+	}
+	if (vc->fsroot[0] == '\0') {
+		fprintf(stderr, "missing parameter FSROOT in config\n");
+		return (-1);
+	}
+
+	return (0);
+}
+
+char *
+vc_trim_whitespace(char *s)
+{
+	char *r, *p;
+
+	p = s - 1;
+	r = s;
+	if (s == NULL)
+		return (NULL);
+	while (*++p && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r'))
+		r = p + 1;
+	if (*r == '\'' && *r++)
+		while (*++p && *p != '\'' && *p != '\n' && *p != '\r');
+	if (*r == '"' && *r++)
+		while (*++p && *p != '"' && *p != '\n' && *p != '\r');
+	if (*p == '\'' || *p == '"')
+		*p = 0;
+	while (*++p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r');
+	*p = 0;
+	return (r);
+}
+
+int
+vc_allow_ip4net(const char *vpsname, in_addr_t addr, in_addr_t mask)
+{
+	struct vps_arg_set vas;
+	struct vps_arg_item item;
+
+	memset(&vas, 0, sizeof(vas));
+	memset(&item, 0, sizeof(item));
+	snprintf(vas.vps_name, sizeof(vas.vps_name), "%s", vpsname);
+	vas.data = (void*)&item;
+	vas.datalen = sizeof(item);
+	item.type = VPS_ARG_ITEM_IP4;
+	item.u.ip4.addr.s_addr = addr;
+	item.u.ip4.mask.s_addr = mask;
+
+	DBGfprintf(stdout, "%s: addr=%08x mask=%08x\n", __func__, addr, mask);
+
+	if ((ioctl(vpsfd, VPS_IOC_ARGSET, &vas)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_ARGSET: %s\n", strerror(errno));
+		return (-1);
+	}
+
+	return (0);
+}
+
+int
+vc_allow_ip6net(const char *vpsname, struct in6_addr *addr, u_int8_t *plen)
+{
+	struct vps_arg_set vas;
+	struct vps_arg_item item;
+
+	memset(&vas, 0, sizeof(vas));
+	memset(&item, 0, sizeof(item));
+	snprintf(vas.vps_name, sizeof(vas.vps_name), "%s", vpsname);
+	vas.data = (void*)&item;
+	vas.datalen = sizeof (item);
+	item.type = VPS_ARG_ITEM_IP6;
+	memcpy(&item.u.ip6.addr, addr, sizeof(*addr));
+	memcpy(&item.u.ip6.plen, plen, sizeof(*plen));
+
+	if ((ioctl(vpsfd, VPS_IOC_ARGSET, &vas)) == -1) {
+		fprintf (stderr, "ioctl VPS_IOC_ARGSET: %s\n", strerror(errno));
+		return (-1);
+	}
+
+	return (0);
+}
+
+int
+vc_show(int argc, char **argv)
+{
+	struct vps_getextinfo vgx;
+	struct vps_extinfo *xinfo;
+	caddr_t data;
+	int datalen;
+
+	if (argc < 1)
+		return (vc_usage(stderr));
+
+	datalen = sizeof(*xinfo);
+	data = malloc(datalen);
+	memset(&vgx, 0, sizeof(vgx));
+	memset(data, 0, datalen);
+	snprintf(vgx.vps_name, sizeof(vgx.vps_name), "%s", argv[0]);
+	vgx.data = data;
+	vgx.datalen = datalen;
+
+	if ((ioctl(vpsfd, VPS_IOC_GETXINFO, &vgx)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_GETXINFO: %s\n",
+			strerror(errno));
+		free(data);
+		return (-1);
+	}
+
+	xinfo = (struct vps_extinfo *)vgx.data;
+
+	fprintf(stdout, "Name:          %-20s\n", xinfo->name);
+	fprintf(stdout, "Status:        %-20s\n", vc_statusstr(xinfo->status));
+	fprintf(stdout, "VFS root:      %-20s\n", xinfo->fsroot);
+	fprintf(stdout, "Processes:     %8d\n", xinfo->nprocs);
+	fprintf(stdout, "Sockets:       %8d\n", xinfo->nsocks);
+	fprintf(stdout, "Interfaces:    %8d\n", xinfo->nifaces);
+	fprintf(stdout, "Restore count: %8d\n", xinfo->restore_count);
+
+	free(data);
+
+	return (0);
+}
+
+int
+vc_arg_show(int argc, char **argv)
+{
+	struct vps_arg_get vag;
+	struct vps_arg_item *item;
+	caddr_t data;
+	char *start_allow, *pos_allow;
+	char *start_nosys, *pos_nosys;
+	const char *resstr;
+	char event;
+	int datalen;
+
+	if (argc < 1)
+		return (vc_usage(stderr));
+
+	datalen = 0x100000;
+	data = malloc(datalen);
+	memset(&vag, 0, sizeof(vag));
+	memset(data, 0, datalen);
+	snprintf(vag.vps_name, sizeof(vag.vps_name), "%s", argv[0]);
+	vag.data = data;
+	vag.datalen = datalen;
+
+	if ((ioctl(vpsfd, VPS_IOC_ARGGET, &vag)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_ARGGET: %s\n",
+			strerror(errno));
+		free(data);
+		return (-1);
+	}
+
+	for (item = (struct vps_arg_item *)vag.data;
+		(caddr_t)item < ((caddr_t)vag.data) + vag.datalen;
+		item++) {
+
+		char addr[0x20], mask[0x20];
+
+		if (item->type != VPS_ARG_ITEM_IP4)
+			continue;
+
+		inet_ntop(AF_INET, &item->u.ip4.addr, addr, 0x20);
+		inet_ntop(AF_INET, &item->u.ip4.mask, mask, 0x20);
+
+		fprintf(stdout, "IPv4 Networks: \n%s/%s\n", addr, mask);
+	}
+	for (item = (struct vps_arg_item *)vag.data;
+		(caddr_t)item < ((caddr_t)vag.data) + vag.datalen;
+		item++) {
+
+		char addr[0x80];
+
+		if (item->type != VPS_ARG_ITEM_IP6)
+			continue;
+
+		inet_ntop(AF_INET6, &item->u.ip6.addr, addr, 0x80);
+
+		fprintf(stdout, "\nIPv6 Networks: \n%s/%hhu\n", addr, item->u.ip6.plen);
+	}
+
+	pos_allow = start_allow = malloc (0x1000);
+	pos_nosys = start_nosys = malloc (0x1000);
+
+	for (item = (struct vps_arg_item *)vag.data;
+		(caddr_t)item < ((caddr_t)vag.data) + vag.datalen;
+		item++) {
+		if (item->type != VPS_ARG_ITEM_PRIV)
+			continue;
+
+		switch (item->u.priv.value) {
+		case VPS_ARG_PRIV_ALLOW:
+			pos_allow += snprintf(pos_allow, 0x1000 - (pos_allow - start_allow),
+						"%s, ", priv_ntos(item->u.priv.priv));
+			break;
+		/*
+		case VPS_ARG_PRIV_DENY:
+			break;
+		*/
+		case VPS_ARG_PRIV_NOSYS:
+			pos_nosys += snprintf(pos_nosys, 0x1000 - (pos_nosys - start_nosys),
+						"%s, ", priv_ntos(item->u.priv.priv));
+			break;
+		default:
+			break;
+		}
+	}
+
+	start_allow[pos_allow - start_allow - 2] = '\0';
+	start_nosys[pos_nosys - start_nosys - 2] = '\0';
+	fprintf(stdout, "\nALLOW privileges: \n%s\n", start_allow);
+	fprintf(stdout, "\nNOSYS privileges: \n%s\n", start_nosys);
+	free(start_allow);
+	free(start_nosys);
+
+	fprintf(stdout, "\n%-10s %1s %12s %12s %12s %12s %12s\n",
+		"Resource", "S", "Current", "Soft Limit", "Hard Limit", "Soft Hits", "Hard Hits"); 
+
+	for (item = (struct vps_arg_item *)vag.data;
+		(caddr_t)item < ((caddr_t)vag.data) + vag.datalen;
+		item++) {
+		if (item->type != VPS_ARG_ITEM_LIMIT)
+			continue;
+
+		switch (item->u.limit.resource) {
+		case VPS_ACC_VIRT:
+			resstr = "virt";
+			break;
+		case VPS_ACC_PHYS:
+			resstr = "phys";
+			break;
+		case VPS_ACC_KMEM:
+			resstr = "kmem";
+			break;
+		case VPS_ACC_KERNEL:
+			resstr = "kernel";
+			break;
+		case VPS_ACC_BUFFER:
+			resstr = "buffer";
+			break;
+		case VPS_ACC_PCTCPU:
+			resstr = "pctcpu";
+			break;
+		case VPS_ACC_BLOCKIO:
+			resstr = "blockio";
+			break;
+		case VPS_ACC_THREADS:
+			resstr = "threads";
+			break;
+		case VPS_ACC_PROCS:
+			resstr = "procs";
+			break;
+		default:
+			resstr = "unknown";
+			break;
+		}
+
+		if (item->u.limit.cur > item->u.limit.soft)
+			event = 'C';
+		else
+		if (item->u.limit.hits_soft != 0 && item->u.limit.hits_hard == 0)
+			event = 'x';
+		else
+		if (item->u.limit.hits_hard != 0)
+			event = 'X';
+		else
+			event = '_';
+		if (item->u.limit.soft == 0 && item->u.limit.hard == 0)
+			event = '_';
+
+		fprintf(stdout, "%-10s %c %12zu %12zu %12zu %12u %12u\n",
+			resstr, event, item->u.limit.cur, item->u.limit.soft, item->u.limit.hard,
+			item->u.limit.hits_soft, item->u.limit.hits_hard);
+	}
+
+	free(data);
+	return (0);
+}
+
+int
+vc_arg_ipnet(int argc, char **argv)
+{
+	struct vps_arg_set vas;
+	struct vps_arg_item *item;
+	char **ap, *argv2[0x100], *input, *sep;
+	char *strtmp, *straddr;
+	const char *strmask;
+	int cmd;
+
+	if (argc < 3)
+		return (vc_usage(stderr));
+
+	if (strcmp(argv[1], "add") == 0)
+		cmd = 0;
+	else
+	if (strcmp(argv[1], "rem") == 0)
+		cmd = 1;
+	else
+		return (vc_usage(stderr));
+
+	vas.datalen = sizeof(*item) * 0x100;
+	vas.data = malloc(vas.datalen);
+	memset(vas.data, 0, vas.datalen);
+	item = (struct vps_arg_item *)vas.data;
+	if (vas.data == NULL) {
+		fprintf(stderr, "%s: malloc: %s\n", __func__, strerror(errno));
+		return (-1);
+	}
+	input = strdup(argv[2]);
+	for (ap = argv2; (*ap = strsep(&input, " ,")) != NULL;)
+		if (**ap != '\0') {
+
+			strtmp = straddr = strdup(*ap);
+			sep = strstr(strtmp, "/");
+			if (sep == NULL) {
+				strmask = "255.255.255.255";
+			} else {
+				*sep = '\0';
+				strmask = sep+1;
+			}
+
+			if ( (inet_pton(AF_INET, straddr, &item->u.ip4.addr) == 1) &&
+				 (inet_pton(AF_INET, strmask, &item->u.ip4.mask) == 1) )
+					item->type = VPS_ARG_ITEM_IP4;
+			else
+			if ( (inet_pton(AF_INET6, straddr, &item->u.ip6.addr) == 1) &&
+				 /*(inet_pton(AF_INET6, strmask, &item->u.ip6.mask) == 1) )*/
+				 (sscanf(strmask, "%hhu", &item->u.ip6.plen) == 1) )
+					item->type = VPS_ARG_ITEM_IP6;
+			else {
+				fprintf(stderr, "could not parse address [%s]\n", *ap);
+				free(strtmp);
+				free(input);
+				free(vas.data);
+				return (-1);
+			}
+			item->revoke = cmd;
+
+			/*
+			fprintf(stderr, "%s: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x / %u\n",
+			    __func__,
+			    htons(item->u.ip6.addr.s6_addr16[0]),
+			    htons(item->u.ip6.addr.s6_addr16[1]), 
+			    htons(item->u.ip6.addr.s6_addr16[2]),
+			    htons(item->u.ip6.addr.s6_addr16[3]), 
+			    htons(item->u.ip6.addr.s6_addr16[4]),
+			    htons(item->u.ip6.addr.s6_addr16[5]), 
+			    htons(item->u.ip6.addr.s6_addr16[6]),
+			    htons(item->u.ip6.addr.s6_addr16[7]), 
+			    item->u.ip6.plen);
+			*/
+
+			++item;
+			if (++ap >= &argv2[0x100])
+				break;
+		}
+	free(input);
+
+	strncpy(vas.vps_name, argv[0], sizeof(vas.vps_name));
+	vas.datalen = ((caddr_t)item) - (caddr_t)vas.data;
+	if ((ioctl(vpsfd, VPS_IOC_ARGSET, &vas)) == -1) {
+		fprintf (stderr, "ioctl VPS_IOC_ARGSET: %s\n",
+			strerror(errno));
+		return (-1);
+	}
+
+	return (0);
+}
+
+int
+vc_arg_priv(int argc, char **argv)
+{
+	struct vps_arg_set vas;
+	struct vps_arg_item *item;
+	char **ap, *argv2[0x100], *input;
+	int cmd;
+
+	if (argc < 3)
+		return (vc_usage(stderr));
+
+	if (strcmp(argv[1], "allow") == 0)
+		cmd = VPS_ARG_PRIV_ALLOW;
+	else
+	if (strcmp(argv[1], "deny") == 0)
+		cmd = VPS_ARG_PRIV_DENY;
+	else
+	if (strcmp(argv[1], "nosys") == 0)
+		cmd = VPS_ARG_PRIV_NOSYS;
+	else
+		return (vc_usage(stderr));
+
+	vas.datalen = sizeof(*item) * 0x100;
+	vas.data = malloc(vas.datalen);
+	memset(vas.data, 0, vas.datalen);
+	item = (struct vps_arg_item *)vas.data;
+	if (vas.data == NULL) {
+		fprintf(stderr, "%s: malloc: %s\n", __func__, strerror(errno));
+		return (-1);
+	}
+	input = strdup(argv[2]);
+	for (ap = argv2; (*ap = strsep(&input, " ,")) != NULL;)
+		if (**ap != '\0') {
+
+			item->type = VPS_ARG_ITEM_PRIV;
+			item->u.priv.value = cmd;
+			if ((item->u.priv.priv = priv_ston(*ap)) == 0)
+				item->u.priv.priv = atoi(*ap);
+			if (item->u.priv.priv < _PRIV_LOWEST || item->u.priv.priv > _PRIV_HIGHEST) {
+				fprintf(stderr, "%s: invalid privilege %d [%s]\n",
+					__func__, item->u.priv.priv, *ap);
+				free(vas.data);
+				free(input);
+				return (-1);
+			}
+
+			++item;
+			if (++ap >= &argv2[0x100])
+				break;
+		}
+	free(input);
+
+	strncpy(vas.vps_name, argv[0], sizeof(vas.vps_name));
+	vas.datalen = ((caddr_t)item) - (caddr_t)vas.data;
+	if ((ioctl(vpsfd, VPS_IOC_ARGSET, &vas)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_ARGSET: %s\n",
+			strerror(errno));
+		return (-1);
+	}
+
+	return (0);
+}
+
+int
+vc_arg_limit(int argc, char **argv)
+{
+	struct vps_arg_set vas;
+	struct vps_arg_item *item;
+	char **ap, *argv2[0x100], *input, resstr[0x100];
+
+	/* "vpsctl limit vps192 virt:100:200,phys:50:100" */
+
+	if (argc < 2)
+		return (vc_usage(stderr));
+
+	vas.datalen = sizeof(*item) * 0x100;
+	vas.data = malloc(vas.datalen);
+	memset(vas.data, 0, vas.datalen);
+	item = (struct vps_arg_item *)vas.data;
+	if (vas.data == NULL) {
+		fprintf(stderr, "%s: malloc: %s\n", __func__, strerror(errno));
+		return (-1);
+	}
+	input = strdup(argv[1]);
+	for (ap = argv2; (*ap = strsep(&input, " ,")) != NULL;)
+		if (**ap != '\0') {
+
+			item->type = VPS_ARG_ITEM_LIMIT;
+
+			if ((strlen(*ap) > 0x100) ||
+			    (sscanf(*ap, "%[^:]:%zu:%zu", resstr,
+			     &item->u.limit.soft, &item->u.limit.hard) != 3)) {
+				fprintf(stderr, "%s: invalid argument [%s]\n",
+					__func__, *ap);
+				free(vas.data);
+				free(input);
+				return (-1);
+			}
+
+			if      (strcmp(resstr, "virt") == 0)
+				item->u.limit.resource = VPS_ACC_VIRT;
+			else if (strcmp(resstr, "phys") == 0)
+				item->u.limit.resource = VPS_ACC_PHYS;
+			/*
+			else if (strcmp(resstr, "kmem") == 0)
+				item->u.limit.resource = VPS_ACC_KMEM;
+			else if (strcmp(resstr, "kernel") == 0)
+				item->u.limit.resource = VPS_ACC_KERNEL;
+			else if (strcmp(resstr, "buffer") == 0)
+				item->u.limit.resource = VPS_ACC_BUFFER;
+			*/
+			else if (strcmp(resstr, "pctcpu") == 0)
+				item->u.limit.resource = VPS_ACC_PCTCPU;
+			else if (strcmp(resstr, "blockio") == 0)
+				item->u.limit.resource = VPS_ACC_BLOCKIO;
+			else if (strcmp(resstr, "threads") == 0)
+				item->u.limit.resource = VPS_ACC_THREADS;
+			else if (strcmp(resstr, "procs") == 0)
+				item->u.limit.resource = VPS_ACC_PROCS;
+			else {
+				fprintf(stderr, "%s: invalid resource [%s]\n",
+					__func__, resstr);
+				free(vas.data);
+				free(input);
+				return (-1);
+			}
+
+			++item;
+			if (++ap >= &argv2[0x100])
+				break;
+		}
+	free(input);
+
+	strncpy(vas.vps_name, argv[0], sizeof(vas.vps_name));
+	vas.datalen = ((caddr_t)item) - (caddr_t)vas.data;
+	if ((ioctl(vpsfd, VPS_IOC_ARGSET, &vas)) == -1) {
+		fprintf (stderr, "ioctl VPS_IOC_ARGSET: %s\n",
+			strerror(errno));
+		return (errno);
+	}
+
+	return (0);
+}
+
+static int
+vc_argtest_getall(int argc, char **argv)
+{
+	struct vps_arg_get vag;
+	struct vps_arg_item *item;
+	caddr_t data;
+	int datalen;
+
+	if (argc < 1)
+		return (vc_usage(stderr));
+
+	datalen = 0x100000;
+	data = malloc(datalen);
+	memset(&vag, 0, sizeof(vag));
+	memset(data, 0, datalen);
+
+	vag.data = data;
+	vag.datalen = datalen;
+	snprintf(vag.vps_name, sizeof(vag.vps_name), "%s", argv[0]);
+
+	printf("vag.data=%p vag.datalen=%zu\n", vag.data, vag.datalen);
+	if ((ioctl(vpsfd, VPS_IOC_ARGGET, &vag)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_ARGGET: %s\n",
+			strerror(errno));
+		return (errno);
+	}
+
+	fprintf(stdout, "ioctl VPS_IOC_ARGGET: got %zu bytes\n", vag.datalen);
+
+	for (item = (struct vps_arg_item *)vag.data;
+		(caddr_t)item < ((caddr_t)vag.data) + vag.datalen;
+		item++) {
+
+		switch (item->type) {
+		case VPS_ARG_ITEM_PRIV:
+			fprintf(stdout, "item: type=priv priv=%d value=%d\n",
+				item->u.priv.priv, item->u.priv.value);
+			break;
+		case VPS_ARG_ITEM_IP4:
+			fprintf(stdout, "item: type=ip4 addr=%08x mask=%08x\n",
+				item->u.ip4.addr.s_addr, item->u.ip4.mask.s_addr);
+			break;
+		/*
+		case VPS_ARG_ITEM_IP6:
+			fprintf(stdout, "item: type=priv priv=%d value=%d\n",
+				item->u.priv.priv, item->u.priv.value);
+			break;
+		*/
+		case VPS_ARG_ITEM_LIMIT:
+			fprintf(stdout, "item: type=limit resource=%u soft=%zu hard=%zu\n",
+				item->u.limit.resource, item->u.limit.soft, item->u.limit.hard);
+			break;
+		default:
+			fprintf(stdout, "unknown item type %d\n", item->type);
+			break;
+		}
+	}
+	fprintf(stdout, "---------------------------");
+
+	return (0);
+}
+
+int
+vc_argtest(int argc, char **argv)
+{
+	struct vps_arg_set vas;
+	struct vps_arg_item *item;
+	void *data;
+	int datalen;
+
+	if (argc < 1)
+		return (vc_usage(stderr));
+
+	vc_argtest_getall (argc, argv);
+
+	datalen = 0x10000;
+	data = malloc(datalen);
+	memset(&vas, 0, sizeof(vas));
+	memset(data, 0, datalen);
+
+	vas.data = data;
+	vas.datalen = datalen;
+	snprintf(vas.vps_name, sizeof(vas.vps_name), "%s", argv[0]);
+
+	item = (struct vps_arg_item *)data;
+	item->type = VPS_ARG_ITEM_IP4;
+	item->u.ip4.addr.s_addr = inet_addr("78.142.178.192");
+	item->u.ip4.mask.s_addr = inet_addr("255.255.255.255");
+	item++;
+	item->type = VPS_ARG_ITEM_IP4;
+	item->u.ip4.addr.s_addr = inet_addr("192.168.0.0");
+	item->u.ip4.mask.s_addr = inet_addr("255.255.0.0");
+	item++;
+	item->type = VPS_ARG_ITEM_PRIV;
+	item->u.priv.priv = 123;
+	item->u.priv.value = VPS_ARG_PRIV_ALLOW;
+	item++;
+	vas.datalen = ((caddr_t)item) - (caddr_t)data;
+	printf("vas.data=%p vas.datalen=%zu\n", vas.data, vas.datalen);
+	if ((ioctl(vpsfd, VPS_IOC_ARGSET, &vas)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_ARGSET: %s\n",
+			strerror(errno));
+		return (-1);
+	}
+	vc_argtest_getall(argc, argv);
+
+	item = (struct vps_arg_item *)data;
+	item->type = VPS_ARG_ITEM_IP4;
+	item->revoke = 1;
+	item->u.ip4.addr.s_addr = inet_addr ("78.142.178.192");
+	item->u.ip4.mask.s_addr = inet_addr ("255.255.255.255");
+	item++;
+	vas.datalen = ((caddr_t)item) - (caddr_t)data;
+	printf("vas.data=%p vas.datalen=%zu\n", vas.data, vas.datalen);
+	if ((ioctl(vpsfd, VPS_IOC_ARGSET, &vas)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_ARGSET: %s\n",
+			strerror(errno));
+		return (-1);
+	}
+	vc_argtest_getall(argc, argv);
+
+	return (0);
+}
+
+int
+vc_quota_recalc(int argc, char **argv)
+{
+	struct vps_arg_item *items;
+	struct vps_arg_get va;
+	size_t datalen;
+	caddr_t data;
+
+	if (argc < 1)
+		return (vc_usage(stderr));
+
+	datalen = 0x10000;
+	data = malloc(datalen);
+	memset(&va, 0, sizeof(va));
+	memset(data, 0, datalen);
+
+	va.data = data;
+	va.datalen = datalen;
+	snprintf(va.vps_name, sizeof(va.vps_name), "%s", argv[0]);
+
+	if ((ioctl(vpsfd, VPS_IOC_FSCALCPATH, &va)) == -1) {
+		fprintf(stderr, "ioctl VPS_IOC_FSCALCPATH: %s\n",
+			strerror(errno));
+		return (errno);
+	}
+
+	items = (struct vps_arg_item *)va.data;
+	printf("usage for vpsfs on [%s]: blocks_used=%zu nodes_used=%zu\n",
+		va.vps_name, items[0].u.limit.cur, items[1].u.limit.cur);
+
+	free(data);
+
+	return (0);
+}
+
+int
+vc_showdump(int argc, char **argv)
+{
+	struct vps_snapst_ctx *ctx;
+	struct stat sb;
+	int size, fd;
+	void *p;
+
+	if (argc < 1) {
+		fprintf(stderr, "no path given\n");
+		return (vc_usage(stderr));
+	}
+
+	if ((fd = open(argv[0], O_RDONLY)) == -1) {
+		fprintf(stderr, "open [%s]: %s\n",
+			argv[0], strerror(errno));
+		return (errno);
+	}
+	if ((fstat(fd, &sb)) == -1) {
+		fprintf(stderr, "fstat: %s\n",
+			strerror(errno));
+		return (errno);
+	}
+	size = sb.st_size;
+
+	if ((p = mmap(NULL, size, PROT_READ|PROT_WRITE,
+		      MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+		fprintf(stderr, "mmap: %s\n",
+			strerror(errno));
+		return (errno);
+	}
+
+	ctx = malloc(sizeof(*ctx));
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->data = p;
+	ctx->dsize = size;
+	ctx->rootobj = (struct vps_dumpobj *)(void *)(((caddr_t)ctx->data) +
+			sizeof(struct vps_dumpheader));
+	ctx->relative = 1;
+	ctx->elements = -1;
+
+	vps_libdump_printheader(p);
+	if (vps_dumpobj_printtree(ctx))
+		printf("%s: tree is invalid !\n", __func__);
+	else
+		printf("%s: tree is good !\n", __func__);
+
+	free(ctx);
+	munmap(p, size);
+	close(fd);
+
+	return (0);
+}
+
+
+static int
+vc_ttyloop(int ptsmfd, const char *esc_pattern)
+{
+	struct termios tios;
+	char buf_last[0x100];
+	char buf[0x10000];
+	int buf_last_len;
+	fd_set rfds;
+	int rlen;
+	int wlen;
+	int flags;
+	int rc;
+
+	tcgetattr(0, &tios);
+	cfmakeraw(&tios);
+	tcsetattr(0, TCSADRAIN, &tios);
+
+	flags = fcntl(ptsmfd, F_GETFL);
+	flags |= O_NONBLOCK;
+	fcntl(ptsmfd, F_SETFL, flags);
+
+	flags = fcntl(0, F_GETFL);
+	flags |= O_NONBLOCK;
+	fcntl(0, F_SETFL, flags);
+
+	memset(buf_last, 0, sizeof(buf_last));
+	buf_last_len = 0;
+
+	for (;;) {
+
+		FD_ZERO(&rfds);
+		FD_SET(ptsmfd, &rfds);
+		FD_SET(0, &rfds);
+		if ((select(ptsmfd+1, &rfds, NULL, NULL, NULL)) == -1) {
+			fprintf(stderr, "select(): %s\n", strerror(errno));
+			exit(-1);
+		}
+
+		if (FD_ISSET(ptsmfd, &rfds)) {
+
+			rlen = read(ptsmfd, buf, sizeof(buf));
+			if (rlen == 0) {
+				return (0);
+			} else if (rlen == -1) {
+				if (errno == EINTR || errno == EAGAIN) {
+					continue;
+				} else {
+					fprintf(stderr, "read(): %s\n", strerror(errno));
+					return (-1);
+				}
+			}
+
+			wlen = 0;
+			while (wlen < rlen) {
+				rc = write(1, buf+wlen, rlen-wlen);
+				if (rc == -1) {
+					if (errno == EINTR || errno == EAGAIN) {
+						rc = 0;
+					} else {
+						fprintf(stderr, "write(): %s\n", strerror(errno));
+						return (-1);
+					}
+				}
+				wlen += rc;
+			}
+		}
+
+		if (FD_ISSET(0, &rfds)) {
+
+			rlen = read(0, buf, sizeof(buf));
+			if (rlen == 0) {
+				return (0);
+			} else if (rlen == -1) {
+				if (errno == EINTR || errno == EAGAIN) {
+					continue;
+				} else {
+					fprintf(stderr, "read(): %s\n", strerror(errno));
+					return (-1);
+				}
+			}
+
+			if (esc_pattern != NULL) {
+				int llen;
+
+				assert(strlen(esc_pattern) < sizeof(buf_last));
+
+				if (rlen > (int)sizeof(buf_last) - 1)
+					llen = sizeof(buf_last) - 1;
+				else
+					llen = rlen;
+
+				if (llen > (int)strlen(esc_pattern))
+					buf_last_len = 0;
+
+				if (buf_last_len > 0x10) {
+					memmove(buf_last, buf_last + llen, buf_last_len);
+					buf_last_len -= llen;
+				}
+				memcpy(buf_last + buf_last_len, buf + rlen - llen, llen);
+				buf_last_len += llen;
+				buf_last[buf_last_len] = 0;
+
+				/*
+				fprintf(stderr,
+				    "esc_pattern=[%02x %02x %02x %02x %02x %02x %02x %02x]\n",
+				    esc_pattern[0], esc_pattern[1], esc_pattern[2], esc_pattern[3],
+				    esc_pattern[4], esc_pattern[5], esc_pattern[6], esc_pattern[7]);
+				fprintf(stderr,
+				    "buf_last=[%02x %02x %02x %02x %02x %02x %02x %02x]\n",
+				    buf_last[0], buf_last[1], buf_last[2], buf_last[3],
+				    buf_last[4], buf_last[5], buf_last[6], buf_last[7]);
+				*/
+
+				if (strstr(buf_last, esc_pattern) != NULL) {
+					/* fprintf(stderr, "matched escape pattern!\n"); */
+					return (0);
+				}
+			}
+
+			wlen = 0;
+			while (wlen < rlen) {
+				rc = write(ptsmfd, buf+wlen, rlen-wlen);
+				if (rc == -1) {
+					if (errno == EINTR || errno == EAGAIN) {
+						rc = 0;
+					} else {
+						fprintf(stderr, "write(): %s\n", strerror(errno));
+						return (-1);
+					}
+				}
+				wlen += rc;
+			}
+		}
+
+	} /* for() */
+
+	return (rc);
+}
+
+/* EOF */
diff -Naupr -x .svn -x 'rsync_vps.*' -I '$Id.*$' -I '$FreeBSD.*$' clean-head/usr.sbin/vpsctl/vpsctl.h head/usr.sbin/vpsctl/vpsctl.h
--- clean-head/usr.sbin/vpsctl/vpsctl.h	1970-01-01 01:00:00.000000000 +0100
+++ head/usr.sbin/vpsctl/vpsctl.h	2013-06-24 14:20:21.000000000 +0200
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2009-2013 Klaus P. Ohrhallinger <k@7he.at>
+ * All rights reserved.
+ *
+ * Development of this software was partly funded by:
+ *    TransIP.nl <http://www.transip.nl/>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: vpsctl.h 126 2013-04-07 15:55:54Z klaus $
+ *
+ */
+
+#ifndef _VPSCTL_H
+#define _VPSCTL_H
+
+#define _PATH_VPSDEV	"/dev/vps"
+#define _PATH_CONFDIR	"/etc/vps"
+
+#define DEFAULTLEN	0x40
+
+int priv_ston(const char *);
+const char *priv_ntos(int);
+
+struct vps_instinfo;
+struct vps_arg_ifmove;
+struct vps_arg_snapst;
+
+struct vps_dumpinfo_ext {
+        int magic;
+        int version;
+        time_t time;
+        int size;
+};
+
+/*
+ * This is a structure which holds the values set in config
+ * files and is used only in the vpsctl command.
+ */
+struct epair_cf {
+	struct epair_cf *next;
+	int idx;
+	int ifidx;
+	char *ifconfig;
+};
+struct netif_addr {
+	int af;
+	const char *str;
+	struct sockaddr *sock;
+	union {
+		struct in_addr in;
+		struct in6_addr in6;
+	} addr;
+};
+struct netif_cf {
+	struct netif_cf *next;
+	int idx;
+	int ifidx;
+	int ifaddr_cnt;
+	struct netif_addr *ifaddr[10];
+};
+struct ip_network {
+	int af;
+	const char *str;
+	union {
+		struct in_addr in;
+		struct in6_addr in6;
+	} addr;
+	union {
+		struct in_addr in;
+		/*struct in6_addr in6;*/
+		u_int8_t in6;
+	} mask;
+};
+struct vps_conf {
+	char name[MAXHOSTNAMELEN];
+	char fsroot[MAXPATHLEN];
+	char fsroot_priv[MAXPATHLEN];
+	char initproc[MAXPATHLEN];
+	char cmd_mountroot[MAXPATHLEN];
+	char cmd_unmountroot[MAXPATHLEN];
+	char devfs_ruleset[DEFAULTLEN];
+	char network_announce[DEFAULTLEN];
+	char network_revoke[DEFAULTLEN];
+	struct epair_cf *epair;
+	struct netif_cf *netif;
+	struct ip_network *ip_networks[10];
+	int ip_networks_cnt;
+	char *priv_allow;
+	char *priv_nosys;
+	char *priv_deny;
+	char *limits;
+};
+
+#endif /* _VPSCTL_H */
