summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-09-01 11:18:45 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-09-17 18:55:23 -0700
commitc35e8733434d23d3fa75fabc7880ff9e029daab9 (patch)
tree54addc6a0833c8038e70a3e5aa5de245cb2a0ca2 /fs
parente22951e5c661b79d9345987983809ccb15b8ff60 (diff)
xfs: refcover CoW leftovers in the realtime volume
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/libxfs/xfs_refcount.c39
-rw-r--r--fs/xfs/xfs_reflink.c7
2 files changed, 32 insertions, 14 deletions
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
index 5f28c9440920..3a0bd1c002ab 100644
--- a/fs/xfs/libxfs/xfs_refcount.c
+++ b/fs/xfs/libxfs/xfs_refcount.c
@@ -1797,16 +1797,20 @@ xfs_refcount_recover_cow_leftovers(
{
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;
union xfs_btree_irec high;
xfs_fsblock_t fsb;
xfs_fsblock_t bno;
+ xfs_fsblock_t cow_start;
+ bool isrt = pag == NULL;
int error;
- if (mp->m_sb.sb_agblocks >= XFS_REFC_COW_START)
+ if (!isrt && mp->m_sb.sb_agblocks >= XFS_REFC_COW_START)
+ return -EOPNOTSUPP;
+ if (isrt && mp->m_sb.sb_rextents >= XFS_RTREFC_COW_START)
return -EOPNOTSUPP;
INIT_LIST_HEAD(&debris);
@@ -1825,20 +1829,29 @@ xfs_refcount_recover_cow_leftovers(
if (error)
return error;
- error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
- if (error)
- goto out_trans;
- cur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
+ if (isrt) {
+ xfs_rtlock(NULL, mp, XFS_RTLOCK_REFCOUNT);
+ cur = xfs_rtrefcountbt_init_cursor(mp, tp, mp->m_rrefcountip);
+ } else {
+ error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
+ if (error)
+ goto out_trans;
+ cur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
+ }
+ cow_start = xrefc_cow_start(cur);
/* Find all the leftover CoW staging extents. */
memset(&low, 0, sizeof(low));
memset(&high, 0, sizeof(high));
- low.rc.rc_startblock = XFS_REFC_COW_START;
- high.rc.rc_startblock = -1U;
+ low.rc.rc_startblock = cow_start;
+ high.rc.rc_startblock = -1ULL;
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_rtunlock(mp, XFS_RTLOCK_REFCOUNT);
xfs_trans_cancel(tp);
if (error)
goto out_free;
@@ -1851,14 +1864,14 @@ xfs_refcount_recover_cow_leftovers(
goto out_free;
/* Free the orphan record */
- bno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START;
- fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, bno);
- xfs_refcount_free_cow_extent(tp, false, fsb,
+ bno = rr->rr_rrec.rc_startblock - cow_start;
+ fsb = isrt ? bno : XFS_AGB_TO_FSB(mp, pag->pag_agno, bno);
+ xfs_refcount_free_cow_extent(tp, isrt, fsb,
rr->rr_rrec.rc_blockcount);
/* Free the block. */
xfs_free_extent_later(tp, fsb, rr->rr_rrec.rc_blockcount, NULL,
- 0);
+ isrt ? XFS_FREE_EXTENT_REALTIME : 0);
error = xfs_trans_commit(tp);
if (error)
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index e3518a58df00..d7631824f98e 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -849,8 +849,13 @@ xfs_reflink_recover_cow(
break;
}
}
+ if (error)
+ return error;
- return error;
+ if (xfs_has_realtime(mp))
+ return xfs_refcount_recover_cow_leftovers(mp, NULL);
+
+ return 0;
}
/*