diff mbox

[10/15] xfs: split xfs_bmap_shift_extents

Message ID 20171019065942.18813-11-hch@lst.de (mailing list archive)
State Accepted
Headers show

Commit Message

Christoph Hellwig Oct. 19, 2017, 6:59 a.m. UTC
Have a separate helper for insert vs collapse, as this prepares us for
simplifying the code in the next patches.

Also changed the done output argument to a bool intead of int for both
new functions.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/xfs/libxfs/xfs_bmap.c | 197 ++++++++++++++++++++++++++++++++---------------
 fs/xfs/libxfs/xfs_bmap.h |  10 ++-
 fs/xfs/xfs_bmap_util.c   |  14 ++--
 3 files changed, 148 insertions(+), 73 deletions(-)

Comments

Darrick J. Wong Oct. 21, 2017, 12:22 a.m. UTC | #1
On Thu, Oct 19, 2017 at 08:59:37AM +0200, Christoph Hellwig wrote:
> Have a separate helper for insert vs collapse, as this prepares us for
> simplifying the code in the next patches.
> 
> Also changed the done output argument to a bool intead of int for both
> new functions.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>

Looks ok,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

> ---
>  fs/xfs/libxfs/xfs_bmap.c | 197 ++++++++++++++++++++++++++++++++---------------
>  fs/xfs/libxfs/xfs_bmap.h |  10 ++-
>  fs/xfs/xfs_bmap_util.c   |  14 ++--
>  3 files changed, 148 insertions(+), 73 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index 89ea8a5235c0..7d3a38e69d28 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -5689,57 +5689,151 @@ xfs_bmse_shift_one(
>  	return xfs_rmap_map_extent(mp, dfops, ip, whichfork, &new);
>  }
>  
> -/*
> - * Shift extent records to the left/right to cover/create a hole.
> - *
> - * @stop_fsb specifies the file offset at which to stop shift and the
> - * file offset where we've left off is returned in @next_fsb. @offset_shift_fsb
> - * is the length by which each extent is shifted. If there is no hole to shift
> - * the extents into, this will be considered invalid operation and we abort
> - * immediately.
> - */
>  int
> -xfs_bmap_shift_extents(
> +xfs_bmap_collapse_extents(
>  	struct xfs_trans	*tp,
>  	struct xfs_inode	*ip,
>  	xfs_fileoff_t		*next_fsb,
>  	xfs_fileoff_t		offset_shift_fsb,
> -	int			*done,
> +	bool			*done,
>  	xfs_fileoff_t		stop_fsb,
>  	xfs_fsblock_t		*firstblock,
> -	struct xfs_defer_ops	*dfops,
> -	enum shift_direction	direction)
> +	struct xfs_defer_ops	*dfops)
>  {
> -	struct xfs_btree_cur		*cur = NULL;
> -	struct xfs_bmbt_irec            got;
> -	struct xfs_mount		*mp = ip->i_mount;
> -	struct xfs_ifork		*ifp;
> -	xfs_extnum_t			current_ext;
> -	xfs_extnum_t			total_extents;
> -	xfs_extnum_t			stop_extent;
> -	int				error = 0;
> -	int				whichfork = XFS_DATA_FORK;
> -	int				logflags = 0;
> +	int			whichfork = XFS_DATA_FORK;
> +	struct xfs_mount	*mp = ip->i_mount;
> +	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
> +	struct xfs_btree_cur	*cur = NULL;
> +	struct xfs_bmbt_irec	got;
> +	xfs_extnum_t		current_ext;
> +	xfs_extnum_t		total_extents;
> +	xfs_extnum_t		stop_extent;
> +	int			error = 0;
> +	int			logflags = 0;
>  
>  	if (unlikely(XFS_TEST_ERROR(
>  	    (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
>  	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
>  	     mp, XFS_ERRTAG_BMAPIFORMAT))) {
> -		XFS_ERROR_REPORT("xfs_bmap_shift_extents",
> -				 XFS_ERRLEVEL_LOW, mp);
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
>  		return -EFSCORRUPTED;
>  	}
>  
>  	if (XFS_FORCED_SHUTDOWN(mp))
>  		return -EIO;
>  
> -	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
> -	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
> -	ASSERT(direction == SHIFT_LEFT || direction == SHIFT_RIGHT);
> +	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL));
> +
> +	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
> +		error = xfs_iread_extents(tp, ip, whichfork);
> +		if (error)
> +			return error;
> +	}
> +
> +	if (ifp->if_flags & XFS_IFBROOT) {
> +		cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
> +		cur->bc_private.b.firstblock = *firstblock;
> +		cur->bc_private.b.dfops = dfops;
> +		cur->bc_private.b.flags = 0;
> +	}
> +
> +	/*
> +	 * There may be delalloc extents in the data fork before the range we
> +	 * are collapsing out, so we cannot use the count of real extents here.
> +	 * Instead we have to calculate it from the incore fork.
> +	 */
> +	total_extents = xfs_iext_count(ifp);
> +	if (total_extents == 0) {
> +		*done = true;
> +		goto del_cursor;
> +	}
> +
> +	/*
> +	 * Look up the extent index for the fsb where we start shifting. We can
> +	 * henceforth iterate with current_ext as extent list changes are locked
> +	 * out via ilock.
> +	 *
> +	 * If next_fsb lies in a hole beyond which there are no extents we are
> +	 * done.
> +	 */
> +	if (!xfs_iext_lookup_extent(ip, ifp, *next_fsb, &current_ext, &got)) {
> +		*done = true;
> +		goto del_cursor;
> +	}
> +
> +	stop_extent = total_extents;
> +	if (current_ext >= stop_extent) {
> +		error = -EIO;
> +		goto del_cursor;
> +	}
> +
> +	error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb,
> +				   &current_ext, &got, cur, &logflags,
> +				   SHIFT_LEFT, dfops);
> +	if (error)
> +		goto del_cursor;
> +	/*
> +	 * If there was an extent merge during the shift, the extent
> +	 * count can change. Update the total and grade the next record.
> +	 */
> +	total_extents = xfs_iext_count(ifp);
> +	stop_extent = total_extents;
> +	if (current_ext == stop_extent) {
> +		*done = true;
> +		goto del_cursor;
> +	}
> +	xfs_iext_get_extent(ifp, current_ext, &got);
> +
> +	if (!*done)
> +		*next_fsb = got.br_startoff;
> +
> +del_cursor:
> +	if (cur)
> +		xfs_btree_del_cursor(cur,
> +			error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
> +
> +	if (logflags)
> +		xfs_trans_log_inode(tp, ip, logflags);
> +
> +	return error;
> +}
> +
> +int
> +xfs_bmap_insert_extents(
> +	struct xfs_trans	*tp,
> +	struct xfs_inode	*ip,
> +	xfs_fileoff_t		*next_fsb,
> +	xfs_fileoff_t		offset_shift_fsb,
> +	bool			*done,
> +	xfs_fileoff_t		stop_fsb,
> +	xfs_fsblock_t		*firstblock,
> +	struct xfs_defer_ops	*dfops)
> +{
> +	int			whichfork = XFS_DATA_FORK;
> +	struct xfs_mount	*mp = ip->i_mount;
> +	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
> +	struct xfs_btree_cur	*cur = NULL;
> +	struct xfs_bmbt_irec	got, s;
> +	xfs_extnum_t		current_ext;
> +	xfs_extnum_t		total_extents;
> +	xfs_extnum_t		stop_extent;
> +	int			error = 0;
> +	int			logflags = 0;
> +
> +	if (unlikely(XFS_TEST_ERROR(
> +	    (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
> +	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
> +	     mp, XFS_ERRTAG_BMAPIFORMAT))) {
> +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
> +		return -EFSCORRUPTED;
> +	}
> +
> +	if (XFS_FORCED_SHUTDOWN(mp))
> +		return -EIO;
> +
> +	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL));
>  
> -	ifp = XFS_IFORK_PTR(ip, whichfork);
>  	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
> -		/* Read in all the extents */
>  		error = xfs_iread_extents(tp, ip, whichfork);
>  		if (error)
>  			return error;
> @@ -5759,7 +5853,7 @@ xfs_bmap_shift_extents(
>  	 */
>  	total_extents = xfs_iext_count(ifp);
>  	if (total_extents == 0) {
> -		*done = 1;
> +		*done = true;
>  		goto del_cursor;
>  	}
>  
> @@ -5767,12 +5861,10 @@ xfs_bmap_shift_extents(
>  	 * In case of first right shift, we need to initialize next_fsb
>  	 */
>  	if (*next_fsb == NULLFSBLOCK) {
> -		ASSERT(direction == SHIFT_RIGHT);
> -
>  		current_ext = total_extents - 1;
>  		xfs_iext_get_extent(ifp, current_ext, &got);
>  		if (stop_fsb > got.br_startoff) {
> -			*done = 1;
> +			*done = true;
>  			goto del_cursor;
>  		}
>  		*next_fsb = got.br_startoff;
> @@ -5787,46 +5879,27 @@ xfs_bmap_shift_extents(
>  		 */
>  		if (!xfs_iext_lookup_extent(ip, ifp, *next_fsb, &current_ext,
>  				&got)) {
> -			*done = 1;
> +			*done = true;
>  			goto del_cursor;
>  		}
>  	}
>  
>  	/* Lookup the extent index at which we have to stop */
> -	if (direction == SHIFT_RIGHT) {
> -		struct xfs_bmbt_irec s;
> -
> -		xfs_iext_lookup_extent(ip, ifp, stop_fsb, &stop_extent, &s);
> -		/* Make stop_extent exclusive of shift range */
> -		stop_extent--;
> -		if (current_ext <= stop_extent) {
> -			error = -EIO;
> -			goto del_cursor;
> -		}
> -	} else {
> -		stop_extent = total_extents;
> -		if (current_ext >= stop_extent) {
> -			error = -EIO;
> -			goto del_cursor;
> -		}
> +	xfs_iext_lookup_extent(ip, ifp, stop_fsb, &stop_extent, &s);
> +	/* Make stop_extent exclusive of shift range */
> +	stop_extent--;
> +	if (current_ext <= stop_extent) {
> +		error = -EIO;
> +		goto del_cursor;
>  	}
>  
>  	error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb,
>  				   &current_ext, &got, cur, &logflags,
> -				   direction, dfops);
> +				   SHIFT_RIGHT, dfops);
>  	if (error)
>  		goto del_cursor;
> -	/*
> -	 * If there was an extent merge during the shift, the extent
> -	 * count can change. Update the total and grade the next record.
> -	 */
> -	if (direction == SHIFT_LEFT) {
> -		total_extents = xfs_iext_count(ifp);
> -		stop_extent = total_extents;
> -	}
> -
>  	if (current_ext == stop_extent) {
> -		*done = 1;
> +		*done = true;
>  		goto del_cursor;
>  	}
>  	xfs_iext_get_extent(ifp, current_ext, &got);
> diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
> index 985b1c26566a..f7ccf2de1a8c 100644
> --- a/fs/xfs/libxfs/xfs_bmap.h
> +++ b/fs/xfs/libxfs/xfs_bmap.h
> @@ -227,10 +227,14 @@ int	xfs_bmap_del_extent_delay(struct xfs_inode *ip, int whichfork,
>  void	xfs_bmap_del_extent_cow(struct xfs_inode *ip, xfs_extnum_t *idx,
>  		struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *del);
>  uint	xfs_default_attroffset(struct xfs_inode *ip);
> -int	xfs_bmap_shift_extents(struct xfs_trans *tp, struct xfs_inode *ip,
> +int	xfs_bmap_collapse_extents(struct xfs_trans *tp, struct xfs_inode *ip,
>  		xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb,
> -		int *done, xfs_fileoff_t stop_fsb, xfs_fsblock_t *firstblock,
> -		struct xfs_defer_ops *dfops, enum shift_direction direction);
> +		bool *done, xfs_fileoff_t stop_fsb, xfs_fsblock_t *firstblock,
> +		struct xfs_defer_ops *dfops);
> +int	xfs_bmap_insert_extents(struct xfs_trans *tp, struct xfs_inode *ip,
> +		xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb,
> +		bool *done, xfs_fileoff_t stop_fsb, xfs_fsblock_t *firstblock,
> +		struct xfs_defer_ops *dfops);
>  int	xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset);
>  int	xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork,
>  		xfs_fileoff_t off, xfs_filblks_t len, xfs_filblks_t prealloc,
> diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
> index 3273f083c496..034f3429ca8c 100644
> --- a/fs/xfs/xfs_bmap_util.c
> +++ b/fs/xfs/xfs_bmap_util.c
> @@ -1322,7 +1322,6 @@ xfs_collapse_file_space(
>  	xfs_off_t		offset,
>  	xfs_off_t		len)
>  {
> -	int			done = 0;
>  	struct xfs_mount	*mp = ip->i_mount;
>  	struct xfs_trans	*tp;
>  	int			error;
> @@ -1332,6 +1331,7 @@ xfs_collapse_file_space(
>  	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);
> +	bool			done = false;
>  
>  	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
>  	trace_xfs_collapse_file_space(ip);
> @@ -1359,9 +1359,8 @@ xfs_collapse_file_space(
>  		xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
>  
>  		xfs_defer_init(&dfops, &first_block);
> -		error = xfs_bmap_shift_extents(tp, ip, &next_fsb, shift_fsb,
> -				&done, stop_fsb, &first_block, &dfops,
> -				SHIFT_LEFT);
> +		error = xfs_bmap_collapse_extents(tp, ip, &next_fsb, shift_fsb,
> +				&done, stop_fsb, &first_block, &dfops);
>  		if (error)
>  			goto out_bmap_cancel;
>  
> @@ -1406,7 +1405,7 @@ xfs_insert_file_space(
>  	xfs_fileoff_t		stop_fsb = XFS_B_TO_FSB(mp, offset);
>  	xfs_fileoff_t		next_fsb = NULLFSBLOCK;
>  	xfs_fileoff_t		shift_fsb = XFS_B_TO_FSB(mp, len);
> -	int			done = 0;
> +	bool			done = false;
>  
>  	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
>  	trace_xfs_insert_file_space(ip);
> @@ -1433,9 +1432,8 @@ xfs_insert_file_space(
>  		xfs_ilock(ip, XFS_ILOCK_EXCL);
>  		xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
>  		xfs_defer_init(&dfops, &first_block);
> -		error = xfs_bmap_shift_extents(tp, ip, &next_fsb, shift_fsb,
> -				&done, stop_fsb, &first_block, &dfops,
> -				SHIFT_RIGHT);
> +		error = xfs_bmap_insert_extents(tp, ip, &next_fsb, shift_fsb,
> +				&done, stop_fsb, &first_block, &dfops);
>  		if (error)
>  			goto out_bmap_cancel;
>  
> -- 
> 2.14.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 89ea8a5235c0..7d3a38e69d28 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -5689,57 +5689,151 @@  xfs_bmse_shift_one(
 	return xfs_rmap_map_extent(mp, dfops, ip, whichfork, &new);
 }
 
-/*
- * Shift extent records to the left/right to cover/create a hole.
- *
- * @stop_fsb specifies the file offset at which to stop shift and the
- * file offset where we've left off is returned in @next_fsb. @offset_shift_fsb
- * is the length by which each extent is shifted. If there is no hole to shift
- * the extents into, this will be considered invalid operation and we abort
- * immediately.
- */
 int
-xfs_bmap_shift_extents(
+xfs_bmap_collapse_extents(
 	struct xfs_trans	*tp,
 	struct xfs_inode	*ip,
 	xfs_fileoff_t		*next_fsb,
 	xfs_fileoff_t		offset_shift_fsb,
-	int			*done,
+	bool			*done,
 	xfs_fileoff_t		stop_fsb,
 	xfs_fsblock_t		*firstblock,
-	struct xfs_defer_ops	*dfops,
-	enum shift_direction	direction)
+	struct xfs_defer_ops	*dfops)
 {
-	struct xfs_btree_cur		*cur = NULL;
-	struct xfs_bmbt_irec            got;
-	struct xfs_mount		*mp = ip->i_mount;
-	struct xfs_ifork		*ifp;
-	xfs_extnum_t			current_ext;
-	xfs_extnum_t			total_extents;
-	xfs_extnum_t			stop_extent;
-	int				error = 0;
-	int				whichfork = XFS_DATA_FORK;
-	int				logflags = 0;
+	int			whichfork = XFS_DATA_FORK;
+	struct xfs_mount	*mp = ip->i_mount;
+	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
+	struct xfs_btree_cur	*cur = NULL;
+	struct xfs_bmbt_irec	got;
+	xfs_extnum_t		current_ext;
+	xfs_extnum_t		total_extents;
+	xfs_extnum_t		stop_extent;
+	int			error = 0;
+	int			logflags = 0;
 
 	if (unlikely(XFS_TEST_ERROR(
 	    (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
 	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
 	     mp, XFS_ERRTAG_BMAPIFORMAT))) {
-		XFS_ERROR_REPORT("xfs_bmap_shift_extents",
-				 XFS_ERRLEVEL_LOW, mp);
+		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
 		return -EFSCORRUPTED;
 	}
 
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return -EIO;
 
-	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
-	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-	ASSERT(direction == SHIFT_LEFT || direction == SHIFT_RIGHT);
+	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL));
+
+	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+		error = xfs_iread_extents(tp, ip, whichfork);
+		if (error)
+			return error;
+	}
+
+	if (ifp->if_flags & XFS_IFBROOT) {
+		cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
+		cur->bc_private.b.firstblock = *firstblock;
+		cur->bc_private.b.dfops = dfops;
+		cur->bc_private.b.flags = 0;
+	}
+
+	/*
+	 * There may be delalloc extents in the data fork before the range we
+	 * are collapsing out, so we cannot use the count of real extents here.
+	 * Instead we have to calculate it from the incore fork.
+	 */
+	total_extents = xfs_iext_count(ifp);
+	if (total_extents == 0) {
+		*done = true;
+		goto del_cursor;
+	}
+
+	/*
+	 * Look up the extent index for the fsb where we start shifting. We can
+	 * henceforth iterate with current_ext as extent list changes are locked
+	 * out via ilock.
+	 *
+	 * If next_fsb lies in a hole beyond which there are no extents we are
+	 * done.
+	 */
+	if (!xfs_iext_lookup_extent(ip, ifp, *next_fsb, &current_ext, &got)) {
+		*done = true;
+		goto del_cursor;
+	}
+
+	stop_extent = total_extents;
+	if (current_ext >= stop_extent) {
+		error = -EIO;
+		goto del_cursor;
+	}
+
+	error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb,
+				   &current_ext, &got, cur, &logflags,
+				   SHIFT_LEFT, dfops);
+	if (error)
+		goto del_cursor;
+	/*
+	 * If there was an extent merge during the shift, the extent
+	 * count can change. Update the total and grade the next record.
+	 */
+	total_extents = xfs_iext_count(ifp);
+	stop_extent = total_extents;
+	if (current_ext == stop_extent) {
+		*done = true;
+		goto del_cursor;
+	}
+	xfs_iext_get_extent(ifp, current_ext, &got);
+
+	if (!*done)
+		*next_fsb = got.br_startoff;
+
+del_cursor:
+	if (cur)
+		xfs_btree_del_cursor(cur,
+			error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+
+	if (logflags)
+		xfs_trans_log_inode(tp, ip, logflags);
+
+	return error;
+}
+
+int
+xfs_bmap_insert_extents(
+	struct xfs_trans	*tp,
+	struct xfs_inode	*ip,
+	xfs_fileoff_t		*next_fsb,
+	xfs_fileoff_t		offset_shift_fsb,
+	bool			*done,
+	xfs_fileoff_t		stop_fsb,
+	xfs_fsblock_t		*firstblock,
+	struct xfs_defer_ops	*dfops)
+{
+	int			whichfork = XFS_DATA_FORK;
+	struct xfs_mount	*mp = ip->i_mount;
+	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
+	struct xfs_btree_cur	*cur = NULL;
+	struct xfs_bmbt_irec	got, s;
+	xfs_extnum_t		current_ext;
+	xfs_extnum_t		total_extents;
+	xfs_extnum_t		stop_extent;
+	int			error = 0;
+	int			logflags = 0;
+
+	if (unlikely(XFS_TEST_ERROR(
+	    (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
+	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
+	     mp, XFS_ERRTAG_BMAPIFORMAT))) {
+		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
+		return -EFSCORRUPTED;
+	}
+
+	if (XFS_FORCED_SHUTDOWN(mp))
+		return -EIO;
+
+	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL));
 
-	ifp = XFS_IFORK_PTR(ip, whichfork);
 	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
-		/* Read in all the extents */
 		error = xfs_iread_extents(tp, ip, whichfork);
 		if (error)
 			return error;
@@ -5759,7 +5853,7 @@  xfs_bmap_shift_extents(
 	 */
 	total_extents = xfs_iext_count(ifp);
 	if (total_extents == 0) {
-		*done = 1;
+		*done = true;
 		goto del_cursor;
 	}
 
@@ -5767,12 +5861,10 @@  xfs_bmap_shift_extents(
 	 * In case of first right shift, we need to initialize next_fsb
 	 */
 	if (*next_fsb == NULLFSBLOCK) {
-		ASSERT(direction == SHIFT_RIGHT);
-
 		current_ext = total_extents - 1;
 		xfs_iext_get_extent(ifp, current_ext, &got);
 		if (stop_fsb > got.br_startoff) {
-			*done = 1;
+			*done = true;
 			goto del_cursor;
 		}
 		*next_fsb = got.br_startoff;
@@ -5787,46 +5879,27 @@  xfs_bmap_shift_extents(
 		 */
 		if (!xfs_iext_lookup_extent(ip, ifp, *next_fsb, &current_ext,
 				&got)) {
-			*done = 1;
+			*done = true;
 			goto del_cursor;
 		}
 	}
 
 	/* Lookup the extent index at which we have to stop */
-	if (direction == SHIFT_RIGHT) {
-		struct xfs_bmbt_irec s;
-
-		xfs_iext_lookup_extent(ip, ifp, stop_fsb, &stop_extent, &s);
-		/* Make stop_extent exclusive of shift range */
-		stop_extent--;
-		if (current_ext <= stop_extent) {
-			error = -EIO;
-			goto del_cursor;
-		}
-	} else {
-		stop_extent = total_extents;
-		if (current_ext >= stop_extent) {
-			error = -EIO;
-			goto del_cursor;
-		}
+	xfs_iext_lookup_extent(ip, ifp, stop_fsb, &stop_extent, &s);
+	/* Make stop_extent exclusive of shift range */
+	stop_extent--;
+	if (current_ext <= stop_extent) {
+		error = -EIO;
+		goto del_cursor;
 	}
 
 	error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb,
 				   &current_ext, &got, cur, &logflags,
-				   direction, dfops);
+				   SHIFT_RIGHT, dfops);
 	if (error)
 		goto del_cursor;
-	/*
-	 * If there was an extent merge during the shift, the extent
-	 * count can change. Update the total and grade the next record.
-	 */
-	if (direction == SHIFT_LEFT) {
-		total_extents = xfs_iext_count(ifp);
-		stop_extent = total_extents;
-	}
-
 	if (current_ext == stop_extent) {
-		*done = 1;
+		*done = true;
 		goto del_cursor;
 	}
 	xfs_iext_get_extent(ifp, current_ext, &got);
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
index 985b1c26566a..f7ccf2de1a8c 100644
--- a/fs/xfs/libxfs/xfs_bmap.h
+++ b/fs/xfs/libxfs/xfs_bmap.h
@@ -227,10 +227,14 @@  int	xfs_bmap_del_extent_delay(struct xfs_inode *ip, int whichfork,
 void	xfs_bmap_del_extent_cow(struct xfs_inode *ip, xfs_extnum_t *idx,
 		struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *del);
 uint	xfs_default_attroffset(struct xfs_inode *ip);
-int	xfs_bmap_shift_extents(struct xfs_trans *tp, struct xfs_inode *ip,
+int	xfs_bmap_collapse_extents(struct xfs_trans *tp, struct xfs_inode *ip,
 		xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb,
-		int *done, xfs_fileoff_t stop_fsb, xfs_fsblock_t *firstblock,
-		struct xfs_defer_ops *dfops, enum shift_direction direction);
+		bool *done, xfs_fileoff_t stop_fsb, xfs_fsblock_t *firstblock,
+		struct xfs_defer_ops *dfops);
+int	xfs_bmap_insert_extents(struct xfs_trans *tp, struct xfs_inode *ip,
+		xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb,
+		bool *done, xfs_fileoff_t stop_fsb, xfs_fsblock_t *firstblock,
+		struct xfs_defer_ops *dfops);
 int	xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset);
 int	xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork,
 		xfs_fileoff_t off, xfs_filblks_t len, xfs_filblks_t prealloc,
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 3273f083c496..034f3429ca8c 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1322,7 +1322,6 @@  xfs_collapse_file_space(
 	xfs_off_t		offset,
 	xfs_off_t		len)
 {
-	int			done = 0;
 	struct xfs_mount	*mp = ip->i_mount;
 	struct xfs_trans	*tp;
 	int			error;
@@ -1332,6 +1331,7 @@  xfs_collapse_file_space(
 	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);
+	bool			done = false;
 
 	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
 	trace_xfs_collapse_file_space(ip);
@@ -1359,9 +1359,8 @@  xfs_collapse_file_space(
 		xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 
 		xfs_defer_init(&dfops, &first_block);
-		error = xfs_bmap_shift_extents(tp, ip, &next_fsb, shift_fsb,
-				&done, stop_fsb, &first_block, &dfops,
-				SHIFT_LEFT);
+		error = xfs_bmap_collapse_extents(tp, ip, &next_fsb, shift_fsb,
+				&done, stop_fsb, &first_block, &dfops);
 		if (error)
 			goto out_bmap_cancel;
 
@@ -1406,7 +1405,7 @@  xfs_insert_file_space(
 	xfs_fileoff_t		stop_fsb = XFS_B_TO_FSB(mp, offset);
 	xfs_fileoff_t		next_fsb = NULLFSBLOCK;
 	xfs_fileoff_t		shift_fsb = XFS_B_TO_FSB(mp, len);
-	int			done = 0;
+	bool			done = false;
 
 	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
 	trace_xfs_insert_file_space(ip);
@@ -1433,9 +1432,8 @@  xfs_insert_file_space(
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
 		xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 		xfs_defer_init(&dfops, &first_block);
-		error = xfs_bmap_shift_extents(tp, ip, &next_fsb, shift_fsb,
-				&done, stop_fsb, &first_block, &dfops,
-				SHIFT_RIGHT);
+		error = xfs_bmap_insert_extents(tp, ip, &next_fsb, shift_fsb,
+				&done, stop_fsb, &first_block, &dfops);
 		if (error)
 			goto out_bmap_cancel;