summaryrefslogtreecommitdiffstats
path: root/sys/nfs/nfs_node.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/nfs/nfs_node.c')
-rw-r--r--sys/nfs/nfs_node.c36
1 files changed, 27 insertions, 9 deletions
diff --git a/sys/nfs/nfs_node.c b/sys/nfs/nfs_node.c
index 70ccacb047d..2fcfcf3c7ed 100644
--- a/sys/nfs/nfs_node.c
+++ b/sys/nfs/nfs_node.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_node.c,v 1.47 2009/08/11 17:06:11 thib Exp $ */
+/* $OpenBSD: nfs_node.c,v 1.48 2009/08/14 17:52:18 thib Exp $ */
/* $NetBSD: nfs_node.c,v 1.16 1996/02/18 11:53:42 fvdl Exp $ */
/*
@@ -83,7 +83,7 @@ nfs_nget(struct mount *mnt, nfsfh_t *fh, int fhsize, struct nfsnode **npp)
{
extern int (**nfsv2_vnodeop_p)(void *); /* XXX */
struct nfsmount *nmp;
- struct nfsnode *np, find;
+ struct nfsnode *np, find, *np2;
struct vnode *vp, *nvp;
struct proc *p = curproc; /* XXX */
int error;
@@ -91,28 +91,43 @@ nfs_nget(struct mount *mnt, nfsfh_t *fh, int fhsize, struct nfsnode **npp)
nmp = VFSTONFS(mnt);
loop:
- /* XXXTHIB: locking. */
+ rw_enter_write(&nfs_hashlock);
find.n_fhp = fh;
find.n_fhsize = fhsize;
np = RB_FIND(nfs_nodetree, &nmp->nm_ntree, &find);
if (np != NULL) {
+ rw_exit_write(&nfs_hashlock);
vp = NFSTOV(np);
- if (vget(vp, LK_EXCLUSIVE, p))
+ error = vget(vp, LK_EXCLUSIVE, p);
+ if (error)
goto loop;
*npp = np;
return (0);
}
- if (rw_enter(&nfs_hashlock, RW_WRITE|RW_SLEEPFAIL))
- goto loop;
-
+ /*
+ * getnewvnode() could recycle a vnode, potentially formerly
+ * owned by NFS. This will cause a VOP_RECLAIM() to happen,
+ * which will cause recursive locking, so we unlock before
+ * calling getnewvnode() lock again afterwards, but must check
+ * to see if this nfsnode has been added while we did not hold
+ * the lock.
+ */
+ rw_exit_write(&nfs_hashlock);
error = getnewvnode(VT_NFS, mnt, nfsv2_vnodeop_p, &nvp);
+ rw_enter_write(&nfs_hashlock);
if (error) {
*npp = NULL;
- rw_exit(&nfs_hashlock);
+ rw_exit_write(&nfs_hashlock);
return (error);
}
+ np = RB_FIND(nfs_nodetree, &nmp->nm_ntree, &find);
+ if (np != NULL) {
+ rw_exit_write(&nfs_hashlock);
+ goto loop;
+ }
+
vp = nvp;
np = pool_get(&nfs_node_pool, PR_WAITOK | PR_ZERO);
vp->v_data = np;
@@ -133,7 +148,8 @@ loop:
np->n_fhp = &np->n_fh;
bcopy(fh, np->n_fhp, fhsize);
np->n_fhsize = fhsize;
- RB_INSERT(nfs_nodetree, &nmp->nm_ntree, np);
+ np2 = RB_INSERT(nfs_nodetree, &nmp->nm_ntree, np);
+ KASSERT(np2 == NULL);
np->n_accstamp = -1;
rw_exit(&nfs_hashlock);
*npp = np;
@@ -190,7 +206,9 @@ nfs_reclaim(void *v)
vprint("nfs_reclaim: pushing active", vp);
#endif
+ rw_enter_write(&nfs_hashlock);
RB_REMOVE(nfs_nodetree, &nmp->nm_ntree, np);
+ rw_exit_write(&nfs_hashlock);
if (np->n_rcred)
crfree(np->n_rcred);