diff options
author | Mateusz Guzik <mjg@FreeBSD.org> | 2021-01-31 20:54:35 +0000 |
---|---|---|
committer | Mateusz Guzik <mjg@FreeBSD.org> | 2021-02-01 04:53:23 +0000 |
commit | 6f19dc2124a31aadf419743288d2ec1abd895563 (patch) | |
tree | 94ccc64f7446e1f652c61dd8c2613ac016ccb568 /sys/kern | |
parent | bbfb1edd70e15241d852d82eb7e1c1049a01b886 (diff) | |
download | src-6f19dc2124a31aadf419743288d2ec1abd895563.tar.gz src-6f19dc2124a31aadf419743288d2ec1abd895563.zip |
cache: add delayed degenerate path handling
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/vfs_cache.c | 57 |
1 files changed, 25 insertions, 32 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 028e3af38ef9..7f0e59f1a1ee 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -3737,7 +3737,6 @@ 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 int cache_fplookup_trailingslash(struct cache_fpl *fpl); -static int cache_fplookup_preparse(struct cache_fpl *fpl); static void cache_fpl_pathlen_dec(struct cache_fpl *fpl); static void cache_fpl_pathlen_inc(struct cache_fpl *fpl); static void cache_fpl_pathlen_add(struct cache_fpl *fpl, size_t n); @@ -4518,6 +4517,9 @@ cache_fplookup_degenerate(struct cache_fpl *fpl) struct vnode *dvp; enum vgetstate dvs; int error, lkflags; +#ifdef INVARIANTS + char *cp; +#endif fpl->tvp = fpl->dvp; fpl->tvp_seqc = fpl->dvp_seqc; @@ -4525,6 +4527,14 @@ cache_fplookup_degenerate(struct cache_fpl *fpl) cnp = fpl->cnp; dvp = fpl->dvp; +#ifdef INVARIANTS + for (cp = cnp->cn_pnbuf; *cp != '\0'; cp++) { + KASSERT(*cp == '/', + ("%s: encountered non-slash; string [%s]\n", __func__, + cnp->cn_pnbuf)); + } +#endif + if (__predict_false(cnp->cn_nameiop != LOOKUP)) { cache_fpl_smr_exit(fpl); return (cache_fpl_handled_error(fpl, EISDIR)); @@ -4589,6 +4599,9 @@ cache_fplookup_noentry(struct cache_fpl *fpl) } if (cnp->cn_nameptr[0] == '\0') { + if (fpl->tvp == NULL) { + return (cache_fplookup_degenerate(fpl)); + } return (cache_fplookup_trailingslash(fpl)); } @@ -4897,7 +4910,7 @@ cache_symlink_resolve(struct cache_fpl *fpl, const char *string, size_t len) cache_fpl_pathlen_add(fpl, adjust); cnp->cn_nameptr = cnp->cn_pnbuf; fpl->nulchar = &cnp->cn_nameptr[ndp->ni_pathlen - 1]; - + fpl->tvp = NULL; return (0); } @@ -4957,8 +4970,7 @@ cache_fplookup_symlink(struct cache_fpl *fpl) return (cache_fpl_aborted(fpl)); } } - - return (cache_fplookup_preparse(fpl)); + return (0); } static int @@ -5238,30 +5250,6 @@ cache_fpl_pathlen_dec(struct cache_fpl *fpl) } #endif -static int __always_inline -cache_fplookup_preparse(struct cache_fpl *fpl) -{ - struct componentname *cnp; - - cnp = fpl->cnp; - - if (__predict_false(cnp->cn_nameptr[0] == '\0')) { - return (cache_fplookup_degenerate(fpl)); - } - - /* - * By this point the shortest possible pathname is one character + nul - * terminator, hence 2. - */ - KASSERT(fpl->debug.ni_pathlen >= 2, ("%s: pathlen %zu\n", __func__, - fpl->debug.ni_pathlen)); - KASSERT(&cnp->cn_nameptr[fpl->debug.ni_pathlen - 2] == fpl->nulchar - 1, - ("%s: mismatch on string (%p != %p) [%s]\n", __func__, - &cnp->cn_nameptr[fpl->debug.ni_pathlen - 2], fpl->nulchar - 1, - cnp->cn_pnbuf)); - return (0); -} - static void cache_fplookup_parse(struct cache_fpl *fpl) { @@ -5534,6 +5522,13 @@ cache_fplookup_failed_vexec(struct cache_fpl *fpl, int error) dvp_seqc = fpl->dvp_seqc; /* + * Hack: delayed degenerate path checking. + */ + if (cnp->cn_nameptr[0] == '\0' && fpl->tvp == NULL) { + return (cache_fplookup_degenerate(fpl)); + } + + /* * Hack: delayed name len checking. */ if (__predict_false(cnp->cn_namelen > NAME_MAX)) { @@ -5624,10 +5619,7 @@ cache_fplookup_impl(struct vnode *dvp, struct cache_fpl *fpl) return (cache_fpl_aborted(fpl)); } - error = cache_fplookup_preparse(fpl); - if (__predict_false(cache_fpl_terminated(fpl))) { - return (error); - } + MPASS(fpl->tvp == NULL); for (;;) { cache_fplookup_parse(fpl); @@ -5787,6 +5779,7 @@ cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status, fpl.nulchar = &cnp->cn_nameptr[ndp->ni_pathlen - 1]; fpl.fsearch = false; fpl.savename = (cnp->cn_flags & SAVENAME) != 0; + fpl.tvp = NULL; /* for degenerate path handling */ fpl.pwd = pwdp; pwd = pwd_get_smr(); *(fpl.pwd) = pwd; |