Index: fs/rootfs/rootfs.h
===================================================================
RCS file: fs/rootfs/rootfs.h
diff -N fs/rootfs/rootfs.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ fs/rootfs/rootfs.h	19 May 2002 22:57:17 -0000
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2002 Maxime Henrion <mux@FreeBSD.org>
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FS_ROOTFS_ROOTFS_H_
+#define _FS_ROOTFS_ROOTFS_H_
+
+#define ROOTFS_NONE	0
+#define ROOTFS_ROOT	1
+#define ROOTFS_DIR	2
+
+struct rootfs_node {
+	int		de_type;
+	const char	*de_name;
+	int		de_namelen;
+	struct vnode	*de_vnode;
+};
+
+void	rootfs_init(void);
+void	rootfs_fini(void);
+
+#endif /* _FS_ROOTFS_ROOTFS_H_ */
Index: fs/rootfs/rootfs_vnops.c
===================================================================
RCS file: fs/rootfs/rootfs_vnops.c
diff -N fs/rootfs/rootfs_vnops.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ fs/rootfs/rootfs_vnops.c	19 May 2002 23:04:14 -0000
@@ -0,0 +1,272 @@
+/*-
+ * Copyright (c) 2002 Maxime Henrion <mux@FreeBSD.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/systm.h>
+#include <sys/vnode.h>
+
+#include <fs/rootfs/rootfs.h>
+
+
+static int	rootfs_access(struct vop_access_args *);
+static int	rootfs_getattr(struct vop_getattr_args *);
+static int	rootfs_inactive(struct vop_inactive_args *);
+static int	rootfs_lookup(struct vop_lookup_args *);
+static int	rootfs_reclaim(struct vop_reclaim_args *);
+static int	rootfs_allocv(struct rootfs_node *, struct vnode **,
+		    struct thread *);
+
+static struct rootfs_node rootfs_nodes[] = {
+	{ ROOTFS_ROOT, NULL, 0, NULL },
+	{ ROOTFS_DIR, "dev", 3, NULL },
+	{ ROOTFS_DIR, "root", 4, NULL },
+	{ ROOTFS_NONE, NULL, 0, NULL }
+};
+
+/*
+ * Rootfs is used internally in the kernel when
+ * doing root mounting only.  We don't need
+ * to do real access control at this time.
+ */
+static int
+rootfs_access(struct vop_access_args *ap)
+{
+	int error;
+
+	error = suser(ap->a_td);
+	KASSERT(error == 0, ("%s: uid is not root", __func__));
+	return (error);
+}
+
+/*
+ * Translation of a component pathname.
+ */
+static int
+rootfs_lookup(struct vop_lookup_args *ap)
+{
+	struct vnode *dvp, **vpp;
+	struct componentname *cnp;
+	struct rootfs_node *de;
+	struct thread *td;
+	char *pname;
+	int error, flags, nameiop, namelen;
+
+	dvp = ap->a_dvp;
+	vpp = ap->a_vpp;
+	cnp = ap->a_cnp;
+	pname = cnp->cn_nameptr;
+	namelen = cnp->cn_namelen;
+	nameiop = cnp->cn_nameiop;
+	td = cnp->cn_thread;
+	flags = cnp->cn_flags;
+
+	if ((flags & ISLASTCN) && (nameiop != LOOKUP))
+		panic("nameiop != LOOKUP in rootfs");
+
+	/* self */
+	if (namelen == 1 && *pname == '.') {
+		*vpp = dvp;
+		VREF(dvp);
+		return (0);
+	}
+
+	/* parent */
+	if (flags & ISDOTDOT) {
+		de = (struct rootfs_node *)dvp->v_data;
+		if (de->de_type != ROOTFS_DIR)
+			goto notfound;
+		VOP_UNLOCK(dvp, 0, td);
+		/*
+		 * Since we support only one level of directories,
+		 * we always return the vnode for /.
+		 */
+		de = rootfs_nodes;
+		error = rootfs_allocv(de, vpp, td);
+		if (error) {
+			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
+			return (error);
+		}
+		if ((flags & LOCKPARENT) && (flags & ISLASTCN))
+			error = vn_lock(dvp, LK_EXCLUSIVE, td);
+		if (error)
+			vput(*vpp);
+		return (error);
+	}
+
+	/* directory entry */
+	de = (struct rootfs_node *)dvp->v_data;
+	if (de->de_type != ROOTFS_ROOT)
+		goto notfound;
+	de = rootfs_nodes + 1;		/* First dir is at offset 1 */
+	while (de->de_type != ROOTFS_NONE) {
+		if (de->de_namelen == namelen &&
+		    (bcmp(de->de_name, pname, namelen) == 0)) {
+			error = rootfs_allocv(de, vpp, td);
+			if (error)
+				return (error);
+			if (!(flags & LOCKPARENT) || !(flags & ISLASTCN))
+				VOP_UNLOCK(dvp, 0, td);
+			return (0);
+		}
+		de++;
+	}
+
+notfound:
+	return (ENOENT);
+}
+
+/*
+ * This is for the VOP_GETATTR() call in vfs_nmount().
+ */
+static int
+rootfs_getattr(struct vop_getattr_args *ap)
+{
+	struct vattr *vap;
+
+	vap = ap->a_vap;
+	vattr_null(vap);
+	vap->va_uid = 0;
+	return (0);
+}
+
+static int
+rootfs_reclaim(struct vop_reclaim_args *ap)
+{
+	struct rootfs_node *de;
+	struct vnode *vp;
+
+	vp = ap->a_vp;
+	de = (struct rootfs_node *)vp->v_data;
+	if (de != NULL) {
+		de->de_vnode = NULL;
+		vp->v_data = NULL;
+	}
+	return (0);
+}
+
+static int
+rootfs_inactive(struct vop_inactive_args *ap)
+{
+	struct thread *td;
+	struct vnode *vp;
+
+	vp = ap->a_vp;
+	td = ap->a_td;
+	VOP_UNLOCK(vp, 0, td);
+	vrecycle(vp, NULL, td);
+	return (0);
+}
+
+static vop_t **rootfs_vnodeop_p;
+static struct vnodeopv_entry_desc rootfs_vnodeop_entries[] = {
+	{ &vop_default_desc,		(vop_t *) vop_defaultop },
+	{ &vop_access_desc,		(vop_t *) rootfs_access },
+	{ &vop_getattr_desc,		(vop_t *) rootfs_getattr },
+	{ &vop_inactive_desc,		(vop_t *) rootfs_inactive },
+	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
+	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
+	{ &vop_lookup_desc,		(vop_t *) rootfs_lookup },
+	{ &vop_reclaim_desc,		(vop_t *) rootfs_reclaim },
+	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
+	{ NULL,				NULL }
+};
+static struct vnodeopv_desc rootfs_vnodeop_opv_desc =
+	{ &rootfs_vnodeop_p, rootfs_vnodeop_entries };
+
+VNODEOP_SET(rootfs_vnodeop_opv_desc);
+
+/*
+ * Returns with the root vnode locked.
+ */
+void
+rootfs_init()
+{
+	struct thread *td;
+	struct vnode *vp;
+	int error;
+
+	td = curthread;
+	error = rootfs_allocv(rootfs_nodes, &vp, td);
+	vp->v_type = VDIR;
+	vp->v_flag |= VROOT;
+	rootvnode = vp;
+}
+
+/*
+ * Release our vnodes.
+ */
+void
+rootfs_fini()
+{
+	struct rootfs_node *de;
+	struct vnode *vp;
+
+	de = rootfs_nodes;
+	while (de->de_type != ROOTFS_NONE) {
+		if (de->de_vnode != NULL) {
+			vp = de->de_vnode;
+			vrele(vp);
+		}
+		de++;
+	}
+}
+
+static int
+rootfs_allocv(de, vpp, td)
+	struct rootfs_node *de;
+	struct vnode **vpp;
+	struct thread *td;
+{
+	struct vnode *vp;
+	int i;
+
+	i = 0;
+	
+loop:
+	vp = de->de_vnode;
+	if (vp != NULL) {
+		if (vget(vp, LK_EXCLUSIVE, td))
+			goto loop;
+		*vpp = vp;
+		return (0);
+	}
+
+	getnewvnode(VT_NON, NULL, rootfs_vnodeop_p, &vp);
+	vp->v_type = VDIR;
+	vp->v_data = (void *)de;
+	de->de_vnode = vp;
+	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
+	*vpp = vp;
+	return (0);
+}
Index: kern/init_main.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/init_main.c,v
retrieving revision 1.194
diff -u -p -r1.194 init_main.c
--- kern/init_main.c	2 May 2002 20:27:42 -0000	1.194
+++ kern/init_main.c	19 May 2002 22:58:35 -0000
@@ -52,6 +52,7 @@
 #include <sys/lock.h>
 #include <sys/mount.h>
 #include <sys/mutex.h>
