Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Feb 2020 22:28:55 +0000 (UTC)
From:      Mateusz Guzik <mjg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r357746 - head/sys/kern
Message-ID:  <202002102228.01AMSttn049062@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202002102228.01AMSttn049062>