aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMateusz Guzik <mjg@FreeBSD.org>2021-01-31 20:54:35 +0000
committerMateusz Guzik <mjg@FreeBSD.org>2021-02-01 04:53:23 +0000
commit6f19dc2124a31aadf419743288d2ec1abd895563 (patch)
tree94ccc64f7446e1f652c61dd8c2613ac016ccb568 /sys
parentbbfb1edd70e15241d852d82eb7e1c1049a01b886 (diff)
downloadsrc-6f19dc2124a31aadf419743288d2ec1abd895563.tar.gz
src-6f19dc2124a31aadf419743288d2ec1abd895563.zip
cache: add delayed degenerate path handling
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/vfs_cache.c57
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;