]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: repair inodes that have realtime extents
authorDarrick J. Wong <djwong@kernel.org>
Thu, 21 Nov 2024 00:20:39 +0000 (16:20 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 23 Dec 2024 21:06:08 +0000 (13:06 -0800)
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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/scrub/inode_repair.c

index a94f9df0ca78f6807fc2f4a0a56f3a47c482b1c3..816e81330ffc9942efdc5c8df8efeeb85a41f58b 100644 (file)
@@ -38,6 +38,8 @@
 #include "xfs_log_priv.h"
 #include "xfs_health.h"
 #include "xfs_symlink_remote.h"
+#include "xfs_rtgroup.h"
+#include "xfs_rtrmap_btree.h"
 #include "scrub/xfs_scrub.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
@@ -773,17 +775,71 @@ 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_inode               *ri = priv;
+       int                             error = 0;
+
+       if (xchk_should_terminate(ri->sc, &error))
+               return error;
+
+       /* We only care about this inode. */
+       if (rec->rm_owner != ri->sc->sm->sm_ino)
+               return 0;
+
+       if (rec->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))
+               return -EFSCORRUPTED;
+
+       ri->rt_blocks += rec->rm_blockcount;
+       ri->rt_extents++;
+       return 0;
+}
+
+/* Count extents and blocks for an inode from all realtime rmap data. */
+STATIC int
+xrep_dinode_count_rtgroup_rmaps(
+       struct xrep_inode       *ri,
+       struct xfs_rtgroup      *rtg)
+{
+       struct xfs_scrub        *sc = ri->sc;
+       int                     error;
+
+       error = xrep_rtgroup_init(sc, rtg, &sc->sr, XFS_RTGLOCK_RMAP);
+       if (error)
+               return error;
+
+       error = xfs_rmap_query_all(sc->sr.rmap_cur, xrep_dinode_walk_rtrmap,
+                       ri);
+       xchk_rtgroup_btcur_free(&sc->sr);
+       xchk_rtgroup_free(sc, &sc->sr);
+       return error;
+}
+
 /* Count extents and blocks for a given inode from all rmap data. */
 STATIC int
 xrep_dinode_count_rmaps(
        struct xrep_inode       *ri)
 {
        struct xfs_perag        *pag = NULL;
+       struct xfs_rtgroup      *rtg = NULL;
        int                     error;
 
-       if (!xfs_has_rmapbt(ri->sc->mp) || xfs_has_realtime(ri->sc->mp))
+       if (!xfs_has_rmapbt(ri->sc->mp))
                return -EOPNOTSUPP;
 
+       while ((rtg = xfs_rtgroup_next(ri->sc->mp, rtg))) {
+               error = xrep_dinode_count_rtgroup_rmaps(ri, rtg);
+               if (error) {
+                       xfs_rtgroup_rele(rtg);
+                       return error;
+               }
+       }
+
        while ((pag = xfs_perag_next(ri->sc->mp, pag))) {
                error = xrep_dinode_count_ag_rmaps(ri, pag);
                if (error) {