PERFORCE change 120919 for review

Roman Divacky rdivacky at FreeBSD.org
Mon Jun 4 17:23:59 UTC 2007


http://perforce.freebsd.org/chv.cgi?CH=120919

Change 120919 by rdivacky at rdivacky_witten on 2007/06/04 17:23:48

	o	Introduce kern_get_at() function instead of duplicating the same
		code everywhere
	o	Reimplement kern_symlink and kern_unlink as wrappers around their *at
		counterparts to avoid code duplication
	o	vrele(dir_vn) in kern_symlink and kern_unlink as necessary
	
	The code upto this commit has bugs :( including panics, deadlocks etc.

Affected files ...

.. //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_syscalls.c#15 edit

Differences ...

==== //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_syscalls.c#15 (text+ko) ====

@@ -85,6 +85,7 @@
 static int setfflags(struct thread *td, struct vnode *, int);
 static int setutimes(struct thread *td, struct vnode *,
     const struct timespec *, int, int);
+static int kern_get_at(struct thread *td, int dirfd, struct vnode **dir_vn);
 static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
     struct thread *td);
 static int kern_common_open(struct thread *td, int flags, int mode,
@@ -984,6 +985,26 @@
 	return kern_common_open(td, flags, mode, &nd);
 }
 
+static int
+kern_get_at(struct thread *td, int dirfd, struct vnode **dir_vn)
+{
+	int error;
+
+	if (dirfd == AT_FDCWD)
+		*dir_vn = NULL;
+	else {
+		error = fgetvp(td, dirfd, dir_vn);
+		if (error)
+			return (error);
+		if ((*dir_vn)->v_type != VDIR) {
+			vrele(*dir_vn);
+			return (ENOTDIR);
+		}
+	}
+
+	return (0);
+}
+
 int
 kern_openat(struct thread *td, char *path, enum uio_seg pathseg, int flags,
     int mode, int dirfd)
@@ -996,22 +1017,14 @@
 	AUDIT_ARG(mode, mode);
 	/* XXX: audit dirfd */
 
-	if (dirfd == AT_FDCWD)
-		dir_vn = NULL;
-	else {
-		error = fgetvp(td, dirfd, &dir_vn);
-		if (error)
-			return (error);
-		if (dir_vn->v_type != VDIR) {
-			vrele(dir_vn);
-			return (ENOTDIR);
-		}
-	}
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 
 	NDINIT_AT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td, dir_vn);
 
 	error = kern_common_open(td, flags, mode, &nd);
-	if (dirfd != AT_FDCWD)
+	if (dir_vn)
 		vrele(dir_vn);
 	return (error);
 }
@@ -1462,47 +1475,25 @@
 	int error;
 	struct vnode *pdir_vn, *ldir_vn;
 
-	if (olddirfd == AT_FDCWD)
-		pdir_vn = NULL;
-	else {
-		error = fgetvp(td, olddirfd, &pdir_vn);
-		if (error)
-			return (error);
-		if (pdir_vn->v_type != VDIR) {
-			vrele(pdir_vn);
-			return (ENOTDIR);
-		}
-	}
+	error = kern_get_at(td, olddirfd, &pdir_vn);
+	if (error)
+		return (error);
 
 	NDINIT_AT(&ndp, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, segflg, path, td, pdir_vn);
 
-	if (newdirfd == AT_FDCWD)
-		ldir_vn = NULL;
-	else {
-		error = fgetvp(td, newdirfd, &ldir_vn);
-		if (error)
-			return (error);
-		if (ldir_vn->v_type != VDIR) {
-			vrele(ldir_vn);
-			return (ENOTDIR);
-		}
-	}
+	error = kern_get_at(td, newdirfd, &ldir_vn);
+	if (error)
+		return (error);
 
 	NDINIT_AT(&ndl, CREATE, LOCKPARENT | SAVENAME| MPSAFE | AUDITVNODE1, segflg,
 		link, td, ldir_vn);
 
 	error = kern_common_link(td, &ndp, &ndl);
