Module Name:    src
Committed By:   yamt
Date:           Thu Sep  1 15:31:27 UTC 2011

Modified Files:
        src/sys/kern: vfs_lookup.c

Log Message:
redo vfs_lookup.c rev.1.126.
when crossing a mount point, don't keep the parent vnode locked.
ie. don't lock a vnode while holding another vnode which belongs to a
different filesystem.  otherwise we propagate slowness (or deadness) of a
filesystem to another via vnode lock chain.


To generate a diff of this commit:
cvs rdiff -u -r1.189 -r1.190 src/sys/kern/vfs_lookup.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/vfs_lookup.c
diff -u src/sys/kern/vfs_lookup.c:1.189 src/sys/kern/vfs_lookup.c:1.190
--- src/sys/kern/vfs_lookup.c:1.189	Sat Aug 13 19:40:02 2011
+++ src/sys/kern/vfs_lookup.c	Thu Sep  1 15:31:27 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_lookup.c,v 1.189 2011/08/13 19:40:02 riastradh Exp $	*/
+/*	$NetBSD: vfs_lookup.c,v 1.190 2011/09/01 15:31:27 yamt Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.189 2011/08/13 19:40:02 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.190 2011/09/01 15:31:27 yamt Exp $");
 
 #include "opt_magiclinks.h"
 
@@ -1040,11 +1040,16 @@
 	       (cnp->cn_flags & NOCROSSMOUNT) == 0) {
 		error = vfs_busy(mp, NULL);
 		if (error != 0) {
-			vput(foundobj);
+			if (searchdir != foundobj) {
+				vput(foundobj);
+			} else {
+				vrele(foundobj);
+			}
 			goto done;
 		}
-		KASSERT(searchdir != foundobj);
-		VOP_UNLOCK(searchdir);
+		if (searchdir != foundobj) {
+			VOP_UNLOCK(searchdir);
+		}
 		vput(foundobj);
 		error = VFS_ROOT(mp, &foundobj);
 		vfs_unbusy(mp, false, NULL);
@@ -1052,9 +1057,22 @@
 			vn_lock(searchdir, LK_EXCLUSIVE | LK_RETRY);
 			goto done;
 		}
-		VOP_UNLOCK(foundobj);
-		vn_lock(searchdir, LK_EXCLUSIVE | LK_RETRY);
-		vn_lock(foundobj, LK_EXCLUSIVE | LK_RETRY);
+		/*
+		 * avoid locking vnodes from two filesystems because it's
+		 * prune to deadlock.  eg. when using puffs.
+		 * also, it isn't a good idea to propagate slowness of a
+		 * filesystem up to the root directory.
+		 * for now, only handle the common case.  (ie. foundobj is VDIR)
+		 */
+		if (foundobj->v_type == VDIR) {
+			vrele(searchdir);
+			*newsearchdir_ret = searchdir = foundobj;
+			vref(searchdir);
+		} else {
+			VOP_UNLOCK(foundobj);
+			vn_lock(searchdir, LK_EXCLUSIVE | LK_RETRY);
+			vn_lock(foundobj, LK_EXCLUSIVE | LK_RETRY);
+		}
 	}
 
 	*foundobj_ret = foundobj;
@@ -1240,9 +1258,11 @@
 		 * Check for directory, if the component was
 		 * followed by a series of slashes.
 		 */
-		if ((foundobj->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
-			KASSERT(foundobj != searchdir);
-			if (searchdir) {
+		if ((foundobj->v_type != VDIR) &&
+		    (cnp->cn_flags & REQUIREDIR)) {
+			if (searchdir == foundobj) {
+				vrele(searchdir);
+			} else {
 				vput(searchdir);
 			}
 			vput(foundobj);
@@ -1545,7 +1565,11 @@
 	vref(startdir);
 	vn_lock(startdir, LK_EXCLUSIVE | LK_RETRY);
 	error = lookup_once(state, startdir, &startdir, &foundobj);
-	vput(startdir);
+	if (error == 0 && startdir == foundobj) {
+		vrele(startdir);
+	} else {
+		vput(startdir);
+	}
 	if (error) {
 		goto bad;
 	}

Reply via email to