diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2021-05-01 21:53:21 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2021-07-07 10:50:13 +0000 |
commit | 2622570aeb3d162812d72f7ef192c322cd8b73ef (patch) | |
tree | bccaa12fa802f2cadf29a132c32d675b9c0f8b42 | |
parent | 9487bd8ee37e6a0394946909636267f644ee8df0 (diff) |
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)
-rw-r--r-- | sys/sys/namei.h | 12 | ||||
-rw-r--r-- | sys/sys/param.h | 2 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_extern.h | 3 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_softdep.c | 32 | ||||
-rw-r--r-- | 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); |