|
@@ -1899,17 +1899,28 @@ xfs_swap_extents(
|
|
|
* performed with log redo items!
|
|
|
*/
|
|
|
if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
|
|
|
+ int w = XFS_DATA_FORK;
|
|
|
+ uint32_t ipnext = XFS_IFORK_NEXTENTS(ip, w);
|
|
|
+ uint32_t tipnext = XFS_IFORK_NEXTENTS(tip, w);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Conceptually this shouldn't affect the shape of either bmbt,
|
|
|
+ * but since we atomically move extents one by one, we reserve
|
|
|
+ * enough space to rebuild both trees.
|
|
|
+ */
|
|
|
+ resblks = XFS_SWAP_RMAP_SPACE_RES(mp, ipnext, w);
|
|
|
+ resblks += XFS_SWAP_RMAP_SPACE_RES(mp, tipnext, w);
|
|
|
+
|
|
|
/*
|
|
|
- * Conceptually this shouldn't affect the shape of either
|
|
|
- * bmbt, but since we atomically move extents one by one,
|
|
|
- * we reserve enough space to rebuild both trees.
|
|
|
+ * 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.
|
|
|
*/
|
|
|
- resblks = XFS_SWAP_RMAP_SPACE_RES(mp,
|
|
|
- XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK),
|
|
|
- XFS_DATA_FORK) +
|
|
|
- XFS_SWAP_RMAP_SPACE_RES(mp,
|
|
|
- XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK),
|
|
|
- XFS_DATA_FORK);
|
|
|
+ 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);
|
|
|
}
|
|
|
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp);
|
|
|
if (error)
|