diff options
author | rmacklem <rmacklem@FreeBSD.org> | 2009-11-23 16:08:15 +0000 |
---|---|---|
committer | rmacklem <rmacklem@FreeBSD.org> | 2009-11-23 16:08:15 +0000 |
commit | 5ca6063e7ac9d5a6d4c779de09ce3f21674d67ec (patch) | |
tree | 0b543a7629289b71573c6701db6a97e241450b04 /sys/fs | |
parent | 396246bb32eb9a9a68bbe890fc9487b2da481295 (diff) | |
download | FreeBSD-src-5ca6063e7ac9d5a6d4c779de09ce3f21674d67ec.zip FreeBSD-src-5ca6063e7ac9d5a6d4c779de09ce3f21674d67ec.tar.gz |
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
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/nfsserver/nfs_nfsdport.c | 82 |
1 files changed, 44 insertions, 38 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 1e87523..ca80fde 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -1675,7 +1675,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram, 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 *nd, int isdgram, 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 *nd, int isdgram, 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 |