+#include <sys/namei.h>
 #include <sys/sysctl.h>
 #include <sys/proc.h>
 #include <sys/resourcevar.h>
@@ -76,6 +77,8 @@
 #include <sys/user.h>
 #include <sys/copyright.h>
 
+#include <fs/rootfs/rootfs.h>
+
 void mi_startup(void);				/* Should be elsewhere */
 
 /* Components of the first process -- never freed. */
@@ -487,34 +490,20 @@ start_init(void *dummy)
 	td = curthread;
 	p = td->td_proc;
 
-	vfs_mountroot(NULL);
-
-	/* Get the vnode for '/'.  Set p->p_fd->fd_cdir to reference it. */
-	if (VFS_ROOT(TAILQ_FIRST(&mountlist), &rootvnode))
-		panic("cannot find root vnode");
-	FILEDESC_LOCK(p->p_fd);
-	p->p_fd->fd_cdir = rootvnode;
-	VREF(p->p_fd->fd_cdir);
-	p->p_fd->fd_rdir = rootvnode;
-	VREF(p->p_fd->fd_rdir);
-	FILEDESC_UNLOCK(p->p_fd);
-	VOP_UNLOCK(rootvnode, 0, td);
-
-	if (devfs_present) {
-		/*
-		 * For disk based systems, we probably cannot do this yet
-		 * since the fs will be read-only.  But a NFS root
-		 * might be ok.  It is worth a shot.
-		 */
-		error = vn_mkdir("/dev", 0700, UIO_SYSSPACE, td);
-		if (error == EEXIST)
-			error = 0;
-		if (error == 0)
-			error = kernel_vmount(0, "fstype", "devfs",
-			    "fspath", "/dev", NULL);
-		if (error != 0)
-			init_does_devfs = 1;
-	}
+	vfs_mountroot();
+	/*
+	 * For disk based systems, we probably cannot do this yet
+	 * since the fs will be read-only.  But a NFS root
+	 * might be ok.  It is worth a shot.
+	 */
+	error = vn_mkdir("/dev", 0700, UIO_SYSSPACE, td);
+	if (error == EEXIST)
+		error = 0;
+	if (error == 0)
+		error = kernel_vmount(0, "fstype", "devfs",
+		    "fspath", "/dev", NULL);
+	if (error)
+		init_does_devfs = 1;
 
 	/*
 	 * Need just enough stack to hold the faked-up "execve()" arguments.
Index: kern/vfs_conf.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_conf.c,v
retrieving revision 1.68
diff -u -p -r1.68 vfs_conf.c
--- kern/vfs_conf.c	17 Apr 2002 13:06:36 -0000	1.68
+++ kern/vfs_conf.c	19 May 2002 23:33:55 -0000
@@ -52,6 +52,7 @@
 #include <sys/vnode.h>
 #include <sys/mount.h>
 #include <sys/malloc.h>
+#include <sys/namei.h>
 #include <sys/reboot.h>
 #include <sys/diskslice.h>
 #include <sys/disklabel.h>
@@ -59,6 +60,8 @@
 #include <sys/cons.h>
 #include <sys/proc.h>
 
+#include <fs/rootfs/rootfs.h>
+
 #include "opt_ddb.h"
 
 #ifdef DDB
@@ -100,7 +103,7 @@ dev_t		rootdev = NODEV;
  * Find and mount the root filesystem
  */
 void
