]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - libxfs/xfs_alloc.c
Merge back recent changes from xfs kernel headers.
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_alloc.c
index 36f108dff3f2b3dd26647946c366f23baaf029fa..1ad83c977e7264e5158da011a6d57a71592332e9 100644 (file)
@@ -1,40 +1,40 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- * 
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
  * published by the Free Software Foundation.
- * 
+ *
  * This program is distributed in the hope that it would be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * 
+ *
  * Further, this software is distributed without any warranty that it is
  * free of the rightful claim of any third person regarding infringement
  * or the like.  Any license provided herein, whether implied or
  * otherwise, applies only to this software file.  Patent licenses, if
  * any, provided herein do not apply to combinations of this program with
  * other software, or any other product whatsoever.
- * 
+ *
  * You should have received a copy of the GNU General Public License along
  * with this program; if not, write the Free Software Foundation, Inc., 59
  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- * 
+ *
  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
  * Mountain View, CA  94043, or:
- * 
- * http://www.sgi.com 
- * 
- * For further information regarding this notice, see: 
- * 
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
+
 #include <xfs.h>
 
 #define XFS_ABSDIFF(a,b)       (((a) <= (b)) ? ((b) - (a)) : ((a) - (b)))
-#define        XFSA_FIXUP_BNO_OK       1
-#define        XFSA_FIXUP_CNT_OK       2
+#define XFSA_FIXUP_BNO_OK      1
+#define XFSA_FIXUP_CNT_OK      2
 
 /*
  * Compute aligned version of the found extent.
@@ -344,12 +344,14 @@ xfs_alloc_read_agfl(
        xfs_buf_t       **bpp)          /* buffer for the ag free block array */
 {
        xfs_buf_t       *bp;            /* return value */
-       xfs_daddr_t     d;              /* disk block address */
        int             error;
 
        ASSERT(agno != NULLAGNUMBER);
-       d = XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR);
-       if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, 1, 0, &bp)))
+       error = xfs_trans_read_buf(
+                       mp, tp, mp->m_ddev_targp,
+                       XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
+                       XFS_FSS_TO_BB(mp, 1), 0, &bp);
+       if (error)
                return error;
        ASSERT(bp);
        ASSERT(!XFS_BUF_GETERROR(bp));
@@ -439,13 +441,13 @@ xfs_alloc_trace_modagf(
                (void *)(__psunsigned_t)INT_GET(agf->agf_seqno, ARCH_CONVERT),
                (void *)(__psunsigned_t)INT_GET(agf->agf_length, ARCH_CONVERT),
                (void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_BNO],
-                                               ARCH_CONVERT);
+                                               ARCH_CONVERT),
                (void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_CNT],
-                                               ARCH_CONVERT);
+                                               ARCH_CONVERT),
                (void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_BNO],
-                                               ARCH_CONVERT);
+                                               ARCH_CONVERT),
                (void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_CNT],
-                                               ARCH_CONVERT);
+                                               ARCH_CONVERT),
                (void *)(__psunsigned_t)INT_GET(agf->agf_flfirst, ARCH_CONVERT),
                (void *)(__psunsigned_t)INT_GET(agf->agf_fllast, ARCH_CONVERT),
                (void *)(__psunsigned_t)INT_GET(agf->agf_flcount, ARCH_CONVERT),
@@ -509,7 +511,7 @@ xfs_alloc_ag_vextent(
 #ifdef XFS_ALLOC_TRACE
                xfs_mount_t     *mp = args->mp;
 #endif
-               long            slen = (long)args->len;
+               long            slen = (long)args->len;
 
                ASSERT(args->len >= args->minlen && args->len <= args->maxlen);
                ASSERT(!(args->wasfromfl) || !args->isfl);
@@ -534,8 +536,8 @@ xfs_alloc_ag_vextent(
                        xfs_trans_mod_sb(args->tp,
                                args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS :
                                        XFS_TRANS_SB_FDBLOCKS, -slen);
-               XFS_STATS_INC(xfsstats.xs_allocx);
-               XFS_STATS_ADD(xfsstats.xs_allocb, args->len);
+               XFS_STATS_INC(xs_allocx);
+               XFS_STATS_ADD(xs_allocb, args->len);
        }
        return 0;
 }
@@ -570,7 +572,7 @@ xfs_alloc_ag_vextent_exact(
         * Allocate/initialize a cursor for the by-number freespace btree.
         */
        bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_BNO, 0, 0);
