Date: Wed, 6 Jan 2021 07:36:11 GMT From: Mateusz Guzik <mjg@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 71a6a0b5452d - main - cache: skip checking for spurious slashes if possible Message-ID: <202101060736.1067aBGF077377@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by mjg: URL: https://cgit.FreeBSD.org/src/commit/?id=71a6a0b5452d7e7e2ca5fc15680cfc70f72eeb1b commit 71a6a0b5452d7e7e2ca5fc15680cfc70f72eeb1b Author: Mateusz Guzik <mjg@FreeBSD.org> AuthorDate: 2021-01-01 04:05:04 +0000 Commit: Mateusz Guzik <mjg@FreeBSD.org> CommitDate: 2021-01-06 07:28:06 +0000 cache: skip checking for spurious slashes if possible Tested by: pho --- sys/kern/vfs_cache.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 40298cd9fbdc..710c499d6bb5 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -3640,6 +3640,7 @@ struct cache_fpl { static bool cache_fplookup_is_mp(struct cache_fpl *fpl); static int cache_fplookup_cross_mount(struct cache_fpl *fpl); static int cache_fplookup_partial_setup(struct cache_fpl *fpl); +static int cache_fplookup_skip_slashes(struct cache_fpl *fpl); static void cache_fpl_cleanup_cnp(struct componentname *cnp) @@ -4006,6 +4007,17 @@ cache_fplookup_partial_setup(struct cache_fpl *fpl) if (cache_fpl_isdotdot(cnp)) cnp->cn_flags |= ISDOTDOT; + /* + * Skip potential extra slashes parsing did not take care of. + * cache_fplookup_skip_slashes explains the mechanism. + */ + if (__predict_false(*(cnp->cn_nameptr) == '/')) { + do { + cnp->cn_nameptr++; + ndp->ni_pathlen--; + } while (*(cnp->cn_nameptr) == '/'); + } + return (0); } @@ -4064,6 +4076,7 @@ cache_fplookup_final_modifying(struct cache_fpl *fpl) dvp = fpl->dvp; dvp_seqc = fpl->dvp_seqc; + MPASS(*(cnp->cn_nameptr) != '/'); MPASS(cache_fpl_islastcn(ndp)); if ((cnp->cn_flags & LOCKPARENT) == 0) MPASS((cnp->cn_flags & WANTPARENT) != 0); @@ -4309,6 +4322,8 @@ cache_fplookup_final(struct cache_fpl *fpl) dvp_seqc = fpl->dvp_seqc; tvp = fpl->tvp; + MPASS(*(cnp->cn_nameptr) != '/'); + if (cnp->cn_nameiop != LOOKUP) { return (cache_fplookup_final_modifying(fpl)); } @@ -4397,6 +4412,7 @@ cache_fplookup_noentry(struct cache_fpl *fpl) dvp = fpl->dvp; dvp_seqc = fpl->dvp_seqc; + MPASS(*(cnp->cn_nameptr) != '/'); MPASS((cnp->cn_flags & MAKEENTRY) == 0); MPASS((cnp->cn_flags & ISDOTDOT) == 0); MPASS(!cache_fpl_isdotdot(cnp)); @@ -4664,6 +4680,9 @@ cache_fplookup_next(struct cache_fpl *fpl) } if (__predict_false(ncp == NULL)) { + if (cnp->cn_nameptr[0] == '/') { + return (cache_fplookup_skip_slashes(fpl)); + } return (cache_fplookup_noentry(fpl)); } @@ -4969,10 +4988,56 @@ cache_fplookup_parse_advance(struct cache_fpl *fpl) cnp = fpl->cnp; cnp->cn_nameptr = ndp->ni_next; - while (*cnp->cn_nameptr == '/') { + KASSERT(*(cnp->cn_nameptr) == '/', + ("%s: should have seen slash at %p ; buf %p [%s]\n", __func__, + cnp->cn_nameptr, cnp->cn_pnbuf, cnp->cn_pnbuf)); + cnp->cn_nameptr++; + ndp->ni_pathlen--; +} + +/* + * Skip spurious slashes in a pathname (e.g., "foo///bar") and retry. + * + * Lockless lookup tries to elide checking for spurious slashes and should they + * be present is guaranteed to fail to find an entry. In this case the caller + * must check if the name starts with a slash and this call routine. It is + * going to fast forward across the spurious slashes and set the state up for + * retry. + */ +static int __noinline +cache_fplookup_skip_slashes(struct cache_fpl *fpl) +{ + struct nameidata *ndp; + struct componentname *cnp; + + ndp = fpl->ndp; + cnp = fpl->cnp; + + MPASS(*(cnp->cn_nameptr) == '/'); + do { cnp->cn_nameptr++; ndp->ni_pathlen--; - } + } while (*(cnp->cn_nameptr) == '/'); + + /* + * Go back to one slash so that cache_fplookup_parse_advance has + * something to skip. + */ + cnp->cn_nameptr--; + ndp->ni_pathlen++; + + /* + * cache_fplookup_parse_advance starts from ndp->ni_next + */ + ndp->ni_next = cnp->cn_nameptr; + + /* + * Retry the lookup, similar to dot lookups. + */ + fpl->tvp = fpl->dvp; + fpl->tvp_seqc = fpl->dvp_seqc; + + return (0); } /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101060736.1067aBGF077377>