-vfs_mountroot(void *foo __unused)
+vfs_mountroot(void)
 {
 	char		*cp;
 	int		i, error;
@@ -181,20 +184,20 @@ vfs_mountroot(void *foo __unused)
 static int
 vfs_mountroot_try(char *mountfrom)
 {
-        struct mount	*mp;
-	char		*vfsname, *path;
-	int		error;
-	char		patt[32];
-	int		s;
-
-	vfsname = NULL;
-	path    = NULL;
-	mp      = NULL;
-	error   = EINVAL;
+	struct thread *td;
+	struct mount *mp;
+	struct nameidata nd;
+	struct proc *p;
+	struct vnode *vp;
+	char *vfsname, *path;
+	char patt[32];
+	int error, mntflags, s;
 
 	if (mountfrom == NULL)
-		return(error);		/* don't complain */
+		return (EINVAL);	/* don't complain */
 
+	td = curthread;
+	p = td->td_proc;
 	s = splcam();			/* Overkill, but annoying without it */
 	printf("Mounting root from %s\n", mountfrom);
 	splx(s);
@@ -202,63 +205,91 @@ vfs_mountroot_try(char *mountfrom)
 	/* parse vfs name and path */
 	vfsname = malloc(MFSNAMELEN, M_MOUNT, M_WAITOK);
 	path = malloc(MNAMELEN, M_MOUNT, M_WAITOK);
-	vfsname[0] = path[0] = 0;
+	vfsname[0] = path[0] = '\0';
 	sprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN);
-	if (sscanf(mountfrom, patt, vfsname, path) < 1)
-		goto done;
-
-	/* allocate a root mount */
-	error = vfs_rootmountalloc(vfsname, path[0] != 0 ? path : ROOTNAME,
-				   &mp);
-	if (error != 0) {
-		printf("Can't allocate root mount for filesystem '%s': %d\n",
-		       vfsname, error);
+	if (sscanf(mountfrom, patt, vfsname, path) < 1) {
+		error = EINVAL;
 		goto done;
 	}
-	mp->mnt_flag |= MNT_ROOTFS;
 
 	/* do our best to set rootdev */
 	if ((path[0] != 0) && setrootbyname(path))
 		printf("setrootbyname failed\n");
 
+	rootfs_init();
+
+	/*
+	 * Set cdir and rdir to make namei() work.
+	 */
+	FILEDESC_LOCK(p->p_fd);
+	p->p_fd->fd_cdir = rootvnode;
+	VREF(p->p_fd->fd_cdir);
+	p->p_fd->fd_rdir = rootvnode;
+	VREF(p->p_fd->fd_rdir);
+	FILEDESC_UNLOCK(p->p_fd);
+	VOP_UNLOCK(rootvnode, 0, td);
+
+	error = kernel_vmount(0, "fstype", "devfs", "fspath", "/dev", NULL);
+	if (error)
+		panic("%s: unable to mount devfs on rootfs, error = %d",
+		    __func__, error);
+
 	/* If the root device is a type "memory disk", mount RW */
 	if (rootdev != NODEV && devsw(rootdev) &&
 	    (devsw(rootdev)->d_flags & D_MEMDISK))
-		mp->mnt_flag &= ~MNT_RDONLY;
+		mntflags = 0;
+	else
+		mntflags = MNT_RDONLY;
+
+	error = kernel_vmount(mntflags, "fstype", vfsname, "fspath", "/root",
+	    "from", path, NULL);
+	if (error)
+		panic("%s: unable to mount root filesystem, error = %d",
+		    __func__, error);
+	/* Unmount devfs. */
+	error = kernel_umount("/dev", MNT_FORCE, td);
+	if (error)
+		panic("%s: unable to unmount devfs, error = %d\n",
+		    __func__, error);
 
+	/*
+	 * Do the vnode translation trick.
+	 * Here we assume that rootfs mounted the real
+	 * fs in /root.
+	 */
+	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, "/root", td);
+	if ((error = namei(&nd)) != 0)
+		panic("%s: can't find /root vnode, error = %d",
+		    __func__, error);
+	vp = nd.ni_vp;
+	NDFREE(&nd, NDF_ONLY_PNBUF);
+	rootvnode = vp;
+	mp = vp->v_mount;
 	/* 
-	 * Set the mount path to be something useful, because the
-	 * filesystem code isn't responsible now for initialising
-	 * f_mntonname unless they want to override the default
-	 * (which is `path'.)
+	 * f_mntonname now contains "/root", change it to "/".
 	 */
 	strncpy(mp->mnt_stat.f_mntonname, "/", MNAMELEN);
+	rootfs_fini();
 
-	error = VFS_MOUNT(mp, NULL, NULL, NULL, curthread);
+	/*
+	 * Properly reset the filedesc structure with the new rootvnode.
+	 */
+	FILEDESC_LOCK(p->p_fd);
+	vrele(p->p_fd->fd_cdir);
+	p->p_fd->fd_cdir = rootvnode;
+	VREF(p->p_fd->fd_cdir);
+	vrele(p->p_fd->fd_rdir);
+	p->p_fd->fd_rdir = rootvnode;
+	VREF(p->p_fd->fd_rdir);
+	FILEDESC_UNLOCK(p->p_fd);
+	VOP_UNLOCK(rootvnode, 0, td);
 
 done:
-	if (vfsname != NULL)
-		free(vfsname, M_MOUNT);
-	if (path != NULL)
-		free(path, M_MOUNT);
-	if (error != 0) {
-		if (mp != NULL) {
-			vfs_unbusy(mp, curthread);
-			free(mp, M_MOUNT);
-		}
+	if (error)
 		printf("Root mount failed: %d\n", error);
-	} else {
-
-		/* register with list of mounted filesystems */
-		mtx_lock(&mountlist_mtx);
-		TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list);
-		mtx_unlock(&mountlist_mtx);
-
-		/* sanity check system clock against root filesystem timestamp */
+	else	/* initialize the time of day register */
 		inittodr(mp->mnt_time);
-		vfs_unbusy(mp, curthread);
-	}
-	return(error);
+	return (error);
 }
 
 /*
Index: kern/vfs_syscalls.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.253
diff -u -p -r1.253 vfs_syscalls.c
--- kern/vfs_syscalls.c	14 May 2002 21:59:49 -0000	1.253
+++ kern/vfs_syscalls.c	18 May 2002 16:12:00 -0000
@@ -434,7 +434,6 @@ vfs_nmount(td, fsflags, fsoptions)
 		mp->mnt_flag |= fsflags &
 		    (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT);
 		VOP_UNLOCK(vp, 0, td);
-		mp->mnt_optnew = optlist;
 		goto update;
 	}
 	/*
@@ -528,8 +527,8 @@ vfs_nmount(td, fsflags, fsoptions)
 	mp->mnt_iosize_max = DFLTPHYS;
 	VOP_UNLOCK(vp, 0, td);
 
-	mp->mnt_opt = optlist;
 update:
+	mp->mnt_optnew = optlist;
 	/*
 	 * Check if the fs implements the new VFS_NMOUNT()
 	 * function, since the new system call was used.
@@ -567,6 +566,17 @@ update:
 	 * get.  No freeing of cn_pnbuf.
 	 */
 	error = VFS_NMOUNT(mp, &nd, td);
