Wed Apr 22 21:35:52 2020 UTC ()
lookup_fastforward(): handle dotdot lookups and give up less often in
the union mount case.


(ad)
diff -r1.139 -r1.140 src/sys/kern/vfs_cache.c
diff -r1.218 -r1.219 src/sys/kern/vfs_lookup.c

cvs diff -r1.139 -r1.140 src/sys/kern/vfs_cache.c (expand / switch to context diff)
--- src/sys/kern/vfs_cache.c 2020/04/13 19:23:18 1.139
+++ src/sys/kern/vfs_cache.c 2020/04/22 21:35:52 1.140
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_cache.c,v 1.139 2020/04/13 19:23:18 ad Exp $	*/
+/*	$NetBSD: vfs_cache.c,v 1.140 2020/04/22 21:35:52 ad Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2019, 2020 The NetBSD Foundation, Inc.
@@ -172,7 +172,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_cache.c,v 1.139 2020/04/13 19:23:18 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_cache.c,v 1.140 2020/04/22 21:35:52 ad Exp $");
 
 #define __NAMECACHE_PRIVATE
 #ifdef _KERNEL_OPT
@@ -664,10 +664,17 @@
 	 * before we get its lock.
 	 *
 	 * Note that the two locks can be the same if looking up a dot, for
-	 * example: /usr/bin/.
+	 * example: /usr/bin/.  If looking up the parent (..) we can't wait
+	 * on the lock as child -> parent is the wrong direction.
 	 */
 	if (*plock != &dvi->vi_nc_lock) {
-		rw_enter(&dvi->vi_nc_lock, RW_READER);
+		if (namelen == 2 && name[0] == '.' && name[1] == '.') {
+			if (!rw_tryenter(&dvi->vi_nc_lock, RW_READER)) {
+				return false;
+			}
+		} else {
+			rw_enter(&dvi->vi_nc_lock, RW_READER);
+		}
 		if (*plock != NULL) {
 			rw_exit(*plock);
 		}

cvs diff -r1.218 -r1.219 src/sys/kern/vfs_lookup.c (expand / switch to context diff)
--- src/sys/kern/vfs_lookup.c 2020/04/21 21:42:47 1.218
+++ src/sys/kern/vfs_lookup.c 2020/04/22 21:35:52 1.219
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_lookup.c,v 1.218 2020/04/21 21:42:47 ad Exp $	*/
+/*	$NetBSD: vfs_lookup.c,v 1.219 2020/04/22 21:35:52 ad Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.218 2020/04/21 21:42:47 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.219 2020/04/22 21:35:52 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_magiclinks.h"
@@ -1286,14 +1286,19 @@
 		}
 
 		/*
-		 * Can't deal with dotdot lookups, because it means lock
-		 * order reversal, and there are checks in lookup_once()
-		 * that need to be made.  Also check for missing mountpoints.
+		 * Can't deal with DOTDOT lookups if NOCROSSMOUNT or the
+		 * lookup is chrooted.
 		 */
-		if ((cnp->cn_flags & ISDOTDOT) != 0 ||
-		    searchdir->v_mount == NULL) {
-			error = EOPNOTSUPP;
-			break;
+		if ((cnp->cn_flags & ISDOTDOT) != 0) {
+			if ((searchdir->v_vflag & VV_ROOT) != 0 &&
+			    (cnp->cn_flags & NOCROSSMOUNT)) {
+			    	error = EOPNOTSUPP;
+				break;
+			}
+			if (ndp->ni_rootdir != rootvnode) {
+			    	error = EOPNOTSUPP;
+				break;
+			}
 		}
 
 		/*
@@ -1309,13 +1314,6 @@
 			}
 		}
 
-		/* Can't deal with -o union lookups. */
-		if ((searchdir->v_vflag & VV_ROOT) != 0 &&
-		    (searchdir->v_mount->mnt_flag & MNT_UNION) != 0) {
-		    	error = EOPNOTSUPP;
-		    	break;
-		}
-
 		/*
 		 * Good, now look for it in cache.  cache_lookup_linked()
 		 * will fail if there's nothing there, or if there's no
@@ -1329,9 +1327,18 @@
 		}
 		KASSERT(plock != NULL && rw_lock_held(plock));
 
-		/* Scored a hit.  Negative is good too (ENOENT). */
+		/*
+		 * Scored a hit.  Negative is good too (ENOENT).  If there's
+		 * a '-o union' mount here, punt and let lookup_once() deal
+		 * with it.
+		 */
 		if (foundobj == NULL) {
-			error = ENOENT;
+			if ((searchdir->v_vflag & VV_ROOT) != 0 &&
+			    (searchdir->v_mount->mnt_flag & MNT_UNION) != 0) {
+			    	error = EOPNOTSUPP;
+			} else {
+				error = ENOENT;
+			}
 			break;
 		}