3182 lines · 76.8 KB · Text
RawDownload
--- 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.