+	if (!error) {
+		if (mp->mnt_opt != NULL)
+			vfs_freeopts(mp->mnt_opt);
+		mp->mnt_opt = mp->mnt_optnew;
+	} else
+		vfs_freeopts(mp->mnt_optnew);
+	/*
+	 * Prevent external consumers of mount
+	 * options to read mnt_optnew.
+	 */
+	mp->mnt_optnew = NULL;
 	if (mp->mnt_flag & MNT_UPDATE) {
 		if (mp->mnt_kern_flag & MNTK_WANTRDWR)
 			mp->mnt_flag &= ~MNT_RDONLY;
@@ -576,10 +586,6 @@ update:
 		if (error) {
 			mp->mnt_flag = flag;
 			mp->mnt_kern_flag = kern_flag;
-			vfs_freeopts(mp->mnt_optnew);
-		} else {
-			vfs_freeopts(mp->mnt_opt);
-			mp->mnt_opt = mp->mnt_optnew;
 		}
 		if ((mp->mnt_flag & MNT_RDONLY) == 0) {
 			if (mp->mnt_syncer == NULL)
@@ -619,10 +625,8 @@ update:
 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
 			error = vfs_allocate_syncvnode(mp);
 		vfs_unbusy(mp, td);
-		if ((error = VFS_START(mp, 0, td)) != 0) {
+		if ((error = VFS_START(mp, 0, td)) != 0)
 			vrele(vp);
-			goto bad;
-		}
 	} else {
 		mtx_lock(&vp->v_interlock);
 		vp->v_flag &= ~VMOUNT;
@@ -631,9 +635,8 @@ update:
 		vfs_unbusy(mp, td);
 		free((caddr_t)mp, M_MOUNT);
 		vput(vp);
-		goto bad;
 	}
-	return (0);
+	return (error);
 bad:
 	vfs_freeopts(optlist);
 	return (error);
@@ -1185,6 +1188,30 @@ dounmount(mp, flags, td)
 		vfs_freeopts(mp->mnt_opt);
 	free((caddr_t)mp, M_MOUNT);
 	return (0);
+}
+
+int
+kernel_umount(path, flags, td)
+	const char *path;
+	int flags;
+	struct thread *td;
+{
+	struct mount *mp;
+	struct nameidata nd;
+	struct vnode *vp;
+	int error;
+
+	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, td);
+	if ((error = namei(&nd)) != 0)
+		return (error);
+	vp = nd.ni_vp;
+	NDFREE(&nd, NDF_ONLY_PNBUF);
+	mp = vp->v_mount;
+	KASSERT(vp->v_flag & VROOT, ("%s(%s): vnode is not VROOT",
+	    __func__, path));
+	vput(vp);
+	error = dounmount(mp, flags, td);
+	return (error);
 }
 
 /*
Index: ufs/ffs/ffs_extern.h
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ffs/ffs_extern.h,v
retrieving revision 1.47
diff -u -p -r1.47 ffs_extern.h
--- ufs/ffs/ffs_extern.h	19 Mar 2002 22:40:46 -0000	1.47
+++ ufs/ffs/ffs_extern.h	11 May 2002 16:39:26 -0000
@@ -71,9 +71,7 @@ int	ffs_isblock(struct fs *, u_char *, u
 int	ffs_isfreeblock(struct fs *, unsigned char *, ufs_daddr_t);
 int	ffs_mountfs(struct vnode *, struct mount *, struct thread *,
 	     struct malloc_type *);
-int	ffs_mountroot(void);
-int	ffs_mount(struct mount *, char *, caddr_t, struct nameidata *,
-	    struct thread *);
+int	ffs_mount(struct mount *, struct nameidata *, struct thread *);
 int	ffs_reallocblks(struct vop_reallocblks_args *);
 int	ffs_realloccg(struct inode *,
 	    ufs_daddr_t, ufs_daddr_t, int, int, struct ucred *, struct buf **);
Index: ufs/ffs/ffs_snapshot.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ffs/ffs_snapshot.c,v
retrieving revision 1.35
diff -u -p -r1.35 ffs_snapshot.c
--- ufs/ffs/ffs_snapshot.c	12 May 2002 20:21:40 -0000	1.35
+++ ufs/ffs/ffs_snapshot.c	16 May 2002 22:22:07 -0000
@@ -138,7 +138,7 @@ ffs_snapshot(mp, snapfile)
 	 * Create the snapshot file.
 	 */
 restart:
