diff options
author | jhb <jhb@FreeBSD.org> | 2007-01-02 17:27:52 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2007-01-02 17:27:52 +0000 |
commit | bdddbb74e0dffee9c71c534a8654ff1d248a85d1 (patch) | |
tree | 69a9082867eb6bedb9e35707827b0daec8465bda | |
parent | d6c46f500a7e28bf62006a794ea943bb4b4abde4 (diff) | |
download | FreeBSD-src-bdddbb74e0dffee9c71c534a8654ff1d248a85d1.zip FreeBSD-src-bdddbb74e0dffee9c71c534a8654ff1d248a85d1.tar.gz |
Use the vnode interlock to close a race where pfs_vncache_alloc() could
attempt to vn_lock() a destroyed vnode resulting in a hang.
MFC after: 1 week
Submitted by: ups
Reviewed by: des
-rw-r--r-- | sys/fs/pseudofs/pseudofs_vncache.c | 17 |
1 files changed, 9 insertions, 8 deletions
diff --git a/sys/fs/pseudofs/pseudofs_vncache.c b/sys/fs/pseudofs/pseudofs_vncache.c index 4ce29af..e6961bd 100644 --- a/sys/fs/pseudofs/pseudofs_vncache.c +++ b/sys/fs/pseudofs/pseudofs_vncache.c @@ -109,28 +109,29 @@ pfs_vncache_alloc(struct mount *mp, struct vnode **vpp, struct pfs_node *pn, pid_t pid) { struct pfs_vdata *pvd; + struct vnode *vp; int error; /* * See if the vnode is in the cache. * XXX linear search is not very efficient. */ +retry: mtx_lock(&pfs_vncache_mutex); for (pvd = pfs_vncache; pvd; pvd = pvd->pvd_next) { if (pvd->pvd_pn == pn && pvd->pvd_pid == pid && pvd->pvd_vnode->v_mount == mp) { - if (vget(pvd->pvd_vnode, 0, curthread) == 0) { + vp = pvd->pvd_vnode; + VI_LOCK(vp); + mtx_unlock(&pfs_vncache_mutex); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, curthread) == 0) { ++pfs_vncache_hits; - *vpp = pvd->pvd_vnode; - mtx_unlock(&pfs_vncache_mutex); + *vpp = vp; /* XXX see comment at top of pfs_lookup() */ - cache_purge(*vpp); - vn_lock(*vpp, LK_RETRY | LK_EXCLUSIVE, - curthread); + cache_purge(vp); return (0); } - /* XXX if this can happen, we're in trouble */ - break; + goto retry; } } mtx_unlock(&pfs_vncache_mutex); |