summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2007-01-02 17:27:52 +0000
committerjhb <jhb@FreeBSD.org>2007-01-02 17:27:52 +0000
commitbdddbb74e0dffee9c71c534a8654ff1d248a85d1 (patch)
tree69a9082867eb6bedb9e35707827b0daec8465bda /sys/fs
parentd6c46f500a7e28bf62006a794ea943bb4b4abde4 (diff)
downloadFreeBSD-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
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/pseudofs/pseudofs_vncache.c17
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);
OpenPOWER on IntegriCloud