diff mbox

[19/34] xfs: simplify xfs_bmap_punch_delalloc_range

Message ID 20180523144357.18985-20-hch@lst.de (mailing list archive)
State New, archived
Headers show

Commit Message

Christoph Hellwig May 23, 2018, 2:43 p.m. UTC
Instead of using xfs_bmapi_read to find delalloc extents and then punch
them out using xfs_bunmapi, opencode the loop to iterate over the extents
and call xfs_bmap_del_extent_delay directly.  This both simplifies the
code and reduces the number of extent tree lookups required.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/xfs/xfs_bmap_util.c | 78 ++++++++++++++----------------------------
 1 file changed, 25 insertions(+), 53 deletions(-)

Comments

Brian Foster May 23, 2018, 4:17 p.m. UTC | #1
On Wed, May 23, 2018 at 04:43:42PM +0200, Christoph Hellwig wrote:
> Instead of using xfs_bmapi_read to find delalloc extents and then punch
> them out using xfs_bunmapi, opencode the loop to iterate over the extents
> and call xfs_bmap_del_extent_delay directly.  This both simplifies the
> code and reduces the number of extent tree lookups required.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  fs/xfs/xfs_bmap_util.c | 78 ++++++++++++++----------------------------
>  1 file changed, 25 insertions(+), 53 deletions(-)
> 
> diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
> index 06badcbadeb4..c009bdf9fdce 100644
> --- a/fs/xfs/xfs_bmap_util.c
> +++ b/fs/xfs/xfs_bmap_util.c
...
> @@ -708,63 +706,37 @@ xfs_bmap_punch_delalloc_range(
>  	xfs_fileoff_t		start_fsb,
>  	xfs_fileoff_t		length)
>  {
> -	xfs_fileoff_t		remaining = length;
> +	struct xfs_ifork	*ifp = &ip->i_df;
> +	struct xfs_bmbt_irec	got, del;
> +	struct xfs_iext_cursor	icur;
>  	int			error = 0;
>  
>  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
>  
> -	do {
> -		int		done;
> -		xfs_bmbt_irec_t	imap;
> -		int		nimaps = 1;
> -		xfs_fsblock_t	firstblock;
> -		struct xfs_defer_ops dfops;
> +	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
> +		error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
> +		if (error)
> +			return error;
> +	}
>  
> -		/*
> -		 * Map the range first and check that it is a delalloc extent
> -		 * before trying to unmap the range. Otherwise we will be
> -		 * trying to remove a real extent (which requires a
> -		 * transaction) or a hole, which is probably a bad idea...
> -		 */
> -		error = xfs_bmapi_read(ip, start_fsb, 1, &imap, &nimaps,
> -				       XFS_BMAPI_ENTIRE);
> +	if (!xfs_iext_lookup_extent(ip, ifp, start_fsb, &icur, &got))
> +		return 0;
>  
> -		if (error) {
> -			/* something screwed, just bail */
> -			if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
> -				xfs_alert(ip->i_mount,
> -			"Failed delalloc mapping lookup ino %lld fsb %lld.",
> -						ip->i_ino, start_fsb);
> -			}
> +	do {
> +		if (got.br_startoff >= start_fsb + length)
>  			break;
> -		}
> -		if (!nimaps) {
> -			/* nothing there */
> -			goto next_block;
> -		}
> -		if (imap.br_startblock != DELAYSTARTBLOCK) {
> -			/* been converted, ignore */
> -			goto next_block;
> -		}
> -		WARN_ON(imap.br_blockcount == 0);
> +		if (!isnullstartblock(got.br_startblock))
> +			continue;
>  
> -		/*
> -		 * Note: while we initialise the firstblock/dfops pair, they
> -		 * should never be used because blocks should never be
> -		 * allocated or freed for a delalloc extent and hence we need
> -		 * don't cancel or finish them after the xfs_bunmapi() call.
> -		 */
> -		xfs_defer_init(&dfops, &firstblock);
> -		error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock,
> -					&dfops, &done);
> +		del = got;
> +		xfs_trim_extent(&del, start_fsb, length);
> +		error = xfs_bmap_del_extent_delay(ip, XFS_DATA_FORK, &icur,
> +				&got, &del);
>  		if (error)
>  			break;
> -
> -		ASSERT(!xfs_defer_has_unfinished_work(&dfops));
> -next_block:
> -		start_fsb++;
> -		remaining--;
> -	} while(remaining > 0);
> +		if (!xfs_iext_get_extent(ifp, &icur, &got))
> +			break;

Mostly looks Ok, but I'm not following what this get_extent() call is
for..? It also doesn't look like it would always do the right thing with
sub-page blocks. Consider a page with a couple discontig delalloc blocks
that happen to be the first extents in the file. The first
xfs_bmap_del_extent_delay() would do:

	xfs_iext_remove(ip, icur, state);
	xfs_iext_prev(ifp, icur);

