xfs: Hold inode locks in xfs_rename
authorAllison Henderson <allison.henderson@oracle.com>
Mon, 15 Apr 2024 21:55:14 +0000 (14:55 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 21:59:02 +0000 (14:59 -0700)
Modify xfs_rename to hold all inode locks across a rename operation
We will need this later when we add parent pointers

Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Catherine Hoang <catherine.hoang@oracle.com>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/xfs_inode.c

index 36e1012e156a1c46c311c31f598a17a557d711d4..2aec7ab59aeb7f3302d193682e1606a365aeb5cc 100644 (file)
@@ -2804,6 +2804,21 @@ xfs_remove(
        return error;
 }
 
+static inline void
+xfs_iunlock_rename(
+       struct xfs_inode        **i_tab,
+       int                     num_inodes)
+{
+       int                     i;
+
+       for (i = num_inodes - 1; i >= 0; i--) {
+               /* Skip duplicate inodes if src and target dps are the same */
+               if (!i_tab[i] || (i > 0 && i_tab[i] == i_tab[i - 1]))
+                       continue;
+               xfs_iunlock(i_tab[i], XFS_ILOCK_EXCL);
+       }
+}
+
 /*
  * Enter all inodes for a rename transaction into a sorted array.
  */
@@ -3113,8 +3128,10 @@ retry:
         * Attach the dquots to the inodes
         */
        error = xfs_qm_vop_rename_dqattach(inodes);
-       if (error)
-               goto out_trans_cancel;
+       if (error) {
+               xfs_trans_cancel(tp);
+               goto out_release_wip;
+       }
 
        /*
         * Lock all the participating inodes. Depending upon whether
@@ -3125,18 +3142,16 @@ retry:
        xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
 
        /*
-        * Join all the inodes to the transaction. From this point on,
-        * we can rely on either trans_commit or trans_cancel to unlock
-        * them.
+        * Join all the inodes to the transaction.
         */
-       xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, src_dp, 0);
        if (new_parent)
-               xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, target_dp, 0);
+       xfs_trans_ijoin(tp, src_ip, 0);
        if (target_ip)
-               xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, target_ip, 0);
        if (wip)
-               xfs_trans_ijoin(tp, wip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, wip, 0);
 
        /*
         * If we are using project inheritance, we only allow renames
@@ -3150,10 +3165,13 @@ retry:
        }
 
        /* RENAME_EXCHANGE is unique from here on. */
-       if (flags & RENAME_EXCHANGE)
-               return xfs_cross_rename(tp, src_dp, src_name, src_ip,
+       if (flags & RENAME_EXCHANGE) {
+               error = xfs_cross_rename(tp, src_dp, src_name, src_ip,
                                        target_dp, target_name, target_ip,
                                        spaceres);
+               xfs_iunlock_rename(inodes, num_inodes);
+               return error;
+       }
 
        /*
         * Try to reserve quota to handle an expansion of the target directory.
@@ -3167,6 +3185,7 @@ retry:
                if (error == -EDQUOT || error == -ENOSPC) {
                        if (!retried) {
                                xfs_trans_cancel(tp);
+                               xfs_iunlock_rename(inodes, num_inodes);
                                xfs_blockgc_free_quota(target_dp, 0);
                                retried = true;
                                goto retry;
@@ -3393,12 +3412,14 @@ retry:
                xfs_dir_update_hook(src_dp, wip, 1, src_name);
 
        error = xfs_finish_rename(tp);
+       xfs_iunlock_rename(inodes, num_inodes);
        if (wip)
                xfs_irele(wip);
        return error;
 
 out_trans_cancel:
        xfs_trans_cancel(tp);
+       xfs_iunlock_rename(inodes, num_inodes);
 out_release_wip:
        if (wip)
                xfs_irele(wip);