PERFORCE change 100171 for review

John Baldwin jhb at FreeBSD.org
Tue Jun 27 20:55:54 UTC 2006


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

Change 100171 by jhb at jhb_mutex on 2006/06/27 20:55:43

	Revert last.  All the other places that do getdirentries() do
	things differently.  It's going to be simpler to just add the
	VFS Giant locking I think.

Affected files ...

.. //depot/projects/smpng/sys/kern/vfs_syscalls.c#108 edit
.. //depot/projects/smpng/sys/sys/syscallsubr.h#32 edit

Differences ...

==== //depot/projects/smpng/sys/kern/vfs_syscalls.c#108 (text+ko) ====

@@ -3563,67 +3563,144 @@
 		long *basep;
 	} */ *uap;
 {
+	struct vnode *vp;
+	struct file *fp;
+	struct uio auio, kuio;
+	struct iovec aiov, kiov;
 	struct dirent *dp, *edp;
-	char *dirbuf;
-	int error, readcnt, ufs_43;
-	long base;
+	caddr_t dirbuf;
+	int error, eofflag, readcnt, vfslocked;
+	long loff;
 
 	/* XXX arbitrary sanity limit on `count'. */
 	if (uap->count > 64 * 1024)
 		return (EINVAL);
-
-	dirbuf = malloc(uap->count, M_TEMP, M_WAITOK);
-	error = kern_getdirentries(td, uap->fd, dirbuf, uap->count, &base,
-	    UIO_SYSSPACE, &ufs_43);
+	if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
+		return (error);
+	if ((fp->f_flag & FREAD) == 0) {
+		fdrop(fp, td);
+		return (EBADF);
+	}
+	vp = fp->f_vnode;
+unionread:
+	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
+	if (vp->v_type != VDIR) {
+		VFS_UNLOCK_GIANT(vfslocked);
+		fdrop(fp, td);
+		return (EINVAL);
+	}
+	aiov.iov_base = uap->buf;
+	aiov.iov_len = uap->count;
+	auio.uio_iov = &aiov;
+	auio.uio_iovcnt = 1;
+	auio.uio_rw = UIO_READ;
+	auio.uio_segflg = UIO_USERSPACE;
+	auio.uio_td = td;
+	auio.uio_resid = uap->count;
+	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
+	loff = auio.uio_offset = fp->f_offset;
+#ifdef MAC
+	error = mac_check_vnode_readdir(td->td_ucred, vp);
 	if (error) {
-		free(dirbuf, M_TEMP);
+		VOP_UNLOCK(vp, 0, td);
+		VFS_UNLOCK_GIANT(vfslocked);
+		fdrop(fp, td);
 		return (error);
 	}
-
-	readcnt = td->td_retval[0];
+#endif
 #	if (BYTE_ORDER != LITTLE_ENDIAN)
-	/*
-	 * On big endian systems, we can return the contents from a 4.3
-	 * UFS without performing a fixup.
-	 */
-	if (!ufs_43) {
-#	else
+		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
+			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
+			    NULL, NULL);
+			fp->f_offset = auio.uio_offset;
+		} else
+#	endif
 	{
-#	endif
-		edp = (struct dirent *)&dirbuf[readcnt];
-		for (dp = (struct dirent *)dirbuf; dp < edp; ) {
-#			if (BYTE_ORDER == LITTLE_ENDIAN)
-				/*
-				 * The expected low byte of
-				 * dp->d_namlen is our dp->d_type.
-				 * The high MBZ byte of dp->d_namlen
-				 * is our dp->d_namlen.
-				 */
-				dp->d_type = dp->d_namlen;
-				dp->d_namlen = 0;
-#			else
-				/*
-				 * The dp->d_type is the high byte
-				 * of the expected dp->d_namlen,
-				 * so must be zero'ed.
-				 */
-				dp->d_type = 0;
-#			endif
-			if (dp->d_reclen > 0) {
-				dp = (struct dirent *)
-				    ((char *)dp + dp->d_reclen);
-			} else {
-				error = EIO;
-				break;
+		kuio = auio;
+		kuio.uio_iov = &kiov;
+		kuio.uio_segflg = UIO_SYSSPACE;
+		kiov.iov_len = uap->count;
+		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
+		kiov.iov_base = dirbuf;
+		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
+			    NULL, NULL);
+		fp->f_offset = kuio.uio_offset;
+		if (error == 0) {
+			readcnt = uap->count - kuio.uio_resid;
+			edp = (struct dirent *)&dirbuf[readcnt];
+			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
+#				if (BYTE_ORDER == LITTLE_ENDIAN)
+					/*
+					 * The expected low byte of
+					 * dp->d_namlen is our dp->d_type.
+					 * The high MBZ byte of dp->d_namlen
+					 * is our dp->d_namlen.
+					 */
+					dp->d_type = dp->d_namlen;
+					dp->d_namlen = 0;
+#				else
+					/*
+					 * The dp->d_type is the high byte
+					 * of the expected dp->d_namlen,
+					 * so must be zero'ed.
+					 */
+					dp->d_type = 0;
+#				endif
+				if (dp->d_reclen > 0) {
+					dp = (struct dirent *)
+					    ((char *)dp + dp->d_reclen);
+				} else {
+					error = EIO;
+					break;
+				}
+			}
+			if (dp >= edp)
+				error = uiomove(dirbuf, readcnt, &auio);
+		}
+		FREE(dirbuf, M_TEMP);
+	}
+	VOP_UNLOCK(vp, 0, td);
+	if (error) {
+		VFS_UNLOCK_GIANT(vfslocked);
+		fdrop(fp, td);
+		return (error);
+	}
+	if (uap->count == auio.uio_resid) {
+		if (union_dircheckp) {
+			error = union_dircheckp(td, &vp, fp);
+			if (error == -1) {
+				VFS_UNLOCK_GIANT(vfslocked);
+				goto unionread;
+			}
+			if (error) {
+				VFS_UNLOCK_GIANT(vfslocked);
+				fdrop(fp, td);
+				return (error);
 			}
 		}
+		/*
+		 * XXX We could delay dropping the lock above but
+		 * union_dircheckp complicates things.
+		 */
+		vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, td);
+		if ((vp->v_vflag & VV_ROOT) &&
+		    (vp->v_mount->mnt_flag & MNT_UNION)) {
+			struct vnode *tvp = vp;
+			vp = vp->v_mount->mnt_vnodecovered;
+			VREF(vp);
+			fp->f_vnode = vp;
+			fp->f_data = vp;
+			fp->f_offset = 0;
+			vput(tvp);
+			VFS_UNLOCK_GIANT(vfslocked);
+			goto unionread;
+		}
+		VOP_UNLOCK(vp, 0, td);
 	}
