@@ -2037,14 +2037,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;
@@ -2054,7 +2055,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_sb.sb_rgblocks >= XFS_MAX_RGBLOCKS)
return -EOPNOTSUPP;
INIT_LIST_HEAD(&debris);
@@ -2073,10 +2079,16 @@ 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(NULL, rtg, XFS_RTGLOCK_REFCOUNT);
+ cur = xfs_rtrefcountbt_init_cursor(mp, tp, rtg,
+ rtg->rtg_refcountip);
+ } 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. */
memset(&low, 0, sizeof(low));
@@ -2086,7 +2098,10 @@ xfs_refcount_recover_cow_leftovers(
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;
@@ -2099,14 +2114,18 @@ 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. */
xfs_free_extent_later(tp, fsb, rr->rr_rrec.rc_blockcount, NULL,
- 0);
+ rtg != NULL ? XFS_FREE_EXTENT_REALTIME : 0);
error = xfs_trans_commit(tp);
if (error)
@@ -2128,6 +2147,22 @@ xfs_refcount_recover_cow_leftovers(
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.
@@ -12,6 +12,7 @@ struct xfs_perag;
struct xfs_btree_cur;
struct xfs_bmbt_irec;
struct xfs_refcount_irec;
+struct xfs_rtgroup;
extern int xfs_refcount_lookup_le(struct xfs_btree_cur *cur,
enum xfs_refc_domain domain, xfs_agblock_t bno, int *stat);
@@ -99,8 +100,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
@@ -1002,7 +1002,9 @@ xfs_reflink_recover_cow(
struct xfs_mount *mp)
{
struct xfs_perag *pag;
+ struct xfs_rtgroup *rtg;
xfs_agnumber_t agno;
+ xfs_rgnumber_t rgno;
int error = 0;
if (!xfs_has_reflink(mp))
@@ -1012,11 +1014,19 @@ xfs_reflink_recover_cow(
error = xfs_refcount_recover_cow_leftovers(mp, pag);
if (error) {
xfs_perag_put(pag);
- break;
+ return error;
}
}
- return error;
+ for_each_rtgroup(mp, rgno, rtg) {
+ error = xfs_refcount_recover_rtcow_leftovers(mp, rtg);
+ if (error) {
+ xfs_rtgroup_put(rtg);
+ return error;
+ }
+ }
+
+ return 0;
}
/*