... which I think sets cur->pos to -1, causes the get_extent() to fail
and thus fails to remove the subsequent delalloc blocks. Hm?

Brian

> +	} while (xfs_iext_next_extent(ifp, &icur, &got));
>  
>  	return error;
>  }
> -- 
> 2.17.0
> 
> --
> 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
Christoph Hellwig May 24, 2018, 8:01 a.m. UTC | #2
On Wed, May 23, 2018 at 12:17:11PM -0400, Brian Foster wrote:
> Mostly looks Ok, but I'm not following what this get_extent() call is
> for..? It also doesn't look like it would always do the right thing with
> sub-page blocks. Consider a page with a couple discontig delalloc blocks
> that happen to be the first extents in the file. The first
> xfs_bmap_del_extent_delay() would do:
> 
> 	xfs_iext_remove(ip, icur, state);
> 	xfs_iext_prev(ifp, icur);
> 
> ... which I think sets cur->pos to -1, causes the get_extent() to fail
> and thus fails to remove the subsequent delalloc blocks. Hm?

True.  This function should probably walk the extent list backwards
like xfs_bunmapi as that is the model that xfs_bmap_del_extent_* is
built around.
diff mbox

Patch

diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 06badcbadeb4..c009bdf9fdce 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -695,12 +695,10 @@  xfs_getbmap(
 }
 
 /*
- * dead simple method of punching delalyed allocation blocks from a range in
- * the inode. Walks a block at a time so will be slow, but is only executed in
- * rare error cases so the overhead is not critical. This will always punch out
- * both the start and end blocks, even if the ranges only partially overlap
- * them, so it is up to the caller to ensure that partial blocks are not
- * passed in.
+ * Dead simple method of punching delalyed allocation blocks from a range in
+ * the inode.  This will always punch out both the start and end blocks, even
+ * if the ranges only partially overlap them, so it is up to the caller to
+ * ensure that partial blocks are not passed in.
  */
 int
 xfs_bmap_punch_delalloc_range(
@@ -708,63 +706,37 @@  xfs_bmap_punch_delalloc_range(
 	xfs_fileoff_t		start_fsb,
 	xfs_fileoff_t		length)
 {
-	xfs_fileoff_t		remaining = length;
+	struct xfs_ifork	*ifp = &ip->i_df;
+	struct xfs_bmbt_irec	got, del;
+	struct xfs_iext_cursor	icur;
 	int			error = 0;
 
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
-	do {
-		int		done;
-		xfs_bmbt_irec_t	imap;
-		int		nimaps = 1;
-		xfs_fsblock_t	firstblock;
-		struct xfs_defer_ops dfops;
+	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+		error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
+		if (error)
+			return error;
+	}
 
-		/*
-		 * Map the range first and check that it is a delalloc extent
-		 * before trying to unmap the range. Otherwise we will be
-		 * trying to remove a real extent (which requires a
-		 * transaction) or a hole, which is probably a bad idea...
-		 */
-		error = xfs_bmapi_read(ip, start_fsb, 1, &imap, &nimaps,
-				       XFS_BMAPI_ENTIRE);
+	if (!xfs_iext_lookup_extent(ip, ifp, start_fsb, &icur, &got))
+		return 0;
 
-		if (error) {
-			/* something screwed, just bail */
-			if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-				xfs_alert(ip->i_mount,
-			"Failed delalloc mapping lookup ino %lld fsb %lld.",
-						ip->i_ino, start_fsb);
-			}
+	do {
+		if (got.br_startoff >= start_fsb + length)
 			break;
-		}
-		if (!nimaps) {
-			/* nothing there */
-			goto next_block;
-		}
-		if (imap.br_startblock != DELAYSTARTBLOCK) {
-			/* been converted, ignore */
-			goto next_block;
-		}
-		WARN_ON(imap.br_blockcount == 0);
+		if (!isnullstartblock(got.br_startblock))
+			continue;
 
-		/*
-		 * Note: while we initialise the firstblock/dfops pair, they
-		 * should never be used because blocks should never be
-		 * allocated or freed for a delalloc extent and hence we need
-		 * don't cancel or finish them after the xfs_bunmapi() call.
-		 */
-		xfs_defer_init(&dfops, &firstblock);
-		error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock,
-					&dfops, &done);
+		del = got;
+		xfs_trim_extent(&del, start_fsb, length);
+		error = xfs_bmap_del_extent_delay(ip, XFS_DATA_FORK, &icur,
+				&got, &del);
 		if (error)
 			break;
-
-		ASSERT(!xfs_defer_has_unfinished_work(&dfops));
-next_block:
-		start_fsb++;
-		remaining--;
-	} while(remaining > 0);
+		if (!xfs_iext_get_extent(ifp, &icur, &got))
+			break;
+	} while (xfs_iext_next_extent(ifp, &icur, &got));
 
 	return error;
 }