The branch main has been updated by kib:

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

commit bc6d0d72f4f4e96b24d0ad558b271cb6f483801e
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2022-06-22 13:54:01 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2022-06-24 14:46:26 +0000

    UFS rename: make it reliable when using SU and reaching nlink limit
    
    PR:     165392
    Reviewed by:    mckusick
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D35577
---
 sys/ufs/ufs/ufs_vnops.c | 95 +++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 84 insertions(+), 11 deletions(-)

diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index 0a7e6a7875ec..7e54cf3916c8 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -196,6 +196,21 @@ ufs_itimes(struct vnode *vp)
        VI_UNLOCK(vp);
 }
 
+static int
+ufs_sync_nlink1(struct mount *mp)
+{
+       int error;
+
+       error = vfs_busy(mp, 0);
+       if (error == 0) {
+               VFS_SYNC(mp, MNT_WAIT);
+               vfs_unbusy(mp);
+               error = ERELOOKUP;
+       }
+       vfs_rel(mp);
+       return (error);
+}
+
 static int
 ufs_sync_nlink(struct vnode *vp, struct vnode *vp1)
 {
@@ -214,13 +229,7 @@ ufs_sync_nlink(struct vnode *vp, struct vnode *vp1)
        VOP_UNLOCK(vp);
        if (vp1 != NULL)
                VOP_UNLOCK(vp1);
-       error = vfs_busy(mp, 0);
-       if (error == 0) {
-               VFS_SYNC(mp, MNT_WAIT);
-               vfs_unbusy(mp);
-               error = ERELOOKUP;
-       }
-       vfs_rel(mp);
+       error = ufs_sync_nlink1(mp);
        vn_lock_pair(vp, false, vp1, false);
        return (error);
 }
@@ -1441,8 +1450,34 @@ relock:
        newparent = 0;
        ino = fip->i_number;
        if (fip->i_nlink >= UFS_LINK_MAX) {
-               error = EMLINK;
-               goto unlockout;
+               if (!DOINGSOFTDEP(fvp) || fip->i_effnlink >= UFS_LINK_MAX) {
+                       error = EMLINK;
+                       goto unlockout;
+               }
+               vfs_ref(mp);
+               MPASS(!want_seqc_end);
+               if (checkpath_locked) {
+                       sx_xunlock(&VFSTOUFS(mp)->um_checkpath_lock);
+                       checkpath_locked = false;
+               }
+               VOP_UNLOCK(fdvp);
+               VOP_UNLOCK(fvp);
+               vref(tdvp);
+               if (tvp != NULL)
+                       vref(tvp);
+               VOP_VPUT_PAIR(tdvp, &tvp, true);
+               error = ufs_sync_nlink1(mp);
+               if (error == ERELOOKUP) {
+                       error = 0;
+                       atomic_add_int(&rename_restarts, 1);
+                       goto relock;
+               }
+               vrele(fdvp);
+               vrele(fvp);
+               vrele(tdvp);
+               if (tvp != NULL)
+                       vrele(tvp);
+               return (error);
        }
        if ((fip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))
            || (fdp->i_flags & APPEND)) {
@@ -1556,8 +1591,46 @@ relock:
                         * .. is rewritten below.
                         */
                        if (tdp->i_nlink >= UFS_LINK_MAX) {
-                               error = EMLINK;
-                               goto bad;
+                               if (!DOINGSOFTDEP(tdvp) ||
+                                   tdp->i_effnlink >= UFS_LINK_MAX) {
+                                       error = EMLINK;
+                                       goto unlockout;
+                               }
+                               fip->i_effnlink--;
+                               fip->i_nlink--;
+                               DIP_SET(fip, i_nlink, fip->i_nlink);
+                               UFS_INODE_SET_FLAG(fip, IN_CHANGE);
+                               if (DOINGSOFTDEP(fvp))
+                                       softdep_revert_link(tdp, fip);
+                               MPASS(want_seqc_end);
+                               if (tvp != NULL)
+                                       vn_seqc_write_end(tvp);
+                               vn_seqc_write_end(tdvp);
+                               vn_seqc_write_end(fvp);
+                               vn_seqc_write_end(fdvp);
+                               want_seqc_end = false;
+                               vfs_ref(mp);
+                               MPASS(checkpath_locked);
+                               sx_xunlock(&VFSTOUFS(mp)->um_checkpath_lock);
+                               checkpath_locked = false;
+                               VOP_UNLOCK(fdvp);
+                               VOP_UNLOCK(fvp);
+                               vref(tdvp);
+                               if (tvp != NULL)
+                                       vref(tvp);
+                               VOP_VPUT_PAIR(tdvp, &tvp, true);
+                               error = ufs_sync_nlink1(mp);
+                               if (error == ERELOOKUP) {
+                                       error = 0;
+                                       atomic_add_int(&rename_restarts, 1);
+                                       goto relock;
+                               }
+                               vrele(fdvp);
+                               vrele(fvp);
+                               vrele(tdvp);
+                               if (tvp != NULL)
+                                       vrele(tvp);
+                               return (error);
                        }
                }
                ufs_makedirentry(fip, tcnp, &newdir);

Reply via email to