Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Dec 2008 12:12:23 +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: r186561 - head/sys/fs/pseudofs
Message-ID:  <200812291212.mBTCCN0I056860@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Mon Dec 29 12:12:23 2008
New Revision: 186561
URL: http://svn.freebsd.org/changeset/base/186561

Log:
  Drop the pseudofs vnode lock around call to pfs_read handler. The handler
  may need to lock arbitrary vnodes, causing either lock order reversal or
  recursive vnode lock acquisition.
  
  Tested by:	pho
  Approved by:	des
  MFC after:	2 weeks

Modified:
  head/sys/fs/pseudofs/pseudofs_vnops.c

Modified: head/sys/fs/pseudofs/pseudofs_vnops.c
==============================================================================
--- head/sys/fs/pseudofs/pseudofs_vnops.c	Mon Dec 29 12:07:18 2008	(r186560)
+++ head/sys/fs/pseudofs/pseudofs_vnops.c	Mon Dec 29 12:12:23 2008	(r186561)
@@ -476,7 +476,7 @@ pfs_read(struct vop_read_args *va)
 	struct uio *uio = va->a_uio;
 	struct proc *proc;
 	struct sbuf *sb = NULL;
-	int error;
+	int error, locked;
 	unsigned int buflen, offset, resid;
 
 	PFS_TRACE(("%s", pn->pn_name));
@@ -502,13 +502,15 @@ pfs_read(struct vop_read_args *va)
 		PROC_UNLOCK(proc);
 	}
 
+	vhold(vn);
+	locked = VOP_ISLOCKED(vn);
+	VOP_UNLOCK(vn, 0);
+
 	if (pn->pn_flags & PFS_RAWRD) {
 		PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
 		error = pn_fill(curthread, proc, pn, NULL, uio);
 		PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid));
-		if (proc != NULL)
-			PRELE(proc);
-		PFS_RETURN (error);
+		goto ret;
 	}
 
 	/* beaucoup sanity checks so we don't ask for bogus allocation */
@@ -518,34 +520,35 @@ pfs_read(struct vop_read_args *va)
 	    (buflen = offset + resid + 1) < offset || buflen > INT_MAX) {
 		if (proc != NULL)
 			PRELE(proc);
-		PFS_RETURN (EINVAL);
+		error = EINVAL;
+		goto ret;
 	}
 	if (buflen > MAXPHYS + 1) {
-		if (proc != NULL)
-			PRELE(proc);
-		PFS_RETURN (EIO);
+		error = EIO;
+		goto ret;
 	}
 
 	sb = sbuf_new(sb, NULL, buflen, 0);
 	if (sb == NULL) {
-		if (proc != NULL)
-			PRELE(proc);
-		PFS_RETURN (EIO);
+		error = EIO;
+		goto ret;
 	}
 
 	error = pn_fill(curthread, proc, pn, sb, uio);
 
-	if (proc != NULL)
-		PRELE(proc);
-
 	if (error) {
 		sbuf_delete(sb);
-		PFS_RETURN (error);
+		goto ret;
 	}
 
 	sbuf_finish(sb);
 	error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
 	sbuf_delete(sb);
+ret:
+	vn_lock(vn, locked | LK_RETRY);
+	vdrop(vn);
+	if (proc != NULL)
+		PRELE(proc);
 	PFS_RETURN (error);
 }
 



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