+               args->agno, XFS_BTNUM_BNO, NULL, 0);
        /*
         * Lookup bno and minlen in the btree (minlen is irrelevant, really).
         * Look for the closest free block <= bno, it must contain bno
@@ -596,7 +598,7 @@ xfs_alloc_ag_vextent_exact(
        minend = args->agbno + args->minlen;
        maxend = args->agbno + args->maxlen;
        fend = fbno + flen;
-       /* 
+       /*
         * Give up if the freespace isn't long enough for the minimum request.
         */
        if (fend < minend) {
@@ -626,11 +628,11 @@ xfs_alloc_ag_vextent_exact(
         * Allocate/initialize a cursor for the by-size btree.
         */
        cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_CNT, 0, 0);
+               args->agno, XFS_BTNUM_CNT, NULL, 0);
        ASSERT(args->agbno + args->len <=
                INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length,
                        ARCH_CONVERT));
-       if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, 
+       if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
                        args->agbno, args->len, XFSA_FIXUP_BNO_OK))) {
                xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR);
                goto error0;
@@ -685,21 +687,15 @@ xfs_alloc_ag_vextent_near(
        /*
         * Randomly don't execute the first algorithm.
         */
-       static int      seed;           /* randomizing seed value */
        int             dofirst;        /* set to do first algorithm */
-       timespec_t      now;            /* current time */
 
-       if (!seed) {
-               nanotime(&now);
-               seed = (int)now.tv_sec ^ (int)now.tv_nsec;
-       }
        dofirst = random() & 1;
 #endif
        /*
         * Get a cursor for the by-size btree.
         */
        cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_CNT, 0, 0);
+               args->agno, XFS_BTNUM_CNT, NULL, 0);
        ltlen = 0;
        bno_cur_lt = bno_cur_gt = NULL;
        /*
@@ -710,7 +706,7 @@ xfs_alloc_ag_vextent_near(
        /*
         * If none, then pick up the last entry in the tree unless the
         * tree is empty.
-        */ 
+        */
        if (!i) {
                if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, &ltbno,
                                &ltlen, &i)))
@@ -722,7 +718,7 @@ xfs_alloc_ag_vextent_near(
                ASSERT(i == 1);
        }
        args->wasfromfl = 0;
-       /* 
+       /*
         * First algorithm.
         * If the requested extent is large wrt the freespaces available
         * in this a.g., then the cursor will be pointing to a btree entry
@@ -827,7 +823,7 @@ xfs_alloc_ag_vextent_near(
                 * Set up a cursor for the by-bno tree.
                 */
                bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp,
-                       args->agbp, args->agno, XFS_BTNUM_BNO, 0, 0);
+                       args->agbp, args->agno, XFS_BTNUM_BNO, NULL, 0);
                /*
                 * Fix up the btree entries.
                 */
@@ -855,7 +851,7 @@ xfs_alloc_ag_vextent_near(
         * Allocate and initialize the cursor for the leftward search.
         */
        bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_BNO, 0, 0);
+               args->agno, XFS_BTNUM_BNO, NULL, 0);
        /*
         * Lookup <= bno to find the leftward search's starting point.
         */
@@ -867,7 +863,7 @@ xfs_alloc_ag_vextent_near(
                 * search.
                 */
                bno_cur_gt = bno_cur_lt;
-               bno_cur_lt = 0;
+               bno_cur_lt = NULL;
        }
        /*
         * Found something.  Duplicate the cursor for the rightward search.
@@ -1212,7 +1208,7 @@ xfs_alloc_ag_vextent_size(
         * Allocate and initialize a cursor for the by-size btree.
         */
        cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_CNT, 0, 0);
+               args->agno, XFS_BTNUM_CNT, NULL, 0);
        bno_cur = NULL;
        /*
         * Look for an entry >= maxlen+alignment-1 blocks.
@@ -1223,7 +1219,7 @@ xfs_alloc_ag_vextent_size(
        /*
         * If none, then pick up the last entry in the tree unless the
         * tree is empty.
-        */ 
+        */
        if (!i) {
                if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, &fbno,
                                &flen, &i)))
