Re: git: c35ec1efdcb2 - main - vfs: [1/2] fix stalls in vnode reclaim by not requeieing from vnlru
- Reply: Mateusz Guzik : "Re: git: c35ec1efdcb2 - main - vfs: [1/2] fix stalls in vnode reclaim by not requeieing from vnlru"
- In reply to: Mateusz Guzik : "git: c35ec1efdcb2 - main - vfs: [1/2] fix stalls in vnode reclaim by not requeieing from vnlru"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 26 Mar 2022 20:42:13 UTC
On 3/10/22 05:42, Mateusz Guzik wrote: > The branch main has been updated by mjg: > > URL: https://cgit.FreeBSD.org/src/commit/?id=c35ec1efdcb2978bc3b6a0098c2b412be8d33e39 > > commit c35ec1efdcb2978bc3b6a0098c2b412be8d33e39 > Author: Mateusz Guzik <mjg@FreeBSD.org> > AuthorDate: 2022-03-07 10:33:59 +0000 > Commit: Mateusz Guzik <mjg@FreeBSD.org> > CommitDate: 2022-03-10 09:41:50 +0000 > > vfs: [1/2] fix stalls in vnode reclaim by not requeieing from vnlru > > Reported by: pho > --- > sys/kern/vfs_subr.c | 55 +++++++++++++++++++++++++++++++++++++++++++---------- > 1 file changed, 45 insertions(+), 10 deletions(-) > > diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c > index afafd02d92b9..436323873f7f 100644 > --- a/sys/kern/vfs_subr.c > +++ b/sys/kern/vfs_subr.c > @@ -113,6 +113,8 @@ static void vn_seqc_init(struct vnode *); > static void vn_seqc_write_end_free(struct vnode *vp); > static void vgonel(struct vnode *); > static bool vhold_recycle_free(struct vnode *); > +static void vdropl_recycle(struct vnode *vp); > +static void vdrop_recycle(struct vnode *vp); > static void vfs_knllock(void *arg); > static void vfs_knlunlock(void *arg); > static void vfs_knl_assert_lock(void *arg, int what); > @@ -1207,11 +1209,11 @@ restart: > mtx_unlock(&vnode_list_mtx); > > if (vn_start_write(vp, &mp, V_NOWAIT) != 0) { > - vdrop(vp); > + vdrop_recycle(vp); > goto next_iter_unlocked; > } > if (VOP_LOCK(vp, LK_EXCLUSIVE|LK_NOWAIT) != 0) { > - vdrop(vp); > + vdrop_recycle(vp); > vn_finished_write(mp); > goto next_iter_unlocked; > } > @@ -1222,14 +1224,14 @@ restart: > (vp->v_object != NULL && vp->v_object->handle == vp && > vp->v_object->resident_page_count > trigger)) { > VOP_UNLOCK(vp); > - vdropl(vp); > + vdropl_recycle(vp); > vn_finished_write(mp); > goto next_iter_unlocked; > } > counter_u64_add(recycles_count, 1); > vgonel(vp); > VOP_UNLOCK(vp); > - vdropl(vp); > + vdropl_recycle(vp); > vn_finished_write(mp); > done++; > next_iter_unlocked: > @@ -1613,7 +1615,7 @@ vtryrecycle(struct vnode *vp) > CTR2(KTR_VFS, > "%s: impossible to recycle, vp %p lock is already held", > __func__, vp); > - vdrop(vp); > + vdrop_recycle(vp); > return (EWOULDBLOCK); > } > /* > @@ -1624,7 +1626,7 @@ vtryrecycle(struct vnode *vp) > CTR2(KTR_VFS, > "%s: impossible to recycle, cannot start the write for %p", > __func__, vp); > - vdrop(vp); > + vdrop_recycle(vp); > return (EBUSY); > } > /* > @@ -1636,7 +1638,7 @@ vtryrecycle(struct vnode *vp) > VI_LOCK(vp); > if (vp->v_usecount) { > VOP_UNLOCK(vp); > - vdropl(vp); > + vdropl_recycle(vp); > vn_finished_write(vnmp); > CTR2(KTR_VFS, > "%s: impossible to recycle, %p is already referenced", > @@ -1648,7 +1650,7 @@ vtryrecycle(struct vnode *vp) > vgonel(vp); > } > VOP_UNLOCK(vp); > - vdropl(vp); > + vdropl_recycle(vp); > vn_finished_write(vnmp); > return (0); > } > @@ -3598,8 +3600,8 @@ vdrop(struct vnode *vp) > vdropl(vp); > } > > -void > -vdropl(struct vnode *vp) > +static void __always_inline > +vdropl_impl(struct vnode *vp, bool enqueue) > { Hi, It seems like enqueue is completely unused within the function. Was there a hunk missing from the final commit? Cheers, Mitchell > > ASSERT_VI_LOCKED(vp, __func__); > @@ -3627,6 +3629,39 @@ vdropl(struct vnode *vp) > vdbatch_enqueue(vp); > } > > +void > +vdropl(struct vnode *vp) > +{ > + > + vdropl_impl(vp, true); > +} > + > +/* > + * vdrop a vnode when recycling > + * > + * This is a special case routine only to be used when recycling, differs from > + * regular vdrop by not requeieing the vnode on LRU. > + * > + * Consider a case where vtryrecycle continuously fails with all vnodes (due to > + * e.g., frozen writes on the filesystem), filling the batch and causing it to > + * be requeued. Then vnlru will end up revisiting the same vnodes. This is a > + * loop which can last for as long as writes are frozen. > + */ > +static void > +vdropl_recycle(struct vnode *vp) > +{ > + > + vdropl_impl(vp, false); > +} > + > +static void > +vdrop_recycle(struct vnode *vp) > +{ > + > + VI_LOCK(vp); > + vdropl_recycle(vp); > +} > + > /* > * Call VOP_INACTIVE on the vnode and manage the DOINGINACT and OWEINACT > * flags. DOINGINACT prevents us from recursing in calls to vinactive.