aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMateusz Guzik <mjguzik@gmail.com>2020-12-28 06:53:17 +0000
committerMateusz Guzik <mjg@FreeBSD.org>2021-01-01 00:10:42 +0000
commit0b5bd1afd89fa42629a28dc01eae5e39c8e5fecd (patch)
tree6f0382a64c354814275a9faf6a307666d682d624 /sys
parent1d6eb976774af6a84414a6785217b305021ce841 (diff)
downloadsrc-0b5bd1afd89fa42629a28dc01eae5e39c8e5fecd.tar.gz
src-0b5bd1afd89fa42629a28dc01eae5e39c8e5fecd.zip
cache: support lockless lookup of degenerate paths
Tested by: pho
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/vfs_cache.c61
1 files changed, 52 insertions, 9 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index c9b0010020f8..cde2fde8a9ec 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -4224,6 +4224,56 @@ cache_fplookup_final(struct cache_fpl *fpl)
return (cache_fplookup_final_child(fpl, tvs));
}
+/*
+ * Comment from locked lookup:
+ * Check for degenerate name (e.g. / or "") which is a way of talking about a
+ * directory, e.g. like "/." or ".".
+ */
+static int __noinline
+cache_fplookup_degenerate(struct cache_fpl *fpl)
+{
+ struct componentname *cnp;
+ struct vnode *dvp;
+ enum vgetstate dvs;
+ int error, lkflags;
+
+ fpl->tvp = fpl->dvp;
+ fpl->tvp_seqc = fpl->dvp_seqc;
+
+ cnp = fpl->cnp;
+ dvp = fpl->dvp;
+
+ if (__predict_false(cnp->cn_nameiop != LOOKUP)) {
+ cache_fpl_smr_exit(fpl);
+ return (cache_fpl_handled(fpl, EISDIR));
+ }
+
+ MPASS((cnp->cn_flags & SAVESTART) == 0);
+
+ if ((cnp->cn_flags & (LOCKPARENT|WANTPARENT)) != 0) {
+ return (cache_fplookup_final_withparent(fpl));
+ }
+
+ dvs = vget_prep_smr(dvp);
+ cache_fpl_smr_exit(fpl);
+ if (__predict_false(dvs == VGET_NONE)) {
+ return (cache_fpl_aborted(fpl));
+ }
+
+ if ((cnp->cn_flags & LOCKLEAF) != 0) {
+ lkflags = LK_SHARED;
+ if ((cnp->cn_flags & LOCKSHARED) == 0)
+ lkflags = LK_EXCLUSIVE;
+ error = vget_finish(dvp, lkflags, dvs);
+ if (__predict_false(error != 0)) {
+ return (cache_fpl_aborted(fpl));
+ }
+ } else {
+ vget_finish_ref(dvp, dvs);
+ }
+ return (cache_fpl_handled(fpl, 0));
+}
+
static int __noinline
cache_fplookup_noentry(struct cache_fpl *fpl)
{
@@ -4694,15 +4744,8 @@ cache_fplookup_preparse(struct cache_fpl *fpl)
ndp = fpl->ndp;
cnp = fpl->cnp;
- /*
- * TODO
- * Original comment:
- * 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')) {
- return (cache_fpl_aborted(fpl));
+ return (cache_fplookup_degenerate(fpl));
}
/*
@@ -4913,7 +4956,7 @@ cache_fplookup_impl(struct vnode *dvp, struct cache_fpl *fpl)
VNPASS(cache_fplookup_vnode_supported(fpl->dvp), fpl->dvp);
error = cache_fplookup_preparse(fpl);
- if (__predict_false(error != 0)) {
+ if (__predict_false(cache_fpl_terminated(fpl))) {
goto out;
}