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>