-	if (olddirfd != AT_FDCWD)
+	if (pdir_vn)
 		vrele(pdir_vn);
-	if (newdirfd != AT_FDCWD)
+	if (ldir_vn)
 		vrele(ldir_vn);
 	return (error);
-
-	NDINIT(&ndp, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, segflg, path, td);
-	NDINIT(&ndl, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE2,
-	    segflg, link, td);
-
-	return kern_common_link(td, &ndp, &ndl);
 }
 
 static int
@@ -1587,73 +1578,7 @@
 int
 kern_symlink(struct thread *td, char *path, char *link, enum uio_seg segflg)
 {
-	struct mount *mp;
-	struct vattr vattr;
-	char *syspath;
-	int error;
-	struct nameidata nd;
-	int vfslocked;
-
-	if (segflg == UIO_SYSSPACE) {
-		syspath = path;
-	} else {
-		syspath = uma_zalloc(namei_zone, M_WAITOK);
-		if ((error = copyinstr(path, syspath, MAXPATHLEN, NULL)) != 0)
-			goto out;
-	}
-	AUDIT_ARG(text, syspath);
-restart:
-	bwillwrite();
-	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
-	    segflg, link, td);
-	if ((error = namei(&nd)) != 0)
-		goto out;
-	vfslocked = NDHASGIANT(&nd);
-	if (nd.ni_vp) {
-		NDFREE(&nd, NDF_ONLY_PNBUF);
-		if (nd.ni_vp == nd.ni_dvp)
-			vrele(nd.ni_dvp);
-		else
-			vput(nd.ni_dvp);
-		vrele(nd.ni_vp);
-		VFS_UNLOCK_GIANT(vfslocked);
-		error = EEXIST;
-		goto out;
-	}
-	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
-		NDFREE(&nd, NDF_ONLY_PNBUF);
-		vput(nd.ni_dvp);
-		VFS_UNLOCK_GIANT(vfslocked);
-		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
-			goto out;
-		goto restart;
-	}
-	VATTR_NULL(&vattr);
-	FILEDESC_SLOCK(td->td_proc->p_fd);
-	vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask;
-	FILEDESC_SUNLOCK(td->td_proc->p_fd);
-#ifdef MAC
-	vattr.va_type = VLNK;
-	error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd,
-	    &vattr);
-	if (error)
-		goto out2;
-#endif
-	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
-	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, syspath);
-	if (error == 0)
-		vput(nd.ni_vp);
-#ifdef MAC
-out2:
-#endif
-	NDFREE(&nd, NDF_ONLY_PNBUF);
-	vput(nd.ni_dvp);
-	vn_finished_write(mp);
-	VFS_UNLOCK_GIANT(vfslocked);
-out:
-	if (segflg != UIO_SYSSPACE)
-		uma_zfree(namei_zone, syspath);
-	return (error);
+	return kern_symlinkat(td, path, link, segflg, AT_FDCWD);
 }
 
 int
@@ -1666,7 +1591,7 @@
 	int error;
 	struct nameidata nd;
 	int vfslocked;
-	struct vnode *dir_vn;
+	struct vnode *dir_vn = NULL;
 
 	if (segflg == UIO_SYSSPACE) {
 		syspath = path;
@@ -1677,17 +1602,11 @@
 	}
 	AUDIT_ARG(text, syspath);
 restart:
-	if (dirfd == AT_FDCWD)
-		dir_vn = NULL;
-	else {
-		error = fgetvp(td, dirfd, &dir_vn);
-		if (error)
-			return (error);
-		if (dir_vn->v_type != VDIR) {
-			vrele(dir_vn);
-			return (ENOTDIR);
-		}
-	}
+	if (dir_vn)
+		vrele(dir_vn);
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 	bwillwrite();
 	NDINIT_AT(&nd, CREATE, LOCKPARENT | SAVENAME | MPSAFE | AUDITVNODE1,
 	    segflg, link, td, dir_vn);
@@ -1736,6 +1655,8 @@
 	vn_finished_write(mp);
 	VFS_UNLOCK_GIANT(vfslocked);
 out:
