Re: [PATCH CANDIDATE 6.1] xfs: give xfs_extfree_intent its own perag reference

"Darrick J. Wong" <[email protected]> Thu, 27 Mar 2025 12:38:13 -0700
Newsgroups dev.linux.lists.xfs-stable
Message-ID <20250327193813.GK4001511@frogsfrogsfrogs>
On Thu, Mar 20, 2025 at 06:01:12PM -0700, Leah Rumancik wrote:
> From: "Darrick J. Wong" <[email protected]>
> 
> [ Upstream commit f6b384631e1e3482c24e35b53adbd3da50e47e8f ]
> 
> Give the xfs_extfree_intent an passive reference to the perag structure
> data.  This reference will be used to enable scrub intent draining
> functionality in subsequent patches.  The space being freed must already
> be allocated, so we need to able to run even if the AG is being offlined
> or shrunk.
> 
> Signed-off-by: Darrick J. Wong <[email protected]>
> Reviewed-by: Dave Chinner <[email protected]>
> Signed-off-by: Leah Rumancik <[email protected]>
> ---
> 
> This is to fix build fialure noted here:
> https://lore.kernel.org/stable/[email protected]/
> 
> Tested on auto group x 9 configs with no regressions seen.

LGTM
Acked-by: "Darrick J. Wong" <[email protected]>

--D

