svn commit: r363705 - head/sys/kern
Mateusz Guzik
mjg at FreeBSD.org
Thu Jul 30 15:45:12 UTC 2020
Author: mjg
Date: Thu Jul 30 15:45:11 2020
New Revision: 363705
URL: https://svnweb.freebsd.org/changeset/base/363705
Log:
vfs: add support for WANTPARENT and LOCKPARENT to lockless lookup
This makes the realpath syscall operational with the new lookup. Note that the
walk to obtain the full path name still takes locks.
Tested by: pho
Differential Revision: https://reviews.freebsd.org/D23917
Modified:
head/sys/kern/vfs_cache.c
Modified: head/sys/kern/vfs_cache.c
==============================================================================
--- head/sys/kern/vfs_cache.c Thu Jul 30 15:44:10 2020 (r363704)
+++ head/sys/kern/vfs_cache.c Thu Jul 30 15:45:11 2020 (r363705)
@@ -3011,8 +3011,8 @@ cache_fpl_handled_impl(struct cache_fpl *fpl, int erro
#define cache_fpl_handled(x, e) cache_fpl_handled_impl((x), (e), __LINE__)
#define CACHE_FPL_SUPPORTED_CN_FLAGS \
- (LOCKLEAF | FOLLOW | LOCKSHARED | SAVENAME | ISOPEN | NOMACCHECK | \
- AUDITVNODE1 | AUDITVNODE2)
+ (LOCKLEAF | LOCKPARENT | WANTPARENT | FOLLOW | LOCKSHARED | SAVENAME | \
+ ISOPEN | NOMACCHECK | AUDITVNODE1 | AUDITVNODE2)
static bool
cache_can_fplookup(struct cache_fpl *fpl)
@@ -3208,10 +3208,42 @@ cache_fplookup_partial_setup(struct cache_fpl *fpl)
}
static int
-cache_fplookup_final(struct cache_fpl *fpl)
+cache_fplookup_final_child(struct cache_fpl *fpl, enum vgetstate tvs)
{
struct componentname *cnp;
- enum vgetstate tvs;
+ struct vnode *tvp;
+ seqc_t tvp_seqc;
+ int error;
+
+ cnp = fpl->cnp;
+ tvp = fpl->tvp;
+ tvp_seqc = fpl->tvp_seqc;
+
+ if ((cnp->cn_flags & LOCKLEAF) != 0) {
+ error = vget_finish(tvp, cnp->cn_lkflags, tvs);
+ if (error != 0) {
+ return (cache_fpl_aborted(fpl));
+ }
+ } else {
+ vget_finish_ref(tvp, tvs);
+ }
+
+ if (!vn_seqc_consistent(tvp, tvp_seqc)) {
+ if ((cnp->cn_flags & LOCKLEAF) != 0)
+ vput(tvp);
+ else
+ vrele(tvp);
+ return (cache_fpl_aborted(fpl));
+ }
+
+ return (cache_fpl_handled(fpl, 0));
+}
+
+static int __noinline
+cache_fplookup_final_withparent(struct cache_fpl *fpl)
+{
+ enum vgetstate dvs, tvs;
+ struct componentname *cnp;
struct vnode *dvp, *tvp;
seqc_t dvp_seqc, tvp_seqc;
int error;
@@ -3222,39 +3254,90 @@ cache_fplookup_final(struct cache_fpl *fpl)
tvp = fpl->tvp;
tvp_seqc = fpl->tvp_seqc;
- VNPASS(cache_fplookup_vnode_supported(dvp), dvp);
+ MPASS((cnp->cn_flags & (LOCKPARENT|WANTPARENT)) != 0);
+ /*
+ * This is less efficient than it can be for simplicity.
+ */
+ dvs = vget_prep_smr(dvp);
+ if (dvs == VGET_NONE) {
+ return (cache_fpl_aborted(fpl));
+ }
tvs = vget_prep_smr(tvp);
if (tvs == VGET_NONE) {
- return (cache_fpl_partial(fpl));
- }
-
- if (!vn_seqc_consistent(dvp, dvp_seqc)) {
cache_fpl_smr_exit(fpl);
- vget_abort(tvp, tvs);
+ vget_abort(dvp, dvs);
return (cache_fpl_aborted(fpl));
}
cache_fpl_smr_exit(fpl);
- if ((cnp->cn_flags & LOCKLEAF) != 0) {
- error = vget_finish(tvp, cnp->cn_lkflags, tvs);
+ if ((cnp->cn_flags & LOCKPARENT) != 0) {
+ error = vget_finish(dvp, LK_EXCLUSIVE, dvs);
if (error != 0) {
+ vget_abort(tvp, tvs);
return (cache_fpl_aborted(fpl));
}
} else {
- vget_finish_ref(tvp, tvs);
+ vget_finish_ref(dvp, dvs);
}
- if (!vn_seqc_consistent(tvp, tvp_seqc)) {
- if ((cnp->cn_flags & LOCKLEAF) != 0)
- vput(tvp);
+ if (!vn_seqc_consistent(dvp, dvp_seqc)) {
+ vget_abort(tvp, tvs);
+ if ((cnp->cn_flags & LOCKPARENT) != 0)
+ vput(dvp);
else
- vrele(tvp);
+ vrele(dvp);
+ cache_fpl_aborted(fpl);
+ return (error);
+ }
+
+ error = cache_fplookup_final_child(fpl, tvs);
+ if (error != 0) {
+ MPASS(fpl->status == CACHE_FPL_STATUS_ABORTED);
+ if ((cnp->cn_flags & LOCKPARENT) != 0)
+ vput(dvp);
+ else
+ vrele(dvp);
+ return (error);
+ }
+
+ MPASS(fpl->status == CACHE_FPL_STATUS_HANDLED);
+ return (0);
+}
+
+static int
+cache_fplookup_final(struct cache_fpl *fpl)
+{
+ struct componentname *cnp;
+ enum vgetstate tvs;
+ struct vnode *dvp, *tvp;
+ seqc_t dvp_seqc, tvp_seqc;
+
+ cnp = fpl->cnp;
+ dvp = fpl->dvp;
+ dvp_seqc = fpl->dvp_seqc;
+ tvp = fpl->tvp;
+ tvp_seqc = fpl->tvp_seqc;
+
+ VNPASS(cache_fplookup_vnode_supported(dvp), dvp);
+
+ if ((cnp->cn_flags & (LOCKPARENT|WANTPARENT)) != 0)
+ return (cache_fplookup_final_withparent(fpl));
+
+ tvs = vget_prep_smr(tvp);
+ if (tvs == VGET_NONE) {
+ return (cache_fpl_partial(fpl));
+ }
+
+ if (!vn_seqc_consistent(dvp, dvp_seqc)) {
+ cache_fpl_smr_exit(fpl);
+ vget_abort(tvp, tvs);
return (cache_fpl_aborted(fpl));
}
- return (cache_fpl_handled(fpl, 0));
+ cache_fpl_smr_exit(fpl);
+ return (cache_fplookup_final_child(fpl, tvs));
}
static int
More information about the svn-src-head
mailing list