+	if (dir_vn)
+		vrele(dir_vn);
 	if (segflg != UIO_SYSSPACE)
 		uma_zfree(namei_zone, syspath);
 	return (error);
@@ -1817,94 +1738,32 @@
 int
 kern_unlink(struct thread *td, char *path, enum uio_seg pathseg)
 {
-	struct mount *mp;
-	struct vnode *vp;
-	int error;
-	struct nameidata nd;
-	int vfslocked;
-
-restart:
-	bwillwrite();
-	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
-	if ((error = namei(&nd)) != 0)
-		return (error == EINVAL ? EPERM : error);
-	vfslocked = NDHASGIANT(&nd);
-	vp = nd.ni_vp;
-	if (vp->v_type == VDIR)
-		error = EPERM;		/* POSIX */
-	else {
-		/*
-		 * The root of a mounted filesystem cannot be deleted.
-		 *
-		 * XXX: can this only be a VDIR case?
-		 */
-		if (vp->v_vflag & VV_ROOT)
-			error = EBUSY;
-	}
-	if (error == 0) {
-		if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
-			NDFREE(&nd, NDF_ONLY_PNBUF);
-			vput(nd.ni_dvp);
-			if (vp == nd.ni_dvp)
-				vrele(vp);
-			else
-				vput(vp);
-			VFS_UNLOCK_GIANT(vfslocked);
-			if ((error = vn_start_write(NULL, &mp,
-			    V_XSLEEP | PCATCH)) != 0)
-				return (error);
-			goto restart;
-		}
-#ifdef MAC
-		error = mac_check_vnode_delete(td->td_ucred, nd.ni_dvp, vp,
-		    &nd.ni_cnd);
-		if (error)
-			goto out;
-#endif
-		VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
-		error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
-#ifdef MAC
-out:
-#endif
-		vn_finished_write(mp);
-	}
-	NDFREE(&nd, NDF_ONLY_PNBUF);
-	vput(nd.ni_dvp);
-	if (vp == nd.ni_dvp)
-		vrele(vp);
-	else
-		vput(vp);
-	VFS_UNLOCK_GIANT(vfslocked);
-	return (error);
+	return kern_unlinkat(td, path, pathseg, AT_FDCWD);
 }
 
 int
 kern_unlinkat(struct thread *td, char *path, enum uio_seg pathseg, int dirfd)
 {
 	struct mount *mp;
-	struct vnode *vp, *dir_vn;
+	struct vnode *vp, *dir_vn = NULL;
 	int error;
 	struct nameidata nd;
 	int vfslocked;
 	
 restart:
-	if (dirfd == AT_FDCWD)
-		dir_vn = NULL;
-	else {
-		error = fgetvp(td, dirfd, &dir_vn);
-		if (error)
-			return (error);
-		if (dir_vn->v_type != VDIR) {
-			vrele(dir_vn);
-			return (ENOTDIR);
-		}
-	}
+	if (dir_vn)
+		vrele(dir_vn);
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 	bwillwrite();
 	NDINIT_AT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
 	    pathseg, path, td, dir_vn);
-	if ((error = namei(&nd)) != 0)
+	if ((error = namei(&nd)) != 0) {
+		if (dir_vn)
+			vrele(dir_vn);		
 		return (error == EINVAL ? EPERM : error);
+	}
 	vfslocked = NDHASGIANT(&nd);
 	vp = nd.ni_vp;
 	if (vp->v_type == VDIR)
@@ -1928,8 +1787,11 @@
 				vput(vp);
 			VFS_UNLOCK_GIANT(vfslocked);
 			if ((error = vn_start_write(NULL, &mp,
-			    V_XSLEEP | PCATCH)) != 0)
+			    V_XSLEEP | PCATCH)) != 0) {
+				if (dir_vn)
+					vrele(dir_vn);
 				return (error);
+			}
 			goto restart;
 		}
 #ifdef MAC
@@ -1947,6 +1809,8 @@
 	}
 	NDFREE(&nd, NDF_ONLY_PNBUF);
 	vput(nd.ni_dvp);
