summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2009-11-23 16:08:15 +0000
committerrmacklem <rmacklem@FreeBSD.org>2009-11-23 16:08:15 +0000
commit5ca6063e7ac9d5a6d4c779de09ce3f21674d67ec (patch)
tree0b543a7629289b71573c6701db6a97e241450b04 /sys/fs
parent396246bb32eb9a9a68bbe890fc9487b2da481295 (diff)
downloadFreeBSD-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.c82
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
OpenPOWER on IntegriCloud