Message ID | 20230118224505.1964941-14-david@fromorbit.com (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | xfs: per-ag centric allocation alogrithms | expand |
On Thu, 2023-01-19 at 09:44 +1100, Dave Chinner wrote: > From: Dave Chinner <dchinner@redhat.com> > > We currently don't have any flags or operational state in the > xfs_perag except for the pagf_init and pagi_init flags. And the > agflreset flag. Oh, there's also the pagf_metadata and pagi_inodeok > flags, too. > > For controlling per-ag operations, we are going to need some atomic > state flags. Hence add an opstate field similar to what we already > have in the mount and log, and convert all these state flags across > to atomic bit operations. > > Signed-off-by: Dave Chinner <dchinner@redhat.com> Seems like a reasonable conversion Reviewed-by: Allison Henderson <allison.henderson@oracle.com> > --- > fs/xfs/libxfs/xfs_ag.h | 27 ++++++++++++++---- > fs/xfs/libxfs/xfs_alloc.c | 23 ++++++++------- > fs/xfs/libxfs/xfs_alloc_btree.c | 2 +- > fs/xfs/libxfs/xfs_bmap.c | 2 +- > fs/xfs/libxfs/xfs_ialloc.c | 14 ++++----- > fs/xfs/libxfs/xfs_ialloc_btree.c | 4 +-- > fs/xfs/libxfs/xfs_refcount_btree.c | 2 +- > fs/xfs/libxfs/xfs_rmap_btree.c | 2 +- > fs/xfs/scrub/agheader_repair.c | 28 +++++++++--------- > fs/xfs/scrub/fscounters.c | 9 ++++-- > fs/xfs/scrub/repair.c | 2 +- > fs/xfs/xfs_filestream.c | 5 ++-- > fs/xfs/xfs_super.c | 46 ++++++++++++++++++---------- > -- > 13 files changed, 101 insertions(+), 65 deletions(-) > > diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h > index aeb21c8df201..187d30d9bb13 100644 > --- a/fs/xfs/libxfs/xfs_ag.h > +++ b/fs/xfs/libxfs/xfs_ag.h > @@ -35,13 +35,9 @@ struct xfs_perag { > atomic_t pag_ref; /* passive reference count */ > atomic_t pag_active_ref; /* active reference count */ > wait_queue_head_t pag_active_wq;/* woken active_ref falls to > zero */ > - char pagf_init; /* this agf's entry is > initialized */ > - char pagi_init; /* this agi's entry is > initialized */ > - char pagf_metadata; /* the agf is preferred to be > metadata */ > - char pagi_inodeok; /* The agi is ok for inodes > */ > + unsigned long pag_opstate; > uint8_t pagf_levels[XFS_BTNUM_AGF]; > /* # of levels in bno & cnt > btree */ > - bool pagf_agflreset; /* agfl requires reset before > use */ > uint32_t pagf_flcount; /* count of blocks in > freelist */ > xfs_extlen_t pagf_freeblks; /* total free blocks */ > xfs_extlen_t pagf_longest; /* longest free space */ > @@ -108,6 +104,27 @@ struct xfs_perag { > #endif /* __KERNEL__ */ > }; > > +/* > + * Per-AG operational state. These are atomic flag bits. > + */ > +#define XFS_AGSTATE_AGF_INIT 0 > +#define XFS_AGSTATE_AGI_INIT 1 > +#define XFS_AGSTATE_PREFERS_METADATA 2 > +#define XFS_AGSTATE_ALLOWS_INODES 3 > +#define XFS_AGSTATE_AGFL_NEEDS_RESET 4 > + > +#define __XFS_AG_OPSTATE(name, NAME) \ > +static inline bool xfs_perag_ ## name (struct xfs_perag *pag) \ > +{ \ > + return test_bit(XFS_AGSTATE_ ## NAME, &pag->pag_opstate); \ > +} > + > +__XFS_AG_OPSTATE(initialised_agf, AGF_INIT) > +__XFS_AG_OPSTATE(initialised_agi, AGI_INIT) > +__XFS_AG_OPSTATE(prefers_metadata, PREFERS_METADATA) > +__XFS_AG_OPSTATE(allows_inodes, ALLOWS_INODES) > +__XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET) > + > int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t > agcount, > xfs_rfsblock_t dcount, xfs_agnumber_t > *maxagi); > int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t > agno); > diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c > index 9f26a9368eeb..246c2e7d9e7a 100644 > --- a/fs/xfs/libxfs/xfs_alloc.c > +++ b/fs/xfs/libxfs/xfs_alloc.c > @@ -2435,7 +2435,7 @@ xfs_agfl_reset( > struct xfs_mount *mp = tp->t_mountp; > struct xfs_agf *agf = agbp->b_addr; > > - ASSERT(pag->pagf_agflreset); > + ASSERT(xfs_perag_agfl_needs_reset(pag)); > trace_xfs_agfl_reset(mp, agf, 0, _RET_IP_); > > xfs_warn(mp, > @@ -2450,7 +2450,7 @@ xfs_agfl_reset( > XFS_AGF_FLCOUNT); > > pag->pagf_flcount = 0; > - pag->pagf_agflreset = false; > + clear_bit(XFS_AGSTATE_AGFL_NEEDS_RESET, &pag->pag_opstate); > } > > /* > @@ -2605,7 +2605,7 @@ xfs_alloc_fix_freelist( > /* deferred ops (AGFL block frees) require permanent > transactions */ > ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); > > - if (!pag->pagf_init) { > + if (!xfs_perag_initialised_agf(pag)) { > error = xfs_alloc_read_agf(pag, tp, flags, &agbp); > if (error) { > /* Couldn't lock the AGF so skip this AG. */ > @@ -2620,7 +2620,8 @@ xfs_alloc_fix_freelist( > * somewhere else if we are not being asked to try harder at > this > * point > */ > - if (pag->pagf_metadata && (args->datatype & > XFS_ALLOC_USERDATA) && > + if (xfs_perag_prefers_metadata(pag) && > + (args->datatype & XFS_ALLOC_USERDATA) && > (flags & XFS_ALLOC_FLAG_TRYLOCK)) { > ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); > goto out_agbp_relse; > @@ -2646,7 +2647,7 @@ xfs_alloc_fix_freelist( > } > > /* reset a padding mismatched agfl before final free space > check */ > - if (pag->pagf_agflreset) > + if (xfs_perag_agfl_needs_reset(pag)) > xfs_agfl_reset(tp, agbp, pag); > > /* If there isn't enough total space or single-extent, reject > it. */ > @@ -2803,7 +2804,7 @@ xfs_alloc_get_freelist( > if (be32_to_cpu(agf->agf_flfirst) == xfs_agfl_size(mp)) > agf->agf_flfirst = 0; > > - ASSERT(!pag->pagf_agflreset); > + ASSERT(!xfs_perag_agfl_needs_reset(pag)); > be32_add_cpu(&agf->agf_flcount, -1); > pag->pagf_flcount--; > > @@ -2892,7 +2893,7 @@ xfs_alloc_put_freelist( > if (be32_to_cpu(agf->agf_fllast) == xfs_agfl_size(mp)) > agf->agf_fllast = 0; > > - ASSERT(!pag->pagf_agflreset); > + ASSERT(!xfs_perag_agfl_needs_reset(pag)); > be32_add_cpu(&agf->agf_flcount, 1); > pag->pagf_flcount++; > > @@ -3099,7 +3100,7 @@ xfs_alloc_read_agf( > return error; > > agf = agfbp->b_addr; > - if (!pag->pagf_init) { > + if (!xfs_perag_initialised_agf(pag)) { > pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks); > pag->pagf_btreeblks = be32_to_cpu(agf- > >agf_btreeblks); > pag->pagf_flcount = be32_to_cpu(agf->agf_flcount); > @@ -3111,8 +3112,8 @@ xfs_alloc_read_agf( > pag->pagf_levels[XFS_BTNUM_RMAPi] = > be32_to_cpu(agf- > >agf_levels[XFS_BTNUM_RMAPi]); > pag->pagf_refcount_level = be32_to_cpu(agf- > >agf_refcount_level); > - pag->pagf_init = 1; > - pag->pagf_agflreset = xfs_agfl_needs_reset(pag- > >pag_mount, agf); > + if (xfs_agfl_needs_reset(pag->pag_mount, agf)) > + set_bit(XFS_AGSTATE_AGFL_NEEDS_RESET, &pag- > >pag_opstate); > > /* > * Update the in-core allocbt counter. Filter out the > rmapbt > @@ -3127,6 +3128,8 @@ xfs_alloc_read_agf( > if (allocbt_blks > 0) > atomic64_add(allocbt_blks, > &pag->pag_mount- > >m_allocbt_blks); > + > + set_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate); > } > #ifdef DEBUG > else if (!xfs_is_shutdown(pag->pag_mount)) { > diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c > b/fs/xfs/libxfs/xfs_alloc_btree.c > index 549a3cba0234..0f29c7b1b39f 100644 > --- a/fs/xfs/libxfs/xfs_alloc_btree.c > +++ b/fs/xfs/libxfs/xfs_alloc_btree.c > @@ -315,7 +315,7 @@ xfs_allocbt_verify( > level = be16_to_cpu(block->bb_level); > if (bp->b_ops->magic[0] == cpu_to_be32(XFS_ABTC_MAGIC)) > btnum = XFS_BTNUM_CNTi; > - if (pag && pag->pagf_init) { > + if (pag && xfs_perag_initialised_agf(pag)) { > if (level >= pag->pagf_levels[btnum]) > return __this_address; > } else if (level >= mp->m_alloc_maxlevels) > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c > index f15d45af661f..6aad0ea5e606 100644 > --- a/fs/xfs/libxfs/xfs_bmap.c > +++ b/fs/xfs/libxfs/xfs_bmap.c > @@ -3147,7 +3147,7 @@ xfs_bmap_longest_free_extent( > int error = 0; > > pag = xfs_perag_get(mp, ag); > - if (!pag->pagf_init) { > + if (!xfs_perag_initialised_agf(pag)) { > error = xfs_alloc_read_agf(pag, tp, > XFS_ALLOC_FLAG_TRYLOCK, > NULL); > if (error) { > diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c > index c8d837d8876f..2a323ffa5ba9 100644 > --- a/fs/xfs/libxfs/xfs_ialloc.c > +++ b/fs/xfs/libxfs/xfs_ialloc.c > @@ -998,8 +998,8 @@ xfs_dialloc_ag_inobt( > int i, j; > int searchdistance = 10; > > - ASSERT(pag->pagi_init); > - ASSERT(pag->pagi_inodeok); > + ASSERT(xfs_perag_initialised_agi(pag)); > + ASSERT(xfs_perag_allows_inodes(pag)); > ASSERT(pag->pagi_freecount > 0); > > restart_pagno: > @@ -1592,10 +1592,10 @@ xfs_dialloc_good_ag( > > if (!pag) > return false; > - if (!pag->pagi_inodeok) > + if (!xfs_perag_allows_inodes(pag)) > return false; > > - if (!pag->pagi_init) { > + if (!xfs_perag_initialised_agi(pag)) { > error = xfs_ialloc_read_agi(pag, tp, NULL); > if (error) > return false; > @@ -1606,7 +1606,7 @@ xfs_dialloc_good_ag( > if (!ok_alloc) > return false; > > - if (!pag->pagf_init) { > + if (!xfs_perag_initialised_agf(pag)) { > error = xfs_alloc_read_agf(pag, tp, flags, NULL); > if (error) > return false; > @@ -2603,10 +2603,10 @@ xfs_ialloc_read_agi( > return error; > > agi = agibp->b_addr; > - if (!pag->pagi_init) { > + if (!xfs_perag_initialised_agi(pag)) { > pag->pagi_freecount = be32_to_cpu(agi- > >agi_freecount); > pag->pagi_count = be32_to_cpu(agi->agi_count); > - pag->pagi_init = 1; > + set_bit(XFS_AGSTATE_AGI_INIT, &pag->pag_opstate); > } > > /* > diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c > b/fs/xfs/libxfs/xfs_ialloc_btree.c > index d657af2ec350..3675a0d29310 100644 > --- a/fs/xfs/libxfs/xfs_ialloc_btree.c > +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c > @@ -291,8 +291,8 @@ xfs_inobt_verify( > * Similarly, during log recovery we will have a perag > structure > * attached, but the agi information will not yet have been > initialised > * from the on disk AGI. We don't currently use any of this > information, > - * but beware of the landmine (i.e. need to check pag- > >pagi_init) if we > - * ever do. > + * but beware of the landmine (i.e. need to check > + * xfs_perag_initialised_agi(pag)) if we ever do. > */ > if (xfs_has_crc(mp)) { > fa = xfs_btree_sblock_v5hdr_verify(bp); > diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c > b/fs/xfs/libxfs/xfs_refcount_btree.c > index e1f789866683..d20abf0390fc 100644 > --- a/fs/xfs/libxfs/xfs_refcount_btree.c > +++ b/fs/xfs/libxfs/xfs_refcount_btree.c > @@ -227,7 +227,7 @@ xfs_refcountbt_verify( > return fa; > > level = be16_to_cpu(block->bb_level); > - if (pag && pag->pagf_init) { > + if (pag && xfs_perag_initialised_agf(pag)) { > if (level >= pag->pagf_refcount_level) > return __this_address; > } else if (level >= mp->m_refc_maxlevels) > diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c > b/fs/xfs/libxfs/xfs_rmap_btree.c > index 7f83f62e51e0..d3285684bb5e 100644 > --- a/fs/xfs/libxfs/xfs_rmap_btree.c > +++ b/fs/xfs/libxfs/xfs_rmap_btree.c > @@ -313,7 +313,7 @@ xfs_rmapbt_verify( > return fa; > > level = be16_to_cpu(block->bb_level); > - if (pag && pag->pagf_init) { > + if (pag && xfs_perag_initialised_agf(pag)) { > if (level >= pag->pagf_levels[XFS_BTNUM_RMAPi]) > return __this_address; > } else if (level >= mp->m_rmap_maxlevels) > diff --git a/fs/xfs/scrub/agheader_repair.c > b/fs/xfs/scrub/agheader_repair.c > index b80b9111e781..c37e6d72760b 100644 > --- a/fs/xfs/scrub/agheader_repair.c > +++ b/fs/xfs/scrub/agheader_repair.c > @@ -191,14 +191,15 @@ xrep_agf_init_header( > struct xfs_agf *old_agf) > { > struct xfs_mount *mp = sc->mp; > + struct xfs_perag *pag = sc->sa.pag; > struct xfs_agf *agf = agf_bp->b_addr; > > memcpy(old_agf, agf, sizeof(*old_agf)); > memset(agf, 0, BBTOB(agf_bp->b_length)); > agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); > agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION); > - agf->agf_seqno = cpu_to_be32(sc->sa.pag->pag_agno); > - agf->agf_length = cpu_to_be32(sc->sa.pag->block_count); > + agf->agf_seqno = cpu_to_be32(pag->pag_agno); > + agf->agf_length = cpu_to_be32(pag->block_count); > agf->agf_flfirst = old_agf->agf_flfirst; > agf->agf_fllast = old_agf->agf_fllast; > agf->agf_flcount = old_agf->agf_flcount; > @@ -206,8 +207,8 @@ xrep_agf_init_header( > uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); > > /* Mark the incore AGF data stale until we're done fixing > things. */ > - ASSERT(sc->sa.pag->pagf_init); > - sc->sa.pag->pagf_init = 0; > + ASSERT(xfs_perag_initialised_agf(pag)); > + clear_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate); > } > > /* Set btree root information in an AGF. */ > @@ -333,7 +334,7 @@ xrep_agf_commit_new( > pag->pagf_levels[XFS_BTNUM_RMAPi] = > be32_to_cpu(agf- > >agf_levels[XFS_BTNUM_RMAPi]); > pag->pagf_refcount_level = be32_to_cpu(agf- > >agf_refcount_level); > - pag->pagf_init = 1; > + set_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate); > > return 0; > } > @@ -434,7 +435,7 @@ xrep_agf( > > out_revert: > /* Mark the incore AGF state stale and revert the AGF. */ > - sc->sa.pag->pagf_init = 0; > + clear_bit(XFS_AGSTATE_AGF_INIT, &sc->sa.pag->pag_opstate); > memcpy(agf, &old_agf, sizeof(old_agf)); > return error; > } > @@ -618,7 +619,7 @@ xrep_agfl_update_agf( > xfs_force_summary_recalc(sc->mp); > > /* Update the AGF counters. */ > - if (sc->sa.pag->pagf_init) > + if (xfs_perag_initialised_agf(sc->sa.pag)) > sc->sa.pag->pagf_flcount = flcount; > agf->agf_flfirst = cpu_to_be32(0); > agf->agf_flcount = cpu_to_be32(flcount); > @@ -822,14 +823,15 @@ xrep_agi_init_header( > struct xfs_agi *old_agi) > { > struct xfs_agi *agi = agi_bp->b_addr; > + struct xfs_perag *pag = sc->sa.pag; > struct xfs_mount *mp = sc->mp; > > memcpy(old_agi, agi, sizeof(*old_agi)); > memset(agi, 0, BBTOB(agi_bp->b_length)); > agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); > agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); > - agi->agi_seqno = cpu_to_be32(sc->sa.pag->pag_agno); > - agi->agi_length = cpu_to_be32(sc->sa.pag->block_count); > + agi->agi_seqno = cpu_to_be32(pag->pag_agno); > + agi->agi_length = cpu_to_be32(pag->block_count); > agi->agi_newino = cpu_to_be32(NULLAGINO); > agi->agi_dirino = cpu_to_be32(NULLAGINO); > if (xfs_has_crc(mp)) > @@ -840,8 +842,8 @@ xrep_agi_init_header( > sizeof(agi->agi_unlinked)); > > /* Mark the incore AGF data stale until we're done fixing > things. */ > - ASSERT(sc->sa.pag->pagi_init); > - sc->sa.pag->pagi_init = 0; > + ASSERT(xfs_perag_initialised_agi(pag)); > + clear_bit(XFS_AGSTATE_AGI_INIT, &pag->pag_opstate); > } > > /* Set btree root information in an AGI. */ > @@ -928,7 +930,7 @@ xrep_agi_commit_new( > pag = sc->sa.pag; > pag->pagi_count = be32_to_cpu(agi->agi_count); > pag->pagi_freecount = be32_to_cpu(agi->agi_freecount); > - pag->pagi_init = 1; > + set_bit(XFS_AGSTATE_AGI_INIT, &pag->pag_opstate); > > return 0; > } > @@ -993,7 +995,7 @@ xrep_agi( > > out_revert: > /* Mark the incore AGI state stale and revert the AGI. */ > - sc->sa.pag->pagi_init = 0; > + clear_bit(XFS_AGSTATE_AGI_INIT, &sc->sa.pag->pag_opstate); > memcpy(agi, &old_agi, sizeof(old_agi)); > return error; > } > diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c > index ef97670970c3..f0c7f41897b9 100644 > --- a/fs/xfs/scrub/fscounters.c > +++ b/fs/xfs/scrub/fscounters.c > @@ -86,7 +86,8 @@ xchk_fscount_warmup( > for_each_perag(mp, agno, pag) { > if (xchk_should_terminate(sc, &error)) > break; > - if (pag->pagi_init && pag->pagf_init) > + if (xfs_perag_initialised_agi(pag) && > + xfs_perag_initialised_agf(pag)) > continue; > > /* Lock both AG headers. */ > @@ -101,7 +102,8 @@ xchk_fscount_warmup( > * These are supposed to be initialized by the header > read > * function. > */ > - if (!pag->pagi_init || !pag->pagf_init) { > + if (!xfs_perag_initialised_agi(pag) || > + !xfs_perag_initialised_agf(pag)) { > error = -EFSCORRUPTED; > break; > } > @@ -220,7 +222,8 @@ xchk_fscount_aggregate_agcounts( > break; > > /* This somehow got unset since the warmup? */ > - if (!pag->pagi_init || !pag->pagf_init) { > + if (!xfs_perag_initialised_agi(pag) || > + !xfs_perag_initialised_agf(pag)) { > error = -EFSCORRUPTED; > break; > } > diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c > index 4b92f9253ccd..d0b1644efb89 100644 > --- a/fs/xfs/scrub/repair.c > +++ b/fs/xfs/scrub/repair.c > @@ -206,7 +206,7 @@ xrep_calc_ag_resblks( > return 0; > > pag = xfs_perag_get(mp, sm->sm_agno); > - if (pag->pagi_init) { > + if (xfs_perag_initialised_agi(pag)) { > /* Use in-core icount if possible. */ > icount = pag->pagi_count; > } else { > diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c > index 34b21a29c39b..7e8b25ab6c46 100644 > --- a/fs/xfs/xfs_filestream.c > +++ b/fs/xfs/xfs_filestream.c > @@ -125,7 +125,7 @@ xfs_filestream_pick_ag( > > pag = xfs_perag_get(mp, ag); > > - if (!pag->pagf_init) { > + if (!xfs_perag_initialised_agf(pag)) { > err = xfs_alloc_read_agf(pag, NULL, trylock, > NULL); > if (err) { > if (err != -EAGAIN) { > @@ -159,7 +159,8 @@ xfs_filestream_pick_ag( > xfs_ag_resv_needed(pag, > XFS_AG_RESV_NONE)); > if (((minlen && longest >= minlen) || > (!minlen && pag->pagf_freeblks >= minfree)) && > - (!pag->pagf_metadata || !(flags & > XFS_PICK_USERDATA) || > + (!xfs_perag_prefers_metadata(pag) || > + !(flags & XFS_PICK_USERDATA) || > (flags & XFS_PICK_LOWSPACE))) { > > /* Break out, retaining the reference on the > AG. */ > diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c > index 96375b5622fd..2479b5cbd75e 100644 > --- a/fs/xfs/xfs_super.c > +++ b/fs/xfs/xfs_super.c > @@ -247,6 +247,32 @@ xfs_fs_show_options( > return 0; > } > > +static bool > +xfs_set_inode_alloc_perag( > + struct xfs_perag *pag, > + xfs_ino_t ino, > + xfs_agnumber_t max_metadata) > +{ > + if (!xfs_is_inode32(pag->pag_mount)) { > + set_bit(XFS_AGSTATE_ALLOWS_INODES, &pag- > >pag_opstate); > + clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag- > >pag_opstate); > + return false; > + } > + > + if (ino > XFS_MAXINUMBER_32) { > + clear_bit(XFS_AGSTATE_ALLOWS_INODES, &pag- > >pag_opstate); > + clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag- > >pag_opstate); > + return false; > + } > + > + set_bit(XFS_AGSTATE_ALLOWS_INODES, &pag->pag_opstate); > + if (pag->pag_agno < max_metadata) > + set_bit(XFS_AGSTATE_PREFERS_METADATA, &pag- > >pag_opstate); > + else > + clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag- > >pag_opstate); > + return true; > +} > + > /* > * Set parameters for inode allocation heuristics, taking into > account > * filesystem size and inode32/inode64 mount options; i.e. > specifically > @@ -310,24 +336,8 @@ xfs_set_inode_alloc( > ino = XFS_AGINO_TO_INO(mp, index, agino); > > pag = xfs_perag_get(mp, index); > - > - if (xfs_is_inode32(mp)) { > - if (ino > XFS_MAXINUMBER_32) { > - pag->pagi_inodeok = 0; > - pag->pagf_metadata = 0; > - } else { > - pag->pagi_inodeok = 1; > - maxagi++; > - if (index < max_metadata) > - pag->pagf_metadata = 1; > - else > - pag->pagf_metadata = 0; > - } > - } else { > - pag->pagi_inodeok = 1; > - pag->pagf_metadata = 0; > - } > - > + if (xfs_set_inode_alloc_perag(pag, ino, > max_metadata)) > + maxagi++; > xfs_perag_put(pag); > } >
diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h index aeb21c8df201..187d30d9bb13 100644 --- a/fs/xfs/libxfs/xfs_ag.h +++ b/fs/xfs/libxfs/xfs_ag.h @@ -35,13 +35,9 @@ struct xfs_perag { atomic_t pag_ref; /* passive reference count */ atomic_t pag_active_ref; /* active reference count */ wait_queue_head_t pag_active_wq;/* woken active_ref falls to zero */ - char pagf_init; /* this agf's entry is initialized */ - char pagi_init; /* this agi's entry is initialized */ - char pagf_metadata; /* the agf is preferred to be metadata */ - char pagi_inodeok; /* The agi is ok for inodes */ + unsigned long pag_opstate; uint8_t pagf_levels[XFS_BTNUM_AGF]; /* # of levels in bno & cnt btree */ - bool pagf_agflreset; /* agfl requires reset before use */ uint32_t pagf_flcount; /* count of blocks in freelist */ xfs_extlen_t pagf_freeblks; /* total free blocks */ xfs_extlen_t pagf_longest; /* longest free space */ @@ -108,6 +104,27 @@ struct xfs_perag { #endif /* __KERNEL__ */ }; +/* + * Per-AG operational state. These are atomic flag bits. + */ +#define XFS_AGSTATE_AGF_INIT 0 +#define XFS_AGSTATE_AGI_INIT 1 +#define XFS_AGSTATE_PREFERS_METADATA 2 +#define XFS_AGSTATE_ALLOWS_INODES 3 +#define XFS_AGSTATE_AGFL_NEEDS_RESET 4 + +#define __XFS_AG_OPSTATE(name, NAME) \ +static inline bool xfs_perag_ ## name (struct xfs_perag *pag) \ +{ \ + return test_bit(XFS_AGSTATE_ ## NAME, &pag->pag_opstate); \ +} + +__XFS_AG_OPSTATE(initialised_agf, AGF_INIT) +__XFS_AG_OPSTATE(initialised_agi, AGI_INIT) +__XFS_AG_OPSTATE(prefers_metadata, PREFERS_METADATA) +__XFS_AG_OPSTATE(allows_inodes, ALLOWS_INODES) +__XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET) + int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount, xfs_rfsblock_t dcount, xfs_agnumber_t *maxagi); int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno); diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index 9f26a9368eeb..246c2e7d9e7a 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -2435,7 +2435,7 @@ xfs_agfl_reset( struct xfs_mount *mp = tp->t_mountp; struct xfs_agf *agf = agbp->b_addr; - ASSERT(pag->pagf_agflreset); + ASSERT(xfs_perag_agfl_needs_reset(pag)); trace_xfs_agfl_reset(mp, agf, 0, _RET_IP_); xfs_warn(mp, @@ -2450,7 +2450,7 @@ xfs_agfl_reset( XFS_AGF_FLCOUNT); pag->pagf_flcount = 0; - pag->pagf_agflreset = false; + clear_bit(XFS_AGSTATE_AGFL_NEEDS_RESET, &pag->pag_opstate); } /* @@ -2605,7 +2605,7 @@ xfs_alloc_fix_freelist( /* deferred ops (AGFL block frees) require permanent transactions */ ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); - if (!pag->pagf_init) { + if (!xfs_perag_initialised_agf(pag)) { error = xfs_alloc_read_agf(pag, tp, flags, &agbp); if (error) { /* Couldn't lock the AGF so skip this AG. */ @@ -2620,7 +2620,8 @@ xfs_alloc_fix_freelist( * somewhere else if we are not being asked to try harder at this * point */ - if (pag->pagf_metadata && (args->datatype & XFS_ALLOC_USERDATA) && + if (xfs_perag_prefers_metadata(pag) && + (args->datatype & XFS_ALLOC_USERDATA) && (flags & XFS_ALLOC_FLAG_TRYLOCK)) { ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); goto out_agbp_relse; @@ -2646,7 +2647,7 @@ xfs_alloc_fix_freelist( } /* reset a padding mismatched agfl before final free space check */ - if (pag->pagf_agflreset) + if (xfs_perag_agfl_needs_reset(pag)) xfs_agfl_reset(tp, agbp, pag); /* If there isn't enough total space or single-extent, reject it. */ @@ -2803,7 +2804,7 @@ xfs_alloc_get_freelist( if (be32_to_cpu(agf->agf_flfirst) == xfs_agfl_size(mp)) agf->agf_flfirst = 0; - ASSERT(!pag->pagf_agflreset); + ASSERT(!xfs_perag_agfl_needs_reset(pag)); be32_add_cpu(&agf->agf_flcount, -1); pag->pagf_flcount--; @@ -2892,7 +2893,7 @@ xfs_alloc_put_freelist( if (be32_to_cpu(agf->agf_fllast) == xfs_agfl_size(mp)) agf->agf_fllast = 0; - ASSERT(!pag->pagf_agflreset); + ASSERT(!xfs_perag_agfl_needs_reset(pag)); be32_add_cpu(&agf->agf_flcount, 1); pag->pagf_flcount++; @@ -3099,7 +3100,7 @@ xfs_alloc_read_agf( return error; agf = agfbp->b_addr; - if (!pag->pagf_init) { + if (!xfs_perag_initialised_agf(pag)) { pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks); pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks); pag->pagf_flcount = be32_to_cpu(agf->agf_flcount); @@ -3111,8 +3112,8 @@ xfs_alloc_read_agf( pag->pagf_levels[XFS_BTNUM_RMAPi] = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAPi]); pag->pagf_refcount_level = be32_to_cpu(agf->agf_refcount_level); - pag->pagf_init = 1; - pag->pagf_agflreset = xfs_agfl_needs_reset(pag->pag_mount, agf); + if (xfs_agfl_needs_reset(pag->pag_mount, agf)) + set_bit(XFS_AGSTATE_AGFL_NEEDS_RESET, &pag->pag_opstate); /* * Update the in-core allocbt counter. Filter out the rmapbt @@ -3127,6 +3128,8 @@ xfs_alloc_read_agf( if (allocbt_blks > 0) atomic64_add(allocbt_blks, &pag->pag_mount->m_allocbt_blks); + + set_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate); } #ifdef DEBUG else if (!xfs_is_shutdown(pag->pag_mount)) { diff --git a/fs/xfs/libxfs/xfs_alloc_btree.c b/fs/xfs/libxfs/xfs_alloc_btree.c index 549a3cba0234..0f29c7b1b39f 100644 --- a/fs/xfs/libxfs/xfs_alloc_btree.c +++ b/fs/xfs/libxfs/xfs_alloc_btree.c @@ -315,7 +315,7 @@ xfs_allocbt_verify( level = be16_to_cpu(block->bb_level); if (bp->b_ops->magic[0] == cpu_to_be32(XFS_ABTC_MAGIC)) btnum = XFS_BTNUM_CNTi; - if (pag && pag->pagf_init) { + if (pag && xfs_perag_initialised_agf(pag)) { if (level >= pag->pagf_levels[btnum]) return __this_address; } else if (level >= mp->m_alloc_maxlevels) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index f15d45af661f..6aad0ea5e606 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -3147,7 +3147,7 @@ xfs_bmap_longest_free_extent( int error = 0; pag = xfs_perag_get(mp, ag); - if (!pag->pagf_init) { + if (!xfs_perag_initialised_agf(pag)) { error = xfs_alloc_read_agf(pag, tp, XFS_ALLOC_FLAG_TRYLOCK, NULL); if (error) { diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index c8d837d8876f..2a323ffa5ba9 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -998,8 +998,8 @@ xfs_dialloc_ag_inobt( int i, j; int searchdistance = 10; - ASSERT(pag->pagi_init); - ASSERT(pag->pagi_inodeok); + ASSERT(xfs_perag_initialised_agi(pag)); + ASSERT(xfs_perag_allows_inodes(pag)); ASSERT(pag->pagi_freecount > 0); restart_pagno: @@ -1592,10 +1592,10 @@ xfs_dialloc_good_ag( if (!pag) return false; - if (!pag->pagi_inodeok) + if (!xfs_perag_allows_inodes(pag)) return false; - if (!pag->pagi_init) { + if (!xfs_perag_initialised_agi(pag)) { error = xfs_ialloc_read_agi(pag, tp, NULL); if (error) return false; @@ -1606,7 +1606,7 @@ xfs_dialloc_good_ag( if (!ok_alloc) return false; - if (!pag->pagf_init) { + if (!xfs_perag_initialised_agf(pag)) { error = xfs_alloc_read_agf(pag, tp, flags, NULL); if (error) return false; @@ -2603,10 +2603,10 @@ xfs_ialloc_read_agi( return error; agi = agibp->b_addr; - if (!pag->pagi_init) { + if (!xfs_perag_initialised_agi(pag)) { pag->pagi_freecount = be32_to_cpu(agi->agi_freecount); pag->pagi_count = be32_to_cpu(agi->agi_count); - pag->pagi_init = 1; + set_bit(XFS_AGSTATE_AGI_INIT, &pag->pag_opstate); } /* diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c index d657af2ec350..3675a0d29310 100644 --- a/fs/xfs/libxfs/xfs_ialloc_btree.c +++ b/fs/xfs/libxfs/xfs_ialloc_btree.c @@ -291,8 +291,8 @@ xfs_inobt_verify( * Similarly, during log recovery we will have a perag structure * attached, but the agi information will not yet have been initialised * from the on disk AGI. We don't currently use any of this information, - * but beware of the landmine (i.e. need to check pag->pagi_init) if we - * ever do. + * but beware of the landmine (i.e. need to check + * xfs_perag_initialised_agi(pag)) if we ever do. */ if (xfs_has_crc(mp)) { fa = xfs_btree_sblock_v5hdr_verify(bp); diff --git a/fs/xfs/libxfs/xfs_refcount_btree.c b/fs/xfs/libxfs/xfs_refcount_btree.c index e1f789866683..d20abf0390fc 100644 --- a/fs/xfs/libxfs/xfs_refcount_btree.c +++ b/fs/xfs/libxfs/xfs_refcount_btree.c @@ -227,7 +227,7 @@ xfs_refcountbt_verify( return fa; level = be16_to_cpu(block->bb_level); - if (pag && pag->pagf_init) { + if (pag && xfs_perag_initialised_agf(pag)) { if (level >= pag->pagf_refcount_level) return __this_address; } else if (level >= mp->m_refc_maxlevels) diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c index 7f83f62e51e0..d3285684bb5e 100644 --- a/fs/xfs/libxfs/xfs_rmap_btree.c +++ b/fs/xfs/libxfs/xfs_rmap_btree.c @@ -313,7 +313,7 @@ xfs_rmapbt_verify( return fa; level = be16_to_cpu(block->bb_level); - if (pag && pag->pagf_init) { + if (pag && xfs_perag_initialised_agf(pag)) { if (level >= pag->pagf_levels[XFS_BTNUM_RMAPi]) return __this_address; } else if (level >= mp->m_rmap_maxlevels) diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c index b80b9111e781..c37e6d72760b 100644 --- a/fs/xfs/scrub/agheader_repair.c +++ b/fs/xfs/scrub/agheader_repair.c @@ -191,14 +191,15 @@ xrep_agf_init_header( struct xfs_agf *old_agf) { struct xfs_mount *mp = sc->mp; + struct xfs_perag *pag = sc->sa.pag; struct xfs_agf *agf = agf_bp->b_addr; memcpy(old_agf, agf, sizeof(*old_agf)); memset(agf, 0, BBTOB(agf_bp->b_length)); agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION); - agf->agf_seqno = cpu_to_be32(sc->sa.pag->pag_agno); - agf->agf_length = cpu_to_be32(sc->sa.pag->block_count); + agf->agf_seqno = cpu_to_be32(pag->pag_agno); + agf->agf_length = cpu_to_be32(pag->block_count); agf->agf_flfirst = old_agf->agf_flfirst; agf->agf_fllast = old_agf->agf_fllast; agf->agf_flcount = old_agf->agf_flcount; @@ -206,8 +207,8 @@ xrep_agf_init_header( uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); /* Mark the incore AGF data stale until we're done fixing things. */ - ASSERT(sc->sa.pag->pagf_init); - sc->sa.pag->pagf_init = 0; + ASSERT(xfs_perag_initialised_agf(pag)); + clear_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate); } /* Set btree root information in an AGF. */ @@ -333,7 +334,7 @@ xrep_agf_commit_new( pag->pagf_levels[XFS_BTNUM_RMAPi] = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAPi]); pag->pagf_refcount_level = be32_to_cpu(agf->agf_refcount_level); - pag->pagf_init = 1; + set_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate); return 0; } @@ -434,7 +435,7 @@ xrep_agf( out_revert: /* Mark the incore AGF state stale and revert the AGF. */ - sc->sa.pag->pagf_init = 0; + clear_bit(XFS_AGSTATE_AGF_INIT, &sc->sa.pag->pag_opstate); memcpy(agf, &old_agf, sizeof(old_agf)); return error; } @@ -618,7 +619,7 @@ xrep_agfl_update_agf( xfs_force_summary_recalc(sc->mp); /* Update the AGF counters. */ - if (sc->sa.pag->pagf_init) + if (xfs_perag_initialised_agf(sc->sa.pag)) sc->sa.pag->pagf_flcount = flcount; agf->agf_flfirst = cpu_to_be32(0); agf->agf_flcount = cpu_to_be32(flcount); @@ -822,14 +823,15 @@ xrep_agi_init_header( struct xfs_agi *old_agi) { struct xfs_agi *agi = agi_bp->b_addr; + struct xfs_perag *pag = sc->sa.pag; struct xfs_mount *mp = sc->mp; memcpy(old_agi, agi, sizeof(*old_agi)); memset(agi, 0, BBTOB(agi_bp->b_length)); agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); - agi->agi_seqno = cpu_to_be32(sc->sa.pag->pag_agno); - agi->agi_length = cpu_to_be32(sc->sa.pag->block_count); + agi->agi_seqno = cpu_to_be32(pag->pag_agno); + agi->agi_length = cpu_to_be32(pag->block_count); agi->agi_newino = cpu_to_be32(NULLAGINO); agi->agi_dirino = cpu_to_be32(NULLAGINO); if (xfs_has_crc(mp)) @@ -840,8 +842,8 @@ xrep_agi_init_header( sizeof(agi->agi_unlinked)); /* Mark the incore AGF data stale until we're done fixing things. */ - ASSERT(sc->sa.pag->pagi_init); - sc->sa.pag->pagi_init = 0; + ASSERT(xfs_perag_initialised_agi(pag)); + clear_bit(XFS_AGSTATE_AGI_INIT, &pag->pag_opstate); } /* Set btree root information in an AGI. */ @@ -928,7 +930,7 @@ xrep_agi_commit_new( pag = sc->sa.pag; pag->pagi_count = be32_to_cpu(agi->agi_count); pag->pagi_freecount = be32_to_cpu(agi->agi_freecount); - pag->pagi_init = 1; + set_bit(XFS_AGSTATE_AGI_INIT, &pag->pag_opstate); return 0; } @@ -993,7 +995,7 @@ xrep_agi( out_revert: /* Mark the incore AGI state stale and revert the AGI. */ - sc->sa.pag->pagi_init = 0; + clear_bit(XFS_AGSTATE_AGI_INIT, &sc->sa.pag->pag_opstate); memcpy(agi, &old_agi, sizeof(old_agi)); return error; } diff --git a/fs/xfs/scrub/fscounters.c b/fs/xfs/scrub/fscounters.c index ef97670970c3..f0c7f41897b9 100644 --- a/fs/xfs/scrub/fscounters.c +++ b/fs/xfs/scrub/fscounters.c @@ -86,7 +86,8 @@ xchk_fscount_warmup( for_each_perag(mp, agno, pag) { if (xchk_should_terminate(sc, &error)) break; - if (pag->pagi_init && pag->pagf_init) + if (xfs_perag_initialised_agi(pag) && + xfs_perag_initialised_agf(pag)) continue; /* Lock both AG headers. */ @@ -101,7 +102,8 @@ xchk_fscount_warmup( * These are supposed to be initialized by the header read * function. */ - if (!pag->pagi_init || !pag->pagf_init) { + if (!xfs_perag_initialised_agi(pag) || + !xfs_perag_initialised_agf(pag)) { error = -EFSCORRUPTED; break; } @@ -220,7 +222,8 @@ xchk_fscount_aggregate_agcounts( break; /* This somehow got unset since the warmup? */ - if (!pag->pagi_init || !pag->pagf_init) { + if (!xfs_perag_initialised_agi(pag) || + !xfs_perag_initialised_agf(pag)) { error = -EFSCORRUPTED; break; } diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c index 4b92f9253ccd..d0b1644efb89 100644 --- a/fs/xfs/scrub/repair.c +++ b/fs/xfs/scrub/repair.c @@ -206,7 +206,7 @@ xrep_calc_ag_resblks( return 0; pag = xfs_perag_get(mp, sm->sm_agno); - if (pag->pagi_init) { + if (xfs_perag_initialised_agi(pag)) { /* Use in-core icount if possible. */ icount = pag->pagi_count; } else { diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c index 34b21a29c39b..7e8b25ab6c46 100644 --- a/fs/xfs/xfs_filestream.c +++ b/fs/xfs/xfs_filestream.c @@ -125,7 +125,7 @@ xfs_filestream_pick_ag( pag = xfs_perag_get(mp, ag); - if (!pag->pagf_init) { + if (!xfs_perag_initialised_agf(pag)) { err = xfs_alloc_read_agf(pag, NULL, trylock, NULL); if (err) { if (err != -EAGAIN) { @@ -159,7 +159,8 @@ xfs_filestream_pick_ag( xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE)); if (((minlen && longest >= minlen) || (!minlen && pag->pagf_freeblks >= minfree)) && - (!pag->pagf_metadata || !(flags & XFS_PICK_USERDATA) || + (!xfs_perag_prefers_metadata(pag) || + !(flags & XFS_PICK_USERDATA) || (flags & XFS_PICK_LOWSPACE))) { /* Break out, retaining the reference on the AG. */ diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 96375b5622fd..2479b5cbd75e 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -247,6 +247,32 @@ xfs_fs_show_options( return 0; } +static bool +xfs_set_inode_alloc_perag( + struct xfs_perag *pag, + xfs_ino_t ino, + xfs_agnumber_t max_metadata) +{ + if (!xfs_is_inode32(pag->pag_mount)) { + set_bit(XFS_AGSTATE_ALLOWS_INODES, &pag->pag_opstate); + clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate); + return false; + } + + if (ino > XFS_MAXINUMBER_32) { + clear_bit(XFS_AGSTATE_ALLOWS_INODES, &pag->pag_opstate); + clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate); + return false; + } + + set_bit(XFS_AGSTATE_ALLOWS_INODES, &pag->pag_opstate); + if (pag->pag_agno < max_metadata) + set_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate); + else + clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate); + return true; +} + /* * Set parameters for inode allocation heuristics, taking into account * filesystem size and inode32/inode64 mount options; i.e. specifically @@ -310,24 +336,8 @@ xfs_set_inode_alloc( ino = XFS_AGINO_TO_INO(mp, index, agino); pag = xfs_perag_get(mp, index); - - if (xfs_is_inode32(mp)) { - if (ino > XFS_MAXINUMBER_32) { - pag->pagi_inodeok = 0; - pag->pagf_metadata = 0; - } else { - pag->pagi_inodeok = 1; - maxagi++; - if (index < max_metadata) - pag->pagf_metadata = 1; - else - pag->pagf_metadata = 0; - } - } else { - pag->pagi_inodeok = 1; - pag->pagf_metadata = 0; - } - + if (xfs_set_inode_alloc_perag(pag, ino, max_metadata)) + maxagi++; xfs_perag_put(pag); }