summaryrefslogtreecommitdiff
path: root/fs/xfs/scrub
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-09-01 11:17:59 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-12-15 17:29:18 -0800
commitf27a9a84b202a804a7b13f44974f5d2a684f0dc6 (patch)
treebe3cbbe7f120a68b36b2d0a14c0a7def1e5db34e /fs/xfs/scrub
parente74c55a50a140b6388185cc62bdcbe115c993cd0 (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.c58
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;