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: Christoph Hellwig <hch@lst.de> Reviewed-by: Alex Elder <aelder@sgi.com> Signed-off-by: Felix Blyakher <felixb@sgi.com>
This commit is contained in:
committed by
Felix Blyakher
parent
0b48db80ba
commit
4254b0bbb1
@@ -589,6 +589,37 @@ nextag:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(
|
|||||||
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 @@ nextag:
|
|||||||
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;
|
goto error0;
|
||||||
if (i != 0 &&
|
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
|
||||||
(error = xfs_inobt_get_rec(cur, &rec, &j)) == 0 &&
|
|
||||||
j == 1 &&
|
error = xfs_inobt_get_rec(cur, &rec, &j);
|
||||||
rec.ir_freecount > 0) {
|
if (error)
|
||||||
|
goto error0;
|
||||||
|
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
|
||||||
|
|
||||||
|
if (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 */
|
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* search right with cur, go forward 1 record. */
|
||||||
|
error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0);
|
||||||
|
if (error)
|
||||||
|
goto error1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop until we find an inode chunk with a free inode.
|
||||||
|
*/
|
||||||
|
while (!doneleft || !doneright) {
|
||||||
|
int useleft; /* using left inode chunk this time */
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free inodes to the left? */
|
||||||
|
if (useleft && trec.ir_freecount) {
|
||||||
|
rec = trec;
|
||||||
|
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
|
||||||
|
cur = tcur;
|
||||||
|
goto alloc_inode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free inodes to the right? */
|
||||||
|
if (!useleft && rec.ir_freecount) {
|
||||||
|
xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
|
||||||
|
goto alloc_inode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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)
|
if (error)
|
||||||
goto error0;
|
|
||||||
ASSERT(i == 1);
|
|
||||||
ASSERT(j == 1);
|
|
||||||
/*
|
|
||||||
* Duplicate the cursor, search left & right
|
|
||||||
* simultaneously.
|
|
||||||
*/
|
|
||||||
if ((error = xfs_btree_dup_cursor(cur, &tcur)))
|
|
||||||
goto error0;
|
|
||||||
/*
|
|
||||||
* Search left with tcur, back up 1 record.
|
|
||||||
*/
|
|
||||||
if ((error = xfs_btree_decrement(tcur, 0, &i)))
|
|
||||||
goto error1;
|
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.
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Loop until we find the closest inode chunk
|
|
||||||
* with a free one.
|
|
||||||
*/
|
|
||||||
while (!doneleft || !doneright) {
|
|
||||||
int useleft; /* using left inode
|
|
||||||
chunk this time */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Figure out which block is closer,
|
|
||||||
* if both are valid.
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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) {
|
|
||||||
/*
|
|
||||||
* The last chunk allocated in the group still has
|
|
||||||
* a free inode.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* None left in the last group, search the whole a.g.
|
|
||||||
*/
|
|
||||||
else {
|
|
||||||
if (error)
|
if (error)
|
||||||
goto error0;
|
goto error0;
|
||||||
if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i)))
|
|
||||||
goto error0;
|
if (j == 1 && rec.ir_freecount > 0) {
|
||||||
ASSERT(i == 1);
|
/*
|
||||||
for (;;) {
|
* The last chunk allocated in the group
|
||||||
error = xfs_inobt_get_rec(cur, &rec, &i);
|
* still has a free inode.
|
||||||
if (error)
|
*/
|
||||||
goto error0;
|
goto alloc_inode;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* None left in the last group, search the whole AG
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
goto error0;
|
||||||
|
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
|
||||||
|
if (rec.ir_freecount > 0)
|
||||||
|
break;
|
||||||
|
error = xfs_btree_increment(cur, 0, &i);
|
||||||
|
if (error)
|
||||||
|
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);
|
||||||
|
Reference in New Issue
Block a user