@@ -1252,7 +1248,7 @@ xfs_alloc_ag_vextent_size(
        xfs_alloc_compute_aligned(fbno, flen, args->alignment, args->minlen,
                &rbno, &rlen);
        rlen = XFS_EXTLEN_MIN(args->maxlen, rlen);
-       XFS_WANT_CORRUPTED_GOTO(rlen == 0 || 
+       XFS_WANT_CORRUPTED_GOTO(rlen == 0 ||
                        (rlen <= flen && rbno + rlen <= fbno + flen), error0);
        if (rlen < args->maxlen) {
                xfs_agblock_t   bestfbno;
@@ -1289,7 +1285,7 @@ xfs_alloc_ag_vextent_size(
                                if (rlen == args->maxlen)
                                        break;
                        }
-               } 
+               }
                if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen,
                                &i)))
                        goto error0;
@@ -1317,7 +1313,7 @@ xfs_alloc_ag_vextent_size(
         * Allocate and initialize a cursor for the by-block tree.
         */
        bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_BNO, 0, 0);
+               args->agno, XFS_BTNUM_BNO, NULL, 0);
        if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
                        rbno, rlen, XFSA_FIXUP_CNT_OK)))
                goto error0;
@@ -1379,7 +1375,8 @@ xfs_alloc_ag_vextent_small(
        else if (args->minlen == 1 && args->alignment == 1 && !args->isfl &&
                 (INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_flcount,
                        ARCH_CONVERT) > args->minleft)) {
-               if ((error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno)))
+               error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno);
+               if (error)
                        goto error0;
                if (fbno != NULLAGBLOCK) {
                        if (args->userdata) {
@@ -1437,7 +1434,7 @@ error0:
 STATIC int                     /* error */
 xfs_free_ag_extent(
        xfs_trans_t     *tp,    /* transaction pointer */
-       xfs_buf_t               *agbp,  /* buffer for a.g. freelist header */
+       xfs_buf_t       *agbp,  /* buffer for a.g. freelist header */
        xfs_agnumber_t  agno,   /* allocation group number */
        xfs_agblock_t   bno,    /* starting block number */
        xfs_extlen_t    len,    /* length of extent */
@@ -1461,13 +1458,13 @@ xfs_free_ag_extent(
        xfs_extlen_t    nlen;           /* new length of freespace */
 
        mp = tp->t_mountp;
-       /* 
+       /*
         * Allocate and initialize a cursor for the by-block btree.
         */
-       bno_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO, 0,
+       bno_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO, NULL,
                0);
        cnt_cur = NULL;
-       /* 
+       /*
         * Look for a neighboring block on the left (lower block numbers)
         * that is contiguous with this space.
         */
@@ -1494,7 +1491,7 @@ xfs_free_ag_extent(
                        XFS_WANT_CORRUPTED_GOTO(ltbno + ltlen <= bno, error0);
                }
        }
-       /* 
+       /*
         * Look for a neighboring block on the right (higher block numbers)
         * that is contiguous with this space.
         */
@@ -1524,7 +1521,7 @@ xfs_free_ag_extent(
        /*
         * Now allocate and initialize a cursor for the by-size tree.
         */
-       cnt_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT, 0,
+       cnt_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT, NULL,
                0);
        /*
         * Have both left and right contiguous neighbors.
@@ -1627,7 +1624,7 @@ xfs_free_ag_extent(
                        goto error0;
                XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
                /*
-                * Update the starting block and length of the right 
+                * Update the starting block and length of the right
                 * neighbor in the by-block tree.
                 */
                nbno = bno;
@@ -1679,8 +1676,8 @@ xfs_free_ag_extent(
                xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS);
                if (!isfl)
                        xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len);
-               XFS_STATS_INC(xfsstats.xs_freex);
-               XFS_STATS_ADD(xfsstats.xs_freeb, len);
+               XFS_STATS_INC(xs_freex);
+               XFS_STATS_ADD(xs_freeb, len);
        }
        TRACE_FREE(haveleft ?
                        (haveright ? "both" : "left") :
@@ -1692,9 +1689,9 @@ xfs_free_ag_extent(
         * used in xfs_bmap_finish, we can't allow block to be available
         * for reallocation and non-transaction writing (user data)
         * until we know that the transaction that moved it to the free
-        * list is permanently on disk.  We track the blocks by declaring 
-        * these blocks as "busy"; the busy list is maintained on a per-ag 
-        * basis and each transaction records which entries should be removed 
+        * list is permanently on disk.  We track the blocks by declaring
+        * these blocks as "busy"; the busy list is maintained on a per-ag
+        * basis and each transaction records which entries should be removed
         * when the iclog commits to disk.  If a busy block is allocated,
         * the iclog is pushed up to the LSN that freed the block.
         */
@@ -1710,7 +1707,7 @@ xfs_free_ag_extent(
        return error;
 }
 
-/* 
+/*
  * Visible (exported) allocation/free functions.
  * Some of these are used just by xfs_alloc_btree.c and this file.
  */
@@ -1921,7 +1918,7 @@ xfs_alloc_get_freelist(
        /*
         * Freelist is empty, give up.
         */
-       if (INT_ISZERO(agf->agf_flcount, ARCH_CONVERT)) {
+       if (!agf->agf_flcount) {
                *bnop = NULLAGBLOCK;
                return 0;
        }
@@ -1939,8 +1936,8 @@ xfs_alloc_get_freelist(
        bno = INT_GET(agfl->agfl_bno[INT_GET(agf->agf_flfirst, ARCH_CONVERT)], ARCH_CONVERT);
        INT_MOD(agf->agf_flfirst, ARCH_CONVERT, 1);
        xfs_trans_brelse(tp, agflbp);
-       if (INT_GET(agf->agf_flfirst, ARCH_CONVERT) == XFS_AGFL_SIZE)
-               INT_ZERO(agf->agf_flfirst, ARCH_CONVERT);
+       if (INT_GET(agf->agf_flfirst, ARCH_CONVERT) == XFS_AGFL_SIZE(mp))
+               agf->agf_flfirst = 0;
        pag = &mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)];
        INT_MOD(agf->agf_flcount, ARCH_CONVERT, -1);
        xfs_trans_agflist_delta(tp, -1);
@@ -2038,14 +2035,14 @@ xfs_alloc_put_freelist(
                        INT_GET(agf->agf_seqno, ARCH_CONVERT), &agflbp)))
                return error;
        agfl = XFS_BUF_TO_AGFL(agflbp);
-        INT_MOD(agf->agf_fllast, ARCH_CONVERT, 1);
-        if (INT_GET(agf->agf_fllast, ARCH_CONVERT) == XFS_AGFL_SIZE)
-               INT_ZERO(agf->agf_fllast, ARCH_CONVERT);
+       INT_MOD(agf->agf_fllast, ARCH_CONVERT, 1);
+       if (INT_GET(agf->agf_fllast, ARCH_CONVERT) == XFS_AGFL_SIZE(mp))
+               agf->agf_fllast = 0;
        pag = &mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)];
        INT_MOD(agf->agf_flcount, ARCH_CONVERT, 1);
        xfs_trans_agflist_delta(tp, 1);
        pag->pagf_flcount++;
