Date: Mon, 20 May 2002 14:28:00 -0700 From: Maxime Henrion <mux@freebsd.org> To: arch@FreeBSD.org Subject: Re: a virtual fs to allow root mounting of any fs without special code Message-ID: <20020520212800.GI496@elvis.mu.org> In-Reply-To: <20020520212459.GH496@elvis.mu.org> References: <20020520212459.GH496@elvis.mu.org>
next in thread | previous in thread | raw e-mail | index | archive | help
--JwB53PgKC5A7+0Ej
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Maxime Henrion wrote:
> The attached patch implements the above idea with several restrictions.
Oops! This was an old patch, please consider this one instead.
Sorry,
Maxime
--JwB53PgKC5A7+0Ej
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 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.
*/
--JwB53PgKC5A7+0Ej--
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?20020520212800.GI496>
