int
osi_TryEvictVCache(struct vcache *avc, int *slept) {
+ struct vnode *vp = AFSTOV(avc);
+
if (!VREFCOUNT_GT(avc,0)
&& avc->opens == 0 && (avc->f.states & CUnlinkedDel) == 0) {
/*
* not on the free list.
* XXX assume FreeBSD is the same for now.
*/
+ /*
+ * We only have one caller (afs_ShakeLooseVCaches), which already
+ * holds the write lock. vgonel() sometimes calls VOP_CLOSE(),
+ * so we must drop the write lock around our call to vgone().
+ */
+ ReleaseWriteLock(&afs_xvcache);
AFS_GUNLOCK();
+ *slept = 1;
#if defined(AFS_FBSD80_ENV)
- /* vgone() is correct, but v_usecount is assumed not
- * to be 0, and I suspect that currently our usage ensures that
- * in fact it will */
- if (vrefcnt(AFSTOV(avc)) < 1) {
- vref(AFSTOV(avc));
- }
- vn_lock(AFSTOV(avc), LK_EXCLUSIVE | LK_RETRY); /* !glocked */
-#endif
+ /* vgone() is correct, but vgonel() panics if v_usecount is 0--
+ * this is particularly confusing since vgonel() will trigger
+ * vop_reclaim, in the call path of which we'll check v_usecount
+ * and decide that the vnode is busy. Splat. */
+ if (vrefcnt(vp) < 1)
+ vref(vp);
- vgone(AFSTOV(avc));
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* !glocked */
+#endif
+ vgone(vp);
#if defined(AFS_FBSD80_ENV)
- VOP_UNLOCK(AFSTOV(avc), 0);
+ VOP_UNLOCK(vp, 0);
#endif
AFS_GLOCK();
+ ObtainWriteLock(&afs_xvcache, 340);
return 1;
}
return 0;