-       ASSERT(INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE);
+       ASSERT(INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE(mp));
        blockp = &agfl->agfl_bno[INT_GET(agf->agf_fllast, ARCH_CONVERT)];
        INT_SET(*blockp, ARCH_CONVERT, bno);
        TRACE_MODAGF(NULL, agf, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
@@ -2054,19 +2051,6 @@ xfs_alloc_put_freelist(
                (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl),
                (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl +
                        sizeof(xfs_agblock_t) - 1));
-       /*
-        * Since blocks move to the free list without the coordination
-        * used in xfs_bmap_finish, we can't allow block to be available
-        * for reallocation and non-transaction writing (user data)
-        * until we know that the transaction that moved it to the free
-        * list is permanently on disk.  We track the blocks by declaring
-        * these blocks as "busy"; the busy list is maintained on a per-ag
-        * basis and each transaction records which entries should be removed
-        * when the iclog commits to disk.  If a busy block is allocated,
-        * the iclog is pushed up to the LSN that freed the block.
-        */
-       xfs_alloc_mark_busy(tp, INT_GET(agf->agf_seqno, ARCH_CONVERT), bno, 1);
-
        return 0;
 }
 
@@ -2084,15 +2068,17 @@ xfs_alloc_read_agf(
        xfs_agf_t       *agf;           /* ag freelist header */
        int             agf_ok;         /* set if agf is consistent */
        xfs_buf_t       *bp;            /* return value */
-       xfs_daddr_t     d;              /* disk block address */
-       int             error;
        xfs_perag_t     *pag;           /* per allocation group data */
+       int             error;
 
        ASSERT(agno != NULLAGNUMBER);
-       d = XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR);
-       if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, 1,
+       error = xfs_trans_read_buf(
+                       mp, tp, mp->m_ddev_targp,
+                       XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
+                       XFS_FSS_TO_BB(mp, 1),
                        (flags & XFS_ALLOC_FLAG_TRYLOCK) ? XFS_BUF_TRYLOCK : 0U,
-                       &bp)))
+                       &bp);
+       if (error)
                return error;
        ASSERT(!bp || !XFS_BUF_GETERROR(bp));
        if (!bp) {
@@ -2105,40 +2091,18 @@ xfs_alloc_read_agf(
        agf = XFS_BUF_TO_AGF(bp);
        agf_ok =
                INT_GET(agf->agf_magicnum, ARCH_CONVERT) == XFS_AGF_MAGIC &&
-               XFS_AGF_GOOD_VERSION(INT_GET(agf->agf_versionnum, ARCH_CONVERT)) &&
+               XFS_AGF_GOOD_VERSION(
+                       INT_GET(agf->agf_versionnum, ARCH_CONVERT)) &&
                INT_GET(agf->agf_freeblks, ARCH_CONVERT) <=
                                INT_GET(agf->agf_length, ARCH_CONVERT) &&
-               INT_GET(agf->agf_flfirst, ARCH_CONVERT) < XFS_AGFL_SIZE &&
-               INT_GET(agf->agf_fllast,  ARCH_CONVERT) < XFS_AGFL_SIZE &&
-               INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE;
-       if (XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF,
-                       XFS_RANDOM_ALLOC_READ_AGF)) {
+               INT_GET(agf->agf_flfirst, ARCH_CONVERT) < XFS_AGFL_SIZE(mp) &&
+               INT_GET(agf->agf_fllast,  ARCH_CONVERT) < XFS_AGFL_SIZE(mp) &&
+               INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE(mp);
+       if (unlikely(XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF,
+                       XFS_RANDOM_ALLOC_READ_AGF))) {
+               XFS_CORRUPTION_ERROR("xfs_alloc_read_agf",
+                                    XFS_ERRLEVEL_LOW, mp, agf);
                xfs_trans_brelse(tp, bp);
-#ifdef __KERNEL__      /* additional, temporary, debugging code */
-               cmn_err(CE_NOTE,
-                       "xfs_alloc_read_agf: error in <%s> AG %d",
-                       mp->m_fsname, agno);
-               if (INT_GET(agf->agf_magicnum, ARCH_CONVERT) != XFS_AGF_MAGIC)
-                       cmn_err(CE_NOTE, "bad agf_magicnum 0x%x",
-                               INT_GET(agf->agf_magicnum, ARCH_CONVERT));
-               if (!XFS_AGF_GOOD_VERSION(INT_GET(agf->agf_versionnum, ARCH_CONVERT)))
-                       cmn_err(CE_NOTE, "Bad version number 0x%x",
-                               INT_GET(agf->agf_versionnum, ARCH_CONVERT));
-               if (!(INT_GET(agf->agf_freeblks, ARCH_CONVERT) <=
-                               INT_GET(agf->agf_length, ARCH_CONVERT)))
-                       cmn_err(CE_NOTE, "Bad freeblks %d %d",
-                               INT_GET(agf->agf_freeblks, ARCH_CONVERT),
-                               INT_GET(agf->agf_length, ARCH_CONVERT));
-               if (!(INT_GET(agf->agf_flfirst, ARCH_CONVERT) < XFS_AGFL_SIZE))
-                       cmn_err(CE_NOTE, "Bad flfirst %d",
-                               INT_GET(agf->agf_flfirst, ARCH_CONVERT));
-               if (!(INT_GET(agf->agf_fllast, ARCH_CONVERT) < XFS_AGFL_SIZE))
-                       cmn_err(CE_NOTE, "Bad fllast %d",
-                               INT_GET(agf->agf_fllast, ARCH_CONVERT));
-               if (!(INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE))
-                       cmn_err(CE_NOTE, "Bad flcount %d",
-                               INT_GET(agf->agf_flcount, ARCH_CONVERT));
-#endif
                return XFS_ERROR(EFSCORRUPTED);
        }
        pag = &mp->m_perag[agno];
@@ -2191,6 +2155,8 @@ xfs_alloc_vextent(
        xfs_agnumber_t  sagno;  /* starting allocation group number */
        xfs_alloctype_t type;   /* input allocation type */
        int             bump_rotor = 0;
+       int             no_min = 0;
+       xfs_agnumber_t  rotorstep = xfs_rotorstep; /* inode32 agf stepper */
 
        mp = args->mp;
        type = args->otype = args->type;
@@ -2218,6 +2184,8 @@ xfs_alloc_vextent(
                TRACE_ALLOC("badargs", args);
                return 0;
        }
+       minleft = args->minleft;
+
        switch (type) {
        case XFS_ALLOCTYPE_THIS_AG:
        case XFS_ALLOCTYPE_NEAR_BNO:
@@ -2228,7 +2196,6 @@ xfs_alloc_vextent(
                args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno);
                down_read(&mp->m_peraglock);
                args->pag = &mp->m_perag[args->agno];
-               minleft = args->minleft;
                args->minleft = 0;
                error = xfs_alloc_fix_freelist(args, 0);
                args->minleft = minleft;
@@ -2253,7 +2220,9 @@ xfs_alloc_vextent(
                 */
                if ((args->userdata  == XFS_ALLOC_INITIAL_USER_DATA) &&
                    (mp->m_flags & XFS_MOUNT_32BITINODES)) {
-                       args->fsbno = XFS_AGB_TO_FSB(mp, mp->m_agfrotor, 0);
+                       args->fsbno = XFS_AGB_TO_FSB(mp,
+                                       ((mp->m_agfrotor / rotorstep) %
+                                       mp->m_sb.sb_agcount), 0);
                        bump_rotor = 1;
                }
                args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno);
@@ -2269,7 +2238,8 @@ xfs_alloc_vextent(
                        /*
                         * Start with the last place we left off.
                         */
-                       args->agno = sagno = mp->m_agfrotor;
+                       args->agno = sagno = (mp->m_agfrotor / rotorstep) %
+                                       mp->m_sb.sb_agcount;
                        args->type = XFS_ALLOCTYPE_THIS_AG;
                        flags = XFS_ALLOC_FLAG_TRYLOCK;
                } else if (type == XFS_ALLOCTYPE_FIRST_AG) {
@@ -2296,7 +2266,10 @@ xfs_alloc_vextent(
                down_read(&mp->m_peraglock);
                for (;;) {
                        args->pag = &mp->m_perag[args->agno];
-                       if ((error = xfs_alloc_fix_freelist(args, flags))) {
+                       if (no_min) args->minleft = 0;
+                       error = xfs_alloc_fix_freelist(args, flags);
+                       args->minleft = minleft;
+                       if (error) {
                                TRACE_ALLOC("nofix", args);
                                goto error0;
                        }
@@ -2317,27 +2290,37 @@ xfs_alloc_vextent(
                                args->type = XFS_ALLOCTYPE_THIS_AG;
                        if (++(args->agno) == mp->m_sb.sb_agcount)
                                args->agno = 0;
-                       /* 
+                       /*
                         * Reached the starting a.g., must either be done
                         * or switch to non-trylock mode.
                         */
                        if (args->agno == sagno) {
-                               if (flags == 0) {
+                               if (no_min == 1) {
                                        args->agbno = NULLAGBLOCK;
                                        TRACE_ALLOC("allfailed", args);
                                        break;
                                }
-                               flags = 0;
-                               if (type == XFS_ALLOCTYPE_START_BNO) {
-                                       args->agbno = XFS_FSB_TO_AGBNO(mp,
-                                               args->fsbno);
-                                       args->type = XFS_ALLOCTYPE_NEAR_BNO;
+                               if (flags == 0) {
+                                       no_min = 1;
+                               } else {
+                                       flags = 0;
+                                       if (type == XFS_ALLOCTYPE_START_BNO) {
+                                               args->agbno = XFS_FSB_TO_AGBNO(mp,
+                                                       args->fsbno);
+                                               args->type = XFS_ALLOCTYPE_NEAR_BNO;
+                                       }
                                }
                        }
                }
                up_read(&mp->m_peraglock);
-               if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG))
-                       mp->m_agfrotor = (args->agno + 1) % mp->m_sb.sb_agcount;
+               if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) {
+                       if (args->agno == sagno)
+                               mp->m_agfrotor = (mp->m_agfrotor + 1) %
+                                       (mp->m_sb.sb_agcount * rotorstep);
+                       else
+                               mp->m_agfrotor = (args->agno * rotorstep + 1) %
+                                       (mp->m_sb.sb_agcount * rotorstep);
+               }
                break;
        default:
                ASSERT(0);