On Thu, 2023-01-19 at 09:44 +1100, Dave Chinner wrote: > From: Dave Chinner <dchinner@xxxxxxxxxx> > > In several places we iterate every AG from a specific start agno and > wrap back to the first AG when we reach the end of the filesystem to > continue searching. We don't have a primitive for this iteration > yet, so add one for conversion of these algorithms to per-ag based > iteration. > > The filestream AG select code is a mess, and this initially makes it > worse. The per-ag selection needs to be driven completely into the > filestream code to clean this up and it will be done in a future > patch that makes the filestream allocator use active per-ag > references correctly. > > Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx> > --- > fs/xfs/libxfs/xfs_ag.h | 45 +++++++++++++++++++++- > fs/xfs/libxfs/xfs_bmap.c | 76 ++++++++++++++++++++++-------------- > -- > fs/xfs/libxfs/xfs_ialloc.c | 32 ++++++++-------- > 3 files changed, 104 insertions(+), 49 deletions(-) > > diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h > index 187d30d9bb13..8f43b91d4cf3 100644 > --- a/fs/xfs/libxfs/xfs_ag.h > +++ b/fs/xfs/libxfs/xfs_ag.h > @@ -237,7 +237,6 @@ xfs_perag_next( > #define for_each_perag_from(mp, agno, pag) \ > for_each_perag_range((mp), (agno), (mp)->m_sb.sb_agcount - 1, > (pag)) > > - > #define for_each_perag(mp, agno, pag) \ > (agno) = 0; \ > for_each_perag_from((mp), (agno), (pag)) > @@ -249,6 +248,50 @@ xfs_perag_next( > xfs_perag_rele(pag), \ > (pag) = xfs_perag_grab_tag((mp), (agno), (tag))) > > +static inline struct xfs_perag * > +xfs_perag_next_wrap( > + struct xfs_perag *pag, > + xfs_agnumber_t *agno, > + xfs_agnumber_t stop_agno, > + xfs_agnumber_t wrap_agno) > +{ > + struct xfs_mount *mp = pag->pag_mount; > + > + *agno = pag->pag_agno + 1; > + xfs_perag_rele(pag); > + while (*agno != stop_agno) { > + if (*agno >= wrap_agno) > + *agno = 0; > + if (*agno == stop_agno) > + break; > + > + pag = xfs_perag_grab(mp, *agno); > + if (pag) > + return pag; > + (*agno)++; > + } > + return NULL; > +} > + > +/* > + * Iterate all AGs from start_agno through wrap_agno, then 0 through > + * (start_agno - 1). > + */ > +#define for_each_perag_wrap_at(mp, start_agno, wrap_agno, agno, pag) > \ > + for ((agno) = (start_agno), (pag) = xfs_perag_grab((mp), > (agno)); \ > + (pag) != NULL; \ > + (pag) = xfs_perag_next_wrap((pag), &(agno), > (start_agno), \ > + (wrap_agno))) > + > +/* > + * Iterate all AGs from start_agno through to the end of the > filesystem, then 0 > + * through (start_agno - 1). > + */ > +#define for_each_perag_wrap(mp, start_agno, agno, pag) \ > + for_each_perag_wrap_at((mp), (start_agno), (mp)- > >m_sb.sb_agcount, \ > + (agno), (pag)) > + > + > struct aghdr_init_data { > /* per ag data */ > xfs_agblock_t agno; /* ag to init */ > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c > index 6aad0ea5e606..e5519abbfa0d 100644 > --- a/fs/xfs/libxfs/xfs_bmap.c > +++ b/fs/xfs/libxfs/xfs_bmap.c > @@ -3136,17 +3136,14 @@ xfs_bmap_adjacent( > > static int > xfs_bmap_longest_free_extent( > + struct xfs_perag *pag, > struct xfs_trans *tp, > - xfs_agnumber_t ag, > xfs_extlen_t *blen, > int *notinit) > { > - struct xfs_mount *mp = tp->t_mountp; > - struct xfs_perag *pag; > xfs_extlen_t longest; > int error = 0; > > - pag = xfs_perag_get(mp, ag); > if (!xfs_perag_initialised_agf(pag)) { > error = xfs_alloc_read_agf(pag, tp, > XFS_ALLOC_FLAG_TRYLOCK, > NULL); > @@ -3156,19 +3153,17 @@ xfs_bmap_longest_free_extent( > *notinit = 1; > error = 0; > } > - goto out; > + return error; > } > } > > longest = xfs_alloc_longest_free_extent(pag, > - xfs_alloc_min_freelist(mp, pag), > + xfs_alloc_min_freelist(pag- > >pag_mount, pag), > xfs_ag_resv_needed(pag, > XFS_AG_RESV_NONE)); > if (*blen < longest) > *blen = longest; > > -out: > - xfs_perag_put(pag); > - return error; > + return 0; > } > > static void > @@ -3206,9 +3201,10 @@ xfs_bmap_btalloc_select_lengths( > xfs_extlen_t *blen) > { > struct xfs_mount *mp = ap->ip->i_mount; > - xfs_agnumber_t ag, startag; > + struct xfs_perag *pag; > + xfs_agnumber_t agno, startag; > int notinit = 0; > - int error; > + int error = 0; > > args->type = XFS_ALLOCTYPE_START_BNO; > if (ap->tp->t_flags & XFS_TRANS_LOWMODE) { > @@ -3218,21 +3214,21 @@ xfs_bmap_btalloc_select_lengths( > } > > args->total = ap->total; > - startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno); > + startag = XFS_FSB_TO_AGNO(mp, args->fsbno); > if (startag == NULLAGNUMBER) > - startag = ag = 0; > + startag = 0; > > - while (*blen < args->maxlen) { > - error = xfs_bmap_longest_free_extent(args->tp, ag, > blen, > + *blen = 0; > + for_each_perag_wrap(mp, startag, agno, pag) { > + error = xfs_bmap_longest_free_extent(pag, args->tp, > blen, > ¬init); > if (error) > - return error; > - > - if (++ag == mp->m_sb.sb_agcount) > - ag = 0; > - if (ag == startag) > + break; > + if (*blen >= args->maxlen) > break; > } > + if (pag) > + xfs_perag_rele(pag); > > xfs_bmap_select_minlen(ap, args, blen, notinit); > return 0; Hmm, did you want to return error here? Since now we only break on error in the loop body above? Otherwise looks good. Allison > @@ -3245,7 +3241,8 @@ xfs_bmap_btalloc_filestreams( > xfs_extlen_t *blen) > { > struct xfs_mount *mp = ap->ip->i_mount; > - xfs_agnumber_t ag; > + struct xfs_perag *pag; > + xfs_agnumber_t start_agno; > int notinit = 0; > int error; > > @@ -3259,33 +3256,50 @@ xfs_bmap_btalloc_filestreams( > args->type = XFS_ALLOCTYPE_NEAR_BNO; > args->total = ap->total; > > - ag = XFS_FSB_TO_AGNO(mp, args->fsbno); > - if (ag == NULLAGNUMBER) > - ag = 0; > + start_agno = XFS_FSB_TO_AGNO(mp, args->fsbno); > + if (start_agno == NULLAGNUMBER) > + start_agno = 0; > > - error = xfs_bmap_longest_free_extent(args->tp, ag, blen, > ¬init); > - if (error) > - return error; > + pag = xfs_perag_grab(mp, start_agno); > + if (pag) { > + error = xfs_bmap_longest_free_extent(pag, args->tp, > blen, > + ¬init); > + xfs_perag_rele(pag); > + if (error) > + return error; > + } > > if (*blen < args->maxlen) { > - error = xfs_filestream_new_ag(ap, &ag); > + xfs_agnumber_t agno = start_agno; > + > + error = xfs_filestream_new_ag(ap, &agno); > if (error) > return error; > + if (agno == NULLAGNUMBER) > + goto out_select; > > - error = xfs_bmap_longest_free_extent(args->tp, ag, > blen, > - ¬init); > + pag = xfs_perag_grab(mp, agno); > + if (!pag) > + goto out_select; > + > + error = xfs_bmap_longest_free_extent(pag, args->tp, > + blen, ¬init); > + xfs_perag_rele(pag); > if (error) > return error; > > + start_agno = agno; > + > } > > +out_select: > xfs_bmap_select_minlen(ap, args, blen, notinit); > > /* > * Set the failure fallback case to look in the selected AG > as stream > * may have moved. > */ > - ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0); > + ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, start_agno, 0); > return 0; > } > > diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c > index 2a323ffa5ba9..50fef3f5af51 100644 > --- a/fs/xfs/libxfs/xfs_ialloc.c > +++ b/fs/xfs/libxfs/xfs_ialloc.c > @@ -1725,7 +1725,7 @@ xfs_dialloc( > bool ok_alloc = true; > bool low_space = false; > int flags; > - xfs_ino_t ino; > + xfs_ino_t ino = NULLFSINO; > > /* > * Directories, symlinks, and regular files frequently > allocate at least > @@ -1773,39 +1773,37 @@ xfs_dialloc( > * or in which we can allocate some inodes. Iterate through > the > * allocation groups upward, wrapping at the end. > */ > - agno = start_agno; > flags = XFS_ALLOC_FLAG_TRYLOCK; > - for (;;) { > - pag = xfs_perag_grab(mp, agno); > +retry: > + for_each_perag_wrap_at(mp, start_agno, mp->m_maxagi, agno, > pag) { > if (xfs_dialloc_good_ag(pag, *tpp, mode, flags, > ok_alloc)) { > error = xfs_dialloc_try_ag(pag, tpp, parent, > &ino, ok_alloc); > if (error != -EAGAIN) > break; > + error = 0; > } > > if (xfs_is_shutdown(mp)) { > error = -EFSCORRUPTED; > break; > } > - if (++agno == mp->m_maxagi) > - agno = 0; > - if (agno == start_agno) { > - if (!flags) { > - error = -ENOSPC; > - break; > - } > + } > + if (pag) > + xfs_perag_rele(pag); > + if (error) > + return error; > + if (ino == NULLFSINO) { > + if (flags) { > flags = 0; > if (low_space) > ok_alloc = true; > + goto retry; > } > - xfs_perag_rele(pag); > + return -ENOSPC; > } > - > - if (!error) > - *new_ino = ino; > - xfs_perag_rele(pag); > - return error; > + *new_ino = ino; > + return 0; > } > > /*