--- diff-t9.l+++ diff-t9.r@@ -1,4 +1,5 @@-/* $NetBSD: vfs_syscalls.c,v 1.57 1995/10/07 06:28:51 mycroft Exp $ */+/* $OpenBSD: t9.2,v 1.2 2013/12/01 16:40:56 krw Exp $ */+/* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ /* * Copyright (c) 1989, 1993@@ -17,11 +18,7 @@ * 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.- * 3. All advertising materials mentioning features or use of this software- * must display the following acknowledgement:- * This product includes software developed by the University of- * California, Berkeley and its contributors.- * 4. Neither the name of the University nor the names of its contributors+ * 3. 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. *@@ -53,13 +50,30 @@ #include <sys/uio.h> #include <sys/malloc.h> #include <sys/dirent.h>+#include <sys/extattr.h> #include <sys/syscallargs.h> -#include <vm/vm.h>+#include <uvm/uvm_extern.h> #include <sys/sysctl.h> -static int change_dir __P((struct nameidata *ndp, struct proc *p));+extern int suid_clear;+int usermount = 0; /* sysctl: by default, users may not mount */++static int change_dir(struct nameidata *, struct proc *);++void checkdirs(struct vnode *);++/*+ * Redirection info so we don't have to include the union fs routines in+ * the kernel directly. This way, we can build unionfs as an LKM. The+ * pointer gets filled in later, when we modload the LKM, or when the+ * compiled-in unionfs code gets initialized. For now, we just set+ * it to a stub routine.+ */++int (*union_check_p)(struct proc *, struct vnode **,+ struct file *, struct uio, int *) = NULL; /* * Virtual File System System Calls@@ -69,6 +83,7 @@ * Mount a file system. */ /* ARGSUSED */+int sys_mount(p, v, retval) struct proc *p; void *v;@@ -78,22 +93,36 @@ syscallarg(char *) type; syscallarg(char *) path; syscallarg(int) flags;- syscallarg(caddr_t) data;+ syscallarg(void *) data; } */ *uap = v; register struct vnode *vp; register struct mount *mp;- int error, flag;- u_long fsindex;+ int error, flag = 0;+#ifdef COMPAT_43+ u_long fstypenum = 0;+#endif char fstypename[MFSNAMELEN];+ char fspath[MNAMELEN]; struct vattr va; struct nameidata nd;+ struct vfsconf *vfsp;+ struct timeval tv;++ if (usermount == 0 && (error = suser(p->p_ucred, &p->p_acflag)))+ return (error);++ /*+ * Mount points must fit in MNAMELEN, not MAXPATHLEN.+ */+ error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL);+ if (error)+ return(error); /* * Get vnode to be covered */- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,- SCARG(uap, path), p);- if (error = namei(&nd))+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, p);+ if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; if (SCARG(uap, flags) & MNT_UPDATE) {@@ -113,7 +142,7 @@ return (EOPNOTSUPP); /* Needs translation */ } mp->mnt_flag |=- SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);+ SCARG(uap, flags) & (MNT_RELOAD | MNT_UPDATE); /* * Only root, or the user that did the original mount is * permitted to update it.@@ -134,7 +163,11 @@ } SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; }- VOP_UNLOCK(vp);+ if ((error = vfs_busy(mp, LK_NOWAIT, 0, p)) != 0) {+ vput(vp);+ return (error);+ }+ VOP_UNLOCK(vp, 0, p); goto update; } /*@@ -143,7 +176,7 @@ */ if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || (va.va_uid != p->p_ucred->cr_uid &&- (error = suser(p->p_ucred, &p->p_acflag)))) {+ (error = suser(p->p_ucred, &p->p_acflag)))) { vput(vp); return (error); }@@ -158,40 +191,47 @@ } SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; }- if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))+ if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) return (error); if (vp->v_type != VDIR) { vput(vp); return (ENOTDIR); }- if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN,- (size_t *)0)) {-#if defined(COMPAT_09) || defined(COMPAT_43)+ error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL);+ if (error) {+#ifdef COMPAT_43 /* * Historically filesystem types were identified by number. * If we get an integer for the filesystem type instead of a * string, we check to see if it matches one of the historic * filesystem types.- */ - fsindex = (u_long)SCARG(uap, type);- if (fsindex >= nvfssw || vfssw[fsindex] == NULL) {+ */+ fstypenum = (u_long)SCARG(uap, type);++ for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)+ if (vfsp->vfc_typenum == fstypenum)+ break;+ if (vfsp == NULL) { vput(vp); return (ENODEV); }- strncpy(fstypename, vfssw[fsindex]->vfs_name, MFSNAMELEN);+ strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);+ #else vput(vp); return (error); #endif }- for (fsindex = 0; fsindex < nvfssw; fsindex++)- if (vfssw[fsindex] != NULL &&- !strncmp(vfssw[fsindex]->vfs_name, fstypename, MFSNAMELEN))+ for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {+ if (!strcmp(vfsp->vfc_name, fstypename)) break;- if (fsindex >= nvfssw) {+ }++ if (vfsp == NULL) { vput(vp);- return (ENODEV);+ return (EOPNOTSUPP); }+ if (vp->v_mountedhere != NULL) { vput(vp); return (EBUSY);@@ -203,15 +243,14 @@ mp = (struct mount *)malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); bzero((char *)mp, (u_long)sizeof(struct mount));- mp->mnt_op = vfssw[fsindex];- if (error = vfs_lock(mp)) {- free((caddr_t)mp, M_MOUNT);- vput(vp);- return (error);- }- /* Do this early in case we block later. */- vfssw[fsindex]->vfs_refcount++;- vp->v_mountedhere = mp;+ lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);+ /* This error never happens, but it makes auditing easier */+ if ((error = vfs_busy(mp, LK_NOWAIT, 0, p)))+ return (error);+ mp->mnt_op = vfsp->vfc_vfsops;+ mp->mnt_vfc = vfsp;+ mp->mnt_flag |= (vfsp->vfc_flags & MNT_VISFLAGMASK);+ strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); mp->mnt_vnodecovered = vp; mp->mnt_stat.f_owner = p->p_ucred->cr_uid; update:@@ -223,13 +262,19 @@ else if (mp->mnt_flag & MNT_RDONLY) mp->mnt_flag |= MNT_WANTRDWR; mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |- MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);+ MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_SOFTDEP |+ MNT_NOATIME | MNT_FORCE); mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |- MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);+ MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC |+ MNT_SOFTDEP | MNT_NOATIME | MNT_FORCE); /* * Mount the filesystem. */ error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);+ if (!error) {+ microtime(&tv);+ mp->mnt_stat.f_ctime = tv.tv_sec;+ } if (mp->mnt_flag & MNT_UPDATE) { vrele(vp); if (mp->mnt_flag & MNT_WANTRDWR)@@ -238,23 +283,42 @@ (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); if (error) mp->mnt_flag = flag;++ if ((mp->mnt_flag & MNT_RDONLY) == 0) {+ if (mp->mnt_syncer == NULL)+ error = vfs_allocate_syncvnode(mp);+ } else {+ if (mp->mnt_syncer != NULL)+ vgone(mp->mnt_syncer);+ mp->mnt_syncer = NULL;+ }++ vfs_unbusy(mp, p); return (error); }++ vp->v_mountedhere = mp;+ /* * Put the new filesystem on the mount list after root. */ cache_purge(vp); if (!error) {+ vfsp->vfc_refcount++;+ simple_lock(&mountlist_slock); TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);+ simple_unlock(&mountlist_slock); checkdirs(vp);- VOP_UNLOCK(vp);- vfs_unlock(mp);+ VOP_UNLOCK(vp, 0, p);+ if ((mp->mnt_flag & MNT_RDONLY) == 0)+ error = vfs_allocate_syncvnode(mp);+ vfs_unbusy(mp, p); (void) VFS_STATFS(mp, &mp->mnt_stat, p);- error = VFS_START(mp, 0, p);+ if ((error = VFS_START(mp, 0, p)) != 0)+ vrele(vp); } else { mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;- vfssw[fsindex]->vfs_refcount--;- vfs_unlock(mp);+ vfs_unbusy(mp, p); free((caddr_t)mp, M_MOUNT); vput(vp); }@@ -266,6 +330,7 @@ * or root directory onto which the new filesystem has just been * mounted. If so, replace them with the new mount point. */+void checkdirs(olddp) struct vnode *olddp; {@@ -277,7 +342,7 @@ return; if (VFS_ROOT(olddp->v_mountedhere, &newdp)) panic("mount: lost mount");- for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {+ for (p = LIST_FIRST(&allproc); p != 0; p = LIST_NEXT(p, p_list)) { fdp = p->p_fd; if (fdp->fd_cdir == olddp) { vrele(fdp->fd_cdir);@@ -305,6 +370,7 @@ * not special file (as before). */ /* ARGSUSED */+int sys_unmount(p, v, retval) struct proc *p; void *v;@@ -321,7 +387,7 @@ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, SCARG(uap, path), p);- if (error = namei(&nd))+ if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; mp = vp->v_mount;@@ -352,50 +418,77 @@ return (EINVAL); } vput(vp);- return (dounmount(mp, SCARG(uap, flags), p));++ if (vfs_busy(mp, LK_EXCLUSIVE, NULL, p))+ return (EBUSY);++ return (dounmount(mp, SCARG(uap, flags), p, vp)); } /* * Do the actual file system unmount. */-dounmount(mp, flags, p)- register struct mount *mp;- int flags;- struct proc *p;+int+dounmount(struct mount *mp, int flags, struct proc *p, struct vnode *olddp) { struct vnode *coveredvp;+ struct proc *p2; int error;+ int hadsyncer = 0; - coveredvp = mp->mnt_vnodecovered;- if (vfs_busy(mp))- return (EBUSY);- mp->mnt_flag |= MNT_UNMOUNT;- if (error = vfs_lock(mp))- return (error);-- mp->mnt_flag &=~ MNT_ASYNC;- vnode_pager_umount(mp); /* release cached vnodes */- cache_purgevfs(mp); /* remove cache entries for this file sys */- if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||- (flags & MNT_FORCE))- error = VFS_UNMOUNT(mp, flags, p);- mp->mnt_flag &= ~MNT_UNMOUNT;- vfs_unbusy(mp);- if (error) {- vfs_unlock(mp);- } else {- TAILQ_REMOVE(&mountlist, mp, mnt_list);- if (coveredvp != NULLVP) {- vrele(coveredvp);- coveredvp->v_mountedhere = (struct mount *)0;- }- mp->mnt_op->vfs_refcount--;- vfs_unlock(mp);- if (mp->mnt_vnodelist.lh_first != NULL)- panic("unmount: dangling vnode");- free((caddr_t)mp, M_MOUNT);- }- return (error);+ mp->mnt_flag &=~ MNT_ASYNC;+ cache_purgevfs(mp); /* remove cache entries for this file sys */+ if (mp->mnt_syncer != NULL) {+ hadsyncer = 1;+ vgone(mp->mnt_syncer);+ mp->mnt_syncer = NULL;+ }+ if (((mp->mnt_flag & MNT_RDONLY) ||+ (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||+ (flags & MNT_FORCE))+ error = VFS_UNMOUNT(mp, flags, p);+ simple_lock(&mountlist_slock);+ if (error) {+ if ((mp->mnt_flag & MNT_RDONLY) == 0 && hadsyncer)+ (void) vfs_allocate_syncvnode(mp);+ lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK,+ &mountlist_slock, p);+ return (error);+ }+ TAILQ_REMOVE(&mountlist, mp, mnt_list);+ if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {+ if (olddp) {+ /* + * Try to put processes back in a real directory+ * after a forced unmount.+ * XXX We're not holding a ref on olddp, which may+ * change, so compare id numbers.+ */+ LIST_FOREACH(p2, &allproc, p_list) {+ struct filedesc *fdp = p2->p_fd;+ if (fdp->fd_cdir &&+ fdp->fd_cdir->v_id == olddp->v_id) {+ vrele(fdp->fd_cdir);+ vref(coveredvp);+ fdp->fd_cdir = coveredvp;+ }+ if (fdp->fd_rdir &&+ fdp->fd_rdir->v_id == olddp->v_id) {+ vrele(fdp->fd_rdir);+ vref(coveredvp);+ fdp->fd_rdir = coveredvp;+ }+ }+ }+ coveredvp->v_mountedhere = NULL;+ vrele(coveredvp);+ }+ mp->mnt_vfc->vfc_refcount--;+ if (mp->mnt_vnodelist.lh_first != NULL)+ panic("unmount: dangling vnode");+ lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p);+ free((caddr_t)mp, M_MOUNT);+ return (0); } /*@@ -407,6 +500,7 @@ #endif /* ARGSUSED */+int sys_sync(p, v, retval) struct proc *p; void *v;@@ -415,31 +509,23 @@ register struct mount *mp, *nmp; int asyncflag; - for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {- /*- * Get the next pointer in case we hang on vfs_busy- * while we are being unmounted.- */- nmp = mp->mnt_list.cqe_next;- /*- * The lock check below is to avoid races with mount- * and unmount.- */- if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&- !vfs_busy(mp)) {+ simple_lock(&mountlist_slock);+ TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mnt_list, nmp) {+ if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p))+ continue;+ if ((mp->mnt_flag & MNT_RDONLY) == 0) { asyncflag = mp->mnt_flag & MNT_ASYNC; mp->mnt_flag &= ~MNT_ASYNC;+ uvm_vnp_sync(mp); VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); if (asyncflag) mp->mnt_flag |= MNT_ASYNC;- /*- * Get the next pointer again, as the next filesystem- * might have been unmounted while we were sync'ing.- */- nmp = mp->mnt_list.cqe_next;- vfs_unbusy(mp); }+ simple_lock(&mountlist_slock);+ vfs_unbusy(mp, p); }+ simple_unlock(&mountlist_slock);+ #ifdef DEBUG if (syncprt) vfs_bufstats();@@ -451,6 +537,7 @@ * Change filesystem quotas. */ /* ARGSUSED */+int sys_quotactl(p, v, retval) struct proc *p; void *v;@@ -467,7 +554,7 @@ struct nameidata nd; Lines 1–500 of 3182. Load more
--- diff-t9.l +++ diff-t9.r @@ -1,4 +1,5 @@ -/* $NetBSD: vfs_syscalls.c,v 1.57 1995/10/07 06:28:51 mycroft Exp $ */ +/* $OpenBSD: t9.2,v 1.2 2013/12/01 16:40:56 krw Exp $ */ +/* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ /* * Copyright (c) 1989, 1993 @@ -17,11 +18,7 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. 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. * @@ -53,13 +50,30 @@ #include <sys/uio.h> #include <sys/malloc.h> #include <sys/dirent.h> +#include <sys/extattr.h> #include <sys/syscallargs.h> -#include <vm/vm.h> +#include <uvm/uvm_extern.h> #include <sys/sysctl.h> -static int change_dir __P((struct nameidata *ndp, struct proc *p)); +extern int suid_clear; +int usermount = 0; /* sysctl: by default, users may not mount */ + +static int change_dir(struct nameidata *, struct proc *); + +void checkdirs(struct vnode *); + +/* + * Redirection info so we don't have to include the union fs routines in + * the kernel directly. This way, we can build unionfs as an LKM. The + * pointer gets filled in later, when we modload the LKM, or when the + * compiled-in unionfs code gets initialized. For now, we just set + * it to a stub routine. + */ + +int (*union_check_p)(struct proc *, struct vnode **, + struct file *, struct uio, int *) = NULL; /* * Virtual File System System Calls @@ -69,6 +83,7 @@ * Mount a file system. */ /* ARGSUSED */ +int sys_mount(p, v, retval) struct proc *p; void *v; @@ -78,22 +93,36 @@ syscallarg(char *) type; syscallarg(char *) path; syscallarg(int) flags; - syscallarg(caddr_t) data; + syscallarg(void *) data; } */ *uap = v; register struct vnode *vp; register struct mount *mp; - int error, flag; - u_long fsindex; + int error, flag = 0; +#ifdef COMPAT_43 + u_long fstypenum = 0; +#endif char fstypename[MFSNAMELEN]; + char fspath[MNAMELEN]; struct vattr va; struct nameidata nd; + struct vfsconf *vfsp; + struct timeval tv; + + if (usermount == 0 && (error = suser(p->p_ucred, &p->p_acflag))) + return (error); + + /* + * Mount points must fit in MNAMELEN, not MAXPATHLEN. + */ + error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL); + if (error) + return(error); /* * Get vnode to be covered */ - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, - SCARG(uap, path), p); - if (error = namei(&nd)) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, p); + if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; if (SCARG(uap, flags) & MNT_UPDATE) { @@ -113,7 +142,7 @@ return (EOPNOTSUPP); /* Needs translation */ } mp->mnt_flag |= - SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); + SCARG(uap, flags) & (MNT_RELOAD | MNT_UPDATE); /* * Only root, or the user that did the original mount is * permitted to update it. @@ -134,7 +163,11 @@ } SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; } - VOP_UNLOCK(vp); + if ((error = vfs_busy(mp, LK_NOWAIT, 0, p)) != 0) { + vput(vp); + return (error); + } + VOP_UNLOCK(vp, 0, p); goto update; } /* @@ -143,7 +176,7 @@ */ if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || (va.va_uid != p->p_ucred->cr_uid && - (error = suser(p->p_ucred, &p->p_acflag)))) { + (error = suser(p->p_ucred, &p->p_acflag)))) { vput(vp); return (error); } @@ -158,40 +191,47 @@ } SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; } - if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) + if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) return (error); if (vp->v_type != VDIR) { vput(vp); return (ENOTDIR); } - if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, - (size_t *)0)) { -#if defined(COMPAT_09) || defined(COMPAT_43) + error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL); + if (error) { +#ifdef COMPAT_43 /* * Historically filesystem types were identified by number. * If we get an integer for the filesystem type instead of a * string, we check to see if it matches one of the historic * filesystem types. - */ - fsindex = (u_long)SCARG(uap, type); - if (fsindex >= nvfssw || vfssw[fsindex] == NULL) { + */ + fstypenum = (u_long)SCARG(uap, type); + + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) + if (vfsp->vfc_typenum == fstypenum) + break; + if (vfsp == NULL) { vput(vp); return (ENODEV); } - strncpy(fstypename, vfssw[fsindex]->vfs_name, MFSNAMELEN); + strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); + #else vput(vp); return (error); #endif } - for (fsindex = 0; fsindex < nvfssw; fsindex++) - if (vfssw[fsindex] != NULL && - !strncmp(vfssw[fsindex]->vfs_name, fstypename, MFSNAMELEN)) + for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { + if (!strcmp(vfsp->vfc_name, fstypename)) break; - if (fsindex >= nvfssw) { + } + + if (vfsp == NULL) { vput(vp); - return (ENODEV); + return (EOPNOTSUPP); } + if (vp->v_mountedhere != NULL) { vput(vp); return (EBUSY); @@ -203,15 +243,14 @@ mp = (struct mount *)malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); bzero((char *)mp, (u_long)sizeof(struct mount)); - mp->mnt_op = vfssw[fsindex]; - if (error = vfs_lock(mp)) { - free((caddr_t)mp, M_MOUNT); - vput(vp); - return (error); - } - /* Do this early in case we block later. */ - vfssw[fsindex]->vfs_refcount++; - vp->v_mountedhere = mp; + lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); + /* This error never happens, but it makes auditing easier */ + if ((error = vfs_busy(mp, LK_NOWAIT, 0, p))) + return (error); + mp->mnt_op = vfsp->vfc_vfsops; + mp->mnt_vfc = vfsp; + mp->mnt_flag |= (vfsp->vfc_flags & MNT_VISFLAGMASK); + strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); mp->mnt_vnodecovered = vp; mp->mnt_stat.f_owner = p->p_ucred->cr_uid; update: @@ -223,13 +262,19 @@ else if (mp->mnt_flag & MNT_RDONLY) mp->mnt_flag |= MNT_WANTRDWR; mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | - MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); + MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_SOFTDEP | + MNT_NOATIME | MNT_FORCE); mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | - MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); + MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | + MNT_SOFTDEP | MNT_NOATIME | MNT_FORCE); /* * Mount the filesystem. */ error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); + if (!error) { + microtime(&tv); + mp->mnt_stat.f_ctime = tv.tv_sec; + } if (mp->mnt_flag & MNT_UPDATE) { vrele(vp); if (mp->mnt_flag & MNT_WANTRDWR) @@ -238,23 +283,42 @@ (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); if (error) mp->mnt_flag = flag; + + if ((mp->mnt_flag & MNT_RDONLY) == 0) { + if (mp->mnt_syncer == NULL) + error = vfs_allocate_syncvnode(mp); + } else { + if (mp->mnt_syncer != NULL) + vgone(mp->mnt_syncer); + mp->mnt_syncer = NULL; + } + + vfs_unbusy(mp, p); return (error); } + + vp->v_mountedhere = mp; + /* * Put the new filesystem on the mount list after root. */ cache_purge(vp); if (!error) { + vfsp->vfc_refcount++; + simple_lock(&mountlist_slock); TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); + simple_unlock(&mountlist_slock); checkdirs(vp); - VOP_UNLOCK(vp); - vfs_unlock(mp); + VOP_UNLOCK(vp, 0, p); + if ((mp->mnt_flag & MNT_RDONLY) == 0) + error = vfs_allocate_syncvnode(mp); + vfs_unbusy(mp, p); (void) VFS_STATFS(mp, &mp->mnt_stat, p); - error = VFS_START(mp, 0, p); + if ((error = VFS_START(mp, 0, p)) != 0) + vrele(vp); } else { mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; - vfssw[fsindex]->vfs_refcount--; - vfs_unlock(mp); + vfs_unbusy(mp, p); free((caddr_t)mp, M_MOUNT); vput(vp); } @@ -266,6 +330,7 @@ * or root directory onto which the new filesystem has just been * mounted. If so, replace them with the new mount point. */ +void checkdirs(olddp) struct vnode *olddp; { @@ -277,7 +342,7 @@ return; if (VFS_ROOT(olddp->v_mountedhere, &newdp)) panic("mount: lost mount"); - for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { + for (p = LIST_FIRST(&allproc); p != 0; p = LIST_NEXT(p, p_list)) { fdp = p->p_fd; if (fdp->fd_cdir == olddp) { vrele(fdp->fd_cdir); @@ -305,6 +370,7 @@ * not special file (as before). */ /* ARGSUSED */ +int sys_unmount(p, v, retval) struct proc *p; void *v; @@ -321,7 +387,7 @@ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, SCARG(uap, path), p); - if (error = namei(&nd)) + if ((error = namei(&nd)) != 0) return (error); vp = nd.ni_vp; mp = vp->v_mount; @@ -352,50 +418,77 @@ return (EINVAL); } vput(vp); - return (dounmount(mp, SCARG(uap, flags), p)); + + if (vfs_busy(mp, LK_EXCLUSIVE, NULL, p)) + return (EBUSY); + + return (dounmount(mp, SCARG(uap, flags), p, vp)); } /* * Do the actual file system unmount. */ -dounmount(mp, flags, p) - register struct mount *mp; - int flags; - struct proc *p; +int +dounmount(struct mount *mp, int flags, struct proc *p, struct vnode *olddp) { struct vnode *coveredvp; + struct proc *p2; int error; + int hadsyncer = 0; - coveredvp = mp->mnt_vnodecovered; - if (vfs_busy(mp)) - return (EBUSY); - mp->mnt_flag |= MNT_UNMOUNT; - if (error = vfs_lock(mp)) - return (error); - - mp->mnt_flag &=~ MNT_ASYNC; - vnode_pager_umount(mp); /* release cached vnodes */ - cache_purgevfs(mp); /* remove cache entries for this file sys */ - if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || - (flags & MNT_FORCE)) - error = VFS_UNMOUNT(mp, flags, p); - mp->mnt_flag &= ~MNT_UNMOUNT; - vfs_unbusy(mp); - if (error) { - vfs_unlock(mp); - } else { - TAILQ_REMOVE(&mountlist, mp, mnt_list); - if (coveredvp != NULLVP) { - vrele(coveredvp); - coveredvp->v_mountedhere = (struct mount *)0; - } - mp->mnt_op->vfs_refcount--; - vfs_unlock(mp); - if (mp->mnt_vnodelist.lh_first != NULL) - panic("unmount: dangling vnode"); - free((caddr_t)mp, M_MOUNT); - } - return (error); + mp->mnt_flag &=~ MNT_ASYNC; + cache_purgevfs(mp); /* remove cache entries for this file sys */ + if (mp->mnt_syncer != NULL) { + hadsyncer = 1; + vgone(mp->mnt_syncer); + mp->mnt_syncer = NULL; + } + if (((mp->mnt_flag & MNT_RDONLY) || + (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || + (flags & MNT_FORCE)) + error = VFS_UNMOUNT(mp, flags, p); + simple_lock(&mountlist_slock); + if (error) { + if ((mp->mnt_flag & MNT_RDONLY) == 0 && hadsyncer) + (void) vfs_allocate_syncvnode(mp); + lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, + &mountlist_slock, p); + return (error); + } + TAILQ_REMOVE(&mountlist, mp, mnt_list); + if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { + if (olddp) { + /* + * Try to put processes back in a real directory + * after a forced unmount. + * XXX We're not holding a ref on olddp, which may + * change, so compare id numbers. + */ + LIST_FOREACH(p2, &allproc, p_list) { + struct filedesc *fdp = p2->p_fd; + if (fdp->fd_cdir && + fdp->fd_cdir->v_id == olddp->v_id) { + vrele(fdp->fd_cdir); + vref(coveredvp); + fdp->fd_cdir = coveredvp; + } + if (fdp->fd_rdir && + fdp->fd_rdir->v_id == olddp->v_id) { + vrele(fdp->fd_rdir); + vref(coveredvp); + fdp->fd_rdir = coveredvp; + } + } + } + coveredvp->v_mountedhere = NULL; + vrele(coveredvp); + } + mp->mnt_vfc->vfc_refcount--; + if (mp->mnt_vnodelist.lh_first != NULL) + panic("unmount: dangling vnode"); + lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p); + free((caddr_t)mp, M_MOUNT); + return (0); } /* @@ -407,6 +500,7 @@ #endif /* ARGSUSED */ +int sys_sync(p, v, retval) struct proc *p; void *v; @@ -415,31 +509,23 @@ register struct mount *mp, *nmp; int asyncflag; - for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { - /* - * Get the next pointer in case we hang on vfs_busy - * while we are being unmounted. - */ - nmp = mp->mnt_list.cqe_next; - /* - * The lock check below is to avoid races with mount - * and unmount. - */ - if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && - !vfs_busy(mp)) { + simple_lock(&mountlist_slock); + TAILQ_FOREACH_REVERSE_SAFE(mp, &mountlist, mnt_list, nmp) { + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) + continue; + if ((mp->mnt_flag & MNT_RDONLY) == 0) { asyncflag = mp->mnt_flag & MNT_ASYNC; mp->mnt_flag &= ~MNT_ASYNC; + uvm_vnp_sync(mp); VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); if (asyncflag) mp->mnt_flag |= MNT_ASYNC; - /* - * Get the next pointer again, as the next filesystem - * might have been unmounted while we were sync'ing. - */ - nmp = mp->mnt_list.cqe_next; - vfs_unbusy(mp); } + simple_lock(&mountlist_slock); + vfs_unbusy(mp, p); } + simple_unlock(&mountlist_slock); + #ifdef DEBUG if (syncprt) vfs_bufstats(); @@ -451,6 +537,7 @@ * Change filesystem quotas. */ /* ARGSUSED */ +int sys_quotactl(p, v, retval) struct proc *p; void *v; @@ -467,7 +554,7 @@ struct nameidata nd;