Commit 4254b0bb authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Felix Blyakher

xfs: untangle xfs_dialloc

Clarify the control flow in xfs_dialloc.  Factor out a helper to go to the
next node from the current one and improve the control flow by expanding
composite if statements and using gotos.

The xfs_ialloc_next_rec helper is borrowed from Dave Chinners dynamic
allocation policy patches.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarAlex Elder <aelder@sgi.com>
Signed-off-by: default avatarFelix Blyakher <felixb@sgi.com>
parent 0b48db80
...@@ -589,6 +589,37 @@ xfs_ialloc_ag_select( ...@@ -589,6 +589,37 @@ xfs_ialloc_ag_select(
} }
} }
/*
* Try to retrieve the next record to the left/right from the current one.
*/
STATIC int
xfs_ialloc_next_rec(
struct xfs_btree_cur *cur,
xfs_inobt_rec_incore_t *rec,
int *done,
int left)
{
int error;
int i;
if (left)
error = xfs_btree_decrement(cur, 0, &i);
else
error = xfs_btree_increment(cur, 0, &i);
if (error)
return error;
*done = !i;
if (i) {
error = xfs_inobt_get_rec(cur, rec, &i);
if (error)
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
}
return 0;
}
/* /*
* Visible inode allocation functions. * Visible inode allocation functions.
...@@ -644,8 +675,8 @@ xfs_dialloc( ...@@ -644,8 +675,8 @@ xfs_dialloc(
int j; /* result code */ int j; /* result code */
xfs_mount_t *mp; /* file system mount structure */ xfs_mount_t *mp; /* file system mount structure */
int offset; /* index of inode in chunk */ int offset; /* index of inode in chunk */
xfs_agino_t pagino; /* parent's a.g. relative inode # */ xfs_agino_t pagino; /* parent's AG relative inode # */
xfs_agnumber_t pagno; /* parent's allocation group number */ xfs_agnumber_t pagno; /* parent's AG number */
xfs_inobt_rec_incore_t rec; /* inode allocation record */ xfs_inobt_rec_incore_t rec; /* inode allocation record */
xfs_agnumber_t tagno; /* testing allocation group number */ xfs_agnumber_t tagno; /* testing allocation group number */
xfs_btree_cur_t *tcur; /* temp cursor */ xfs_btree_cur_t *tcur; /* temp cursor */
...@@ -781,186 +812,140 @@ xfs_dialloc( ...@@ -781,186 +812,140 @@ xfs_dialloc(
goto error0; goto error0;
/* /*
* If in the same a.g. as the parent, try to get near the parent. * If in the same AG as the parent, try to get near the parent.
*/ */
if (pagno == agno) { if (pagno == agno) {
if ((error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i))) int doneleft; /* done, to the left */
int doneright; /* done, to the right */
error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i);
if (error)
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
error = xfs_inobt_get_rec(cur, &rec, &j);
if (error)
goto error0; goto error0;
if (i != 0 && XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
(error = xfs_inobt_get_rec(cur, &rec, &j)) == 0 &&
j == 1 && if (rec.ir_freecount > 0) {
rec.ir_freecount > 0) {
/* /*
* Found a free inode in the same chunk * Found a free inode in the same chunk
* as parent, done. * as the parent, done.
*/ */
goto alloc_inode;
} }
/* /*
* In the same a.g. as parent, but parent's chunk is full. * In the same AG as parent, but parent's chunk is full.
*/ */
else {
int doneleft; /* done, to the left */
int doneright; /* done, to the right */
if (error) /* duplicate the cursor, search left & right simultaneously */
goto error0; error = xfs_btree_dup_cursor(cur, &tcur);
ASSERT(i == 1); if (error)
ASSERT(j == 1); goto error0;
/*
* Duplicate the cursor, search left & right /* search left with tcur, back up 1 record */
* simultaneously. error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1);
*/ if (error)
if ((error = xfs_btree_dup_cursor(cur, &tcur))) goto error1;
goto error0;
/* /* search right with cur, go forward 1 record. */
* Search left with tcur, back up 1 record. error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0);
*/ if (error)
if ((error = xfs_btree_decrement(tcur, 0, &i))) goto error1;
goto error1;
doneleft = !i; /*
if (!doneleft) { * Loop until we find an inode chunk with a free inode.
error = xfs_inobt_get_rec(tcur, &trec, &i); */
if (error) while (!doneleft || !doneright) {
goto error1; int useleft; /* using left inode chunk this time */
XFS_WANT_CORRUPTED_GOTO(i == 1, error1);
/* figure out the closer block if both are valid. */
if (!doneleft && !doneright) {
useleft = pagino -
(trec.ir_startino + XFS_INODES_PER_CHUNK - 1) <
rec.ir_startino - pagino;
} else {
useleft = !doneleft;
} }
/*
* Search right with cur, go forward 1 record. /* free inodes to the left? */
*/ if (useleft && trec.ir_freecount) {
if ((error = xfs_btree_increment(cur, 0, &i))) rec = trec;
goto error1; xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
doneright = !i; cur = tcur;
if (!doneright) { goto alloc_inode;
error = xfs_inobt_get_rec(cur, &rec, &i);
if (error)
goto error1;
XFS_WANT_CORRUPTED_GOTO(i == 1, error1);
} }
/*
* Loop until we find the closest inode chunk
* with a free one.
*/
while (!doneleft || !doneright) {
int useleft; /* using left inode
chunk this time */
/* /* free inodes to the right? */
* Figure out which block is closer, if (!useleft && rec.ir_freecount) {
* if both are valid. xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
*/ goto alloc_inode;
if (!doneleft && !doneright)
useleft =
pagino -
(trec.ir_startino +
XFS_INODES_PER_CHUNK - 1) <
rec.ir_startino - pagino;
else
useleft = !doneleft;
/*
* If checking the left, does it have
* free inodes?
*/
if (useleft && trec.ir_freecount) {
/*
* Yes, set it up as the chunk to use.
*/
rec = trec;
xfs_btree_del_cursor(cur,
XFS_BTREE_NOERROR);
cur = tcur;
break;
}
/*
* If checking the right, does it have
* free inodes?
*/
if (!useleft && rec.ir_freecount) {
/*
* Yes, it's already set up.
*/
xfs_btree_del_cursor(tcur,
XFS_BTREE_NOERROR);
break;
}
/*
* If used the left, get another one
* further left.
*/
if (useleft) {
if ((error = xfs_btree_decrement(tcur, 0,
&i)))
goto error1;
doneleft = !i;
if (!doneleft) {
error = xfs_inobt_get_rec(
tcur, &trec, &i);
if (error)
goto error1;
XFS_WANT_CORRUPTED_GOTO(i == 1,
error1);
}
}
/*
* If used the right, get another one
* further right.
*/
else {
if ((error = xfs_btree_increment(cur, 0,
&i)))
goto error1;
doneright = !i;
if (!doneright) {
error = xfs_inobt_get_rec(
cur, &rec, &i);
if (error)
goto error1;
XFS_WANT_CORRUPTED_GOTO(i == 1,
error1);
}
}
} }
ASSERT(!doneleft || !doneright);
/* get next record to check */
if (useleft) {
error = xfs_ialloc_next_rec(tcur, &trec,
&doneleft, 1);
} else {
error = xfs_ialloc_next_rec(cur, &rec,
&doneright, 0);
}
if (error)
goto error1;
} }
ASSERT(!doneleft || !doneright);
} }
/* /*
* In a different a.g. from the parent. * In a different AG from the parent.
* See if the most recently allocated block has any free. * See if the most recently allocated block has any free.
*/ */
else if (be32_to_cpu(agi->agi_newino) != NULLAGINO) { else if (be32_to_cpu(agi->agi_newino) != NULLAGINO) {
if ((error = xfs_inobt_lookup_eq(cur, error = xfs_inobt_lookup_eq(cur, be32_to_cpu(agi->agi_newino),
be32_to_cpu(agi->agi_newino), 0, 0, &i))) 0, 0, &i);
if (error)
goto error0; goto error0;
if (i == 1 &&
(error = xfs_inobt_get_rec(cur, &rec, &j)) == 0 && if (i == 1) {
j == 1 && error = xfs_inobt_get_rec(cur, &rec, &j);
rec.ir_freecount > 0) { if (error)
/* goto error0;
* The last chunk allocated in the group still has
* a free inode. if (j == 1 && rec.ir_freecount > 0) {
*/ /*
* The last chunk allocated in the group
* still has a free inode.
*/
goto alloc_inode;
}
} }
/* /*
* None left in the last group, search the whole a.g. * None left in the last group, search the whole AG
*/ */
else { error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i);
if (error)
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
for (;;) {
error = xfs_inobt_get_rec(cur, &rec, &i);
if (error) if (error)
goto error0; goto error0;
if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
if (rec.ir_freecount > 0)
break;
error = xfs_btree_increment(cur, 0, &i);
if (error)
goto error0; goto error0;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
for (;;) {
error = xfs_inobt_get_rec(cur, &rec, &i);
if (error)
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
if (rec.ir_freecount > 0)
break;
if ((error = xfs_btree_increment(cur, 0, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
}
} }
} }
alloc_inode:
offset = xfs_ialloc_find_free(&rec.ir_free); offset = xfs_ialloc_find_free(&rec.ir_free);
ASSERT(offset >= 0); ASSERT(offset >= 0);
ASSERT(offset < XFS_INODES_PER_CHUNK); ASSERT(offset < XFS_INODES_PER_CHUNK);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment