summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormpi <mpi@openbsd.org>2018-03-28 09:40:26 +0000
committermpi <mpi@openbsd.org>2018-03-28 09:40:26 +0000
commitac2a721c191ba569ac6fef04503e89ce9a869936 (patch)
tree2e776b6d2cd1ecaa0329c6722beacdd81bb51046
parentMark ext2fs inode recursive lock as RWL_IS_VNODE like for ffs to let it (diff)
downloadwireguard-openbsd-ac2a721c191ba569ac6fef04503e89ce9a869936.tar.xz
wireguard-openbsd-ac2a721c191ba569ac6fef04503e89ce9a869936.zip
Check for possible race after sleeping instead of using a rwlock to
protect insertions in `nm_ntree'. This will prevent a future lock ordering problem with NFSnode's lock. ok tedu@, visa@
-rw-r--r--sys/nfs/nfs_node.c22
1 files changed, 7 insertions, 15 deletions
diff --git a/sys/nfs/nfs_node.c b/sys/nfs/nfs_node.c
index 948ec70967a..2887554c0f0 100644
--- a/sys/nfs/nfs_node.c
+++ b/sys/nfs/nfs_node.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_node.c,v 1.65 2016/09/27 01:37:38 dlg Exp $ */
+/* $OpenBSD: nfs_node.c,v 1.66 2018/03/28 09:40:26 mpi Exp $ */
/* $NetBSD: nfs_node.c,v 1.16 1996/02/18 11:53:42 fvdl Exp $ */
/*
@@ -58,8 +58,6 @@
struct pool nfs_node_pool;
extern int prtactive;
-struct rwlock nfs_hashlock = RWLOCK_INITIALIZER("nfshshlk");
-
/* XXX */
extern struct vops nfs_vops;
@@ -98,12 +96,10 @@ nfs_nget(struct mount *mnt, nfsfh_t *fh, int fhsize, struct nfsnode **npp)
nmp = VFSTONFS(mnt);
loop:
- rw_enter_write(&nfs_hashlock);
find.n_fhp = fh;
find.n_fhsize = fhsize;
np = RBT_FIND(nfs_nodetree, &nmp->nm_ntree, &find);
if (np != NULL) {
- rw_exit_write(&nfs_hashlock);
vp = NFSTOV(np);
error = vget(vp, LK_EXCLUSIVE, p);
if (error)
@@ -120,25 +116,24 @@ loop:
* 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, &nfs_vops, &nvp);
/* note that we don't have this vnode set up completely yet */
- rw_enter_write(&nfs_hashlock);
if (error) {
*npp = NULL;
- rw_exit_write(&nfs_hashlock);
return (error);
}
nvp->v_flag |= VLARVAL;
- np = RBT_FIND(nfs_nodetree, &nmp->nm_ntree, &find);
- if (np != NULL) {
+ np = pool_get(&nfs_node_pool, PR_WAITOK | PR_ZERO);
+ /*
+ * getnewvnode() and pool_get() can sleep, check for race.
+ */
+ if (RBT_FIND(nfs_nodetree, &nmp->nm_ntree, &find) != NULL) {
+ pool_put(&nfs_node_pool, np);
vgone(nvp);
- rw_exit_write(&nfs_hashlock);
goto loop;
}
vp = nvp;
- np = pool_get(&nfs_node_pool, PR_WAITOK | PR_ZERO);
vp->v_data = np;
/* we now have an nfsnode on this vnode */
vp->v_flag &= ~VLARVAL;
@@ -162,7 +157,6 @@ loop:
np2 = RBT_INSERT(nfs_nodetree, &nmp->nm_ntree, np);
KASSERT(np2 == NULL);
np->n_accstamp = -1;
- rw_exit(&nfs_hashlock);
*npp = np;
return (0);
@@ -239,9 +233,7 @@ nfs_reclaim(void *v)
ap->a_vp);
#endif
nmp = VFSTONFS(vp->v_mount);
- rw_enter_write(&nfs_hashlock);
RBT_REMOVE(nfs_nodetree, &nmp->nm_ntree, np);
- rw_exit_write(&nfs_hashlock);
if (np->n_rcred)
crfree(np->n_rcred);