]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: repair rmap btree inodes
authorDarrick J. Wong <djwong@kernel.org>
Thu, 21 Nov 2024 00:20:40 +0000 (16:20 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 23 Dec 2024 21:06:08 +0000 (13:06 -0800)
Teach the inode repair code how to deal with realtime rmap btree inodes
that won't load properly.  This is most likely moot since the filesystem
generally won't mount without the rtrmapbt inodes being usable, but
we'll add this for completeness.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/scrub/inode_repair.c

index 816e81330ffc9942efdc5c8df8efeeb85a41f58b..d7e3f033b160738b556d3732d6a06786786c1146 100644 (file)
@@ -944,6 +944,34 @@ xrep_dinode_bad_bmbt_fork(
        return false;
 }
 
+/* Return true if this rmap-format ifork looks like garbage. */
+STATIC bool
+xrep_dinode_bad_rtrmapbt_fork(
+       struct xfs_scrub        *sc,
+       struct xfs_dinode       *dip,
+       unsigned int            dfork_size)
+{
+       struct xfs_rtrmap_root  *dfp;
+       unsigned int            nrecs;
+       unsigned int            level;
+
+       if (dfork_size < sizeof(struct xfs_rtrmap_root))
+               return true;
+
+       dfp = XFS_DFORK_PTR(dip, XFS_DATA_FORK);
+       nrecs = be16_to_cpu(dfp->bb_numrecs);
+       level = be16_to_cpu(dfp->bb_level);
+
+       if (level > sc->mp->m_rtrmap_maxlevels)
+               return true;
+       if (xfs_rtrmap_droot_space_calc(level, nrecs) > dfork_size)
+               return true;
+       if (level > 0 && nrecs == 0)
+               return true;
+
+       return false;
+}
+
 /* Check a metadata-btree fork. */
 STATIC bool
 xrep_dinode_bad_metabt_fork(
@@ -956,6 +984,8 @@ xrep_dinode_bad_metabt_fork(
                return true;
 
        switch (be16_to_cpu(dip->di_metatype)) {
+       case XFS_METAFILE_RTRMAP:
+               return xrep_dinode_bad_rtrmapbt_fork(sc, dip, dfork_size);
        default:
                return true;
        }
@@ -1220,6 +1250,7 @@ xrep_dinode_ensure_forkoff(
        uint16_t                mode)
 {
        struct xfs_bmdr_block   *bmdr;
+       struct xfs_rtrmap_root  *rmdr;
        struct xfs_scrub        *sc = ri->sc;
        xfs_extnum_t            attr_extents, data_extents;
        size_t                  bmdr_minsz = xfs_bmdr_space_calc(1);
@@ -1328,6 +1359,10 @@ xrep_dinode_ensure_forkoff(
                break;
        case XFS_DINODE_FMT_META_BTREE:
                switch (be16_to_cpu(dip->di_metatype)) {
+               case XFS_METAFILE_RTRMAP:
+                       rmdr = XFS_DFORK_PTR(dip, XFS_DATA_FORK);
+                       dfork_min = xfs_rtrmap_broot_space(sc->mp, rmdr);
+                       break;
                default:
                        dfork_min = 0;
                        break;