Module Name: src Committed By: ad Date: Wed Jan 22 12:10:46 UTC 2020
Modified Files: src/sys/kern [ad-namecache]: vfs_lookup.c Log Message: Fast-forward through the namecache was stopping one component too soon when there was an obstacle, e.g. a mountpoint. The obstacle should be returned not the parent directory. To generate a diff of this commit: cvs rdiff -u -r1.212.4.4 -r1.212.4.5 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.212.4.4 src/sys/kern/vfs_lookup.c:1.212.4.5 --- src/sys/kern/vfs_lookup.c:1.212.4.4 Sun Jan 19 21:19:25 2020 +++ src/sys/kern/vfs_lookup.c Wed Jan 22 12:10:46 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_lookup.c,v 1.212.4.4 2020/01/19 21:19:25 ad Exp $ */ +/* $NetBSD: vfs_lookup.c,v 1.212.4.5 2020/01/22 12:10:46 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.212.4.4 2020/01/19 21:19:25 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.212.4.5 2020/01/22 12:10:46 ad Exp $"); #ifdef _KERNEL_OPT #include "opt_magiclinks.h" @@ -954,7 +954,11 @@ lookup_crossmount(struct namei_state *st (mp = foundobj->v_mountedhere) != NULL && (cnp->cn_flags & NOCROSSMOUNT) == 0) { KASSERTMSG(searchdir != foundobj, "same vn %p", searchdir); - /* First get the vnode stable. */ + /* + * First get the vnode stable. LK_SHARED works brilliantly + * here because almost nothing else wants to lock the + * covered vnode. + */ error = vn_lock(foundobj, LK_SHARED); if (error != 0) { vrele(foundobj); @@ -962,7 +966,7 @@ lookup_crossmount(struct namei_state *st break; } - /* Then check to see if something is still mounted there. */ + /* Then check to see if something is still mounted on it. */ if ((mp = foundobj->v_mountedhere) == NULL) { VOP_UNLOCK(foundobj); break; @@ -1109,7 +1113,9 @@ lookup_once(struct namei_state *state, /* * If the file system supports VOP_LOOKUP() with a shared lock, and * we are not making any modifications (nameiop LOOKUP) or this is - * not the last component then get a shared lock LK_SHARED. + * not the last component then get a shared lock LK_SHARED. Where + * we can't do fast-forwarded lookups (for example with layered file + * systems) then this is the fallback for reducing lock contention. */ if ((searchdir->v_mount->mnt_iflag & IMNT_SHRLOOKUP) != 0 && (cnp->cn_nameiop == LOOKUP || (cnp->cn_flags & ISLASTCN) == 0)) { @@ -1237,8 +1243,8 @@ done: /* * Parse out the first path name component that we need to to consider. * - * While doing this, attempt to use the name cache to fastforward through as - * many "easy" to find components of the path as possible. + * While doing this, attempt to use the name cache to fast-forward through + * as many "easy" to find components of the path as possible. * * We use the namecache's node locks to form a chain, and avoid as many * vnode references and locks as possible. In the ideal case, only the @@ -1280,8 +1286,7 @@ lookup_fastforward(struct namei_state *s /* * 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 - * (XXX racy). + * that need to be made. Also check for missing mountpoints. */ if ((cnp->cn_flags & ISDOTDOT) != 0 || (*searchdir)->v_mount == NULL) { @@ -1322,8 +1327,16 @@ lookup_fastforward(struct namei_state *s break; } - /* Stop if we've reached the last component: get vnode. */ - if (cnp->cn_flags & ISLASTCN) { + /* + * Stop and get a hold on the vnode if there's something + * that can't be handled here: + * + * - we've reached the last component. + * - or encountered a mount point that needs to be crossed. + * - or encountered something other than a directory. + */ + if ((cnp->cn_flags & ISLASTCN) != 0 || vp->v_type != VDIR || + (vp->v_type == VDIR && vp->v_mountedhere != NULL)) { mutex_enter(vp->v_interlock); error = vcache_tryvget(vp); /* v_interlock now released */ @@ -1335,17 +1348,6 @@ lookup_fastforward(struct namei_state *s } /* - * Not the last component. If we found something other than - * a directory, or it's a directory with a filesystem - * mounted on it, bail out. - */ - if (vp->v_type != VDIR || vp->v_mountedhere != NULL) { - error = EOPNOTSUPP; - vp = NULL; - break; - } - - /* * Otherwise, we're still in business. Set the found VDIR * vnode as the search dir for the next component and * continue on to it. @@ -1365,9 +1367,8 @@ lookup_fastforward(struct namei_state *s mutex_enter((*searchdir)->v_interlock); error2 = vcache_tryvget(*searchdir); /* v_interlock now unheld */ - if (plock != NULL) { - rw_exit(plock); - } + KASSERT(plock != NULL); + rw_exit(plock); if (__predict_true(error2 == 0)) { vrele(origsearchdir); } else { @@ -1447,7 +1448,7 @@ namei_oneroot(struct namei_state *state, /* * Parse out the first path name component that we need to * to consider. While doing this, attempt to use the name - * cache to fastforward through as many "easy" to find + * cache to fast-forward through as many "easy" to find * components of the path as possible. */ error = lookup_fastforward(state, &searchdir, &foundobj);