Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 Feb 2021 07:58:52 GMT
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: c918922cb9a7 - stable/13 - ufs_direnter: move directory truncation to ffs_vput_pair().
Message-ID:  <202102240758.11O7wqLq046607@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by kib:

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

commit c918922cb9a74f4f5f39420527642f207ba1ce50
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-01-27 20:34:14 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-02-24 07:45:21 +0000

    ufs_direnter: move directory truncation to ffs_vput_pair().
    
    (cherry picked from commit 74a3652f832f4ed0f1ad9f7eb60d70013b478e1a)
---
 sys/ufs/ffs/ffs_vnops.c  | 44 ++++++++++++++++++++++++++++++++++++++------
 sys/ufs/ufs/inode.h      |  2 ++
 sys/ufs/ufs/ufs_lookup.c | 25 ++++++-------------------
 3 files changed, 46 insertions(+), 25 deletions(-)

diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index 2ac67adad5f2..dd0f1ba6b81d 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$");
 
 #include "opt_directio.h"
 #include "opt_ffs.h"
+#include "opt_ufs.h"
 
 #include <sys/param.h>
 #include <sys/bio.h>
@@ -99,6 +100,10 @@ __FBSDID("$FreeBSD$");
 #include <ufs/ufs/inode.h>
 #include <ufs/ufs/ufs_extern.h>
 #include <ufs/ufs/ufsmount.h>
+#include <ufs/ufs/dir.h>
+#ifdef UFS_DIRHASH
+#include <ufs/ufs/dirhash.h>
+#endif
 
 #include <ufs/ffs/fs.h>
 #include <ufs/ffs/ffs_extern.h>
@@ -1929,6 +1934,7 @@ ffs_vput_pair(struct vop_vput_pair_args *ap)
 	struct inode *dp, *ip;
 	ino_t ip_ino;
 	u_int64_t ip_gen;
+	off_t old_size;
 	int error, vp_locked;
 
 	dvp = ap->a_dvp;
@@ -1936,14 +1942,14 @@ ffs_vput_pair(struct vop_vput_pair_args *ap)
 	vpp = ap->a_vpp;
 	vp = vpp != NULL ? *vpp : NULL;
 
-	if ((dp->i_flag & IN_NEEDSYNC) == 0) {
+	if ((dp->i_flag & (IN_NEEDSYNC | IN_ENDOFF)) == 0) {
 		vput(dvp);
 		if (vp != NULL && ap->a_unlock_vp)
 			vput(vp);
 		return (0);
 	}
 
-	mp = NULL;
+	mp = dvp->v_mount;
 	if (vp != NULL) {
 		if (ap->a_unlock_vp) {
 			vput(vp);
@@ -1953,14 +1959,40 @@ ffs_vput_pair(struct vop_vput_pair_args *ap)
 			ip = VTOI(vp);
 			ip_ino = ip->i_number;
 			ip_gen = ip->i_gen;
-			mp = vp->v_mount;
 			VOP_UNLOCK(vp);
 		}
 	}
 
-	do {
-		error = ffs_syncvnode(dvp, MNT_WAIT, 0);
-	} while (error == ERELOOKUP);
+	/*
+	 * If compaction or fsync was requested do it in ffs_vput_pair()
+	 * now that other locks are no longer held.
+         */
+	if ((dp->i_flag & IN_ENDOFF) != 0) {
+		dp->i_flag &= ~IN_ENDOFF;
+		if (I_ENDOFF(dp) != 0 && I_ENDOFF(dp) < dp->i_size) {
+			old_size = dp->i_size;
+			error = UFS_TRUNCATE(dvp, (off_t)I_ENDOFF(dp),
+			    IO_NORMAL | (DOINGASYNC(dvp) ? 0 : IO_SYNC),
+			    curthread->td_ucred);
+			if (error != 0 && error != ERELOOKUP) {
+				if (!ffs_fsfail_cleanup(VFSTOUFS(mp), error)) {
+					vn_printf(dvp,
+					    "IN_ENDOFF: failed to truncate, "
+					    "error %d\n", error);
+				}
+#ifdef UFS_DIRHASH
+				ufsdirhash_free(dp);
+#endif
+			}
+		}
+		SET_I_ENDOFF(dp, 0);
+	}
+	if ((dp->i_flag & IN_NEEDSYNC) != 0) {
+		do {
+			error = ffs_syncvnode(dvp, MNT_WAIT, 0);
+		} while (error == ERELOOKUP);
+	}
+
 	vput(dvp);
 
 	if (vp == NULL || ap->a_unlock_vp)
diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h
index 16db8d6d5cea..4515dcbed401 100644
--- a/sys/ufs/ufs/inode.h
+++ b/sys/ufs/ufs/inode.h
@@ -152,6 +152,8 @@ struct inode {
 #define	IN_IBLKDATA	0x0800		/* datasync requires inode block
 					   update */
 #define	IN_SIZEMOD	0x1000		/* Inode size has been modified */
+#define	IN_ENDOFF	0x2000		/* Free space at the end of directory,
+					   try to truncate when possible */
 
 #define PRINT_INODE_FLAGS "\20\20b16\17b15\16b14\15sizemod" \
 	"\14iblkdata\13is_ufs2\12truncated\11ea_lockwait\10ea_locked" \
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index e614f189a623..3036bce81caf 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -1112,27 +1112,14 @@ ufs_direnter(dvp, tvp, dirp, cnp, newdirbp, isrename)
 		}
 	}
 	UFS_INODE_SET_FLAG(dp, IN_CHANGE | IN_UPDATE);
+
 	/*
-	 * If all went well, and the directory can be shortened, proceed
-	 * with the truncation. Note that we have to unlock the inode for
-	 * the entry that we just entered, as the truncation may need to
-	 * lock other inodes which can lead to deadlock if we also hold a
-	 * lock on the newly entered node.
+	 * If all went well, and the directory can be shortened, mark directory inode
+	 * with the truncation request right before unlock.
 	 */
-	if (isrename == 0 && error == 0 &&
-	    I_ENDOFF(dp) != 0 && I_ENDOFF(dp) < dp->i_size) {
-		if (tvp != NULL)
-			VOP_UNLOCK(tvp);
-		error = UFS_TRUNCATE(dvp, (off_t)I_ENDOFF(dp),
-		    IO_NORMAL | (DOINGASYNC(dvp) ? 0 : IO_SYNC), cr);
-		if (error != 0)
-			vn_printf(dvp,
-			    "ufs_direnter: failed to truncate, error %d\n",
-			    error);
-		error = 0;
-		if (tvp != NULL)
-			vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
-	}
+	if (isrename == 0 && error == 0)
+		UFS_INODE_SET_FLAG(dp, IN_ENDOFF);
+
 	return (error);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202102240758.11O7wqLq046607>