-
-	if (error == 0)
-		error = copyout(dirbuf, uap->buf, readcnt);
-	free(dirbuf, M_TEMP);
-	if (error == 0)
-		error = copyout(&base, uap->basep, sizeof(long));
+	VFS_UNLOCK_GIANT(vfslocked);
+	error = copyout(&loff, uap->basep, sizeof(long));
+	fdrop(fp, td);
+	td->td_retval[0] = uap->count - auio.uio_resid;
 	return (error);
 }
 #endif /* COMPAT_43 */
@@ -3649,20 +3726,6 @@
 		long *basep;
 	} */ *uap;
 {
-	long base;
-	int error;
-
-	error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base,
-	    UIO_USERSPACE, NULL);
-	if (error == 0 && uap->basep != NULL)
-		error = copyout(&base, uap->basep, sizeof(long));
-	return (error);
-}
-
-int
-kern_getdirentries(struct thread *td, int fd, char *buf, u_int count,
-    long *basep, enum uio_seg bufseg, int *ufs_43)
-{
 	struct vnode *vp;
 	struct file *fp;
 	struct uio auio;
@@ -3671,38 +3734,28 @@
 	long loff;
 	int error, eofflag;
 
-	AUDIT_ARG(fd, fd);
-	if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0)
+	AUDIT_ARG(fd, uap->fd);
+	if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
 		return (error);
 	if ((fp->f_flag & FREAD) == 0) {
 		fdrop(fp, td);
 		return (EBADF);
 	}
 	vp = fp->f_vnode;
