vfs: fix a race where reclaim vholds freed vnodes

Reported by:	pho
Tested by:	pho (previous version)
Fixes:	r366974 ("vfs: stop taking the interlock in vnode reclaim")
This commit is contained in:
Mateusz Guzik 2020-10-24 13:30:37 +00:00
parent ab79c9061c
commit 7cc1718613
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=366997

View File

@ -109,6 +109,7 @@ static void syncer_shutdown(void *arg, int howto);
static int vtryrecycle(struct vnode *vp);
static void v_init_counters(struct vnode *);
static void vgonel(struct vnode *);
static bool vhold_recycle(struct vnode *);
static void vfs_knllock(void *arg);
static void vfs_knlunlock(void *arg);
static void vfs_knl_assert_locked(void *arg);
@ -1126,7 +1127,8 @@ vlrureclaim(bool reclaim_nc_src, int trigger, u_long target)
goto next_iter;
}
vhold(vp);
if (!vhold_recycle(vp))
goto next_iter;
TAILQ_REMOVE(&vnode_list, mvp, v_vnodelist);
TAILQ_INSERT_AFTER(&vnode_list, vp, mvp, v_vnodelist);
mtx_unlock(&vnode_list_mtx);
@ -1231,7 +1233,8 @@ vnlru_free_locked(int count, struct vfsops *mnt_op)
if (__predict_false(vp->v_type == VBAD || vp->v_type == VNON)) {
continue;
}
vhold(vp);
if (!vhold_recycle(vp))
continue;
count--;
mtx_unlock(&vnode_list_mtx);
vtryrecycle(vp);
@ -3248,13 +3251,11 @@ vholdnz(struct vnode *vp)
* However, while this is more performant, it hinders debugging by eliminating
* the previously mentioned invariant.
*/
bool
vhold_smr(struct vnode *vp)
static bool __always_inline
_vhold_cond(struct vnode *vp)
{
int count;
VFS_SMR_ASSERT_ENTERED();
count = atomic_load_int(&vp->v_holdcnt);
for (;;) {
if (count & VHOLD_NO_SMR) {
@ -3272,6 +3273,28 @@ vhold_smr(struct vnode *vp)
}
}
bool
vhold_smr(struct vnode *vp)
{
VFS_SMR_ASSERT_ENTERED();
return (_vhold_cond(vp));
}
/*
* Special case for vnode recycling.
*
* Vnodes are present on the global list until UMA takes them out.
* Attempts to recycle only need the relevant lock and have no use for SMR.
*/
static bool
vhold_recycle(struct vnode *vp)
{
mtx_assert(&vnode_list_mtx, MA_OWNED);
return (_vhold_cond(vp));
}
static void __noinline
vdbatch_process(struct vdbatch *vd)
{