socsvn commit: r224304 - soc2011/gk/ino64-head/sys/ufs/ufs

gk at FreeBSD.org gk at FreeBSD.org
Sat Jul 16 10:43:06 UTC 2011


Author: gk
Date: Sat Jul 16 10:43:03 2011
New Revision: 224304
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=224304

Log:
  ufs: Use buffer cache in ufs_readdir
  
  Return EINVAL if buffer is too small
  
  Skip entries with zero inode number

Modified:
  soc2011/gk/ino64-head/sys/ufs/ufs/ufs_vnops.c

Modified: soc2011/gk/ino64-head/sys/ufs/ufs/ufs_vnops.c
==============================================================================
--- soc2011/gk/ino64-head/sys/ufs/ufs/ufs_vnops.c	Sat Jul 16 10:42:52 2011	(r224303)
+++ soc2011/gk/ino64-head/sys/ufs/ufs/ufs_vnops.c	Sat Jul 16 10:43:03 2011	(r224304)
@@ -2130,90 +2130,106 @@
 		int *a_eofflag;
 	} */ *ap;
 {
+	struct vnode *vp = ap->a_vp;
 	struct uio *uio = ap->a_uio;
-	off_t offset, startoffset;
+	struct buf *bp;
 	struct inode *ip;
 	struct direct *dp, *edp;
-	struct dirent dstdp;
-	struct uio auio;
-	struct iovec aiov;
-	caddr_t dirbuf;
-	int error;
-	size_t count, readcnt;
+	struct dirent *dstdp;
+	off_t offset, startoffset;
+	size_t readcnt, skipcnt;
+	ssize_t startresid;
+	int error = 0;
+
+	if (uio->uio_offset < 0)
+		return (EINVAL);
 
-	ip = VTOI(ap->a_vp);
+	ip = VTOI(vp);
 	if (ip->i_effnlink == 0)
 		return (0);
-	count = uio->uio_resid;
-	/*
-	 * Avoid complications for partial directory entries by adjusting
-	 * the i/o to end at a block boundary.  Don't give up (like the old ufs
-	 * does) if the initial adjustment gives a negative count, since
-	 * many callers don't supply a large enough buffer.  The correct
-	 * size is a little larger than DIRBLKSIZ to allow for expansion
-	 * of directory entries, but some callers just use 512.
-	 */
+
 	offset = startoffset = uio->uio_offset;
-	count -= (uio->uio_offset + count) & (DIRBLKSIZ - 1);
-	if (count <= 0)
-		count += DIRBLKSIZ;
-	else if (count > MAXBSIZE)
-		count = MAXBSIZE;
-
-	auio = *uio;
-	auio.uio_iov = &aiov;
-	auio.uio_iovcnt = 1;
-	auio.uio_resid = count;
-	auio.uio_segflg = UIO_SYSSPACE;
-	aiov.iov_len = count;
-	dirbuf = malloc(count, M_TEMP, M_WAITOK);
-	aiov.iov_base = dirbuf;
-	error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
-	if (error == 0) {
-		readcnt = count - auio.uio_resid;
-		edp = (struct direct *)&dirbuf[readcnt];
-		bzero(&dstdp, offsetof(struct dirent, d_name));
-		for (dp = (struct direct *)dirbuf;
-		    !error && uio->uio_resid > 0 && dp < edp; ) {
-			dstdp.d_fileno = dp->d_ino;
+	startresid = uio->uio_resid;
+	dstdp = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK);
+	while (error == 0 && uio->uio_resid > 0 &&
+	    uio->uio_offset < ip->i_size) {
+		error = ffs_blkatoff_ra(vp, uio->uio_offset,
+		    startresid, &bp, 2);
+		if (error)
+			break;
+		if (bp->b_offset + bp->b_bcount > ip->i_size)
+			readcnt = ip->i_size - bp->b_offset;
+		else
+			readcnt = bp->b_bcount;
+		skipcnt = (size_t)(uio->uio_offset - bp->b_offset) &
+		    ~(size_t)(DIRBLKSIZ - 1);
+		offset = bp->b_offset + skipcnt;
+		dp = (struct direct *)&bp->b_data[skipcnt];
+		edp = (struct direct *)&bp->b_data[readcnt];
+		while (error == 0 && uio->uio_resid > 0 && dp < edp) {
+			if (dp->d_reclen <= 0 ||
+			    (caddr_t)dp + dp->d_reclen > (caddr_t)edp) {
+				error = EIO;
+				break;
+			}
+			if (offset < startoffset)
+				goto nextentry;
+
 #if BYTE_ORDER == LITTLE_ENDIAN
-			if (ap->a_vp->v_mount->mnt_maxsymlinklen <= 0) {
-				dstdp.d_namlen = dp->d_type;
-				dstdp.d_type = dp->d_namlen;
+			if (vp->v_mount->mnt_maxsymlinklen <= 0) {
+				dstdp->d_namlen = dp->d_type;
+				dstdp->d_type = dp->d_namlen;
 			} else
 #endif
 			{
-				dstdp.d_namlen = dp->d_namlen;
-				dstdp.d_type = dp->d_type;
+				dstdp->d_namlen = dp->d_namlen;
+				dstdp->d_type = dp->d_type;
 			}
 
-			if (dp->d_reclen > 0 && dstdp.d_namlen <= MAXNAMLEN) {
-				dstdp.d_off = offset + dp->d_reclen;
-				dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp);
-				bcopy(dp->d_name, dstdp.d_name, dstdp.d_namlen);
-				dstdp.d_name[dstdp.d_namlen] = '\0';
-				if(dstdp.d_reclen > uio->uio_resid)
-					break;
-				/* advance dp */
-				error = uiomove((caddr_t)&dstdp,
-				    dstdp.d_reclen, uio);
-				if (error == 0) {
-					offset += dp->d_reclen;
-					dp = (struct direct *)
-					    ((char *)dp + dp->d_reclen);
-				}
-			} else {
+			if (__offsetof(struct direct, d_name) +
+			    dstdp->d_namlen > dp->d_reclen) {
 				error = EIO;
 				break;
 			}
+
+			if (dp->d_ino == 0)
+				goto nextentry;
+
+			dstdp->d_fileno = dp->d_ino;
+			dstdp->d_off = offset + dp->d_reclen;
+			dstdp->d_reclen = GENERIC_DIRSIZ(dstdp);
+			bcopy(dp->d_name, dstdp->d_name, dstdp->d_namlen);
+			dstdp->d_name[dstdp->d_namlen] = '\0';
+			if(dstdp->d_reclen > uio->uio_resid) {
+				if (uio->uio_resid == startresid)
+					error = EINVAL;
+				else
+					error = -1;
+				break;
+			}
+			/* advance dp */
+			error = uiomove((caddr_t)dstdp, dstdp->d_reclen, uio);
+			if (error)
+				break;
+nextentry:
+			offset += dp->d_reclen;
+			dp = (struct direct *)((caddr_t)dp + dp->d_reclen);
 		}
-		/* we need to correct uio_offset */
-		uio->uio_offset = startoffset + (caddr_t)dp - dirbuf;
+		brelse(bp);
+		uio->uio_offset = offset;
 	}
 
-	free(dirbuf, M_TEMP);
-	if (ap->a_eofflag)
-		*ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
+	/* we need to correct uio_offset */
+	if (uio->uio_resid == startresid)
+		uio->uio_offset = startoffset;
+	else
+		uio->uio_offset = offset;
+
+	free(dstdp, M_TEMP);
+	if (error == -1)
+		error = 0;
+	if (error == 0 && ap->a_eofflag)
+		*ap->a_eofflag = ip->i_size <= uio->uio_offset;
 	return (error);
 }
 


More information about the svn-soc-all mailing list