aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_bmap_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_bmap_util.c')
-rw-r--r--fs/xfs/xfs_bmap_util.c47
1 files changed, 27 insertions, 20 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index c83f549dc17b..8cd8c412f52d 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1208,18 +1208,15 @@ xfs_free_file_space(
/*
* Now that we've unmap all full blocks we'll have to zero out any
- * partial block at the beginning and/or end. xfs_zero_range is
- * smart enough to skip any holes, including those we just created,
- * but we must take care not to zero beyond EOF and enlarge i_size.
+ * partial block at the beginning and/or end. iomap_zero_range is smart
+ * enough to skip any holes, including those we just created, but we
+ * must take care not to zero beyond EOF and enlarge i_size.
*/
-
if (offset >= XFS_ISIZE(ip))
return 0;
-
if (offset + len > XFS_ISIZE(ip))
len = XFS_ISIZE(ip) - offset;
-
- return xfs_zero_range(ip, offset, len, NULL);
+ return iomap_zero_range(VFS_I(ip), offset, len, NULL, &xfs_iomap_ops);
}
/*
@@ -1329,7 +1326,6 @@ xfs_collapse_file_space(
int error;
struct xfs_defer_ops dfops;
xfs_fsblock_t first_block;
- xfs_fileoff_t stop_fsb = XFS_B_TO_FSB(mp, VFS_I(ip)->i_size);
xfs_fileoff_t next_fsb = XFS_B_TO_FSB(mp, offset + len);
xfs_fileoff_t shift_fsb = XFS_B_TO_FSB(mp, len);
uint resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
@@ -1364,7 +1360,7 @@ xfs_collapse_file_space(
xfs_defer_init(&dfops, &first_block);
error = xfs_bmap_collapse_extents(tp, ip, &next_fsb, shift_fsb,
- &done, stop_fsb, &first_block, &dfops);
+ &done, &first_block, &dfops);
if (error)
goto out_bmap_cancel;
@@ -1899,17 +1895,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)
@@ -2003,11 +2010,11 @@ xfs_swap_extents(
ip->i_cowfp = tip->i_cowfp;
tip->i_cowfp = cowfp;
- if (ip->i_cowfp && ip->i_cnextents)
+ if (ip->i_cowfp && ip->i_cowfp->if_bytes)
xfs_inode_set_cowblocks_tag(ip);
else
xfs_inode_clear_cowblocks_tag(ip);
- if (tip->i_cowfp && tip->i_cnextents)
+ if (tip->i_cowfp && tip->i_cowfp->if_bytes)
xfs_inode_set_cowblocks_tag(tip);
else
xfs_inode_clear_cowblocks_tag(tip);