socsvn commit: r224305 - in soc2011/gk/ino64-head/sys: fs/nfsclient nfsclient

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


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

Log:
  Fix NFS readdir offset and buffer size alignment
  
  Align read result by DIRBLKSIZ (512 bytes)
  Fail if buffer is less than DIRBLKSIZ
  
  Bug fixed:
  getdirentries() call with not DIRBLKSIZ aligned offset and/or buffer size
  results in file offset that doesn't start on dirent boundary.
  Next getdirentries() call will return garbled output.
  
  Todo:
  Application is still allowed to use arbitrary offsets. Unlike other
  filesystems NFS readdir will not "correct" offset and will fill buffer
  with data that doesn't start on dirent boundary.

Modified:
  soc2011/gk/ino64-head/sys/fs/nfsclient/nfs_clbio.c
  soc2011/gk/ino64-head/sys/nfsclient/nfs_bio.c

Modified: soc2011/gk/ino64-head/sys/fs/nfsclient/nfs_clbio.c
==============================================================================
--- soc2011/gk/ino64-head/sys/fs/nfsclient/nfs_clbio.c	Sat Jul 16 10:43:03 2011	(r224304)
+++ soc2011/gk/ino64-head/sys/fs/nfsclient/nfs_clbio.c	Sat Jul 16 10:43:14 2011	(r224305)
@@ -459,6 +459,8 @@
 		return (0);
 	if (uio->uio_offset < 0)	/* XXX VDIR cookies can be negative */
 		return (EINVAL);
+	if (vp->v_type == VDIR && uio->uio_resid < DIRBLKSIZ)
+		return (EINVAL);
 	td = uio->uio_td;
 
 	mtx_lock(&nmp->nm_mtx);
@@ -601,6 +603,8 @@
 		    && uio->uio_offset >= np->n_direofoffset) {
 		    return (0);
 		}
+		if (uio->uio_resid < DIRBLKSIZ)
+		    return (0);
 		lbn = (uoff_t)uio->uio_offset / NFS_DIRBLKSIZ;
 		on = uio->uio_offset & (NFS_DIRBLKSIZ - 1);
 		bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, td);
@@ -709,6 +713,9 @@
 		n = lmin(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid - on);
 		if (np->n_direofoffset && n > np->n_direofoffset - uio->uio_offset)
 			n = np->n_direofoffset - uio->uio_offset;
+		else
+			/* Align offset. Abort if n <= 0 or resid < DIRBLKSIZ */
+			n -= (uio->uio_offset + n) & (DIRBLKSIZ - 1);
 		break;
 	    default:
 		ncl_printf(" ncl_bioread: type %x unexpected\n", vp->v_type);

Modified: soc2011/gk/ino64-head/sys/nfsclient/nfs_bio.c
==============================================================================
--- soc2011/gk/ino64-head/sys/nfsclient/nfs_bio.c	Sat Jul 16 10:43:03 2011	(r224304)
+++ soc2011/gk/ino64-head/sys/nfsclient/nfs_bio.c	Sat Jul 16 10:43:14 2011	(r224305)
@@ -458,6 +458,8 @@
 		return (0);
 	if (uio->uio_offset < 0)	/* XXX VDIR cookies can be negative */
 		return (EINVAL);
+	if (vp->v_type == VDIR && uio->uio_resid < DIRBLKSIZ)
+		return (EINVAL);
 	td = uio->uio_td;
 
 	mtx_lock(&nmp->nm_mtx);
@@ -594,6 +596,8 @@
 		    && uio->uio_offset >= np->n_direofoffset) {
 		    return (0);
 		}
+		if (uio->uio_resid < DIRBLKSIZ)
+		    return (0);
 		lbn = (uoff_t)uio->uio_offset / NFS_DIRBLKSIZ;
 		on = uio->uio_offset & (NFS_DIRBLKSIZ - 1);
 		bp = nfs_getcacheblk(vp, lbn, NFS_DIRBLKSIZ, td);
@@ -702,6 +706,10 @@
 		n = lmin(uio->uio_resid, NFS_DIRBLKSIZ - bp->b_resid - on);
 		if (np->n_direofoffset && n > np->n_direofoffset - uio->uio_offset)
 			n = np->n_direofoffset - uio->uio_offset;
+		else {
+			/* Align offset. Abort if n <= 0 or resid < DIRBLKSIZ */
+			n -= (uio->uio_offset + n) & (DIRBLKSIZ - 1);
+		}
 		break;
 	    default:
 		nfs_printf(" nfs_bioread: type %x unexpected\n", vp->v_type);


More information about the svn-soc-all mailing list