Author: mjg
Date: Tue Feb 11 18:19:56 2020
New Revision: 357770
URL: https://svnweb.freebsd.org/changeset/base/357770

Log:
  vfs: fix vhold race in mnt_vnode_next_lazy_relock
  
  vdrop can set the hold count to 0 and wait for the ->mnt_listmtx held by
  mnt_vnode_next_lazy_relock caller. The routine incorrectly asserted the
  count has to be > 0.
  
  Reported by:  pho
  Tested by:    pho

Modified:
  head/sys/kern/vfs_subr.c

Modified: head/sys/kern/vfs_subr.c
==============================================================================
--- head/sys/kern/vfs_subr.c    Tue Feb 11 18:16:29 2020        (r357769)
+++ head/sys/kern/vfs_subr.c    Tue Feb 11 18:19:56 2020        (r357770)
@@ -6264,7 +6264,13 @@ mnt_vnode_next_lazy_relock(struct vnode *mvp, struct m
        TAILQ_REMOVE(&mp->mnt_lazyvnodelist, mvp, v_lazylist);
        TAILQ_INSERT_BEFORE(vp, mvp, v_lazylist);
 
-       vholdnz(vp);
+       /*
+        * Note we may be racing against vdrop which transitioned the hold
+        * count to 0 and now waits for the ->mnt_listmtx lock. This is fine,
+        * if we are the only user after we get the interlock we will just
+        * vdrop.
+        */
+       vhold(vp);
        mtx_unlock(&mp->mnt_listmtx);
        VI_LOCK(vp);
        if (VN_IS_DOOMED(vp)) {
@@ -6273,8 +6279,7 @@ mnt_vnode_next_lazy_relock(struct vnode *mvp, struct m
        }
        VNPASS(vp->v_mflag & VMP_LAZYLIST, vp);
        /*
-        * Since we had a period with no locks held we may be the last
-        * remaining user, in which case there is nothing to do.
+        * There is nothing to do if we are the last user.
         */
        if (!refcount_release_if_not_last(&vp->v_holdcnt))
                goto out_lost;
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to