The branch releng/13.0 has been updated by kib:

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

commit b62d17802dcf9b589b6572a010e1a65820117155
Author:     Konstantin Belousov <k...@freebsd.org>
AuthorDate: 2021-01-27 20:34:14 +0000
Commit:     Konstantin Belousov <k...@freebsd.org>
CommitDate: 2021-02-25 20:49:09 +0000

    ufs_direnter: move directory truncation to ffs_vput_pair().
    
    Approved by:    re (delphij, gjb)
    
    (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);
 }
 
_______________________________________________
dev-commits-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "dev-commits-src-all-unsubscr...@freebsd.org"

Reply via email to