]> 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 3ccb367c31cfdcccf6f0128055e087b4d8649d5e..1ad83c977e7264e5158da011a6d57a71592332e9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -11,7 +11,7 @@
  *
  * 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
+ * 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.
@@ -134,7 +134,7 @@ xfs_alloc_compute_diff(
  */
 STATIC void
 xfs_alloc_fix_len(
-       xfs_alloc_arg_t *args)          /* allocation argument structure */
+       xfs_alloc_arg_t *args)          /* allocation argument structure */
 {
        xfs_extlen_t    k;
        xfs_extlen_t    rlen;
@@ -168,7 +168,7 @@ xfs_alloc_fix_len(
  */
 STATIC int
 xfs_alloc_fix_minleft(
-       xfs_alloc_arg_t *args)          /* allocation argument structure */
+       xfs_alloc_arg_t *args)          /* allocation argument structure */
 {
        xfs_agf_t       *agf;           /* a.g. freelist header */
        int             diff;           /* free space difference */
@@ -197,8 +197,8 @@ xfs_alloc_fix_minleft(
  */
 STATIC int                             /* error code */
 xfs_alloc_fixup_trees(
-       xfs_btree_cur_t *cnt_cur,       /* cursor for by-size btree */
-       xfs_btree_cur_t *bno_cur,       /* cursor for by-block btree */
+       xfs_btree_cur_t *cnt_cur,       /* cursor for by-size btree */
+       xfs_btree_cur_t *bno_cur,       /* cursor for by-block btree */
        xfs_agblock_t   fbno,           /* starting block of free extent */
        xfs_extlen_t    flen,           /* length of free extent */
        xfs_agblock_t   rbno,           /* starting block of returned extent */
@@ -368,7 +368,7 @@ STATIC void
 xfs_alloc_trace_alloc(
        char            *name,          /* function tag string */
        char            *str,           /* additional string */
-       xfs_alloc_arg_t *args,          /* allocation argument structure */
+       xfs_alloc_arg_t *args,          /* allocation argument structure */
        int             line)           /* source line number */
 {
        ktrace_enter(xfs_alloc_trace_buf,
@@ -470,7 +470,7 @@ xfs_alloc_trace_modagf(
  */
 STATIC int                     /* error */
 xfs_alloc_ag_vextent(
-       xfs_alloc_arg_t *args)  /* argument structure for allocation */
+       xfs_alloc_arg_t *args)  /* argument structure for allocation */
 {
        int             error=0;
 #ifdef XFS_ALLOC_TRACE
@@ -536,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;
 }
@@ -550,10 +550,10 @@ xfs_alloc_ag_vextent(
  */
 STATIC int                     /* error */
 xfs_alloc_ag_vextent_exact(
-       xfs_alloc_arg_t *args)  /* allocation argument structure */
+       xfs_alloc_arg_t *args)  /* allocation argument structure */
 {
-       xfs_btree_cur_t *bno_cur;/* by block-number btree cursor */
-       xfs_btree_cur_t *cnt_cur;/* by count btree cursor */
+       xfs_btree_cur_t *bno_cur;/* by block-number btree cursor */
+       xfs_btree_cur_t *cnt_cur;/* by count btree cursor */
        xfs_agblock_t   end;    /* end of allocated extent */
        int             error;
        xfs_agblock_t   fbno;   /* start block of found extent */
@@ -563,8 +563,8 @@ xfs_alloc_ag_vextent_exact(
        static char     fname[] = "xfs_alloc_ag_vextent_exact";
 #endif
        int             i;      /* success/failure of operation */
-       xfs_agblock_t   maxend; /* end of maximal extent */
-       xfs_agblock_t   minend; /* end of minimal extent */
+       xfs_agblock_t   maxend; /* end of maximal extent */
+       xfs_agblock_t   minend; /* end of minimal extent */
        xfs_extlen_t    rlen;   /* length of returned extent */
 
        ASSERT(args->alignment == 1);
@@ -572,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
@@ -628,7 +628,7 @@ 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));
@@ -657,11 +657,11 @@ error0:
  */
 STATIC int                             /* error */
 xfs_alloc_ag_vextent_near(
-       xfs_alloc_arg_t *args)          /* allocation argument structure */
+       xfs_alloc_arg_t *args)          /* allocation argument structure */
 {
-       xfs_btree_cur_t *bno_cur_gt;    /* cursor for bno btree, right side */
-       xfs_btree_cur_t *bno_cur_lt;    /* cursor for bno btree, left side */
-       xfs_btree_cur_t *cnt_cur;       /* cursor for count btree */
+       xfs_btree_cur_t *bno_cur_gt;    /* cursor for bno btree, right side */
+       xfs_btree_cur_t *bno_cur_lt;    /* cursor for bno btree, left side */
+       xfs_btree_cur_t *cnt_cur;       /* cursor for count btree */
 #ifdef XFS_ALLOC_TRACE
        static char     fname[] = "xfs_alloc_ag_vextent_near";
 #endif
@@ -687,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;
        /*
@@ -829,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.
                 */
@@ -857,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.
         */
@@ -869,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.
@@ -1196,10 +1190,10 @@ xfs_alloc_ag_vextent_near(
  */
 STATIC int                             /* error */
 xfs_alloc_ag_vextent_size(
-       xfs_alloc_arg_t *args)          /* allocation argument structure */
+       xfs_alloc_arg_t *args)          /* allocation argument structure */
 {
-       xfs_btree_cur_t *bno_cur;       /* cursor for bno btree */
-       xfs_btree_cur_t *cnt_cur;       /* cursor for cnt btree */
+       xfs_btree_cur_t *bno_cur;       /* cursor for bno btree */
+       xfs_btree_cur_t *cnt_cur;       /* cursor for cnt btree */
        int             error;          /* error result */
        xfs_agblock_t   fbno;           /* start of found freespace */
        xfs_extlen_t    flen;           /* length of found freespace */
@@ -1214,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.
@@ -1319,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;
@@ -1352,10 +1346,10 @@ error0:
  */
 STATIC int                     /* error */
 xfs_alloc_ag_vextent_small(
-       xfs_alloc_arg_t *args,  /* allocation argument structure */
-       xfs_btree_cur_t *ccur,  /* by-size cursor */
-       xfs_agblock_t   *fbnop, /* result block number */
-       xfs_extlen_t    *flenp, /* result length */
+       xfs_alloc_arg_t *args,  /* allocation argument structure */
+       xfs_btree_cur_t *ccur,  /* by-size cursor */
+       xfs_agblock_t   *fbnop, /* result block number */
+       xfs_extlen_t    *flenp, /* result length */
        int             *stat)  /* status: 0-freelist, 1-normal/none */
 {
        int             error;
@@ -1381,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) {
@@ -1439,14 +1434,14 @@ 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 */
        int             isfl)   /* set if is freelist blocks - no sb acctg */
 {
-       xfs_btree_cur_t *bno_cur;       /* cursor for by-block btree */
-       xfs_btree_cur_t *cnt_cur;       /* cursor for by-size btree */
+       xfs_btree_cur_t *bno_cur;       /* cursor for by-block btree */
+       xfs_btree_cur_t *cnt_cur;       /* cursor for by-size btree */
        int             error;          /* error return value */
 #ifdef XFS_ALLOC_TRACE
        static char     fname[] = "xfs_free_ag_extent";
@@ -1466,7 +1461,7 @@ xfs_free_ag_extent(
        /*
         * 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;
        /*
@@ -1526,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.
@@ -1681,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") :
@@ -1694,7 +1689,7 @@ 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
+        * 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,
@@ -1746,7 +1741,7 @@ xfs_alloc_compute_maxlevels(
  */
 int                            /* error */
 xfs_alloc_fix_freelist(
-       xfs_alloc_arg_t *args,  /* allocation argument structure */
+       xfs_alloc_arg_t *args,  /* allocation argument structure */
        int             flags)  /* XFS_ALLOC_FLAG_... */
 {
        xfs_buf_t       *agbp;  /* agf buffer pointer */
@@ -1759,7 +1754,7 @@ xfs_alloc_fix_freelist(
        xfs_mount_t     *mp;    /* file system mount point structure */
        xfs_extlen_t    need;   /* total blocks needed in freelist */
        xfs_perag_t     *pag;   /* per-ag information structure */
-       xfs_alloc_arg_t targs;  /* local allocation arguments */
+       xfs_alloc_arg_t targs;  /* local allocation arguments */
        xfs_trans_t     *tp;    /* transaction pointer */
 
        mp = args->mp;
@@ -1879,8 +1874,8 @@ xfs_alloc_fix_freelist(
                if ((error = xfs_alloc_ag_vextent(&targs)))
                        return error;
                /*
-                * Stop if we run out.  Won't happen if callers are obeying
-                * the restrictions correctly.  Can happen for free calls
+                * Stop if we run out.  Won't happen if callers are obeying
+                * the restrictions correctly.  Can happen for free calls
                 * on a completely full ag.
                 */
                if (targs.agbno == NULLAGBLOCK)
@@ -1923,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;
        }
@@ -1942,7 +1937,7 @@ xfs_alloc_get_freelist(
        INT_MOD(agf->agf_flfirst, ARCH_CONVERT, 1);
        xfs_trans_brelse(tp, agflbp);
        if (INT_GET(agf->agf_flfirst, ARCH_CONVERT) == XFS_AGFL_SIZE(mp))
-               INT_ZERO(agf->agf_flfirst, ARCH_CONVERT);
+               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);
@@ -1955,7 +1950,7 @@ xfs_alloc_get_freelist(
         * As blocks are freed, they are added to the per-ag busy list
         * and remain there until the freeing transaction is committed to
         * disk.  Now that we have allocated blocks, this list must be
-        * searched to see if a block is being reused.  If one is, then
+        * searched to see if a block is being reused.  If one is, then
         * the freeing transaction must be pushed to disk NOW by forcing
         * to disk all iclogs up that transaction's LSN.
         */
@@ -1970,7 +1965,7 @@ void
 xfs_alloc_log_agf(
        xfs_trans_t     *tp,    /* transaction pointer */
        xfs_buf_t       *bp,    /* buffer for a.g. freelist header */
-       int             fields) /* mask of fields to be logged (XFS_AGF_...) */
+       int             fields) /* mask of fields to be logged (XFS_AGF_...) */
 {
        int     first;          /* first byte offset */
        int     last;           /* last byte offset */
@@ -2042,7 +2037,7 @@ xfs_alloc_put_freelist(
        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(mp))
-               INT_ZERO(agf->agf_fllast, ARCH_CONVERT);
+               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);
@@ -2056,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;
 }
 
@@ -2116,34 +2098,11 @@ xfs_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 (XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF,
-                       XFS_RANDOM_ALLOC_READ_AGF)) {
+       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(mp)))
-                       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(mp)))
-                       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(mp)))
-                       cmn_err(CE_NOTE, "Bad flcount %d",
-                               INT_GET(agf->agf_flcount, ARCH_CONVERT));
-#endif
                return XFS_ERROR(EFSCORRUPTED);
        }
        pag = &mp->m_perag[agno];
@@ -2183,9 +2142,9 @@ xfs_alloc_read_agf(
  */
 int                            /* error */
 xfs_alloc_vextent(
-       xfs_alloc_arg_t *args)  /* allocation argument structure */
+       xfs_alloc_arg_t *args)  /* allocation argument structure */
 {
-       xfs_agblock_t   agsize; /* allocation group size */
+       xfs_agblock_t   agsize; /* allocation group size */
        int             error;
        int             flags;  /* XFS_ALLOC_FLAG_... locking flags */
 #ifdef XFS_ALLOC_TRACE
@@ -2194,9 +2153,10 @@ xfs_alloc_vextent(
        xfs_extlen_t    minleft;/* minimum left value, temp copy */
        xfs_mount_t     *mp;    /* mount structure pointer */
        xfs_agnumber_t  sagno;  /* starting allocation group number */
-       xfs_alloctype_t type;   /* input allocation type */
+       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;
@@ -2260,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);
@@ -2276,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) {
@@ -2350,8 +2313,14 @@ xfs_alloc_vextent(
                        }
                }
                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);
@@ -2389,7 +2358,7 @@ xfs_free_extent(
 #ifdef DEBUG
        xfs_agf_t       *agf;   /* a.g. freespace header */
 #endif
-       xfs_alloc_arg_t args;   /* allocation argument structure */
+       xfs_alloc_arg_t args;   /* allocation argument structure */
        int             error;
 
        ASSERT(len != 0);