-	NDINIT(&nd, CREATE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, snapfile, td);
+	NDINIT(&nd, CREATE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, snapfile, td);
 	if ((error = namei(&nd)) != 0)
 		return (error);
 	if (nd.ni_vp != NULL) {
Index: ufs/ffs/ffs_vfsops.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.178
diff -u -p -r1.178 ffs_vfsops.c
--- ufs/ffs/ffs_vfsops.c	13 May 2002 09:22:28 -0000	1.178
+++ ufs/ffs/ffs_vfsops.c	16 May 2002 23:39:18 -0000
@@ -72,7 +72,7 @@ static int	ffs_oldfscompat(struct fs *);
 static int	ffs_init(struct vfsconf *);
 
 static struct vfsops ufs_vfsops = {
-	ffs_mount,
+	NULL,
 	ufs_start,
 	ffs_unmount,
 	ufs_root,
@@ -90,6 +90,7 @@ static struct vfsops ufs_vfsops = {
 #else
 	vfs_stdextattrctl,
 #endif
+	ffs_mount,
 };
 
 VFS_SET(ufs_vfsops, ufs, 0);
@@ -100,17 +101,8 @@ VFS_SET(ufs_vfsops, ufs, 0);
  * Called when mounting local physical media
  *
  * PARAMETERS:
- *		mountroot
- *			mp	mount point structure
- *			path	NULL (flag for root mount!!!)
- *			data	<unused>
- *			ndp	<unused>
- *			p	process (user credentials check [statfs])
- *
  *		mount
  *			mp	mount point structure
- *			path	path to mount point
- *			data	pointer to argument struct in user space
  *			ndp	mount point namei() return (used for
  *				credentials on reload), reused to look
  *				up block device.
@@ -126,47 +118,32 @@ VFS_SET(ufs_vfsops, ufs, 0);
  *		EXIT
  *			mount point is locked
  *
- * NOTES:
- *		A NULL path can be used for a flag since the mount
- *		system call will fail with EFAULT in copyinstr in
- *		namei() if it is a genuine NULL from the user.
  */
 int
-ffs_mount(mp, path, data, ndp, td)
+ffs_mount(mp, ndp, td)
         struct mount		*mp;	/* mount struct pointer*/
-        char			*path;	/* path to mount point*/
-        caddr_t			data;	/* arguments to FS specific mount*/
         struct nameidata	*ndp;	/* mount point credentials*/
         struct thread		*td;	/* process requesting mount*/
 {
-	size_t		size;
 	struct vnode	*devvp;
-	struct ufs_args args;
 	struct ufsmount *ump = 0;
+	struct vfsoptlist *opts;
 	struct fs *fs;
-	int error, flags;
+	struct export_args export;
+	char *path, *fspec;
+	int error, flags, len;
 	mode_t accessmode;
 
+	opts = mp->mnt_optnew;
 	/*
-	 * Use NULL path to indicate we are mounting the root file system.
-	 */
-	if (path == NULL) {
-		if ((error = bdevvp(rootdev, &rootvp))) {
-			printf("ffs_mountroot: can't find rootvp\n");
-			return (error);
-		}
-
-		if ((error = ffs_mountfs(rootvp, mp, td, M_FFSNODE)) != 0)
-			return (error);
-		(void)VFS_STATFS(mp, &mp->mnt_stat, td);
-		return (0);
-	}
-
-	/*
-	 * Mounting non-root file system or updating a file system
+	 * The fspath mount option is always present
+	 * and is always a string.
 	 */
-	if ((error = copyin(data, (caddr_t)&args, sizeof(struct ufs_args)))!= 0)
-		return (error);
+	vfs_getopt(opts, "fspath", (void **)&path, NULL);
+	fspec = NULL;
+	error = vfs_getopt(opts, "from", (void **)&fspec, &len);
+	if (!error && fspec[len - 1] != '\0')
+		return (EINVAL);
 
 	/*
 	 * If updating, check whether changing from read-only to
@@ -280,20 +257,27 @@ ffs_mount(mp, path, data, ndp, td)
 		/*
 		 * If not updating name, process export requests.
 		 */
-		if (args.fspec == 0)
-			return (vfs_export(mp, &args.export));
+		if (fspec == NULL) {
+			error = vfs_getopt(opts, "export", (void **)&export,
+			    &len);
+			if (error || len != sizeof(struct export_args))
+				return (EINVAL);
+			return (vfs_export(mp, &export));
+		}
 		/*
 		 * If this is a snapshot request, take the snapshot.
 		 */
 		if (mp->mnt_flag & MNT_SNAPSHOT)
-			return (ffs_snapshot(mp, args.fspec));
+			return (ffs_snapshot(mp, fspec));
 	}
 
 	/*
 	 * Not an update, or updating the name: look up the name
 	 * and verify that it refers to a sensible block device.
 	 */
-	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td);
+	if (fspec == NULL)
+		return (EINVAL);
+	NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, td);
 	if ((error = namei(ndp)) != 0)
 		return (error);
 	NDFREE(ndp, NDF_ONLY_PNBUF);
@@ -350,8 +334,8 @@ ffs_mount(mp, path, data, ndp, td)
 	/*
 	 * Save "mounted from" device name info for mount point (NULL pad).
 	 */
-	copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
-	bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
+	strncpy(mp->mnt_stat.f_mntfromname, fspec, MNAMELEN - 1);
+	mp->mnt_stat.f_mntfromname[MNAMELEN] = '\0';
 	/*
 	 * Initialize filesystem stat information in mount struct.
 	 */