+	if (dir_vn)
+		vrele(dir_vn);
 	if (vp == nd.ni_dvp)
 		vrele(vp);
 	else
@@ -2149,23 +2013,15 @@
 	struct nameidata nd;
 	struct vnode *dir_vn;
 
-	if (dirfd == AT_FDCWD)
-		dir_vn = NULL;
-	else {
-		error = fgetvp(td, dirfd, &dir_vn);
-		if (error)
-			return (error);
-		if (dir_vn->v_type != VDIR) {
-			vrele(dir_vn);
-			return (ENOTDIR);
-		}
-	}
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 
 	NDINIT_AT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
 	    pathseg, path, td, dir_vn);
 
 	error = kern_common_access(td, flags, &nd);
-	if (dirfd != AT_FDCWD)
+	if (dir_vn)
 		vrele(dir_vn);
 	return (error);
 }
@@ -2379,23 +2235,15 @@
 	struct nameidata nd;
 	struct vnode *dir_vn;
 
-	if (dirfd == AT_FDCWD)
-		dir_vn = NULL;
-	else {
-		error = fgetvp(td, dirfd, &dir_vn);
-		if (error)
-			return (error);
-		if (dir_vn->v_type != VDIR) {
-			vrele(dir_vn);
-			return (ENOTDIR);
-		}
-	}
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 
 	NDINIT_AT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1 | 
 		MPSAFE, pathseg, path, td, dir_vn);
 
 	error = kern_common_stat(td, sbp, &nd);
-	if (dirfd != AT_FDCWD)
+	if (dir_vn)
 		vrele(dir_vn);
 	return (error);
 }
@@ -2466,23 +2314,15 @@
 	struct nameidata nd;
 	struct vnode *dir_vn;
 
-	if (dirfd == AT_FDCWD)
-		dir_vn = NULL;
-	else {
-		error = fgetvp(td, dirfd, &dir_vn);
-		if (error)
-			return (error);
-		if (dir_vn->v_type != VDIR) {
-			vrele(dir_vn);
-			return (ENOTDIR);
-		}
-	}
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 
 	NDINIT_AT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKSHARED | AUDITVNODE1 | 
 		MPSAFE, pathseg, path, td, dir_vn);
 
 	error = kern_common_lstat(td, sbp, &nd);
-	if (dirfd != AT_FDCWD)
+	if (dir_vn)
 		vrele(dir_vn);
 	return (error);
 }
@@ -2677,23 +2517,15 @@
 	struct nameidata nd;
 	struct vnode *dir_vn;
 
-	if (dirfd == AT_FDCWD)
-		dir_vn = NULL;
-	else {
-		error = fgetvp(td, dirfd, &dir_vn);
-		if (error)
-			return (error);
-		if (dir_vn->v_type != VDIR) {
-			vrele(dir_vn);
-			return (ENOTDIR);
-		}
-	}
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 
 	NDINIT_AT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, pathseg,
 		path, td, dir_vn);
 
 	error = kern_common_readlink(td, buf, bufseg, count, &nd);
-	if (dirfd != AT_FDCWD)
+	if (dir_vn)
 		vrele(dir_vn);
 	return (error);
 }
@@ -2950,22 +2782,14 @@
 	struct nameidata nd;
 	struct vnode *dir_vn;
 
-	if (dirfd == AT_FDCWD)
-		dir_vn = NULL;
-	else {
-		error = fgetvp(td, dirfd, &dir_vn);
-		if (error)
-			return (error);
-		if (dir_vn->v_type != VDIR) {
-			vrele(dir_vn);
-			return (ENOTDIR);
-		}
-	}
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 
 	NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn);
 
 	error = kern_common_chmod(td, mode, &nd);
-	if (dirfd != AT_FDCWD)
+	if (dir_vn)
 		vrele(dir_vn);
 	return (error);
 }
@@ -3132,22 +2956,14 @@
 	struct nameidata nd;
 	struct vnode *dir_vn;
 