-#ifdef COMPAT_43
-	/*
-	 * This is for ogetdirentries() as it returns the contents of a
-	 * 4.3 UFS directly but has to massage the entries of a 4.4 UFS
-	 * to 4.3 binaries.  Can one even run any 4.3 binaries on any
-	 * version of FreeBSD?
-	 */
-	if (ufs_43 != NULL)
-		*ufs_43 = vp->v_mount->mnt_maxsymlinklen <= 0;
-#endif
 unionread:
 	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
 	if (vp->v_type != VDIR) {
 		error = EINVAL;
 		goto fail;
 	}
-	aiov.iov_base = buf;
-	aiov.iov_len = count;
+	aiov.iov_base = uap->buf;
+	aiov.iov_len = uap->count;
 	auio.uio_iov = &aiov;
 	auio.uio_iovcnt = 1;
 	auio.uio_rw = UIO_READ;
-	auio.uio_segflg = bufseg;
+	auio.uio_segflg = UIO_USERSPACE;
 	auio.uio_td = td;
-	auio.uio_resid = count;
+	auio.uio_resid = uap->count;
 	/* vn_lock(vp, LK_SHARED | LK_RETRY, td); */
 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
 	AUDIT_ARG(vnode, vp, ARG_VNODE1);
@@ -3717,7 +3770,7 @@
 	VOP_UNLOCK(vp, 0, td);
 	if (error)
 		goto fail;
-	if (count == auio.uio_resid) {
+	if (uap->count == auio.uio_resid) {
 		if (union_dircheckp) {
 			error = union_dircheckp(td, &vp, fp);
 			if (error == -1) {
@@ -3746,9 +3799,10 @@
 		}
 		VOP_UNLOCK(vp, 0, td);
 	}
-	if (basep != NULL)
-		*basep = loff;
-	td->td_retval[0] = count - auio.uio_resid;
+	if (uap->basep != NULL) {
+		error = copyout(&loff, uap->basep, sizeof(long));
+	}
+	td->td_retval[0] = uap->count - auio.uio_resid;
 fail:
 	VFS_UNLOCK_GIANT(vfslocked);
 	fdrop(fp, td);
@@ -3770,9 +3824,12 @@
 		u_int count;
 	} */ *uap;
 {
-
-	return (kern_getdirentries(td, uap->fd, uap->buf, uap->count, NULL,
-		UIO_USERSPACE, NULL));
+	struct getdirentries_args ap;
+	ap.fd = uap->fd;
+	ap.buf = uap->buf;
+	ap.count = uap->count;
+	ap.basep = NULL;
+	return (getdirentries(td, &ap));
 }
 
 /*

==== //depot/projects/smpng/sys/sys/syscallsubr.h#32 (text+ko) ====

@@ -79,8 +79,6 @@
 int	kern_fstatfs(struct thread *td, int fd, struct statfs *buf);
 int	kern_futimes(struct thread *td, int fd, struct timeval *tptr,
 	    enum uio_seg tptrseg);
-int	kern_getdirentries(struct thread *td, int fd, char *buf, u_int count,
-	    long *basep, enum uio_seg bufseg, int *ufs_43);
 int	kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
 	    enum uio_seg bufseg, int flags);
 int	kern_getitimer(struct thread *, u_int, struct itimerval *);


More information about the p4-projects mailing list