Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 8 Jan 2009 12:47:30 +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: r186896 - head/sys/kern
Message-ID:  <200901081247.n08ClUT2022668@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Thu Jan  8 12:47:30 2009
New Revision: 186896
URL: http://svn.freebsd.org/changeset/base/186896

Log:
  Do not call namei() while having another user-controlled vnode
  locked. Lookup could attempt to recursively lock that vnode.
  
  Do not call vn_start_write(V_WAIT) while vnode is locked, this may
  result in a deadlock with suspension.
  
  vfs_busy() the mountpoint before dropping vnode lock for vnode
  that was used to look up the mountpoint, to prevent unmount in
  between.
  
  Reported and tested by:	pho
  Reviewed by:	rwatson
  MFC after:	3 weeks

Modified:
  head/sys/kern/vfs_extattr.c

Modified: head/sys/kern/vfs_extattr.c
==============================================================================
--- head/sys/kern/vfs_extattr.c	Thu Jan  8 12:39:40 2009	(r186895)
+++ head/sys/kern/vfs_extattr.c	Thu Jan  8 12:47:30 2009	(r186896)
@@ -87,52 +87,65 @@ extattrctl(td, uap)
 	AUDIT_ARG(text, attrname);
 
 	vfslocked = fnvfslocked = 0;
-	/*
-	 * uap->filename is not always defined.  If it is, grab a vnode lock,
-	 * which VFS_EXTATTRCTL() will later release.
-	 */
+	mp = NULL;
 	filename_vp = NULL;
 	if (uap->filename != NULL) {
-		NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF |
-		    AUDITVNODE2, UIO_USERSPACE, uap->filename, td);
+		NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE2,
+		    UIO_USERSPACE, uap->filename, td);
 		error = namei(&nd);
 		if (error)
 			return (error);
 		fnvfslocked = NDHASGIANT(&nd);
 		filename_vp = nd.ni_vp;
-		NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK);
+		NDFREE(&nd, NDF_NO_VP_RELE);
 	}
 
 	/* uap->path is always defined. */
-	NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
-	    uap->path, td);
+	NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF | AUDITVNODE1,
+	    UIO_USERSPACE, uap->path, td);
 	error = namei(&nd);
-	if (error) {
-		if (filename_vp != NULL)
-			vput(filename_vp);
+	if (error)
 		goto out;
-	}
 	vfslocked = NDHASGIANT(&nd);
 	mp = nd.ni_vp->v_mount;
-	error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
-	NDFREE(&nd, 0);
+	error = vfs_busy(mp, 0);
 	if (error) {
-		if (filename_vp != NULL)
-			vput(filename_vp);
+		NDFREE(&nd, 0);
+		mp = NULL;
 		goto out;
 	}
+	VOP_UNLOCK(nd.ni_vp, 0);
+	error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
+	NDFREE(&nd, NDF_NO_VP_UNLOCK);
+	if (error)
+		goto out;
+	if (filename_vp != NULL) {
+		/*
+		 * uap->filename is not always defined.  If it is,
+		 * grab a vnode lock, which VFS_EXTATTRCTL() will
+		 * later release.
+		 */
+		error = vn_lock(filename_vp, LK_EXCLUSIVE);
+		if (error) {
+			vn_finished_write(mp_writable);
+			goto out;
+		}
+	}
 
 	error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
 	    uap->attrname != NULL ? attrname : NULL, td);
 
 	vn_finished_write(mp_writable);
+out:
+	if (mp != NULL)
+		vfs_unbusy(mp);
+
 	/*
 	 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp,
 	 * so vrele it if it is defined.
 	 */
 	if (filename_vp != NULL)
 		vrele(filename_vp);
-out:
 	VFS_UNLOCK_GIANT(fnvfslocked);
 	VFS_UNLOCK_GIANT(vfslocked);
 	return (error);



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