-	if (dirfd == AT_FDCWD)
-		dir_vn = NULL;
-	else {
-		error = fgetvp(td, dirfd, &dir_vn);
-		if (error)
-			return (error);
-		if (dir_vn->v_type != VDIR) {
-			vrele(dir_vn);
-			return (ENOTDIR);
-		}
-	}
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 
 	NDINIT_AT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn);
 
 	error = kern_common_chown(td, uid, gid, &nd);
-	if (dirfd != AT_FDCWD)
+	if (dir_vn)
 		vrele(dir_vn);
 	return (error);
 }
@@ -3211,22 +3027,14 @@
 	struct nameidata nd;
 	struct vnode *dir_vn;
 
-	if (dirfd == AT_FDCWD)
-		dir_vn = NULL;
-	else {
-		error = fgetvp(td, dirfd, &dir_vn);
-		if (error)
-			return (error);
-		if (dir_vn->v_type != VDIR) {
-			vrele(dir_vn);
-			return (ENOTDIR);
-		}
-	}
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 
 	NDINIT_AT(&nd, LOOKUP, NOFOLLOW | MPSAFE | AUDITVNODE1, pathseg, path, td, dir_vn);
 
 	error = kern_common_chown(td, uid, gid, &nd);
-	if (dirfd != AT_FDCWD)
+	if (dir_vn)
 		vrele(dir_vn);
 	return (error);
 
@@ -3978,69 +3786,7 @@
 int
 kern_rmdir(struct thread *td, char *path, enum uio_seg pathseg)
 {
-	struct mount *mp;
-	struct vnode *vp;
-	int error;
-	struct nameidata nd;
-	int vfslocked;
-
-restart:
-	bwillwrite();
-	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
-	    pathseg, path, td);
-	if ((error = namei(&nd)) != 0)
-		return (error);
-	vfslocked = NDHASGIANT(&nd);
-	vp = nd.ni_vp;
-	if (vp->v_type != VDIR) {
-		error = ENOTDIR;
-		goto out;
-	}
-	/*
-	 * No rmdir "." please.
-	 */
-	if (nd.ni_dvp == vp) {
-		error = EINVAL;
-		goto out;
-	}
-	/*
-	 * The root of a mounted filesystem cannot be deleted.
-	 */
-	if (vp->v_vflag & VV_ROOT) {
-		error = EBUSY;
-		goto out;
-	}
-#ifdef MAC
-	error = mac_check_vnode_delete(td->td_ucred, nd.ni_dvp, vp,
-	    &nd.ni_cnd);
-	if (error)
-		goto out;
-#endif
-	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
-		NDFREE(&nd, NDF_ONLY_PNBUF);
-		vput(vp);
-		if (nd.ni_dvp == vp)
-			vrele(nd.ni_dvp);
-		else
-			vput(nd.ni_dvp);
-		VFS_UNLOCK_GIANT(vfslocked);
-		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
-			return (error);
-		goto restart;
-	}
-	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
-	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
-	error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
-	vn_finished_write(mp);
-out:
-	NDFREE(&nd, NDF_ONLY_PNBUF);
-	vput(vp);
-	if (nd.ni_dvp == vp)
-		vrele(nd.ni_dvp);
-	else
-		vput(nd.ni_dvp);
-	VFS_UNLOCK_GIANT(vfslocked);
-	return (error);
+	return kern_rmdirat(td, path, pathseg, AT_FDCWD);
 }
 
 int
@@ -4053,17 +3799,9 @@
 	int vfslocked;
 
 restart:
-	if (dirfd == AT_FDCWD)
-		dir_vn = NULL;
-	else {
-		error = fgetvp(td, dirfd, &dir_vn);
-		if (error)
-			return (error);
-		if (dir_vn->v_type != VDIR) {
-			vrele(dir_vn);
-			return (ENOTDIR);
-		}
-	}
+	error = kern_get_at(td, dirfd, &dir_vn);
+	if (error)
+		return (error);
 	bwillwrite();
 	NDINIT_AT(&nd, DELETE, LOCKPARENT | LOCKLEAF | MPSAFE | AUDITVNODE1,
 	    pathseg, path, td, dir_vn);


More information about the p4-projects mailing list