summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-01-05 17:47:06 -0800
committerDarrick J. Wong <djwong@kernel.org>2021-03-25 17:08:50 -0700
commit81993c90b72ab8090d0e3ded5954a31f5dddb659 (patch)
treeaf3f734dd7dbed7f6ee0c897e783fe4fec2beb51 /fs
parentd2c40705a28a798416e314eb7b0b9ff5ccc3fdf7 (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.c6
2 files changed, 30 insertions, 15 deletions
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
index 0e6b7c7aba45..b1558686065e 100644
--- a/fs/xfs/libxfs/xfs_refcount.c
+++ b/fs/xfs/libxfs/xfs_refcount.c
@@ -1821,16 +1821,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 is_rt = agno == NULLAGNUMBER;
int error;
- if (mp->m_sb.sb_agblocks >= XFS_REFC_COW_START)
+ if (!is_rt && mp->m_sb.sb_agblocks >= XFS_REFC_COW_START)
+ return -EOPNOTSUPP;
+ if (is_rt && mp->m_sb.sb_rextents >= XFS_RTREFC_COW_START)
return -EOPNOTSUPP;
INIT_LIST_HEAD(&debris);
@@ -1849,20 +1853,29 @@ xfs_refcount_recover_cow_leftovers(
if (error)
return error;
- error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
- if (error)
- goto out_trans;
- cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
+ if (is_rt) {
+ 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, agno, 0, &agbp);
+ if (error)
+ goto out_trans;
+ cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno);
+ }
+ 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;
@@ -1877,14 +1890,14 @@ xfs_refcount_recover_cow_leftovers(
trace_xfs_refcount_recover_extent(mp, agno, &rr->rr_rrec);
/* Free the orphan record */
- bno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START;
- fsb = XFS_AGB_TO_FSB(mp, agno, bno);
+ bno = rr->rr_rrec.rc_startblock - cow_start;
+ fsb = is_rt ? bno : XFS_AGB_TO_FSB(mp, agno, bno);
xfs_refcount_free_cow_extent(tp, fsb,
- rr->rr_rrec.rc_blockcount, false);
+ rr->rr_rrec.rc_blockcount, is_rt);
/* Free the block. */
xfs_bmap_add_free(tp, fsb, rr->rr_rrec.rc_blockcount, NULL,
- false);
+ is_rt);
error = xfs_trans_commit(tp);
if (error)
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 499dd99e3421..fd687eea15f0 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -807,10 +807,12 @@ xfs_reflink_recover_cow(
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
error = xfs_refcount_recover_cow_leftovers(mp, agno);
if (error)
- break;
+ return error;
}
- return error;
+ if (xfs_sb_version_hasrealtime(&mp->m_sb))
+ return xfs_refcount_recover_cow_leftovers(mp, NULLAGNUMBER);
+ return 0;
}
/*