aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMateusz Guzik <mjg@FreeBSD.org>2021-05-11 03:48:08 +0000
committerMateusz Guzik <mjg@FreeBSD.org>2021-05-19 15:53:34 +0000
commitb3e8bfd771b4b172a4f3619da25b79459e46ba41 (patch)
tree61f1c0a0c9ee08a32ea1fac7b2870c6a96ec3e20
parent8aed0580e40e08446ef1fc2cc9bef70cb5f68ec1 (diff)
downloadsrc-b3e8bfd771b4b172a4f3619da25b79459e46ba41.tar.gz
src-b3e8bfd771b4b172a4f3619da25b79459e46ba41.zip
cache: fix lockless absolute symlink traversal to non-fp mounts
Said lookups would incorrectly fail with EOPNOTSUP. Reported by: kib (cherry picked from commit 12288bd999ca3a493b8dc4cba109e5a8fa838c45)
-rw-r--r--sys/kern/vfs_cache.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 8819ef483af5..31d6668a3565 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -3936,6 +3936,7 @@ struct cache_fpl {
#endif
};
+static bool cache_fplookup_mp_supported(struct mount *mp);
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);
@@ -5174,6 +5175,19 @@ cache_fplookup_symlink(struct cache_fpl *fpl)
if (seqc_in_modify(fpl->dvp_seqc)) {
return (cache_fpl_aborted(fpl));
}
+ /*
+ * The main loop assumes that ->dvp points to a vnode belonging
+ * to a filesystem which can do lockless lookup, but the absolute
+ * symlink can be wandering off to one which does not.
+ */
+ mp = atomic_load_ptr(&fpl->dvp->v_mount);
+ if (__predict_false(mp == NULL)) {
+ return (cache_fpl_aborted(fpl));
+ }
+ if (!cache_fplookup_mp_supported(mp)) {
+ cache_fpl_checkpoint(fpl);
+ return (cache_fpl_partial(fpl));
+ }
}
return (0);
}