/*
- * 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.
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));
(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),
#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);
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;
}
* 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
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) {
* 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;
/*
* 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;
/*
/*
* 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, <bno,
<len, &i)))
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
* 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.
*/
* 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.
*/
* search.
*/
bno_cur_gt = bno_cur_lt;
- bno_cur_lt = 0;
+ bno_cur_lt = NULL;
}
/*
* Found something. Duplicate the cursor for the rightward search.
* 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.
/*
* 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)))
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;
if (rlen == args->maxlen)
break;
}
- }
+ }
if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen,
&i)))
goto error0;
* 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;
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) {
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 */
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.
*/
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.
*/
/*
* 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.
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;
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") :
* 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.
*/
return error;
}
-/*
+/*
* Visible (exported) allocation/free functions.
* Some of these are used just by xfs_alloc_btree.c and this file.
*/
/*
* Freelist is empty, give up.
*/
- if (INT_ISZERO(agf->agf_flcount, ARCH_CONVERT)) {
+ if (!agf->agf_flcount) {
*bnop = NULLAGBLOCK;
return 0;
}
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);
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);
(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;
}
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) {
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];
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;
TRACE_ALLOC("badargs", args);
return 0;
}
+ minleft = args->minleft;
+
switch (type) {
case XFS_ALLOCTYPE_THIS_AG:
case XFS_ALLOCTYPE_NEAR_BNO:
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;
*/
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);
/*
* 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) {
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;
}
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);