PERFORCE change 100167 for review

John Baldwin jhb at FreeBSD.org
Tue Jun 27 20:56:50 UTC 2006


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

Change 100167 by jhb at jhb_mutex on 2006/06/27 19:50:52

	Add a kern_getdirentries() and convert getdirentries(), getdents(),
	and ogetdirentries() to use it.  ogetdirentries() is crufty and
	involved some mild pain.

Affected files ...

.. //depot/projects/smpng/sys/kern/vfs_syscalls.c#107 edit
.. //depot/projects/smpng/sys/sys/syscallsubr.h#31 edit

Differences ...

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

@@ -3563,144 +3563,67 @@
 		long *basep;
 	} */ *uap;
 {
-	struct vnode *vp;
-	struct file *fp;
-	struct uio auio, kuio;
-	struct iovec aiov, kiov;
 	struct dirent *dp, *edp;
-	caddr_t dirbuf;
-	int error, eofflag, readcnt, vfslocked;
-	long loff;
+	char *dirbuf;
+	int error, readcnt, ufs_43;
+	long base;
 
 	/* XXX arbitrary sanity limit on `count'. */
 	if (uap->count > 64 * 1024)
 		return (EINVAL);
-	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);
+
+	dirbuf = malloc(uap->count, M_TEMP, M_WAITOK);
+	error = kern_getdirentries(td, uap->fd, dirbuf, uap->count, &base,
+	    UIO_SYSSPACE, &ufs_43);
 	if (error) {
-		VOP_UNLOCK(vp, 0, td);
-		VFS_UNLOCK_GIANT(vfslocked);
-		fdrop(fp, td);
+		free(dirbuf, M_TEMP);
 		return (error);
 	}
-#endif
+
+	readcnt = td->td_retval[0];
 #	if (BYTE_ORDER != LITTLE_ENDIAN)
-		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
+	/*
+	 * On big endian systems, we can return the contents from a 4.3
+	 * UFS without performing a fixup.
+	 */
+	if (!ufs_43) {
+#	else
+	{
 #	endif
-	{
-		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;
-				}
+		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);
-	}
-	VFS_UNLOCK_GIANT(vfslocked);
-	error = copyout(&loff, uap->basep, sizeof(long));
-	fdrop(fp, td);
-	td->td_retval[0] = uap->count - auio.uio_resid;
+
+	if (error == 0)
+		error = copyout(dirbuf, uap->buf, readcnt);
+	free(dirbuf, M_TEMP);
+	if (error == 0)
+		error = copyout(&base, uap->basep, sizeof(long));
 	return (error);
 }
 #endif /* COMPAT_43 */
@@ -3726,6 +3649,20 @@
 		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;
@@ -3734,28 +3671,38 @@
 	long loff;
 	int error, eofflag;
 
-	AUDIT_ARG(fd, uap->fd);
-	if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
+	AUDIT_ARG(fd, fd);
+	if ((error = getvnode(td->td_proc->p_fd, 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 = uap->buf;
-	aiov.iov_len = uap->count;
+	aiov.iov_base = buf;
+	aiov.iov_len = count;
 	auio.uio_iov = &aiov;
 	auio.uio_iovcnt = 1;
 	auio.uio_rw = UIO_READ;
-	auio.uio_segflg = UIO_USERSPACE;
+	auio.uio_segflg = bufseg;
 	auio.uio_td = td;
-	auio.uio_resid = uap->count;
+	auio.uio_resid = count;
 	/* vn_lock(vp, LK_SHARED | LK_RETRY, td); */
 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
 	AUDIT_ARG(vnode, vp, ARG_VNODE1);
@@ -3770,7 +3717,7 @@
 	VOP_UNLOCK(vp, 0, td);
 	if (error)
 		goto fail;
-	if (uap->count == auio.uio_resid) {
+	if (count == auio.uio_resid) {
 		if (union_dircheckp) {
 			error = union_dircheckp(td, &vp, fp);
 			if (error == -1) {
@@ -3799,10 +3746,9 @@
 		}
 		VOP_UNLOCK(vp, 0, td);
 	}
-	if (uap->basep != NULL) {
-		error = copyout(&loff, uap->basep, sizeof(long));
-	}
-	td->td_retval[0] = uap->count - auio.uio_resid;
+	if (basep != NULL)
+		*basep = loff;
+	td->td_retval[0] = count - auio.uio_resid;
 fail:
 	VFS_UNLOCK_GIANT(vfslocked);
 	fdrop(fp, td);
@@ -3824,12 +3770,9 @@
 		u_int count;
 	} */ *uap;
 {
-	struct getdirentries_args ap;
-	ap.fd = uap->fd;
-	ap.buf = uap->buf;
-	ap.count = uap->count;
-	ap.basep = NULL;
-	return (getdirentries(td, &ap));
+
+	return (kern_getdirentries(td, uap->fd, uap->buf, uap->count, NULL,
+		UIO_USERSPACE, NULL));
 }
 
 /*

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

@@ -79,6 +79,8 @@
 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