xfs: xfs_alloc_fix_freelist() can use incore perag structures
authorDave Chinner <dchinner@redhat.com>
Mon, 22 Jun 2015 00:04:31 +0000 (10:04 +1000)
committerDave Chinner <david@fromorbit.com>
Mon, 22 Jun 2015 00:04:31 +0000 (10:04 +1000)
At the moment, xfs_alloc_fix_freelist() uses a mix of per-ag based
access and agf buffer  based access to freelist and space usage
information. However, once the AGF buffer is locked inside this
function, it is guaranteed that both the in-memory and on-disk
values are identical. xfs_alloc_fix_freelist() doesn't modify the
values in the structures directly, so it is a read-only user of the
infomration, and hence can use the per-ag structure exclusively for
determining what it should do.

This opens up an avenue for cleaning up a lot of duplicated logic
whose only difference is the structure it gets the data from, and in
doing so removes a lot of needless byte swapping overhead when
fixing up the free list.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_alloc.h
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/xfs_filestream.c

index 516162be1398404a18e32909f8ff25c065364605..9b3e3681dfa9b196bb29c56707c19f9e2e41f98c 100644 (file)
@@ -1825,11 +1825,11 @@ xfs_alloc_compute_maxlevels(
 xfs_extlen_t
 xfs_alloc_longest_free_extent(
        struct xfs_mount        *mp,
-       struct xfs_perag        *pag)
+       struct xfs_perag        *pag,
+       xfs_extlen_t            need)
 {
-       xfs_extlen_t            need, delta = 0;
+       xfs_extlen_t            delta = 0;
 
-       need = XFS_MIN_FREELIST_PAG(pag, mp);
        if (need > pag->pagf_flcount)
                delta = need - pag->pagf_flcount;
 
@@ -1848,10 +1848,8 @@ xfs_alloc_fix_freelist(
        int             flags)  /* XFS_ALLOC_FLAG_... */
 {
        xfs_buf_t       *agbp;  /* agf buffer pointer */
-       xfs_agf_t       *agf;   /* a.g. freespace structure pointer */
        xfs_buf_t       *agflbp;/* agfl buffer pointer */
        xfs_agblock_t   bno;    /* freelist block */
-       xfs_extlen_t    delta;  /* new blocks needed in freelist */
        int             error;  /* error result code */
        xfs_extlen_t    longest;/* longest extent in allocation group */
        xfs_mount_t     *mp;    /* file system mount point structure */
@@ -1895,7 +1893,7 @@ xfs_alloc_fix_freelist(
                 * total blocks, reject it.
                 */
                need = XFS_MIN_FREELIST_PAG(pag, mp);
-               longest = xfs_alloc_longest_free_extent(mp, pag);
+               longest = xfs_alloc_longest_free_extent(mp, pag, need);
                if ((args->minlen + args->alignment + args->minalignslop - 1) >
                                longest ||
                    ((int)(pag->pagf_freeblks + pag->pagf_flcount -
@@ -1922,25 +1920,16 @@ xfs_alloc_fix_freelist(
                        return 0;
                }
        }
-       /*
-        * Figure out how many blocks we should have in the freelist.
-        */
-       agf = XFS_BUF_TO_AGF(agbp);
-       need = XFS_MIN_FREELIST(agf, mp);
-       /*
-        * If there isn't enough total or single-extent, reject it.
-        */
+
+
+       /* If there isn't enough total space or single-extent, reject it. */
+       need = XFS_MIN_FREELIST_PAG(pag, mp);
        if (!(flags & XFS_ALLOC_FLAG_FREEING)) {
-               delta = need > be32_to_cpu(agf->agf_flcount) ?
-                       (need - be32_to_cpu(agf->agf_flcount)) : 0;
-               longest = be32_to_cpu(agf->agf_longest);
-               longest = (longest > delta) ? (longest - delta) :
-                       (be32_to_cpu(agf->agf_flcount) > 0 || longest > 0);
+               longest = xfs_alloc_longest_free_extent(mp, pag, need);
                if ((args->minlen + args->alignment + args->minalignslop - 1) >
                                longest ||
-                   ((int)(be32_to_cpu(agf->agf_freeblks) +
-                    be32_to_cpu(agf->agf_flcount) - need - args->total) <
-                               (int)args->minleft)) {
+                   ((int)(pag->pagf_freeblks + pag->pagf_flcount -
+                          need - args->total) < (int)args->minleft)) {
                        xfs_trans_brelse(tp, agbp);
                        args->agbp = NULL;
                        return 0;
@@ -1948,21 +1937,25 @@ xfs_alloc_fix_freelist(
        }
        /*
         * Make the freelist shorter if it's too long.
+        *
+        * XXX (dgc): When we have lots of free space, does this buy us
+        * anything other than extra overhead when we need to put more blocks
+        * back on the free list? Maybe we should only do this when space is
+        * getting low or the AGFL is more than half full?
         */
-       while (be32_to_cpu(agf->agf_flcount) > need) {
-               xfs_buf_t       *bp;
+       while (pag->pagf_flcount > need) {
+               struct xfs_buf  *bp;
 
                error = xfs_alloc_get_freelist(tp, agbp, &bno, 0);
                if (error)
                        return error;
-               if ((error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1)))
+               error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1);
+               if (error)
                        return error;
                bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0);
                xfs_trans_binval(tp, bp);
        }
-       /*
-        * Initialize the args structure.
-        */
+
        memset(&targs, 0, sizeof(targs));
        targs.tp = tp;
        targs.mp = mp;
@@ -1971,18 +1964,18 @@ xfs_alloc_fix_freelist(
        targs.alignment = targs.minlen = targs.prod = targs.isfl = 1;
        targs.type = XFS_ALLOCTYPE_THIS_AG;
        targs.pag = pag;
-       if ((error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp)))
+       error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp);
+       if (error)
                return error;
-       /*
-        * Make the freelist longer if it's too short.
-        */
-       while (be32_to_cpu(agf->agf_flcount) < need) {
+
+       /* Make the freelist longer if it's too short. */
+       while (pag->pagf_flcount < need) {
                targs.agbno = 0;
-               targs.maxlen = need - be32_to_cpu(agf->agf_flcount);
-               /*
-                * Allocate as many blocks as possible at once.
-                */
-               if ((error = xfs_alloc_ag_vextent(&targs))) {
+               targs.maxlen = need - pag->pagf_flcount;
+
+               /* Allocate as many blocks as possible at once. */
+               error = xfs_alloc_ag_vextent(&targs);
+               if (error) {
                        xfs_trans_brelse(tp, agflbp);
                        return error;
                }
index d1b4b6a5c8947ee038392ac877f58aeb6063e024..8815fc30f83d0f258b70a11a8770ce0075bb9f02 100644 (file)
@@ -128,12 +128,8 @@ typedef struct xfs_alloc_arg {
 #define XFS_ALLOC_USERDATA             1       /* allocation is for user data*/
 #define XFS_ALLOC_INITIAL_USER_DATA    2       /* special case start of file */
 
-/*
- * Find the length of the longest extent in an AG.
- */
-xfs_extlen_t
-xfs_alloc_longest_free_extent(struct xfs_mount *mp,
-               struct xfs_perag *pag);
+xfs_extlen_t xfs_alloc_longest_free_extent(struct xfs_mount *mp,
+               struct xfs_perag *pag, xfs_extlen_t need);
 
 /*
  * Compute and fill in value of m_ag_maxlevels.
index aeffeaaac0ec406e543730eb608de1eb3ebc40fb..1ad4f1a62ce082678108b6618aeb6aca8348d392 100644 (file)
@@ -3507,7 +3507,8 @@ xfs_bmap_longest_free_extent(
                }
        }
 
-       longest = xfs_alloc_longest_free_extent(mp, pag);
+       longest = xfs_alloc_longest_free_extent(mp, pag,
+                                               XFS_MIN_FREELIST_PAG(pag, mp));
        if (*blen < longest)
                *blen = longest;
 
index da82f1cb4b9bde824979bad9cca0b72c748a49d9..9ac5eaad47bcb591034f04dfc6e105e4d7ae8a95 100644 (file)
@@ -196,7 +196,8 @@ xfs_filestream_pick_ag(
                        goto next_ag;
                }
 
-               longest = xfs_alloc_longest_free_extent(mp, pag);
+               longest = xfs_alloc_longest_free_extent(mp, pag,
+                                               XFS_MIN_FREELIST_PAG(pag, mp));
                if (((minlen && longest >= minlen) ||
                     (!minlen && pag->pagf_freeblks >= minfree)) &&
                    (!pag->pagf_metadata || !(flags & XFS_PICK_USERDATA) ||