Author: mjg
Date: Mon Feb 10 22:28:54 2020
New Revision: 357746
URL: https://svnweb.freebsd.org/changeset/base/357746

Log:
  vfs: fix device count leak on vrele racing with vgone
  
  The race is:
  
  CPU1                                CPU2
                                      devfs_reclaim_vchr
  make v_usecount 0
                                        VI_LOCK
                                        sees v_usecount == 0, no updates
                                        vp->v_rdev = NULL;
                                        ...
                                        VI_UNLOCK
  VI_LOCK
  v_decr_devcount
    sees v_rdev == NULL, no updates
  
  In this scenario si_devcount decrement is not performed.
  
  Note this can only happen if the vnode lock is not held.
  
  Reviewed by:  kib
  Tested by:    pho
  Differential Revision:        https://reviews.freebsd.org/D23529

Modified:
  head/sys/kern/vfs_subr.c

Modified: head/sys/kern/vfs_subr.c
==============================================================================
--- head/sys/kern/vfs_subr.c    Mon Feb 10 20:53:59 2020        (r357745)
+++ head/sys/kern/vfs_subr.c    Mon Feb 10 22:28:54 2020        (r357746)
@@ -3192,12 +3192,22 @@ vputx(struct vnode *vp, enum vputx_op func)
         * count which provides liveness of the vnode, in which case we
         * have to vdrop.
         */
-       if (!refcount_release(&vp->v_usecount)) {
-               if (func == VPUTX_VPUT)
-                       VOP_UNLOCK(vp);
-               return;
+       if (__predict_false(vp->v_type == VCHR && func == VPUTX_VRELE)) {
+               if (refcount_release_if_not_last(&vp->v_usecount))
+                       return;
+               VI_LOCK(vp);
+               if (!refcount_release(&vp->v_usecount)) {
+                       VI_UNLOCK(vp);
+                       return;
+               }
+       } else {
+               if (!refcount_release(&vp->v_usecount)) {
+                       if (func == VPUTX_VPUT)
+                               VOP_UNLOCK(vp);
+                       return;
+               }
+               VI_LOCK(vp);
        }
-       VI_LOCK(vp);
        v_decr_devcount(vp);
        /*
         * By the time we got here someone else might have transitioned
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to