Merge tag 'xfs-5.9-merge-7' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[linux-2.6-microblaze.git] / fs / xfs / xfs_bmap_util.c
index 3052586..73cafc8 100644 (file)
@@ -1567,6 +1567,7 @@ xfs_swap_extents(
        int                     lock_flags;
        uint64_t                f;
        int                     resblks = 0;
+       unsigned int            flags = 0;
 
        /*
         * Lock the inodes against other IO, page faults and truncate to
@@ -1630,17 +1631,16 @@ xfs_swap_extents(
                resblks +=  XFS_SWAP_RMAP_SPACE_RES(mp, tipnext, w);
 
                /*
-                * Handle the corner case where either inode might straddle the
-                * btree format boundary. If so, the inode could bounce between
-                * btree <-> extent format on unmap -> remap cycles, freeing and
-                * allocating a bmapbt block each time.
+                * If either inode straddles a bmapbt block allocation boundary,
+                * the rmapbt algorithm triggers repeated allocs and frees as
+                * extents are remapped. This can exhaust the block reservation
+                * prematurely and cause shutdown. Return freed blocks to the
+                * transaction reservation to counter this behavior.
                 */
-               if (ipnext == (XFS_IFORK_MAXEXT(ip, w) + 1))
-                       resblks += XFS_IFORK_MAXEXT(ip, w);
-               if (tipnext == (XFS_IFORK_MAXEXT(tip, w) + 1))
-                       resblks += XFS_IFORK_MAXEXT(tip, w);
+               flags |= XFS_TRANS_RES_FDBLKS;
        }
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp);
+       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, flags,
+                               &tp);
        if (error)
                goto out_unlock;