diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-09-01 11:18:45 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-09-17 18:55:23 -0700 |
commit | c35e8733434d23d3fa75fabc7880ff9e029daab9 (patch) | |
tree | 54addc6a0833c8038e70a3e5aa5de245cb2a0ca2 /fs | |
parent | e22951e5c661b79d9345987983809ccb15b8ff60 (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 | 7 |
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; } /* |