]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs: refcover CoW leftovers in the realtime volume
authorDarrick J. Wong <djwong@kernel.org>
Wed, 29 May 2024 04:13:18 +0000 (21:13 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 31 Jul 2024 01:46:58 +0000 (18:46 -0700)
Scan the realtime refcount tree at mount time to get rid of leftover
CoW staging extents.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
libxfs/xfs_refcount.c
libxfs/xfs_refcount.h

index cce9221467bf8bbcd56b5da353ddda64bfd484b5..23e1e7b1d8e0470346dc022e2b85b5d07d9ab403 100644 (file)
@@ -2067,14 +2067,15 @@ xfs_refcount_recover_extent(
 }
 
 /* Find and remove leftover CoW reservations. */
-int
-xfs_refcount_recover_cow_leftovers(
+static int
+xfs_refcount_recover_group_cow_leftovers(
        struct xfs_mount                *mp,
-       struct xfs_perag                *pag)
+       struct xfs_perag                *pag,
+       struct xfs_rtgroup              *rtg)
 {
        struct xfs_trans                *tp;
        struct xfs_btree_cur            *cur;
-       struct xfs_buf                  *agbp;
+       struct xfs_buf                  *agbp = NULL;
        struct xfs_refcount_recovery    *rr, *n;
        struct list_head                debris;
        union xfs_btree_irec            low = {
@@ -2089,7 +2090,12 @@ xfs_refcount_recover_cow_leftovers(
 
        /* reflink filesystems mustn't have AGs larger than 2^31-1 blocks */
        BUILD_BUG_ON(XFS_MAX_CRC_AG_BLOCKS >= XFS_REFC_COWFLAG);
-       if (mp->m_sb.sb_agblocks > XFS_MAX_CRC_AG_BLOCKS)
+       if (pag && mp->m_sb.sb_agblocks > XFS_MAX_CRC_AG_BLOCKS)
+               return -EOPNOTSUPP;
+
+       /* rtreflink filesystems can't have rtgroups larger than 2^31-1 blocks */
+       BUILD_BUG_ON(XFS_MAX_RGBLOCKS >= XFS_REFC_COWFLAG);
+       if (rtg && mp->m_rgblocks >= XFS_MAX_RGBLOCKS)
                return -EOPNOTSUPP;
 
        INIT_LIST_HEAD(&debris);
@@ -2108,16 +2114,25 @@ xfs_refcount_recover_cow_leftovers(
        if (error)
                return error;
 
-       error = xfs_alloc_read_agf(pag, tp, 0, &agbp);
-       if (error)
-               goto out_trans;
-       cur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
+       if (rtg) {
+               xfs_rtgroup_lock(rtg, XFS_RTGLOCK_REFCOUNT);
+               cur = xfs_rtrefcountbt_init_cursor(mp, tp, rtg,
+                               rtg->rtg_inodes[XFS_RTG_REFCOUNT]);
+       } else {
+               error = xfs_alloc_read_agf(pag, tp, 0, &agbp);
+               if (error)
+                       goto out_trans;
+               cur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
+       }
 
        /* Find all the leftover CoW staging extents. */
        error = xfs_btree_query_range(cur, &low, &high,
                        xfs_refcount_recover_extent, &debris);
        xfs_btree_del_cursor(cur, error);
-       xfs_trans_brelse(tp, agbp);
+       if (agbp)
+               xfs_trans_brelse(tp, agbp);
+       else
+               xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_REFCOUNT);
        xfs_trans_cancel(tp);
        if (error)
                goto out_free;
@@ -2130,15 +2145,20 @@ xfs_refcount_recover_cow_leftovers(
                        goto out_free;
 
                /* Free the orphan record */
-               fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno,
-                               rr->rr_rrec.rc_startblock);
-               xfs_refcount_free_cow_extent(tp, false, fsb,
+               if (rtg)
+                       fsb = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno,
+                                       rr->rr_rrec.rc_startblock);
+               else
+                       fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno,
+                                       rr->rr_rrec.rc_startblock);
+               xfs_refcount_free_cow_extent(tp, rtg != NULL, fsb,
                                rr->rr_rrec.rc_blockcount);
 
                /* Free the block. */
                error = xfs_free_extent_later(tp, fsb,
                                rr->rr_rrec.rc_blockcount, NULL,
-                               XFS_AG_RESV_NONE, 0);
+                               XFS_AG_RESV_NONE,
+                               rtg != NULL ? XFS_FREE_EXTENT_REALTIME : 0);
                if (error)
                        goto out_trans;
 
@@ -2162,6 +2182,22 @@ out_free:
        return error;
 }
 
+int
+xfs_refcount_recover_cow_leftovers(
+       struct xfs_mount                *mp,
+       struct xfs_perag                *pag)
+{
+       return xfs_refcount_recover_group_cow_leftovers(mp, pag, NULL);
+}
+
+int
+xfs_refcount_recover_rtcow_leftovers(
+       struct xfs_mount                *mp,
+       struct xfs_rtgroup              *rtg)
+{
+       return xfs_refcount_recover_group_cow_leftovers(mp, NULL, rtg);
+}
+
 /*
  * Scan part of the keyspace of the refcount records and tell us if the area
  * has no records, is fully mapped by records, or is partially filled.
index 56e5834feb624264dd1b3ab1248a39cc5e1d03d4..18e0479d3d1d0ab6f87a544a3c9f73b400d59980 100644 (file)
@@ -97,8 +97,10 @@ void xfs_refcount_alloc_cow_extent(struct xfs_trans *tp, bool isrt,
                xfs_fsblock_t fsb, xfs_extlen_t len);
 void xfs_refcount_free_cow_extent(struct xfs_trans *tp, bool isrt,
                xfs_fsblock_t fsb, xfs_extlen_t len);
-extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp,
+int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp,
                struct xfs_perag *pag);
+int xfs_refcount_recover_rtcow_leftovers(struct xfs_mount *mp,
+               struct xfs_rtgroup *rtg);
 
 /*
  * While we're adjusting the refcounts records of an extent, we have