Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 20 May 2002 14:24:59 -0700
From:      Maxime Henrion <mux@freebsd.org>
To:        arch@FreeBSD.org
Subject:   a virtual fs to allow root mounting of any fs without special code
Message-ID:  <20020520212459.GH496@elvis.mu.org>

next in thread | raw e-mail | index | archive | help

--KN5l+BnMqAQyZLvT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

	Hello all,


I've written a small virtual filesystem called rootfs which solves the
chicken and egg problem of root mounting quite nicely.  Currently, we
need special code in each filesystem to allow root mounting.  The reason
for this is that the VFS_MOUNT operations of the filesystems generally
need to do a lookup to get a device file (e.g. /dev/ad0s1a), so they
need devfs to be there, and they need lookups to work.

rootfs is nothing more than a 3-vnodes filesystem (/, /dev and /root).
To mount the root filesystem with rootfs, I do the following :

- initialize rootfs
- mount devfs on /dev (on top of rootfs)
- mount the real fs on /root
- umount devfs from /dev
- translate vnodes so that / is now the /root
- remount devfs on /dev (on top of the real fs)
- terminate rootfs

The attached patch implements the above idea with several restrictions.
First, the filesystem has to be converted to the nmount(2) API for this
to work (of course you also need devfs but it is the default).  Second,
this patch includes the bits necessary to convert ufs to nmount, but not
the various userland updates that are needed to get this to work (I've
got those in my tree, but I wait for UFS2 to be committed to avoid
unnecessary conflicts).  I just give it as a proof of concept, since it
runs fine on my box, but don't try to compile a kernel with it :-P

I also have converted cd9660fs to nmount here and I will test it as soon
as possible, but it's likely to work without further modifications.  NFS
will require a bit more tricks however (it apparently has to configure
the interface with ifioctl() before being able to talk to the server).

Comments are of course much appreciated.

Cheers,
Maxime

--KN5l+BnMqAQyZLvT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="rootfs.diff"

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	16 May 2002 22:39:18 -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(struct vnode **);
+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	17 May 2002 00:03:13 -0000
@@ -0,0 +1,251 @@
+/*-
+ * 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_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;
+
+	printf("%s: resolving %s (len %d)\n", __func__, pname, namelen); 
+
+	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:
+	if ((nameiop == CREATE || nameiop == RENAME) &&
+	    (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) {
+		cnp->cn_flags |= SAVENAME;
+		if (!(flags & LOCKPARENT))
+			VOP_UNLOCK(dvp, 0, td);
+		return (EJUSTRETURN);
+	}
+	return (ENOENT);
+}
+
+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;
+	if (de != NULL) {
+		de->de_vnode = NULL;
+		vp->v_data = NULL;
+	}
+	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_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 vnode **vpp)
+{
+	struct vnode *vp;
+	int error;
+
+	error = rootfs_allocv(rootfs_nodes, &vp, curthread);
+	vp->v_type = VDIR;
+	vp->v_flag |= VROOT;
+	*vpp = vp;
+}
+
+/*
+ * Check that our vnodes are not referenced anymore.
+ * Only /root should still be referenced.
+ */
+void
+rootfs_fini(void)
+{
+	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;
+			printf("%s: directory entry %s has v_usecount == %d\n",
+			    __func__, de->de_name, vp->v_usecount);
+			/* 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	16 May 2002 22:43:04 -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. */
@@ -478,6 +481,10 @@ start_init(void *dummy)
 	char *ucp, **uap, *arg0, *arg1;
 	struct thread *td;
 	struct proc *p;
+	struct mount *mp;
+	struct nameidata nd;
+	struct vnode *oldvp, *vp;
+	char *from, *fstype;
 	int init_does_devfs = 0;
 
 	mtx_lock(&Giant);
@@ -487,11 +494,58 @@ start_init(void *dummy)
 	td = curthread;
 	p = td->td_proc;
 
-	vfs_mountroot(NULL);
+	printf("Calling rootfs_init()...\n");
+	rootfs_init(&rootvnode);
+
+	/*
+	 * 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("unable to mount devfs, error = %d", error);
+	fstype = getenv("vfs.root.mountfrom");
+	from = index(fstype, ':');
+	if (from == NULL)
+		panic("Illegal vfs.root.mountfrom environment string");
+	*from++ = '\0';
+	printf("Mounting root from %s:%s\n", fstype, from);
+	error = kernel_vmount(MNT_RDONLY, "fstype", fstype, "fspath", "/root",
+	    "from", from, NULL);
+	if (error)
+		panic("unable to mount root filesystem, error = %d", error);
+	freeenv(fstype);
+	/* Unmount devfs. */
+	error = kernel_umount("/dev", MNT_FORCE, td);
+	if (error)
+		panic("Unable to umount devfs, error = %d\n", error);
+	printf("Successfully umounted devfs\n");
+
+	/*
+	 * Do the vnode translation trick.
+	 */
+	oldvp = rootvnode;
+	/* Get the real vnode for '/'. */
+	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, "/root", td);
+	if ((error = namei(&nd)) != 0)
+		panic("can't find /root vnode, error = %d", error);
+	vp = nd.ni_vp;
+	NDFREE(&nd, NDF_ONLY_PNBUF);
+	rootvnode = vp;
+	mp = vp->v_mount;
+	strcpy(mp->mnt_stat.f_mntonname, "/");
 
-	/* 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");
+	printf("Evil vnode translation in progress...\n");
+	/*
+	 * Properly reset the init0 filedesc structure.
+	 */
 	FILEDESC_LOCK(p->p_fd);
 	p->p_fd->fd_cdir = rootvnode;
 	VREF(p->p_fd->fd_cdir);
@@ -500,21 +554,27 @@ start_init(void *dummy)
 	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;
+	/* Undo the two references we set earlier. */
+	vrele(oldvp);
+	vrele(oldvp);
+
+	/*
+	 * Finally, try to remount devfs.
+	 * 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) {
+		printf("unable to remount devfs");
+		init_does_devfs = 1;
 	}
+	rootfs_fini();
 
 	/*
 	 * Need just enough stack to hold the faked-up "execve()" arguments.
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	16 May 2002 23:36:09 -0000
@@ -434,24 +434,23 @@ 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;
 	}
 	/*
 	 * If the user is not root, ensure that they own the directory
 	 * onto which we are attempting to mount.
 	 */
-	error = VOP_GETATTR(vp, &va, td->td_ucred, td);
+	error = suser(td);
 	if (error) {
-		vput(vp);
-		goto bad;
-	}
-	if (va.va_uid != td->td_ucred->cr_uid) {
-		error = suser(td);
+		error = VOP_GETATTR(vp, &va, td->td_ucred, td);
 		if (error) {
 			vput(vp);
 			goto bad;
 		}
+		if (va.va_uid != td->td_ucred->cr_uid) {
+			vput(vp);
+			goto bad;
+		}
 	}
 	if ((error = vinvalbuf(vp, V_SAVE, td->td_ucred, td, 0, 0)) != 0) {
 		vput(vp);
@@ -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;
+{
+	register struct vnode *vp;
+	struct mount *mp;
+	int error;
+	struct nameidata nd;
+
+	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.
 	 */

--KN5l+BnMqAQyZLvT--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020520212459.GH496>