git: 71a6a0b5452d - main - cache: skip checking for spurious slashes if possible

Mateusz Guzik mjg at FreeBSD.org
Wed Jan 6 07:36:12 UTC 2021


The branch main has been updated by mjg:

URL: https://cgit.FreeBSD.org/src/commit/?id=71a6a0b5452d7e7e2ca5fc15680cfc70f72eeb1b

commit 71a6a0b5452d7e7e2ca5fc15680cfc70f72eeb1b
Author:     Mateusz Guzik <mjg at FreeBSD.org>
AuthorDate: 2021-01-01 04:05:04 +0000
Commit:     Mateusz Guzik <mjg at 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);
 }
 
 /*


More information about the dev-commits-src-all mailing list