xfs: hoist AGI repair context to a heap object
authorDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 21:55:01 +0000 (14:55 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 21:58:58 +0000 (14:58 -0700)
Save ~460 bytes of stack space by moving all the repair context to a
heap object.  We're going to add even more context data in the next
patch, which is why we really need to do this now.

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

index 427054b65b2384b53c6bd3a5321cff453b551ebc..d210bd7d5eb13d24d54147253e2cb577b2468009 100644 (file)
@@ -796,15 +796,29 @@ enum {
        XREP_AGI_MAX
 };
 
+struct xrep_agi {
+       struct xfs_scrub                *sc;
+
+       /* AGI buffer, tracked separately */
+       struct xfs_buf                  *agi_bp;
+
+       /* context for finding btree roots */
+       struct xrep_find_ag_btree       fab[XREP_AGI_MAX];
+
+       /* old AGI contents in case we have to revert */
+       struct xfs_agi                  old_agi;
+};
+
 /*
  * Given the inode btree roots described by *fab, find the roots, check them
  * for sanity, and pass the root data back out via *fab.
  */
 STATIC int
 xrep_agi_find_btrees(
-       struct xfs_scrub                *sc,
-       struct xrep_find_ag_btree       *fab)
+       struct xrep_agi                 *ragi)
 {
+       struct xfs_scrub                *sc = ragi->sc;
+       struct xrep_find_ag_btree       *fab = ragi->fab;
        struct xfs_buf                  *agf_bp;
        struct xfs_mount                *mp = sc->mp;
        int                             error;
@@ -837,10 +851,11 @@ xrep_agi_find_btrees(
  */
 STATIC void
 xrep_agi_init_header(
-       struct xfs_scrub        *sc,
-       struct xfs_buf          *agi_bp,
-       struct xfs_agi          *old_agi)
+       struct xrep_agi         *ragi)
 {
+       struct xfs_scrub        *sc = ragi->sc;
+       struct xfs_buf          *agi_bp = ragi->agi_bp;
+       struct xfs_agi          *old_agi = &ragi->old_agi;
        struct xfs_agi          *agi = agi_bp->b_addr;
        struct xfs_perag        *pag = sc->sa.pag;
        struct xfs_mount        *mp = sc->mp;
@@ -868,10 +883,12 @@ xrep_agi_init_header(
 /* Set btree root information in an AGI. */
 STATIC void
 xrep_agi_set_roots(
-       struct xfs_scrub                *sc,
-       struct xfs_agi                  *agi,
-       struct xrep_find_ag_btree       *fab)
+       struct xrep_agi                 *ragi)
 {
+       struct xfs_scrub                *sc = ragi->sc;
+       struct xfs_agi                  *agi = ragi->agi_bp->b_addr;
+       struct xrep_find_ag_btree       *fab = ragi->fab;
+
        agi->agi_root = cpu_to_be32(fab[XREP_AGI_INOBT].root);
        agi->agi_level = cpu_to_be32(fab[XREP_AGI_INOBT].height);
 
@@ -884,9 +901,10 @@ xrep_agi_set_roots(
 /* Update the AGI counters. */
 STATIC int
 xrep_agi_calc_from_btrees(
-       struct xfs_scrub        *sc,
-       struct xfs_buf          *agi_bp)
+       struct xrep_agi         *ragi)
 {
+       struct xfs_scrub        *sc = ragi->sc;
+       struct xfs_buf          *agi_bp = ragi->agi_bp;
        struct xfs_btree_cur    *cur;
        struct xfs_agi          *agi = agi_bp->b_addr;
        struct xfs_mount        *mp = sc->mp;
@@ -931,9 +949,10 @@ err:
 /* Trigger reinitialization of the in-core data. */
 STATIC int
 xrep_agi_commit_new(
-       struct xfs_scrub        *sc,
-       struct xfs_buf          *agi_bp)
+       struct xrep_agi         *ragi)
 {
+       struct xfs_scrub        *sc = ragi->sc;
+       struct xfs_buf          *agi_bp = ragi->agi_bp;
        struct xfs_perag        *pag;
        struct xfs_agi          *agi = agi_bp->b_addr;
 
@@ -956,33 +975,36 @@ xrep_agi_commit_new(
 /* Repair the AGI. */
 int
 xrep_agi(
-       struct xfs_scrub                *sc)
+       struct xfs_scrub        *sc)
 {
-       struct xrep_find_ag_btree       fab[XREP_AGI_MAX] = {
-               [XREP_AGI_INOBT] = {
-                       .rmap_owner = XFS_RMAP_OWN_INOBT,
-                       .buf_ops = &xfs_inobt_buf_ops,
-                       .maxlevels = M_IGEO(sc->mp)->inobt_maxlevels,
-               },
-               [XREP_AGI_FINOBT] = {
-                       .rmap_owner = XFS_RMAP_OWN_INOBT,
-                       .buf_ops = &xfs_finobt_buf_ops,
-                       .maxlevels = M_IGEO(sc->mp)->inobt_maxlevels,
-               },
-               [XREP_AGI_END] = {
-                       .buf_ops = NULL
-               },
-       };
-       struct xfs_agi                  old_agi;
-       struct xfs_mount                *mp = sc->mp;
-       struct xfs_buf                  *agi_bp;
-       struct xfs_agi                  *agi;
-       int                             error;
+       struct xrep_agi         *ragi;
+       struct xfs_mount        *mp = sc->mp;
+       int                     error;
 
        /* We require the rmapbt to rebuild anything. */
        if (!xfs_has_rmapbt(mp))
                return -EOPNOTSUPP;
 
+       sc->buf = kzalloc(sizeof(struct xrep_agi), XCHK_GFP_FLAGS);
+       if (!sc->buf)
+               return -ENOMEM;
+       ragi = sc->buf;
+       ragi->sc = sc;
+
+       ragi->fab[XREP_AGI_INOBT] = (struct xrep_find_ag_btree){
+               .rmap_owner     = XFS_RMAP_OWN_INOBT,
+               .buf_ops        = &xfs_inobt_buf_ops,
+               .maxlevels      = M_IGEO(sc->mp)->inobt_maxlevels,
+       };
+       ragi->fab[XREP_AGI_FINOBT] = (struct xrep_find_ag_btree){
+               .rmap_owner     = XFS_RMAP_OWN_INOBT,
+               .buf_ops        = &xfs_finobt_buf_ops,
+               .maxlevels      = M_IGEO(sc->mp)->inobt_maxlevels,
+       };
+       ragi->fab[XREP_AGI_END] = (struct xrep_find_ag_btree){
+               .buf_ops        = NULL,
+       };
+
        /*
         * Make sure we have the AGI buffer, as scrub might have decided it
         * was corrupt after xfs_ialloc_read_agi failed with -EFSCORRUPTED.
@@ -990,14 +1012,13 @@ xrep_agi(
        error = xfs_trans_read_buf(mp, sc->tp, mp->m_ddev_targp,
                        XFS_AG_DADDR(mp, sc->sa.pag->pag_agno,
                                                XFS_AGI_DADDR(mp)),
-                       XFS_FSS_TO_BB(mp, 1), 0, &agi_bp, NULL);
+                       XFS_FSS_TO_BB(mp, 1), 0, &ragi->agi_bp, NULL);
        if (error)
                return error;
-       agi_bp->b_ops = &xfs_agi_buf_ops;
-       agi = agi_bp->b_addr;
+       ragi->agi_bp->b_ops = &xfs_agi_buf_ops;
 
        /* Find the AGI btree roots. */
-       error = xrep_agi_find_btrees(sc, fab);
+       error = xrep_agi_find_btrees(ragi);
        if (error)
                return error;
 
@@ -1006,18 +1027,18 @@ xrep_agi(
                return error;
 
        /* Start rewriting the header and implant the btrees we found. */
-       xrep_agi_init_header(sc, agi_bp, &old_agi);
-       xrep_agi_set_roots(sc, agi, fab);
-       error = xrep_agi_calc_from_btrees(sc, agi_bp);
+       xrep_agi_init_header(ragi);
+       xrep_agi_set_roots(ragi);
+       error = xrep_agi_calc_from_btrees(ragi);
        if (error)
                goto out_revert;
 
        /* Reinitialize in-core state. */
-       return xrep_agi_commit_new(sc, agi_bp);
+       return xrep_agi_commit_new(ragi);
 
 out_revert:
        /* Mark the incore AGI state stale and revert the AGI. */
        clear_bit(XFS_AGSTATE_AGI_INIT, &sc->sa.pag->pag_opstate);
-       memcpy(agi, &old_agi, sizeof(old_agi));
+       memcpy(ragi->agi_bp->b_addr, &ragi->old_agi, sizeof(struct xfs_agi));
        return error;
 }