> 
> - leah
> 
>  fs/xfs/libxfs/xfs_alloc.c |  7 +++--
>  fs/xfs/libxfs/xfs_alloc.h |  4 +++
>  fs/xfs/xfs_extfree_item.c | 58 +++++++++++++++++++++++++--------------
>  3 files changed, 47 insertions(+), 22 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
> index e44f3f5c6d27..c08265f19136 100644
> --- a/fs/xfs/libxfs/xfs_alloc.c
> +++ b/fs/xfs/libxfs/xfs_alloc.c
> @@ -2509,30 +2509,31 @@ xfs_defer_agfl_block(
>  	xefi->xefi_owner = oinfo->oi_owner;
>  	xefi->xefi_agresv = XFS_AG_RESV_AGFL;
>  
>  	trace_xfs_agfl_free_defer(mp, agno, 0, agbno, 1);
>  
> +	xfs_extent_free_get_group(mp, xefi);
>  	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_AGFL_FREE, &xefi->xefi_list);
>  	return 0;
>  }
>  
>  /*
>   * Add the extent to the list of extents to be free at transaction end.
>   * The list is maintained sorted (by block number).
>   */
>  int
>  __xfs_free_extent_later(
>  	struct xfs_trans		*tp,
>  	xfs_fsblock_t			bno,
>  	xfs_filblks_t			len,
>  	const struct xfs_owner_info	*oinfo,
>  	enum xfs_ag_resv_type		type,
>  	bool				skip_discard)
>  {
>  	struct xfs_extent_free_item	*xefi;
> -#ifdef DEBUG
>  	struct xfs_mount		*mp = tp->t_mountp;
> +#ifdef DEBUG
>  	xfs_agnumber_t			agno;
>  	xfs_agblock_t			agbno;
>  
>  	ASSERT(bno != NULLFSBLOCK);
>  	ASSERT(len > 0);
> @@ -2567,13 +2568,15 @@ __xfs_free_extent_later(
>  			xefi->xefi_flags |= XFS_EFI_BMBT_BLOCK;
>  		xefi->xefi_owner = oinfo->oi_owner;
>  	} else {
>  		xefi->xefi_owner = XFS_RMAP_OWN_NULL;
>  	}
> -	trace_xfs_bmap_free_defer(tp->t_mountp,
> +	trace_xfs_bmap_free_defer(mp,
>  			XFS_FSB_TO_AGNO(tp->t_mountp, bno), 0,
>  			XFS_FSB_TO_AGBNO(tp->t_mountp, bno), len);
> +
> +	xfs_extent_free_get_group(mp, xefi);
>  	xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_FREE, &xefi->xefi_list);
>  	return 0;
>  }
>  
>  #ifdef DEBUG
> diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h
> index bbedb18651de..2dd93d62150f 100644
> --- a/fs/xfs/libxfs/xfs_alloc.h
> +++ b/fs/xfs/libxfs/xfs_alloc.h
> @@ -224,14 +224,18 @@ int __xfs_free_extent_later(struct xfs_trans *tp, xfs_fsblock_t bno,
>  struct xfs_extent_free_item {
>  	struct list_head	xefi_list;
>  	uint64_t		xefi_owner;
>  	xfs_fsblock_t		xefi_startblock;/* starting fs block number */
>  	xfs_extlen_t		xefi_blockcount;/* number of blocks in extent */
> +	struct xfs_perag	*xefi_pag;
>  	unsigned int		xefi_flags;
>  	enum xfs_ag_resv_type	xefi_agresv;
>  };
>  
> +void xfs_extent_free_get_group(struct xfs_mount *mp,
> +		struct xfs_extent_free_item *xefi);
> +
>  #define XFS_EFI_SKIP_DISCARD	(1U << 0) /* don't issue discard */
>  #define XFS_EFI_ATTR_FORK	(1U << 1) /* freeing attr fork block */
>  #define XFS_EFI_BMBT_BLOCK	(1U << 2) /* freeing bmap btree block */
>  
>  static inline int
> diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
> index 9c726f082285..ab9d0e8b77da 100644
> --- a/fs/xfs/xfs_extfree_item.c
> +++ b/fs/xfs/xfs_extfree_item.c
> @@ -348,32 +348,27 @@ xfs_trans_free_extent(
>  	struct xfs_extent_free_item	*xefi)
>  {
>  	struct xfs_owner_info		oinfo = { };
>  	struct xfs_mount		*mp = tp->t_mountp;
>  	struct xfs_extent		*extp;
> -	struct xfs_perag		*pag;
>  	uint				next_extent;
> -	xfs_agnumber_t			agno = XFS_FSB_TO_AGNO(mp,
> -							xefi->xefi_startblock);
>  	xfs_agblock_t			agbno = XFS_FSB_TO_AGBNO(mp,
>  							xefi->xefi_startblock);
>  	int				error;
>  
>  	oinfo.oi_owner = xefi->xefi_owner;
>  	if (xefi->xefi_flags & XFS_EFI_ATTR_FORK)
>  		oinfo.oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
>  	if (xefi->xefi_flags & XFS_EFI_BMBT_BLOCK)
>  		oinfo.oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
>  
> -	trace_xfs_bmap_free_deferred(tp->t_mountp, agno, 0, agbno,
> -			xefi->xefi_blockcount);
> +	trace_xfs_bmap_free_deferred(tp->t_mountp, xefi->xefi_pag->pag_agno, 0,
> +			agbno, xefi->xefi_blockcount);
>  
> -	pag = xfs_perag_get(mp, agno);
> -	error = __xfs_free_extent(tp, pag, agbno, xefi->xefi_blockcount,
> -			&oinfo, xefi->xefi_agresv,
> +	error = __xfs_free_extent(tp, xefi->xefi_pag, agbno,
> +			xefi->xefi_blockcount, &oinfo, xefi->xefi_agresv,
>  			xefi->xefi_flags & XFS_EFI_SKIP_DISCARD);
> -	xfs_perag_put(pag);
>  
>  	/*
>  	 * Mark the transaction dirty, even on error. This ensures the
>  	 * transaction is aborted, which:
>  	 *
> @@ -398,18 +393,17 @@ static int
>  xfs_extent_free_diff_items(
>  	void				*priv,
>  	const struct list_head		*a,
>  	const struct list_head		*b)
>  {
> -	struct xfs_mount		*mp = priv;
>  	struct xfs_extent_free_item	*ra;
>  	struct xfs_extent_free_item	*rb;
>  
>  	ra = container_of(a, struct xfs_extent_free_item, xefi_list);
>  	rb = container_of(b, struct xfs_extent_free_item, xefi_list);
> -	return  XFS_FSB_TO_AGNO(mp, ra->xefi_startblock) -
> -		XFS_FSB_TO_AGNO(mp, rb->xefi_startblock);
> +
> +	return ra->xefi_pag->pag_agno - rb->xefi_pag->pag_agno;
>  }
>  
>  /* Log a free extent to the intent item. */
>  STATIC void
>  xfs_extent_free_log_item(
> @@ -464,44 +458,68 @@ xfs_extent_free_create_done(
>  	unsigned int			count)
>  {
>  	return &xfs_trans_get_efd(tp, EFI_ITEM(intent), count)->efd_item;
>  }
>  
> +/* Take a passive ref to the AG containing the space we're freeing. */
> +void
> +xfs_extent_free_get_group(
> +	struct xfs_mount		*mp,
> +	struct xfs_extent_free_item	*xefi)
> +{
> +	xfs_agnumber_t			agno;
> +
> +	agno = XFS_FSB_TO_AGNO(mp, xefi->xefi_startblock);
> +	xefi->xefi_pag = xfs_perag_get(mp, agno);
> +}
> +
> +/* Release a passive AG ref after some freeing work. */
> +static inline void
> +xfs_extent_free_put_group(
> +	struct xfs_extent_free_item	*xefi)
> +{
> +	xfs_perag_put(xefi->xefi_pag);
> +}
> +
>  /* Process a free extent. */
>  STATIC int
>  xfs_extent_free_finish_item(
>  	struct xfs_trans		*tp,
>  	struct xfs_log_item		*done,
>  	struct list_head		*item,
>  	struct xfs_btree_cur		**state)
>  {
>  	struct xfs_extent_free_item	*xefi;
>  	int				error;
>  
>  	xefi = container_of(item, struct xfs_extent_free_item, xefi_list);
>  
>  	error = xfs_trans_free_extent(tp, EFD_ITEM(done), xefi);
> +
> +	xfs_extent_free_put_group(xefi);
>  	kmem_cache_free(xfs_extfree_item_cache, xefi);
>  	return error;
>  }
>  
>  /* Abort all pending EFIs. */
>  STATIC void
>  xfs_extent_free_abort_intent(
>  	struct xfs_log_item		*intent)
>  {
>  	xfs_efi_release(EFI_ITEM(intent));
>  }
>  
>  /* Cancel a free extent. */
>  STATIC void
>  xfs_extent_free_cancel_item(
>  	struct list_head		*item)
>  {
>  	struct xfs_extent_free_item	*xefi;
>  
>  	xefi = container_of(item, struct xfs_extent_free_item, xefi_list);
> +
> +	xfs_extent_free_put_group(xefi);
>  	kmem_cache_free(xfs_extfree_item_cache, xefi);
>  }
>  
>  const struct xfs_defer_op_type xfs_extent_free_defer_type = {
>  	.max_items	= XFS_EFI_MAX_FAST_EXTENTS,
> @@ -528,46 +546,44 @@ xfs_agfl_free_finish_item(
>  	struct xfs_efd_log_item		*efdp = EFD_ITEM(done);
>  	struct xfs_extent_free_item	*xefi;
>  	struct xfs_extent		*extp;
>  	struct xfs_buf			*agbp;
>  	int				error;
> -	xfs_agnumber_t			agno;
>  	xfs_agblock_t			agbno;
>  	uint				next_extent;
> -	struct xfs_perag		*pag;
>  
>  	xefi = container_of(item, struct xfs_extent_free_item, xefi_list);
>  	ASSERT(xefi->xefi_blockcount == 1);
> -	agno = XFS_FSB_TO_AGNO(mp, xefi->xefi_startblock);
>  	agbno = XFS_FSB_TO_AGBNO(mp, xefi->xefi_startblock);
>  	oinfo.oi_owner = xefi->xefi_owner;
>  
> -	trace_xfs_agfl_free_deferred(mp, agno, 0, agbno, xefi->xefi_blockcount);
> +	trace_xfs_agfl_free_deferred(mp, xefi->xefi_pag->pag_agno, 0, agbno,
> +			xefi->xefi_blockcount);
>  
> -	pag = xfs_perag_get(mp, agno);
> -	error = xfs_alloc_read_agf(pag, tp, 0, &agbp);
> +	error = xfs_alloc_read_agf(xefi->xefi_pag, tp, 0, &agbp);
>  	if (!error)
> -		error = xfs_free_agfl_block(tp, agno, agbno, agbp, &oinfo);
> -	xfs_perag_put(pag);
> +		error = xfs_free_agfl_block(tp, xefi->xefi_pag->pag_agno,
> +				agbno, agbp, &oinfo);
>  
>  	/*
>  	 * Mark the transaction dirty, even on error. This ensures the
>  	 * transaction is aborted, which:
>  	 *
>  	 * 1.) releases the EFI and frees the EFD
>  	 * 2.) shuts down the filesystem
>  	 */
>  	tp->t_flags |= XFS_TRANS_DIRTY;
>  	set_bit(XFS_LI_DIRTY, &efdp->efd_item.li_flags);
>  
>  	next_extent = efdp->efd_next_extent;
>  	ASSERT(next_extent < efdp->efd_format.efd_nextents);
>  	extp = &(efdp->efd_format.efd_extents[next_extent]);
>  	extp->ext_start = xefi->xefi_startblock;
>  	extp->ext_len = xefi->xefi_blockcount;
>  	efdp->efd_next_extent++;
>  
> +	xfs_extent_free_put_group(xefi);
>  	kmem_cache_free(xfs_extfree_item_cache, xefi);
>  	return error;
>  }
>  
>  /* sub-type with special handling for AGFL deferred frees */
> @@ -640,11 +656,13 @@ xfs_efi_item_recover(
>  		extp = &efip->efi_format.efi_extents[i];
>  
>  		fake.xefi_startblock = extp->ext_start;
>  		fake.xefi_blockcount = extp->ext_len;
>  
> +		xfs_extent_free_get_group(mp, &fake);
>  		error = xfs_trans_free_extent(tp, efdp, &fake);
> +		xfs_extent_free_put_group(&fake);
>  		if (error == -EFSCORRUPTED)
>  			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
>  					extp, sizeof(*extp));
>  		if (error)
>  			goto abort_error;
> -- 
> 2.49.0.395.g12beb8f557-goog
> 
>