Module Name: src Committed By: ad Date: Thu Jan 23 12:21:01 UTC 2020
Modified Files: src/sys/kern [ad-namecache]: vfs_lookup.c Log Message: - Change style of new code slightly to match rest of file. - NFS lookup needs to cross mountpoint too. - Update comments. To generate a diff of this commit: cvs rdiff -u -r1.212.4.5 -r1.212.4.6 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.5 src/sys/kern/vfs_lookup.c:1.212.4.6 --- src/sys/kern/vfs_lookup.c:1.212.4.5 Wed Jan 22 12:10:46 2020 +++ src/sys/kern/vfs_lookup.c Thu Jan 23 12:21:01 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_lookup.c,v 1.212.4.5 2020/01/22 12:10:46 ad Exp $ */ +/* $NetBSD: vfs_lookup.c,v 1.212.4.6 2020/01/23 12:21:01 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.5 2020/01/22 12:10:46 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.212.4.6 2020/01/23 12:21:01 ad Exp $"); #ifdef _KERNEL_OPT #include "opt_magiclinks.h" @@ -1113,9 +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. Where - * we can't do fast-forwarded lookups (for example with layered file - * systems) then this is the fallback for reducing lock contention. + * not the last component then get a shared lock. 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)) { @@ -1251,13 +1251,13 @@ done: * final vnode will have its reference count adjusted and lock taken. */ static int -lookup_fastforward(struct namei_state *state, struct vnode **searchdir, - struct vnode **foundobj) +lookup_fastforward(struct namei_state *state, struct vnode **searchdir_ret, + struct vnode **foundobj_ret) { struct componentname *cnp = state->cnp; struct nameidata *ndp = state->ndp; krwlock_t *plock; - struct vnode *vp, *origsearchdir; + struct vnode *foundobj, *searchdir; int error, error2; size_t oldpathlen; const char *oldnameptr; @@ -1268,10 +1268,12 @@ lookup_fastforward(struct namei_state *s * case we can't get vnode references and need to roll back. */ plock = NULL; - origsearchdir = *searchdir; + searchdir = *searchdir_ret; oldnameptr = cnp->cn_nameptr; oldpathlen = ndp->ni_pathlen; for (;;) { + foundobj = NULL; + /* * Get the next component name. There should be no slashes * here, and we shouldn't have looped around if we were @@ -1289,15 +1291,15 @@ lookup_fastforward(struct namei_state *s * that need to be made. Also check for missing mountpoints. */ if ((cnp->cn_flags & ISDOTDOT) != 0 || - (*searchdir)->v_mount == NULL) { + searchdir->v_mount == NULL) { error = EOPNOTSUPP; break; } /* * Can't deal with last component when modifying; this needs - * the directory vnode locked and VOP_LOOKUP() called (which - * can and does modify state, despite the name). + * searchdir locked and VOP_LOOKUP() called (which can and + * does modify state, despite the name). */ if ((cnp->cn_flags & ISLASTCN) != 0) { if (cnp->cn_nameiop != LOOKUP || @@ -1313,16 +1315,15 @@ lookup_fastforward(struct namei_state *s * ownership info for the directory, or if the user doesn't * have permission to look up files in this directory. */ - if (!cache_lookup_linked(*searchdir, cnp->cn_nameptr, - cnp->cn_namelen, &vp, &plock, cnp->cn_cred)) { + if (!cache_lookup_linked(searchdir, cnp->cn_nameptr, + cnp->cn_namelen, &foundobj, &plock, cnp->cn_cred)) { error = EOPNOTSUPP; break; } KASSERT(plock != NULL && rw_lock_held(plock)); /* Scored a hit. Negative is good too (ENOENT). */ - if (vp == NULL) { - *foundobj = vp; + if (foundobj == NULL) { error = ENOENT; break; } @@ -1335,15 +1336,16 @@ lookup_fastforward(struct namei_state *s * - 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); + if ((cnp->cn_flags & ISLASTCN) != 0 || + foundobj->v_type != VDIR || + (foundobj->v_type == VDIR && + foundobj->v_mountedhere != NULL)) { + mutex_enter(foundobj->v_interlock); + error = vcache_tryvget(foundobj); /* v_interlock now released */ - if (error == 0) { - *foundobj = vp; + if (error != 0) { + foundobj = NULL; } - vp = NULL; break; } @@ -1353,7 +1355,7 @@ lookup_fastforward(struct namei_state *s * continue on to it. */ cnp->cn_nameptr = ndp->ni_next; - *searchdir = vp; + searchdir = foundobj; } /* @@ -1363,20 +1365,22 @@ lookup_fastforward(struct namei_state *s * bit of a problem. Roll back the fastforward to the beginning and * let lookup_once() take care of it. */ - if (*searchdir != origsearchdir) { - mutex_enter((*searchdir)->v_interlock); - error2 = vcache_tryvget(*searchdir); + if (searchdir != *searchdir_ret) { + mutex_enter(searchdir->v_interlock); + error2 = vcache_tryvget(searchdir); /* v_interlock now unheld */ KASSERT(plock != NULL); rw_exit(plock); if (__predict_true(error2 == 0)) { - vrele(origsearchdir); + /* Returning new searchdir, and maybe new foundobj. */ + vrele(*searchdir_ret); + *searchdir_ret = searchdir; } else { - if (error == 0) { - vrele_async(*foundobj); - *foundobj = NULL; + /* Returning nothing. */ + if (foundobj != NULL) { + vrele(foundobj); + foundobj = NULL; } - *searchdir = origsearchdir; cnp->cn_nameptr = oldnameptr; ndp->ni_pathlen = oldpathlen; error = lookup_parsepath(state); @@ -1386,6 +1390,8 @@ lookup_fastforward(struct namei_state *s rw_exit(plock); } + KASSERT(foundobj == NULL || error == 0); + *foundobj_ret = foundobj; return error; } @@ -1657,10 +1663,12 @@ namei_oneroot(struct namei_state *state, * forever. So convert it to the real root. */ if (searchdir != NULL) { - if ((cnp->cn_flags & LOCKPARENT) != 0) { - VOP_UNLOCK(searchdir); + if (searchdir_locked) { + vput(searchdir); + searchdir_locked = false; + } else { + vrele(searchdir); } - vrele(searchdir); searchdir = NULL; } vrele(foundobj); @@ -1678,10 +1686,13 @@ namei_oneroot(struct namei_state *state, (searchdir == NULL || searchdir->v_mount != foundobj->v_mount)) { if (searchdir) { - if ((cnp->cn_flags & LOCKPARENT) != 0) { - VOP_UNLOCK(searchdir); + if (searchdir_locked) { + vput(searchdir); + searchdir_locked = false; + } else { + vrele(searchdir); } - vrele(searchdir); + searchdir = NULL; } vrele(foundobj); foundobj = NULL; @@ -1708,10 +1719,12 @@ namei_oneroot(struct namei_state *state, if (state->rdonly && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { if (searchdir) { - if ((cnp->cn_flags & LOCKPARENT) != 0) { - VOP_UNLOCK(searchdir); + if (searchdir_locked) { + vput(searchdir); + searchdir_locked = false; + } else { + vrele(searchdir); } - vrele(searchdir); searchdir = NULL; } vrele(foundobj); @@ -1736,7 +1749,9 @@ namei_oneroot(struct namei_state *state, * that uses this combination "knows" this, so * it can't be safely changed. Feh. XXX */ + KASSERT(searchdir_locked); VOP_UNLOCK(searchdir); + searchdir_locked = false; } else if ((cnp->cn_flags & LOCKLEAF) != 0 && (searchdir != foundobj || (cnp->cn_flags & LOCKPARENT) == 0)) { @@ -1891,6 +1906,7 @@ static int do_lookup_for_nfsd_index(struct namei_state *state) { int error = 0; + struct componentname *cnp = state->cnp; struct nameidata *ndp = state->ndp; struct vnode *startdir; @@ -1930,32 +1946,35 @@ do_lookup_for_nfsd_index(struct namei_st vref(startdir); error = lookup_once(state, startdir, &startdir, &foundobj, &startdir_locked); - KASSERT(!startdir_locked); - if (error == 0 && startdir == foundobj) { - vrele(startdir); - } else if (startdir != NULL) { - if (startdir_locked) { - vput(startdir); - } else { - vrele(startdir); - } - } - if (error) { - goto bad; + + KASSERT((cnp->cn_flags & LOCKPARENT) == 0); + if (startdir_locked) { + VOP_UNLOCK(startdir); + startdir_locked = false; } - ndp->ni_vp = foundobj; - if (foundobj == NULL) { - return 0; + /* + * If the vnode we found is mounted on, then cross the mount and get + * the root vnode in foundobj. If this encounters an error, it will + * dispose of foundobj, but searchdir is untouched. + */ + if (error == 0 && foundobj != NULL && + foundobj->v_type == VDIR && + foundobj->v_mountedhere != NULL && + (cnp->cn_flags & NOCROSSMOUNT) == 0) { + error = lookup_crossmount(state, &startdir, &foundobj, + &startdir_locked); } - if ((cnp->cn_flags & LOCKLEAF) != 0) { + /* Now toss startdir and see if we have an error. */ + if (startdir != NULL) + vrele(startdir); + if (error) + foundobj = NULL; + else if (foundobj != NULL && (cnp->cn_flags & LOCKLEAF) != 0) vn_lock(foundobj, LK_EXCLUSIVE | LK_RETRY); - } - return (0); -bad: - ndp->ni_vp = NULL; + ndp->ni_vp = foundobj; return (error); }