diff options
author | truckman <truckman@FreeBSD.org> | 2003-05-25 06:17:33 +0000 |
---|---|---|
committer | truckman <truckman@FreeBSD.org> | 2003-05-25 06:17:33 +0000 |
commit | 9cf579ad75909eb2f46ad9788bc4fc0e9e351206 (patch) | |
tree | 96ec0ac9ef86e544b76d7a438b61445ad1031d07 /sys/nfsserver/nfs_srvsubs.c | |
parent | 52630e2ed7ef26be3e92783583a39f716c3c1149 (diff) | |
download | FreeBSD-src-9cf579ad75909eb2f46ad9788bc4fc0e9e351206.zip FreeBSD-src-9cf579ad75909eb2f46ad9788bc4fc0e9e351206.tar.gz |
Beat vnode locking in the NFS server code into submission. This change
is not pretty, but it fixes the code so that it no longer violates the
vnode locking rules in the VFS API and doesn't trip any of the locking
assertions enabled by the DEBUG_VFS_LOCKS kernel configuration option.
There is one report that this patch fixed a "locking against myself"
panic on an NFS server that was tripped by a diskless client.
Approved by: re (scottl)
Diffstat (limited to 'sys/nfsserver/nfs_srvsubs.c')
-rw-r--r-- | sys/nfsserver/nfs_srvsubs.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/sys/nfsserver/nfs_srvsubs.c b/sys/nfsserver/nfs_srvsubs.c index 5ac51ad..ceb6851 100644 --- a/sys/nfsserver/nfs_srvsubs.c +++ b/sys/nfsserver/nfs_srvsubs.c @@ -592,7 +592,8 @@ MODULE_VERSION(nfsserver, 1); int nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp, - caddr_t *dposp, struct vnode **retdirp, struct thread *td, int pubflag) + caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp, + int *retdirattr_retp, struct thread *td, int pubflag) { int i, rem; struct mbuf *md; @@ -602,6 +603,7 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, struct vnode *dp; int error, rdonly, linklen; struct componentname *cnp = &ndp->ni_cnd; + int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0; *retdirp = NULL; cnp->cn_flags |= NOMACCHECK; @@ -664,6 +666,12 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, * to the returned pointer */ *retdirp = dp; + if (v3) { + vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); + *retdirattr_retp = VOP_GETATTR(dp, retdirattrp, + ndp->ni_cnd.cn_cred, td); + VOP_UNLOCK(dp, 0, td); + } if (pubflag) { /* @@ -736,6 +744,8 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, VREF(dp); ndp->ni_startdir = dp; + if (!lockleaf) + cnp->cn_flags |= LOCKLEAF; for (;;) { cnp->cn_nameptr = cnp->cn_pnbuf; /* @@ -761,6 +771,8 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, cnp->cn_flags |= HASBUF; else uma_zfree(namei_zone, cnp->cn_pnbuf); + if (ndp->ni_vp && !lockleaf) + VOP_UNLOCK(ndp->ni_vp, 0, td); break; } @@ -840,6 +852,8 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, ndp->ni_startdir = ndp->ni_dvp; ndp->ni_dvp = NULL; } + if (!lockleaf) + cnp->cn_flags &= ~LOCKLEAF; /* * nfs_namei() guarentees that fields will not contain garbage |