git: 74a3652f832f - main - ufs_direnter: move directory truncation to ffs_vput_pair().
Konstantin Belousov
kib at FreeBSD.org
Fri Feb 12 01:07:25 UTC 2021
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=74a3652f832f4ed0f1ad9f7eb60d70013b478e1a
commit 74a3652f832f4ed0f1ad9f7eb60d70013b478e1a
Author: Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-01-27 20:34:14 +0000
Commit: Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-02-12 01:02:21 +0000
ufs_direnter: move directory truncation to ffs_vput_pair().
VOP_VPUT_PAIR() provides the hook to do the truncation right before
unlock, which is required since truncation might need to fsync(), which
itself might unlock the directory vnode.
Set new flag IN_ENDOFF which indicates that i_endoff is valid and should
be checked against inode size. Excessive size is chomped, but this
operation is advisory and failure to truncate should not result in the
failure of the main VOP.
Reviewed by: chs, mckusick
Tested by: pho
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
---
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);
}
More information about the dev-commits-src-main
mailing list