softdep_prelink(): only do sync if other thread changed the vnode metadata since previous prelink

We call into softdep_prerename() and softdep_prelink() when there is
low free space in the journal. Functions sync all vnodes participating
in the VOP, in the hope that this would reduce journal utilization. But
if the vnodes are already synced, doing sync would only spend writes,
journal is filled not due to the records from modifications of our
vnodes.

Remember original seqc numbers for vnodes, and only initiate syncs when
seqc changed.

Reviewed by:	mckusick
Discussed with:	markj
Tested by:	pho
Sponsored by:	The FreeBSD Foundation
MFC after:	2 weeks
Differential revision:	https://reviews.freebsd.org/D30041
This commit is contained in:
Konstantin Belousov 2021-05-02 00:53:21 +03:00
parent f756546662
commit 64b494a105
4 changed files with 46 additions and 13 deletions

View file

@ -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

View file

@ -181,7 +181,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,

View file

@ -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");
@ -3384,11 +3385,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)
@ -3404,13 +3407,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);
@ -3421,7 +3439,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);
@ -3431,7 +3449,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;
}
}
@ -3450,6 +3468,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);
}

View file

@ -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);