]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_repair: rebuild the bmap btree for realtime files
authorDarrick J. Wong <djwong@kernel.org>
Wed, 3 Jul 2024 21:22:25 +0000 (14:22 -0700)
committerChristoph Hellwig <hch@lst.de>
Mon, 12 Aug 2024 11:53:50 +0000 (13:53 +0200)
Use the realtime rmap btree information to rebuild an inode's data fork
when appropriate.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
repair/bmap_repair.c

index f1eb04c968c680f65fb4c4ba5b08f4fff324fea6..006be1d8f4135a63cb91b43116af4169c0726e65 100644 (file)
@@ -211,6 +211,101 @@ xrep_bmap_scan_ag(
        return error;
 }
 
+/* Check for any obvious errors or conflicts in the file mapping. */
+STATIC int
+xrep_bmap_check_rtfork_rmap(
+       struct repair_ctx               *sc,
+       struct xfs_btree_cur            *cur,
+       const struct xfs_rmap_irec      *rec)
+{
+       /* xattr extents are never stored on realtime devices */
+       if (rec->rm_flags & XFS_RMAP_ATTR_FORK)
+               return EFSCORRUPTED;
+
+       /* bmbt blocks are never stored on realtime devices */
+       if (rec->rm_flags & XFS_RMAP_BMBT_BLOCK)
+               return EFSCORRUPTED;
+
+       /* Data extents for non-rt files are never stored on the rt device. */
+       if (!XFS_IS_REALTIME_INODE(sc->ip))
+               return EFSCORRUPTED;
+
+       /* Check the file offsets and physical extents. */
+       if (!xfs_verify_fileext(sc->mp, rec->rm_offset, rec->rm_blockcount))
+               return EFSCORRUPTED;
+
+       /* Check that this fits in the rt volume. */
+       if (!xfs_verify_rgbext(cur->bc_ino.rtg, rec->rm_startblock,
+                               rec->rm_blockcount))
+               return EFSCORRUPTED;
+
+       return 0;
+}
+
+/* Record realtime extents that belong to this inode's fork. */
+STATIC int
+xrep_bmap_walk_rtrmap(
+       struct xfs_btree_cur            *cur,
+       const struct xfs_rmap_irec      *rec,
+       void                            *priv)
+{
+       struct xrep_bmap                *rb = priv;
+       int                             error = 0;
+
+       /* Skip extents which are not owned by this inode and fork. */
+       if (rec->rm_owner != rb->sc->ip->i_ino)
+               return 0;
+
+       error = xrep_bmap_check_rtfork_rmap(rb->sc, cur, rec);
+       if (error)
+               return error;
+
+       /*
+        * Record all blocks allocated to this file even if the extent isn't
+        * for the fork we're rebuilding so that we can reset di_nblocks later.
+        */
+       rb->nblocks += rec->rm_blockcount;
+
+       /* If this rmap isn't for the fork we want, we're done. */
+       if (rb->whichfork == XFS_DATA_FORK &&
+           (rec->rm_flags & XFS_RMAP_ATTR_FORK))
+               return 0;
+       if (rb->whichfork == XFS_ATTR_FORK &&
+           !(rec->rm_flags & XFS_RMAP_ATTR_FORK))
+               return 0;
+
+       return xrep_bmap_from_rmap(rb, rec->rm_offset, rec->rm_startblock,
+                       rec->rm_blockcount,
+                       rec->rm_flags & XFS_RMAP_UNWRITTEN);
+}
+
+/*
+ * Scan the realtime reverse mappings to build the new extent map.  The rt rmap
+ * inodes must be loaded from disk explicitly here, since we have not yet
+ * validated the metadata directory tree but do not wish to throw away user
+ * data unnecessarily.
+ */
+STATIC int
+xrep_bmap_scan_rt(
+       struct xrep_bmap        *rb,
+       struct xfs_rtgroup      *rtg)
+{
+       struct repair_ctx       *sc = rb->sc;
+       struct xfs_mount        *mp = sc->mp;
+       struct xfs_inode        *ip = rtg->rtg_inodes[XFS_RTG_RMAP];
+       struct xfs_btree_cur    *cur;
+       int                     error;
+
+       /* failed to load the rtdir inode? */
+       if (!xfs_has_rtrmapbt(mp) || !ip)
+               return ENOENT;
+
+       cur = libxfs_rtrmapbt_init_cursor(mp, sc->tp, rtg, ip);
+       error = -libxfs_rmap_query_all(cur, xrep_bmap_walk_rtrmap, rb);
+       libxfs_btree_del_cursor(cur, error);
+       return error;
+}
+
 /*
  * Collect block mappings for this fork of this inode and decide if we have
  * enough space to rebuild.  Caller is responsible for cleaning up the list if
@@ -221,9 +316,20 @@ xrep_bmap_find_mappings(
        struct xrep_bmap        *rb)
 {
        struct xfs_perag        *pag;
+       struct xfs_rtgroup      *rtg;
        xfs_agnumber_t          agno;
+       xfs_rgnumber_t          rgno;
        int                     error;
 
+       /* Iterate the rtrmaps for extents. */
+       for_each_rtgroup(rb->sc->mp, rgno, rtg) {
+               error = xrep_bmap_scan_rt(rb, rtg);
+               if (error) {
+                       libxfs_rtgroup_put(rtg);
+                       return error;
+               }
+       }
+
        /* Iterate the rmaps for extents. */
        for_each_perag(rb->sc->mp, agno, pag) {
                error = xrep_bmap_scan_ag(rb, pag);
@@ -573,10 +679,6 @@ xrep_bmap_check_inputs(
                return EINVAL;
        }
 
-       /* Don't know how to rebuild realtime data forks. */
-       if (XFS_IS_REALTIME_INODE(sc->ip))
-               return EOPNOTSUPP;
-
        return 0;
 }