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,173 +812,125 @@ xfs_dialloc( ...@@ -781,173 +812,125 @@ 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)))
goto error0;
if (i != 0 &&
(error = xfs_inobt_get_rec(cur, &rec, &j)) == 0 &&
j == 1 &&
rec.ir_freecount > 0) {
/*
* Found a free inode in the same chunk
* as parent, done.
*/
}
/*
* In the same a.g. as parent, but parent's chunk is full.
*/
else {
int doneleft; /* done, to the left */ int doneleft; /* done, to the left */
int doneright; /* done, to the right */ int doneright; /* done, to the right */
error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i);
if (error) if (error)
goto error0; goto error0;
ASSERT(i == 1); XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
ASSERT(j == 1);
/* error = xfs_inobt_get_rec(cur, &rec, &j);
* Duplicate the cursor, search left & right if (error)
* simultaneously.
*/
if ((error = xfs_btree_dup_cursor(cur, &tcur)))
goto error0; goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
if (rec.ir_freecount > 0) {
/* /*
* Search left with tcur, back up 1 record. * Found a free inode in the same chunk
* as the parent, done.
*/ */
if ((error = xfs_btree_decrement(tcur, 0, &i))) goto alloc_inode;
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);
} }
/* /*
* Search right with cur, go forward 1 record. * In the same AG as parent, but parent's chunk is full.
*/ */
if ((error = xfs_btree_increment(cur, 0, &i)))
/* duplicate the cursor, search left & right simultaneously */
error = xfs_btree_dup_cursor(cur, &tcur);
if (error)
goto error0;
/* search left with tcur, back up 1 record */
error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1);
if (error)
goto error1; goto error1;
doneright = !i;
if (!doneright) { /* search right with cur, go forward 1 record. */
error = xfs_inobt_get_rec(cur, &rec, &i); error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0);
if (error) if (error)
goto error1; goto error1;
XFS_WANT_CORRUPTED_GOTO(i == 1, error1);
}
/* /*
* Loop until we find the closest inode chunk * Loop until we find an inode chunk with a free inode.
* with a free one.
*/ */
while (!doneleft || !doneright) { while (!doneleft || !doneright) {
int useleft; /* using left inode int useleft; /* using left inode chunk this time */
chunk this time */
/* /* figure out the closer block if both are valid. */
* Figure out which block is closer, if (!doneleft && !doneright) {
* if both are valid. useleft = pagino -
*/ (trec.ir_startino + XFS_INODES_PER_CHUNK - 1) <
if (!doneleft && !doneright)
useleft =
pagino -
(trec.ir_startino +
XFS_INODES_PER_CHUNK - 1) <
rec.ir_startino - pagino; rec.ir_startino - pagino;
else } else {
useleft = !doneleft; useleft = !doneleft;
/* }
* If checking the left, does it have
* free inodes? /* free inodes to the left? */
*/
if (useleft && trec.ir_freecount) { if (useleft && trec.ir_freecount) {
/*
* Yes, set it up as the chunk to use.
*/
rec = trec; rec = trec;
xfs_btree_del_cursor(cur, xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
XFS_BTREE_NOERROR);
cur = tcur; cur = tcur;
break; goto alloc_inode;
} }
/*
* If checking the right, does it have /* free inodes to the right? */
* free inodes?
*/
if (!useleft && rec.ir_freecount) { if (!useleft && rec.ir_freecount) {
/* xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
* Yes, it's already set up. goto alloc_inode;
*/
xfs_btree_del_cursor(tcur,
XFS_BTREE_NOERROR);
break;
} }
/*
* If used the left, get another one /* get next record to check */
* further left.
*/
if (useleft) { if (useleft) {
if ((error = xfs_btree_decrement(tcur, 0, error = xfs_ialloc_next_rec(tcur, &trec,
&i))) &doneleft, 1);
goto error1; } else {
doneleft = !i; error = xfs_ialloc_next_rec(cur, &rec,
if (!doneleft) { &doneright, 0);
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) if (error)
goto error1; goto error1;
XFS_WANT_CORRUPTED_GOTO(i == 1,
error1);
}
}
} }
ASSERT(!doneleft || !doneright); 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;
if (i == 1) {
error = xfs_inobt_get_rec(cur, &rec, &j);
if (error)
goto error0; goto error0;
if (i == 1 &&
(error = xfs_inobt_get_rec(cur, &rec, &j)) == 0 && if (j == 1 && rec.ir_freecount > 0) {
j == 1 &&
rec.ir_freecount > 0) {
/* /*
* The last chunk allocated in the group still has * The last chunk allocated in the group
* a free inode. * 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) if (error)
goto error0; goto error0;
if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
goto error0;
ASSERT(i == 1);
for (;;) { for (;;) {
error = xfs_inobt_get_rec(cur, &rec, &i); error = xfs_inobt_get_rec(cur, &rec, &i);
if (error) if (error)
...@@ -955,12 +938,14 @@ xfs_dialloc( ...@@ -955,12 +938,14 @@ xfs_dialloc(
XFS_WANT_CORRUPTED_GOTO(i == 1, error0); XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
if (rec.ir_freecount > 0) if (rec.ir_freecount > 0)
break; break;
if ((error = xfs_btree_increment(cur, 0, &i))) error = xfs_btree_increment(cur, 0, &i);
if (error)
goto error0; goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, 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