Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 1 Jan 2012 18:45:59 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r229185 - head/sys/kern
Message-ID:  <201201011845.q01IjxQS025445@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Sun Jan  1 18:45:59 2012
New Revision: 229185
URL: http://svn.freebsd.org/changeset/base/229185

Log:
  Avoid double-unlock or double unreference for ndp->ni_dvp when the vnode dp
  lock upgrade right after the 'success' label fails.
  
  In collaboration with:	pho
  MFC after:	1 week

Modified:
  head/sys/kern/vfs_lookup.c

Modified: head/sys/kern/vfs_lookup.c
==============================================================================
--- head/sys/kern/vfs_lookup.c	Sun Jan  1 18:42:00 2012	(r229184)
+++ head/sys/kern/vfs_lookup.c	Sun Jan  1 18:45:59 2012	(r229185)
@@ -508,12 +508,14 @@ lookup(struct nameidata *ndp)
 	int dvfslocked;			/* VFS Giant state for parent */
 	int tvfslocked;
 	int lkflags_save;
+	int ni_dvp_unlocked;
 	
 	/*
 	 * Setup: break out flag bits into variables.
 	 */
 	dvfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0;
 	vfslocked = 0;
+	ni_dvp_unlocked = 0;
 	ndp->ni_cnd.cn_flags &= ~GIANTHELD;
 	wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
 	KASSERT(cnp->cn_nameiop == LOOKUP || wantparent,
@@ -861,8 +863,10 @@ unionlookup:
 		/*
 		 * Symlink code always expects an unlocked dvp.
 		 */
-		if (ndp->ni_dvp != ndp->ni_vp)
+		if (ndp->ni_dvp != ndp->ni_vp) {
 			VOP_UNLOCK(ndp->ni_dvp, 0);
+			ni_dvp_unlocked = 1;
+		}
 		goto success;
 	}
 
@@ -909,14 +913,17 @@ nextname:
 		VREF(ndp->ni_startdir);
 	}
 	if (!wantparent) {
+		ni_dvp_unlocked = 2;
 		if (ndp->ni_dvp != dp)
 			vput(ndp->ni_dvp);
 		else
 			vrele(ndp->ni_dvp);
 		VFS_UNLOCK_GIANT(dvfslocked);
 		dvfslocked = 0;
-	} else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp)
+	} else if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp != dp) {
 		VOP_UNLOCK(ndp->ni_dvp, 0);
+		ni_dvp_unlocked = 1;
+	}
 
 	if (cnp->cn_flags & AUDITVNODE1)
 		AUDIT_ARG_VNODE1(dp);
@@ -945,10 +952,12 @@ success:
 	return (0);
 
 bad2:
-	if (dp != ndp->ni_dvp)
-		vput(ndp->ni_dvp);
-	else
-		vrele(ndp->ni_dvp);
+	if (ni_dvp_unlocked != 2) {
+		if (dp != ndp->ni_dvp && !ni_dvp_unlocked)
+			vput(ndp->ni_dvp);
+		else
+			vrele(ndp->ni_dvp);
+	}
 bad:
 	if (!dpunlocked)
 		vput(dp);



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