aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-05-01 21:53:21 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-07-07 10:50:13 +0000
commit2622570aeb3d162812d72f7ef192c322cd8b73ef (patch)
treebccaa12fa802f2cadf29a132c32d675b9c0f8b42
parent9487bd8ee37e6a0394946909636267f644ee8df0 (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.h12
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/ufs/ffs/ffs_extern.h3
-rw-r--r--sys/ufs/ffs/ffs_softdep.c32
-rw-r--r--sys/ufs/ufs/ufs_vnops.c12
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);