xfs: don't track the AGFL buffer in the scrub AG context
authorDarrick J. Wong <djwong@kernel.org>
Mon, 7 Nov 2022 01:03:14 +0000 (17:03 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 16 Nov 2022 23:25:01 +0000 (15:25 -0800)
While scrubbing an allocation group, we don't need to hold the AGFL
buffer as part of the scrub context.  All that is necessary to lock an
AG is to hold the AGI and AGF buffers, so fix all the existing users of
the AGFL buffer to grab them only when necessary.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
fs/xfs/scrub/agheader.c
fs/xfs/scrub/agheader_repair.c
fs/xfs/scrub/common.c
fs/xfs/scrub/repair.c
fs/xfs/scrub/scrub.h

index b7b838bd4ba43676ad86b03fbe7ce4266669cfc5..af284baa6f4cb9de8fc5fb7b5b550d90a89ea1d0 100644 (file)
@@ -609,9 +609,16 @@ out:
 /* AGFL */
 
 struct xchk_agfl_info {
-       unsigned int            sz_entries;
+       /* Number of AGFL entries that the AGF claims are in use. */
+       unsigned int            agflcount;
+
+       /* Number of AGFL entries that we found. */
        unsigned int            nr_entries;
+
+       /* Buffer to hold AGFL entries for extent checking. */
        xfs_agblock_t           *entries;
+
+       struct xfs_buf          *agfl_bp;
        struct xfs_scrub        *sc;
 };
 
@@ -641,10 +648,10 @@ xchk_agfl_block(
        struct xfs_scrub        *sc = sai->sc;
 
        if (xfs_verify_agbno(sc->sa.pag, agbno) &&
-           sai->nr_entries < sai->sz_entries)
+           sai->nr_entries < sai->agflcount)
                sai->entries[sai->nr_entries++] = agbno;
        else
-               xchk_block_set_corrupt(sc, sc->sa.agfl_bp);
+               xchk_block_set_corrupt(sc, sai->agfl_bp);
 
        xchk_agfl_block_xref(sc, agbno);
 
@@ -696,19 +703,26 @@ int
 xchk_agfl(
        struct xfs_scrub        *sc)
 {
-       struct xchk_agfl_info   sai;
+       struct xchk_agfl_info   sai = {
+               .sc             = sc,
+       };
        struct xfs_agf          *agf;
        xfs_agnumber_t          agno = sc->sm->sm_agno;
-       unsigned int            agflcount;
        unsigned int            i;
        int                     error;
 
+       /* Lock the AGF and AGI so that nobody can touch this AG. */
        error = xchk_ag_read_headers(sc, agno, &sc->sa);
        if (!xchk_process_error(sc, agno, XFS_AGFL_BLOCK(sc->mp), &error))
-               goto out;
+               return error;
        if (!sc->sa.agf_bp)
                return -EFSCORRUPTED;
-       xchk_buffer_recheck(sc, sc->sa.agfl_bp);
+
+       /* Try to read the AGFL, and verify its structure if we get it. */
+       error = xfs_alloc_read_agfl(sc->sa.pag, sc->tp, &sai.agfl_bp);
+       if (!xchk_process_error(sc, agno, XFS_AGFL_BLOCK(sc->mp), &error))
+               return error;
+       xchk_buffer_recheck(sc, sai.agfl_bp);
 
        xchk_agfl_xref(sc);
 
@@ -717,24 +731,21 @@ xchk_agfl(
 
        /* Allocate buffer to ensure uniqueness of AGFL entries. */
        agf = sc->sa.agf_bp->b_addr;
-       agflcount = be32_to_cpu(agf->agf_flcount);
-       if (agflcount > xfs_agfl_size(sc->mp)) {
+       sai.agflcount = be32_to_cpu(agf->agf_flcount);
+       if (sai.agflcount > xfs_agfl_size(sc->mp)) {
                xchk_block_set_corrupt(sc, sc->sa.agf_bp);
                goto out;
        }
-       memset(&sai, 0, sizeof(sai));
-       sai.sc = sc;
-       sai.sz_entries = agflcount;
-       sai.entries = kmem_zalloc(sizeof(xfs_agblock_t) * agflcount,
-                       KM_MAYFAIL);
+       sai.entries = kvcalloc(sai.agflcount, sizeof(xfs_agblock_t),
+                       GFP_KERNEL | __GFP_RETRY_MAYFAIL);
        if (!sai.entries) {
                error = -ENOMEM;
                goto out;
        }
 
        /* Check the blocks in the AGFL. */
-       error = xfs_agfl_walk(sc->mp, sc->sa.agf_bp->b_addr,
-                       sc->sa.agfl_bp, xchk_agfl_block, &sai);
+       error = xfs_agfl_walk(sc->mp, sc->sa.agf_bp->b_addr, sai.agfl_bp,
+                       xchk_agfl_block, &sai);
        if (error == -ECANCELED) {
                error = 0;
                goto out_free;
@@ -742,7 +753,7 @@ xchk_agfl(
        if (error)
                goto out_free;
 
-       if (agflcount != sai.nr_entries) {
+       if (sai.agflcount != sai.nr_entries) {
                xchk_block_set_corrupt(sc, sc->sa.agf_bp);
                goto out_free;
        }
@@ -758,7 +769,7 @@ xchk_agfl(
        }
 
 out_free:
-       kmem_free(sai.entries);
+       kvfree(sai.entries);
 out:
        return error;
 }
index 1b0b4e243f7712eeb56085f94c6401dbd4c3b586..2e75ff9b5b2e92ee8dcd2ef28f0d414a4cb478ee 100644 (file)
@@ -697,7 +697,6 @@ xrep_agfl(
         * freespace overflow to the freespace btrees.
         */
        sc->sa.agf_bp = agf_bp;
-       sc->sa.agfl_bp = agfl_bp;
        error = xrep_roll_ag_trans(sc);
        if (error)
                goto err;
index 9bbbf20f401b3af92eec89db60909d96ca0b2ada..ad70f29233c3632cd9ef7b8d61e07b19a22584b9 100644 (file)
@@ -424,10 +424,6 @@ xchk_ag_read_headers(
        if (error && want_ag_read_header_failure(sc, XFS_SCRUB_TYPE_AGF))
                return error;
 
-       error = xfs_alloc_read_agfl(sa->pag, sc->tp, &sa->agfl_bp);
-       if (error && want_ag_read_header_failure(sc, XFS_SCRUB_TYPE_AGFL))
-               return error;
-
        return 0;
 }
 
@@ -515,10 +511,6 @@ xchk_ag_free(
        struct xchk_ag          *sa)
 {
        xchk_ag_btcur_free(sa);
-       if (sa->agfl_bp) {
-               xfs_trans_brelse(sc->tp, sa->agfl_bp);
-               sa->agfl_bp = NULL;
-       }
        if (sa->agf_bp) {
                xfs_trans_brelse(sc->tp, sa->agf_bp);
                sa->agf_bp = NULL;
index c18bd039fce9e7c7c74157a93dca2f70b8eaa680..2ada7fc1c3983343fb7bb4a3562e18219bf9adca 100644 (file)
@@ -126,8 +126,6 @@ xrep_roll_ag_trans(
                xfs_trans_bhold(sc->tp, sc->sa.agi_bp);
        if (sc->sa.agf_bp)
                xfs_trans_bhold(sc->tp, sc->sa.agf_bp);
-       if (sc->sa.agfl_bp)
-               xfs_trans_bhold(sc->tp, sc->sa.agfl_bp);
 
        /*
         * Roll the transaction.  We still own the buffer and the buffer lock
@@ -145,8 +143,6 @@ xrep_roll_ag_trans(
                xfs_trans_bjoin(sc->tp, sc->sa.agi_bp);
        if (sc->sa.agf_bp)
                xfs_trans_bjoin(sc->tp, sc->sa.agf_bp);
-       if (sc->sa.agfl_bp)
-               xfs_trans_bjoin(sc->tp, sc->sa.agfl_bp);
 
        return 0;
 }
@@ -498,6 +494,7 @@ xrep_put_freelist(
        struct xfs_scrub        *sc,
        xfs_agblock_t           agbno)
 {
+       struct xfs_buf          *agfl_bp;
        int                     error;
 
        /* Make sure there's space on the freelist. */
@@ -516,8 +513,12 @@ xrep_put_freelist(
                return error;
 
        /* Put the block on the AGFL. */
+       error = xfs_alloc_read_agfl(sc->sa.pag, sc->tp, &agfl_bp);
+       if (error)
+               return error;
+
        error = xfs_alloc_put_freelist(sc->sa.pag, sc->tp, sc->sa.agf_bp,
-                       sc->sa.agfl_bp, agbno, 0);
+                       agfl_bp, agbno, 0);
        if (error)
                return error;
        xfs_extent_busy_insert(sc->tp, sc->sa.pag, agbno, 1,
index 3de5287e98d84cc1743b1ecef978289de418e4ce..151567f88366588a870612a5df90a6ccffd436d7 100644 (file)
@@ -39,7 +39,6 @@ struct xchk_ag {
 
        /* AG btree roots */
        struct xfs_buf          *agf_bp;
-       struct xfs_buf          *agfl_bp;
        struct xfs_buf          *agi_bp;
 
        /* AG btrees */