Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 8 Jan 2012 16:47:38 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r229813 - stable/8/sys/kern
Message-ID:  <201201081647.q08GlcYb098524@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Sun Jan  8 16:47:37 2012
New Revision: 229813
URL: http://svn.freebsd.org/changeset/base/229813

Log:
  MFC r229185:
  Avoid double-unlock or double unreference for ndp->ni_dvp when the vnode dp
  lock upgrade right after the 'success' label fails.

Modified:
  stable/8/sys/kern/vfs_lookup.c
Directory Properties:
  stable/8/sys/   (props changed)

Modified: stable/8/sys/kern/vfs_lookup.c
==============================================================================
--- stable/8/sys/kern/vfs_lookup.c	Sun Jan  8 13:54:08 2012	(r229812)
+++ stable/8/sys/kern/vfs_lookup.c	Sun Jan  8 16:47:37 2012	(r229813)
@@ -470,12 +470,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,
@@ -812,8 +814,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;
 	}
 
@@ -860,14 +864,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);
@@ -896,10 +903,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?201201081647.q08GlcYb098524>