git: 56244d35741a - main - vfs: hoist degenerate path lookups out of the loop
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 24 Mar 2022 11:22:32 UTC
The branch main has been updated by mjg: URL: https://cgit.FreeBSD.org/src/commit/?id=56244d35741a62e725786fc96e7d3d962677c0ad commit 56244d35741a62e725786fc96e7d3d962677c0ad Author: Mateusz Guzik <mjg@FreeBSD.org> AuthorDate: 2022-03-11 15:51:39 +0000 Commit: Mateusz Guzik <mjg@FreeBSD.org> CommitDate: 2022-03-24 11:22:12 +0000 vfs: hoist degenerate path lookups out of the loop --- sys/kern/vfs_lookup.c | 110 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 33 deletions(-) diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 5a0871c91fac..f4fabe55b06e 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -802,6 +802,57 @@ needs_exclusive_leaf(struct mount *mp, int flags) _Static_assert(MAXNAMLEN == NAME_MAX, "MAXNAMLEN and NAME_MAX have different values"); +static int __noinline +vfs_lookup_degenerate(struct nameidata *ndp, struct vnode *dp, int wantparent) +{ + struct componentname *cnp; + struct mount *mp; + int error; + + cnp = &ndp->ni_cnd; + + cnp->cn_flags |= ISLASTCN; + + mp = atomic_load_ptr(&dp->v_mount); + if (needs_exclusive_leaf(mp, cnp->cn_flags)) { + cnp->cn_lkflags &= ~LK_SHARED; + cnp->cn_lkflags |= LK_EXCLUSIVE; + } + + vn_lock(dp, + compute_cn_lkflags(mp, cnp->cn_lkflags | LK_RETRY, + cnp->cn_flags)); + + if (dp->v_type != VDIR) { + error = ENOTDIR; + goto bad; + } + if (cnp->cn_nameiop != LOOKUP) { + error = EISDIR; + goto bad; + } + if (wantparent) { + ndp->ni_dvp = dp; + VREF(dp); + } + ndp->ni_vp = dp; + + if (cnp->cn_flags & AUDITVNODE1) + AUDIT_ARG_VNODE1(dp); + else if (cnp->cn_flags & AUDITVNODE2) + AUDIT_ARG_VNODE2(dp); + + if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) + VOP_UNLOCK(dp); + /* XXX This should probably move to the top of function. */ + if (cnp->cn_flags & SAVESTART) + panic("lookup: SAVESTART"); + return (0); +bad: + VOP_UNLOCK(dp); + return (error); +} + /* * Search a pathname. * This is a very central and rather complicated routine. @@ -886,13 +937,31 @@ vfs_lookup(struct nameidata *ndp) rdonly = cnp->cn_flags & RDONLY; cnp->cn_flags &= ~ISSYMLINK; ndp->ni_dvp = NULL; + + cnp->cn_lkflags = LK_SHARED; + dp = ndp->ni_startdir; + ndp->ni_startdir = NULLVP; + + /* + * Leading slashes, if any, are supposed to be skipped by the caller. + */ + MPASS(cnp->cn_nameptr[0] != '/'); + + /* + * Check for degenerate name (e.g. / or "") which is a way of talking + * about a directory, e.g. like "/." or ".". + */ + if (__predict_false(cnp->cn_nameptr[0] == '\0')) { + error = vfs_lookup_degenerate(ndp, dp, wantparent); + if (error == 0) + goto success_right_lock; + goto bad_unlocked; + } + /* * We use shared locks until we hit the parent of the last cn then * we adjust based on the requesting flags. */ - cnp->cn_lkflags = LK_SHARED; - dp = ndp->ni_startdir; - ndp->ni_startdir = NULLVP; vn_lock(dp, compute_cn_lkflags(dp->v_mount, cnp->cn_lkflags | LK_RETRY, cnp->cn_flags)); @@ -980,37 +1049,10 @@ dirloop: nameicap_tracker_add(ndp, dp); /* - * Check for degenerate name (e.g. / or "") - * which is a way of talking about a directory, - * e.g. like "/." or ".". + * Make sure degenerate names don't get here, their handling was + * previously found in this spot. */ - if (cnp->cn_nameptr[0] == '\0') { - if (dp->v_type != VDIR) { - error = ENOTDIR; - goto bad; - } - if (cnp->cn_nameiop != LOOKUP) { - error = EISDIR; - goto bad; - } - if (wantparent) { - ndp->ni_dvp = dp; - VREF(dp); - } - ndp->ni_vp = dp; - - if (cnp->cn_flags & AUDITVNODE1) - AUDIT_ARG_VNODE1(dp); - else if (cnp->cn_flags & AUDITVNODE2) - AUDIT_ARG_VNODE2(dp); - - if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) - VOP_UNLOCK(dp); - /* XXX This should probably move to the top of function. */ - if (cnp->cn_flags & SAVESTART) - panic("lookup: SAVESTART"); - goto success; - } + MPASS(cnp->cn_nameptr[0] != '\0'); /* * Handle "..": five special cases. @@ -1341,6 +1383,7 @@ success: goto bad2; } } +success_right_lock: if (ndp->ni_vp != NULL) { if ((cnp->cn_flags & ISDOTDOT) == 0) nameicap_tracker_add(ndp, ndp->ni_vp); @@ -1359,6 +1402,7 @@ bad2: bad: if (!dpunlocked) vput(dp); +bad_unlocked: ndp->ni_vp = NULL; return (error); bad_eexist: