git: 2622570aeb3d - stable/13 - softdep_prelink(): only do sync if other thread changed the vnode metadata since previous prelink

Konstantin Belousov kib at FreeBSD.org
Wed Jul 7 11:11:04 UTC 2021


The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=2622570aeb3d162812d72f7ef192c322cd8b73ef

commit 2622570aeb3d162812d72f7ef192c322cd8b73ef
Author:     Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-05-01 21:53:21 +0000
Commit:     Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-07-07 10:50:13 +0000

    softdep_prelink(): only do sync if other thread changed the vnode metadata since previous prelink
    
    FreeBSD_version is bumped due to struct namei size change
    
    (cherry picked from commit 64b494a1050ae2cf2412edc19b57dc80f49eeda1)
---
 sys/sys/namei.h           | 12 +++++++++++-
 sys/sys/param.h           |  2 +-
 sys/ufs/ffs/ffs_extern.h  |  3 ++-
 sys/ufs/ffs/ffs_softdep.c | 32 +++++++++++++++++++++++++++-----
 sys/ufs/ufs/ufs_vnops.c   | 12 ++++++------
 5 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/sys/sys/namei.h b/sys/sys/namei.h
index b4db0e758e2b..9e0a82ea1659 100644
--- a/sys/sys/namei.h
+++ b/sys/sys/namei.h
@@ -38,6 +38,7 @@
 #include <sys/caprights.h>
 #include <sys/filedesc.h>
 #include <sys/queue.h>
+#include <sys/_seqc.h>
 #include <sys/_uio.h>
 
 enum nameiop { LOOKUP, CREATE, DELETE, RENAME };
@@ -111,6 +112,12 @@ struct nameidata {
 	 */
 	struct componentname ni_cnd;
 	struct nameicap_tracker_head ni_cap_tracker;
+	/*
+	 * Private helper data for UFS, must be at the end.  See
+	 * NDINIT_PREFILL().
+	 */
+	seqc_t	ni_dvp_seqc;
+	seqc_t	ni_vp_seqc;
 };
 
 #ifdef _KERNEL
@@ -224,7 +231,8 @@ int	cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status,
  * Note the constant pattern may *hide* bugs.
  */
 #ifdef INVARIANTS
-#define NDINIT_PREFILL(arg)	memset(arg, 0xff, sizeof(*arg))
+#define NDINIT_PREFILL(arg)	memset(arg, 0xff, offsetof(struct nameidata,	\
+    ni_dvp_seqc))
 #define NDINIT_DBG(arg)		{ (arg)->ni_debugflags = NAMEI_DBG_INITED; }
 #define NDREINIT_DBG(arg)	{						\
 	if (((arg)->ni_debugflags & NAMEI_DBG_INITED) == 0)			\
@@ -266,6 +274,8 @@ do {										\
 } while (0)
 
 #define	NDPREINIT(ndp) do {							\
+	(ndp)->ni_dvp_seqc = SEQC_MOD;						\
+	(ndp)->ni_vp_seqc = SEQC_MOD;						\
 } while (0)
 
 #define NDF_NO_DVP_RELE		0x00000001
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 41db9a1675f7..4c43839c297e 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -60,7 +60,7 @@
  *		in the range 5 to 9.
  */
 #undef __FreeBSD_version
-#define __FreeBSD_version 1300510	/* Master, propagated to newvers */
+#define __FreeBSD_version 1300511	/* Master, propagated to newvers */
 
 /*
  * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h
index 544012089046..0365cb76601e 100644
--- a/sys/ufs/ffs/ffs_extern.h
+++ b/sys/ufs/ffs/ffs_extern.h
@@ -178,7 +178,8 @@ int	softdep_request_cleanup(struct fs *, struct vnode *,
 	    struct ucred *, int);
 int	softdep_prerename(struct vnode *, struct vnode *, struct vnode *,
 	    struct vnode *);
-int	softdep_prelink(struct vnode *, struct vnode *);
+int	softdep_prelink(struct vnode *, struct vnode *,
+	    struct componentname *);
 void	softdep_setup_freeblocks(struct inode *, off_t, int);
 void	softdep_setup_inomapdep(struct buf *, struct inode *, ino_t, int);
 void	softdep_setup_blkmapdep(struct buf *, struct mount *, ufs2_daddr_t,
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index dbd08905d953..f6dd5c776611 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -621,9 +621,10 @@ softdep_prerename(fdvp, fvp, tdvp, tvp)
 }
 
 int
-softdep_prelink(dvp, vp)
+softdep_prelink(dvp, vp, cnp)
 	struct vnode *dvp;
 	struct vnode *vp;
+	struct componentname *cnp;
 {
 
 	panic("softdep_prelink called");
@@ -3361,11 +3362,13 @@ softdep_prerename(fdvp, fvp, tdvp, tvp)
  * syscall must be restarted at top level from the lookup.
  */
 int
-softdep_prelink(dvp, vp)
+softdep_prelink(dvp, vp, cnp)
 	struct vnode *dvp;
 	struct vnode *vp;
