svn commit: r200281 - stable/8/sys/fs/nfsserver

Rick Macklem rmacklem at FreeBSD.org
Tue Dec 8 14:41:38 PST 2009


Author: rmacklem
Date: Tue Dec  8 22:41:37 2009
New Revision: 200281
URL: http://svn.freebsd.org/changeset/base/200281

Log:
  MFC: r199715
  Modify the experimental nfs server so that it falls back to
  using VOP_LOOKUP() when VFS_VGET() returns EOPNOTSUPP in the
  ReaddirPlus RPC. This patch is based upon one by pjd@ for the
  regular nfs server which has not yet been committed. It is needed
  when a ZFS volume is exported and ReaddirPlus (which almost
  always happens for NFSv4) is performed by a client. The patch
  also simplifies vnode lock handling somewhat.
  
  Tested by:	gerrit at pmp.uni-hannover.de

Modified:
  stable/8/sys/fs/nfsserver/nfs_nfsdport.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/fs/nfsserver/nfs_nfsdport.c
==============================================================================
--- stable/8/sys/fs/nfsserver/nfs_nfsdport.c	Tue Dec  8 22:38:42 2009	(r200280)
+++ stable/8/sys/fs/nfsserver/nfs_nfsdport.c	Tue Dec  8 22:41:37 2009	(r200281)
@@ -1675,7 +1675,7 @@ nfsrvd_readdirplus(struct nfsrv_descript
 	struct nfsvattr nva, at, *nvap = &nva;
 	struct mbuf *mb0, *mb1;
 	struct nfsreferral *refp;
-	int nlen, r, error = 0, getret = 1, vgetret;
+	int nlen, r, error = 0, getret = 1, usevget = 1;
 	int siz, cnt, fullsiz, eofflag, ncookies, entrycnt;
 	caddr_t bpos0, bpos1;
 	u_int64_t off, toff, verf;
@@ -1683,6 +1683,7 @@ nfsrvd_readdirplus(struct nfsrv_descript
 	nfsattrbit_t attrbits, rderrbits, savbits;
 	struct uio io;
 	struct iovec iv;
+	struct componentname cn;
 
 	if (nd->nd_repstat) {
 		nfsrv_postopattr(nd, getret, &at);
@@ -1761,8 +1762,6 @@ nfsrvd_readdirplus(struct nfsrv_descript
 		return (0);
 	}
 
-	NFSVOPUNLOCK(vp, 0, p);
-
 	MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
 again:
 	eofflag = 0;
@@ -1780,10 +1779,8 @@ again:
 	io.uio_segflg = UIO_SYSSPACE;
 	io.uio_rw = UIO_READ;
 	io.uio_td = NULL;
-	NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
 	nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies,
 	    &cookies);
-	NFSVOPUNLOCK(vp, 0, p);
 	off = (u_int64_t)io.uio_offset;
 	if (io.uio_resid)
 		siz -= io.uio_resid;
@@ -1795,7 +1792,7 @@ again:
 	if (!nd->nd_repstat)
 		nd->nd_repstat = getret;
 	if (nd->nd_repstat) {
-		vrele(vp);
+		vput(vp);
 		if (cookies)
 			free((caddr_t)cookies, M_TEMP);
 		free((caddr_t)rbuf, M_TEMP);
@@ -1808,7 +1805,7 @@ again:
 	 * rpc reply
 	 */
 	if (siz == 0) {
-		vrele(vp);
+		vput(vp);
 		if (nd->nd_flag & ND_NFSV3)
 			nfsrv_postopattr(nd, getret, &at);
 		NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
@@ -1853,33 +1850,7 @@ again:
 		toff = off;
 		goto again;
 	}
-
-	/*
-	 * Probe one of the directory entries to see if the filesystem
-	 * supports VGET for NFSv3. For NFSv4, it will return an
-	 * error later, if attributes are required.
-	 * (To be honest, most if not all NFSv4 clients will require
-	 *  attributes, but??)
-	 */
-	if ((nd->nd_flag & ND_NFSV3)) {
-		vgetret = VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE,
-		    &nvp);
-		if (vgetret != 0) {
-			if (vgetret == EOPNOTSUPP)
-				nd->nd_repstat = NFSERR_NOTSUPP;
-			else
-				nd->nd_repstat = NFSERR_SERVERFAULT;
-			vrele(vp);
-			if (cookies)
-				free((caddr_t)cookies, M_TEMP);
-			free((caddr_t)rbuf, M_TEMP);
-			nfsrv_postopattr(nd, getret, &at);
-			return (0);
-		}
-		if (!vgetret)
-			vput(nvp);
-		nvp = NULL;
-	}
+	NFSVOPUNLOCK(vp, 0, p);
 
 	/*
 	 * Save this position, in case there is an error before one entry
@@ -1937,9 +1908,41 @@ again:
 				if (nd->nd_flag & ND_NFSV4)
 					refp = nfsv4root_getreferral(NULL,
 					    vp, dp->d_fileno);
-				if (refp == NULL)
-					r = VFS_VGET(vp->v_mount, dp->d_fileno,
-					    LK_EXCLUSIVE, &nvp);
+				if (refp == NULL) {
+					if (usevget)
+						r = VFS_VGET(vp->v_mount,
+						    dp->d_fileno, LK_EXCLUSIVE,
+						    &nvp);
+					else
+						r = EOPNOTSUPP;
+					if (r == EOPNOTSUPP) {
+						if (usevget) {
+							usevget = 0;
+							cn.cn_nameiop = LOOKUP;
+							cn.cn_lkflags =
+							    LK_EXCLUSIVE |
+							    LK_RETRY;
+							cn.cn_cred =
+							    nd->nd_cred;
+							cn.cn_thread = p;
+						}
+						cn.cn_nameptr = dp->d_name;
+						cn.cn_namelen = nlen;
+						cn.cn_flags = ISLASTCN |
+						    NOFOLLOW | LOCKLEAF |
+						    MPSAFE;
+						if (nlen == 2 &&
+						    dp->d_name[0] == '.' &&
+						    dp->d_name[1] == '.')
+							cn.cn_flags |=
+							    ISDOTDOT;
+						if (!VOP_ISLOCKED(vp))
+							vn_lock(vp,
+							    LK_EXCLUSIVE |
+							    LK_RETRY);
+						r = VOP_LOOKUP(vp, &nvp, &cn);
+					}
+				}
 				if (!r) {
 				    if (refp == NULL &&
 					((nd->nd_flag & ND_NFSV3) ||
@@ -2018,7 +2021,10 @@ again:
 		cookiep++;
 		ncookies--;
 	}
-	vrele(vp);
+	if (!usevget && VOP_ISLOCKED(vp))
+		vput(vp);
+	else
+		vrele(vp);
 
 	/*
 	 * If dirlen > cnt, we must strip off the last entry. If that


More information about the svn-src-stable-8 mailing list