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.