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