diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-01-05 17:47:06 -0800 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-03-25 17:08:50 -0700 |
commit | 81993c90b72ab8090d0e3ded5954a31f5dddb659 (patch) | |
tree | af3f734dd7dbed7f6ee0c897e783fe4fec2beb51 /fs | |
parent | d2c40705a28a798416e314eb7b0b9ff5ccc3fdf7 (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.c | 39 | ||||
-rw-r--r-- | fs/xfs/xfs_reflink.c | 6 |
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; } /* |