summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2022-07-14 11:16:11 -0700
committerDarrick J. Wong <djwong@kernel.org>2022-11-09 19:08:12 -0800
commit05dfb1432b9118d87adc6d4f49fe85e45d657df1 (patch)
tree8b6356d981d523072be497cbabbe263236ab52e7
parentd920902d452a2efed623e52a163bac4454cff673 (diff)
xfs: walk the rt reference count tree when rebuilding rmap
When we're rebuilding the data device rmap, if we encounter a "refcount" format fork, we have to walk the (realtime) refcount btree inode to build the appropriate mappings. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r--fs/xfs/scrub/rmap_repair.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/fs/xfs/scrub/rmap_repair.c b/fs/xfs/scrub/rmap_repair.c
index 7b8b0c4e6b15..b2626c8dec76 100644
--- a/fs/xfs/scrub/rmap_repair.c
+++ b/fs/xfs/scrub/rmap_repair.c
@@ -32,6 +32,7 @@
#include "xfs_ag.h"
#include "xfs_rtrmap_btree.h"
#include "xfs_rtgroup.h"
+#include "xfs_rtrefcount_btree.h"
#include "scrub/xfs_scrub.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
@@ -539,6 +540,39 @@ xrep_rmap_scan_rtrmapbt(
return -EFSCORRUPTED;
}
+static int
+xrep_rmap_scan_rtrefcountbt(
+ struct xrep_rmap_ifork *rf,
+ struct xfs_inode *ip)
+{
+ struct xfs_scrub *sc = rf->rr->sc;
+ struct xfs_btree_cur *cur;
+ struct xfs_rtgroup *rtg;
+ xfs_rgnumber_t rgno;
+ int error;
+
+ if (rf->whichfork != XFS_DATA_FORK)
+ return -EFSCORRUPTED;
+
+ for_each_rtgroup(sc->mp, rgno, rtg) {
+ if (ip == rtg->rtg_refcountip) {
+ cur = xfs_rtrefcountbt_init_cursor(sc->mp, sc->tp, rtg,
+ ip);
+ error = xrep_rmap_scan_iroot_btree(rf, cur);
+ xfs_btree_del_cursor(cur, error);
+ xfs_rtgroup_put(rtg);
+ return error;
+ }
+ }
+
+ /*
+ * We shouldn't find a refcount format inode that isn't associated with
+ * an rtgroup!
+ */
+ ASSERT(0);
+ return -EFSCORRUPTED;
+}
+
/* Find all the extents from a given AG in an inode fork. */
STATIC int
xrep_rmap_scan_ifork(
@@ -570,6 +604,8 @@ xrep_rmap_scan_ifork(
return error;
} else if (ifp->if_format == XFS_DINODE_FMT_RMAP) {
return xrep_rmap_scan_rtrmapbt(&rf, ip);
+ } else if (ifp->if_format == XFS_DINODE_FMT_REFCOUNT) {
+ return xrep_rmap_scan_rtrefcountbt(&rf, ip);
} else if (ifp->if_format != XFS_DINODE_FMT_EXTENTS) {
return 0;
}