]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: introduce xfs_for_each_perag_wrap()
authorDave Chinner <dchinner@redhat.com>
Tue, 9 May 2023 09:29:50 +0000 (11:29 +0200)
committerCarlos Maiolino <cem@kernel.org>
Wed, 10 May 2023 08:21:00 +0000 (10:21 +0200)
Source kernel commit: 76257a15873ccce817e0c4441f6bb66fb8f8201c

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@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
libxfs/xfs_ag.h
libxfs/xfs_bmap.c
libxfs/xfs_ialloc.c

index 187d30d9bb13956b141fc1d27442fe817d978a41..8f43b91d4cf3533d7c00b8b9816969d84de78ff9 100644 (file)
@@ -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 */
index badc15054fddf0729d220af005c078ddc42ae395..89948e4e2177aa1c7d8e1773b2356dc678879533 100644 (file)
@@ -3129,17 +3129,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);
@@ -3149,19 +3146,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
@@ -3199,9 +3194,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) {
@@ -3211,24 +3207,24 @@ 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,
                                                     &notinit);
                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;
+       return error;
 }
 
 STATIC int
@@ -3238,7 +3234,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;
 
@@ -3252,33 +3249,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, &notinit);
-       if (error)
-               return error;
+       pag = xfs_perag_grab(mp, start_agno);
+       if (pag) {
+               error = xfs_bmap_longest_free_extent(pag, args->tp, blen,
+                               &notinit);
+               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,
-                                                    &notinit);
+               pag = xfs_perag_grab(mp, agno);
+               if (!pag)
+                       goto out_select;
+
+               error = xfs_bmap_longest_free_extent(pag, args->tp,
+                               blen, &notinit);
+               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;
 }
 
index 73add3b381e19304f7e874fc1bc24077fe2a3883..043bf2689851da1f524ad06630d9770242f35a1b 100644 (file)
@@ -1720,7 +1720,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
@@ -1768,39 +1768,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;
 }
 
 /*