diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-09-01 11:17:59 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-12-15 17:29:18 -0800 |
commit | f27a9a84b202a804a7b13f44974f5d2a684f0dc6 (patch) | |
tree | be3cbbe7f120a68b36b2d0a14c0a7def1e5db34e /fs/xfs/scrub | |
parent | e74c55a50a140b6388185cc62bdcbe115c993cd0 (diff) |
xfs: repair inodes that have realtime extents
Plumb into the inode core repair code the ability to search for extents
on realtime devices.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs/xfs/scrub')
-rw-r--r-- | fs/xfs/scrub/inode_repair.c | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c index f3f672cdea98..0bfa7e8f6e03 100644 --- a/fs/xfs/scrub/inode_repair.c +++ b/fs/xfs/scrub/inode_repair.c @@ -32,6 +32,7 @@ #include "xfs_dir2_priv.h" #include "xfs_quota_defs.h" #include "xfs_attr_leaf.h" +#include "libxfs/xfs_rtrmap_btree.h" #include "xfs_log_priv.h" #include "xfs_ag.h" #include "scrub/xfs_scrub.h" @@ -560,6 +561,52 @@ xrep_dinode_count_ag_rmaps( return error; } +/* Count extents and blocks for an inode given an rt rmap. */ +STATIC int +xrep_dinode_walk_rtrmap( + struct xfs_btree_cur *cur, + const struct xfs_rmap_irec *rec, + void *priv) +{ + struct xrep_dinode_stats *dis = priv; + int error = 0; + + if (xchk_should_terminate(dis->sc, &error)) + return error; + + /* We only care about this inode. */ + if (rec->rm_owner != dis->sc->sm->sm_ino) + return 0; + + if (rec->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK)) + return -EFSCORRUPTED; + + dis->rt_blocks += rec->rm_blockcount; + dis->rt_extents++; + return 0; +} + +/* Count extents and blocks for an inode from all realtime rmap data. */ +STATIC int +xrep_dinode_count_rt_rmaps( + struct xrep_dinode_stats *dis) +{ + struct xfs_scrub *sc = dis->sc; + int error; + + if (!xfs_has_realtime(sc->mp) || + xrep_is_rtmeta_ino(sc, sc->sm->sm_ino)) + return 0; + + xchk_rt_lock(sc, &sc->sr); + xrep_rt_btcur_init(sc, &sc->sr); + error = xfs_rmap_query_all(sc->sr.rmap_cur, xrep_dinode_walk_rtrmap, + dis); + xchk_rt_btcur_free(&sc->sr); + xchk_rt_unlock(sc, &sc->sr); + return error; +} + /* Count extents and blocks for a given inode from all rmap data. */ STATIC int xrep_dinode_count_rmaps( @@ -569,9 +616,13 @@ xrep_dinode_count_rmaps( xfs_agnumber_t agno; int error; - if (!xfs_has_rmapbt(dis->sc->mp) || xfs_has_realtime(dis->sc->mp)) + if (!xfs_has_rmapbt(dis->sc->mp)) return -EOPNOTSUPP; + error = xrep_dinode_count_rt_rmaps(dis); + if (error) + return error; + for_each_perag(dis->sc->mp, agno, pag) { error = xrep_dinode_count_ag_rmaps(dis, pag); if (error) { @@ -835,6 +886,7 @@ xrep_dinode_ensure_forkoff( struct xrep_dinode_stats *dis) { struct xfs_bmdr_block *bmdr; + struct xfs_rtrmap_root *rmdr; size_t bmdr_minsz = xfs_bmdr_space_calc(1); unsigned int lit_sz = XFS_LITINO(sc->mp); unsigned int afork_min, dfork_min; @@ -939,6 +991,10 @@ xrep_dinode_ensure_forkoff( bmdr = XFS_DFORK_PTR(dip, XFS_DATA_FORK); dfork_min = xfs_bmap_broot_space(sc->mp, bmdr); break; + case XFS_DINODE_FMT_RMAP: + rmdr = XFS_DFORK_PTR(dip, XFS_DATA_FORK); + dfork_min = xfs_rtrmap_broot_space(sc->mp, rmdr); + break; default: dfork_min = 0; break; |