+	struct componentname *cnp;
 {
 	struct ufsmount *ump;
+	struct nameidata *ndp;
 
 	ASSERT_VOP_ELOCKED(dvp, "prelink dvp");
 	if (vp != NULL)
@@ -3381,13 +3384,28 @@ softdep_prelink(dvp, vp)
 	if (journal_space(ump, 0) || (vp != NULL && IS_SNAPSHOT(VTOI(vp))))
 		return (0);
 
+	/*
+	 * Check if the journal space consumption can in theory be
+	 * accounted on dvp and vp.  If the vnodes metadata was not
+	 * changed comparing with the previous round-trip into
+	 * softdep_prelink(), as indicated by the seqc generation
+	 * recorded in the nameidata, then there is no point in
+	 * starting the sync.
+	 */
+	ndp = __containerof(cnp, struct nameidata, ni_cnd);
+	if (!seqc_in_modify(ndp->ni_dvp_seqc) &&
+	    vn_seqc_consistent(dvp, ndp->ni_dvp_seqc) &&
+	    (vp == NULL || (!seqc_in_modify(ndp->ni_vp_seqc) &&
+	    vn_seqc_consistent(vp, ndp->ni_vp_seqc))))
+		return (0);
+
 	stat_journal_low++;
 	if (vp != NULL) {
 		VOP_UNLOCK(dvp);
 		ffs_syncvnode(vp, MNT_NOWAIT, 0);
 		vn_lock_pair(dvp, false, vp, true);
 		if (dvp->v_data == NULL)
-			return (ERELOOKUP);
+			goto out;
 	}
 	if (vp != NULL)
 		VOP_UNLOCK(vp);
@@ -3398,7 +3416,7 @@ softdep_prelink(dvp, vp)
 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
 		if (vp->v_data == NULL) {
 			vn_lock_pair(dvp, false, vp, true);
-			return (ERELOOKUP);
+			goto out;
 		}
 		ACQUIRE_LOCK(ump);
 		process_removes(vp);
@@ -3408,7 +3426,7 @@ softdep_prelink(dvp, vp)
 		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
 		if (dvp->v_data == NULL) {
 			vn_lock_pair(dvp, true, vp, false);
-			return (ERELOOKUP);
+			goto out;
 		}
 	}
 
@@ -3427,6 +3445,10 @@ softdep_prelink(dvp, vp)
 	FREE_LOCK(ump);
 
 	vn_lock_pair(dvp, false, vp, false);
+out:
+	ndp->ni_dvp_seqc = vn_seqc_read_any(dvp);
+	if (vp != NULL)
+		ndp->ni_vp_seqc = vn_seqc_read_any(vp);
 	return (ERELOOKUP);
 }
 
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index b0fb1b74b900..2dfc2e24f772 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -1010,7 +1010,7 @@ ufs_remove(ap)
 	    (VTOI(dvp)->i_flags & APPEND))
 		return (EPERM);
 	if (DOINGSUJ(dvp)) {
-		error = softdep_prelink(dvp, vp);
+		error = softdep_prelink(dvp, vp, ap->a_cnp);
 		if (error != 0) {
 			MPASS(error == ERELOOKUP);
 			return (error);
@@ -1075,7 +1075,7 @@ ufs_link(ap)
 #endif
 
 	if (DOINGSUJ(tdvp)) {
-		error = softdep_prelink(tdvp, vp);
+		error = softdep_prelink(tdvp, vp, cnp);
 		if (error != 0) {
 			MPASS(error == ERELOOKUP);
 			return (error);
@@ -1147,7 +1147,7 @@ ufs_whiteout(ap)
 
 	if (DOINGSUJ(dvp) && (ap->a_flags == CREATE ||
 	    ap->a_flags == DELETE)) {
-		error = softdep_prelink(dvp, NULL);
+		error = softdep_prelink(dvp, NULL, cnp);
 		if (error != 0) {
 			MPASS(error == ERELOOKUP);
 			return (error);
@@ -1962,7 +1962,7 @@ ufs_mkdir(ap)
 	}
 
 	if (DOINGSUJ(dvp)) {
-		error = softdep_prelink(dvp, NULL);
+		error = softdep_prelink(dvp, NULL, cnp);
 		if (error != 0) {
 			MPASS(error == ERELOOKUP);
 			return (error);
@@ -2226,7 +2226,7 @@ ufs_rmdir(ap)
 		goto out;
 	}
 	if (DOINGSUJ(dvp)) {
-		error = softdep_prelink(dvp, vp);
+		error = softdep_prelink(dvp, vp, cnp);
 		if (error != 0) {
 			MPASS(error == ERELOOKUP);
 			return (error);
@@ -2751,7 +2751,7 @@ ufs_makeinode(mode, dvp, vpp, cnp, callfunc)
 		return (EINVAL);
 	}
 	if (DOINGSUJ(dvp)) {
-		error = softdep_prelink(dvp, NULL);
+		error = softdep_prelink(dvp, NULL, cnp);
 		if (error != 0) {
 			MPASS(error == ERELOOKUP);
 			return (error);


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