FreeBSD/sys/fs/pseudofs/pseudofs_vncache.c
/*
 * Purge the cache of dead entries
 *
 * This is extremely inefficient due to the fact that vgone() not only
 * indirectly modifies the vnode cache, but may also sleep.  We can
 * neither hold pfs_vncache_mutex across a vgone() call, nor make any
 * assumptions about the state of the cache after vgone() returns.  In
 * consequence, we must start over after every vgone() call, and keep
 * trying until we manage to traverse the entire cache.
 *
 * The only way to improve this situation is to change the data structure
 * used to implement the cache.
 */
Purge the cache of dead entries
This is extremely inefficient due to the fact that vgone() not only
indirectly modifies the vnode cache, but may also sleep.  We can
neither hold pfs_vncache_mutex across a vgone() call, nor make any
assumptions about the state of the cache after vgone() returns.  In
consequence, we must start over after every vgone() call, and keep
trying until we manage to traverse the entire cache.

The only way to improve this situation is to change the data structure
used to implement the cache.
Purge the cache of dead entries This is extremely inefficient due to the fact that vgone () not only indirectly modifies the vnode cache but may also sleep . We can neither hold pfs_vncache_mutex across a vgone () call nor make any assumptions about the state of the cache after vgone () returns . In consequence we must start over after every vgone () call and keep trying until we manage to traverse the entire cache . The only way to improve this situation is to change the data structure used to implement the cache .
static void
pfs_purge_locked(struct pfs_node *pn)
{
	struct pfs_vdata *pvd;
	struct vnode *vnp;
	mtx_assert(&pfs_vncache_mutex, MA_OWNED);
	pvd = pfs_vncache;
	while (pvd != NULL) {
		if (pvd->pvd_dead || (pn != NULL && pvd->pvd_pn == pn)) {
			vnp = pvd->pvd_vnode;
			vhold(vnp);
			mtx_unlock(&pfs_vncache_mutex);
			VOP_LOCK(vnp, LK_EXCLUSIVE);
			vgone(vnp);
			VOP_UNLOCK(vnp, 0);
			mtx_lock(&pfs_vncache_mutex);
			vdrop(vnp);
			pvd = pfs_vncache;
		} else {
			pvd = pvd->pvd_next;
		}
	}
}
static void pfs_purge_locked ( struct pfs_node * pn ) { struct pfs_vdata * pvd ; struct vnode * vnp ; mtx_assert ( & pfs_vncache_mutex , MA_OWNED ) ; pvd = pfs_vncache ; while ( pvd != NULL ) { if ( pvd -> pvd_dead || ( pn != NULL && pvd -> pvd_pn == pn ) ) { vnp = pvd -> pvd_vnode ; vhold ( vnp ) ; mtx_unlock ( & pfs_vncache_mutex ) ; VOP_LOCK ( vnp , LK_EXCLUSIVE ) ; vgone ( vnp ) ; VOP_UNLOCK ( vnp , 0 ) ; mtx_lock ( & pfs_vncache_mutex ) ; vdrop ( vnp ) ; pvd = pfs_vncache ; } else { pvd = pvd -> pvd_next ; } } }
Purge the cache of dead entries
 This is extremely inefficient due to the fact that vgone() not only
 indirectly modifies the vnode cache, but may also sleep.
Purge the cache of dead entries This is extremely inefficient due to the fact that vgone () not only indirectly modifies the vnode cache but may also sleep .