Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 23 Nov 2009 16:08:15 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r199715 - head/sys/fs/nfsserver
Message-ID:  <200911231608.nANG8F2Y061838@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Mon Nov 23 16:08:15 2009
New Revision: 199715
URL: http://svn.freebsd.org/changeset/base/199715

Log:
  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.
  
  MFC after:	2 weeks

Modified:
  head/sys/fs/nfsserver/nfs_nfsdport.c

Modified: head/sys/fs/nfsserver/nfs_nfsdport.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdport.c	Mon Nov 23 16:00:16 2009	(r199714)
+++ head/sys/fs/nfsserver/nfs_nfsdport.c	Mon Nov 23 16:08:15 2009	(r199715)
@@ -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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200911231608.nANG8F2Y061838>