dect
/
linux-2.6
Archived
13
0
Fork 0

xfs: factor duplicate code in xfs_alloc_ag_vextent_near into a helper

Add a new xfs_alloc_find_best_extent that does a forward/backward
search in the allocation btree.  That code previously was existed
two times in xfs_alloc_ag_vextent_near, once for each search
direction.

Based on an earlier patch from Dave Chinner.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
This commit is contained in:
Christoph Hellwig 2010-12-10 15:04:11 +00:00 committed by Alex Elder
parent 9f9baab38d
commit 489a150f64
1 changed files with 113 additions and 180 deletions

View File

@ -664,6 +664,95 @@ error0:
return error;
}
/*
* Search the btree in a given direction via the search cursor and compare
* the records found against the good extent we've already found.
*/
STATIC int
xfs_alloc_find_best_extent(
struct xfs_alloc_arg *args, /* allocation argument structure */
struct xfs_btree_cur **gcur, /* good cursor */
struct xfs_btree_cur **scur, /* searching cursor */
xfs_agblock_t gdiff, /* difference for search comparison */
xfs_agblock_t *sbno, /* extent found by search */
xfs_extlen_t *slen,
xfs_extlen_t *slena, /* aligned length */
int dir) /* 0 = search right, 1 = search left */
{
xfs_agblock_t bno;
xfs_agblock_t new;
xfs_agblock_t sdiff;
int error;
int i;
/* The good extent is perfect, no need to search. */
if (!gdiff)
goto out_use_good;
/*
* Look until we find a better one, run out of space or run off the end.
*/
do {
error = xfs_alloc_get_rec(*scur, sbno, slen, &i);
if (error)
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
xfs_alloc_compute_aligned(*sbno, *slen, args->alignment,
args->minlen, &bno, slena);
/*
* The good extent is closer than this one.
*/
if (!dir) {
if (bno >= args->agbno + gdiff)
goto out_use_good;
} else {
if (bno <= args->agbno - gdiff)
goto out_use_good;
}
/*
* Same distance, compare length and pick the best.
*/
if (*slena >= args->minlen) {
args->len = XFS_EXTLEN_MIN(*slena, args->maxlen);
xfs_alloc_fix_len(args);
sdiff = xfs_alloc_compute_diff(args->agbno, args->len,
args->alignment, *sbno,
*slen, &new);
/*
* Choose closer size and invalidate other cursor.
*/
if (sdiff < gdiff)
goto out_use_search;
goto out_use_good;
}
if (!dir)
error = xfs_btree_increment(*scur, 0, &i);
else
error = xfs_btree_decrement(*scur, 0, &i);
if (error)
goto error0;
} while (i);
out_use_good:
xfs_btree_del_cursor(*scur, XFS_BTREE_NOERROR);
*scur = NULL;
return 0;
out_use_search:
xfs_btree_del_cursor(*gcur, XFS_BTREE_NOERROR);
*gcur = NULL;
return 0;
error0:
/* caller invalidates cursors */
return error;
}
/*
* Allocate a variable extent near bno in the allocation group agno.
* Extent's length (returned in len) will be between minlen and maxlen,
@ -931,203 +1020,45 @@ xfs_alloc_ag_vextent_near(
}
}
} while (bno_cur_lt || bno_cur_gt);
/*
* Got both cursors still active, need to find better entry.
*/
if (bno_cur_lt && bno_cur_gt) {
/*
* Left side is long enough, look for a right side entry.
*/
if (ltlena >= args->minlen) {
/*
* Fix up the length.
* Left side is good, look for a right side entry.
*/
args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
xfs_alloc_fix_len(args);
rlen = args->len;
ltdiff = xfs_alloc_compute_diff(args->agbno, rlen,
ltdiff = xfs_alloc_compute_diff(args->agbno, args->len,
args->alignment, ltbno, ltlen, &ltnew);
error = xfs_alloc_find_best_extent(args,
&bno_cur_lt, &bno_cur_gt,
ltdiff, &gtbno, &gtlen, &gtlena,
0 /* search right */);
} else {
ASSERT(gtlena >= args->minlen);
/*
* Not perfect.
*/
if (ltdiff) {
/*
* Look until we find a better one, run out of
* space, or run off the end.
*/
while (bno_cur_lt && bno_cur_gt) {
if ((error = xfs_alloc_get_rec(
bno_cur_gt, &gtbno,
&gtlen, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
xfs_alloc_compute_aligned(gtbno, gtlen,
args->alignment, args->minlen,
&gtbnoa, &gtlena);
/*
* The left one is clearly better.
*/
if (gtbnoa >= args->agbno + ltdiff) {
xfs_btree_del_cursor(
bno_cur_gt,
XFS_BTREE_NOERROR);
bno_cur_gt = NULL;
break;
}
/*
* If we reach a big enough entry,
* compare the two and pick the best.
*/
if (gtlena >= args->minlen) {
args->len =
XFS_EXTLEN_MIN(gtlena,
args->maxlen);
xfs_alloc_fix_len(args);
rlen = args->len;
gtdiff = xfs_alloc_compute_diff(
args->agbno, rlen,
args->alignment,
gtbno, gtlen, &gtnew);
/*
* Right side is better.
*/
if (gtdiff < ltdiff) {
xfs_btree_del_cursor(
bno_cur_lt,
XFS_BTREE_NOERROR);
bno_cur_lt = NULL;
}
/*
* Left side is better.
*/
else {
xfs_btree_del_cursor(
bno_cur_gt,
XFS_BTREE_NOERROR);
bno_cur_gt = NULL;
}
break;
}
/*
* Fell off the right end.
*/
if ((error = xfs_btree_increment(
bno_cur_gt, 0, &i)))
goto error0;
if (!i) {
xfs_btree_del_cursor(
bno_cur_gt,
XFS_BTREE_NOERROR);
bno_cur_gt = NULL;
break;
}
}
}
/*
* The left side is perfect, trash the right side.
*/
else {
xfs_btree_del_cursor(bno_cur_gt,
XFS_BTREE_NOERROR);
bno_cur_gt = NULL;
}
}
/*
* It's the right side that was found first, look left.
*/
else {
/*
* Fix up the length.
* Right side is good, look for a left side entry.
*/
args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen);
xfs_alloc_fix_len(args);
rlen = args->len;
gtdiff = xfs_alloc_compute_diff(args->agbno, rlen,
gtdiff = xfs_alloc_compute_diff(args->agbno, args->len,
args->alignment, gtbno, gtlen, &gtnew);
/*
* Right side entry isn't perfect.
*/
if (gtdiff) {
/*
* Look until we find a better one, run out of
* space, or run off the end.
*/
while (bno_cur_lt && bno_cur_gt) {
if ((error = xfs_alloc_get_rec(
bno_cur_lt, &ltbno,
&ltlen, &i)))
goto error0;
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
xfs_alloc_compute_aligned(ltbno, ltlen,
args->alignment, args->minlen,
&ltbnoa, &ltlena);
/*
* The right one is clearly better.
*/
if (ltbnoa <= args->agbno - gtdiff) {
xfs_btree_del_cursor(
bno_cur_lt,
XFS_BTREE_NOERROR);
bno_cur_lt = NULL;
break;
}
/*
* If we reach a big enough entry,
* compare the two and pick the best.
*/
if (ltlena >= args->minlen) {
args->len = XFS_EXTLEN_MIN(
ltlena, args->maxlen);
xfs_alloc_fix_len(args);
rlen = args->len;
ltdiff = xfs_alloc_compute_diff(
args->agbno, rlen,
args->alignment,
ltbno, ltlen, &ltnew);
/*
* Left side is better.
*/
if (ltdiff < gtdiff) {
xfs_btree_del_cursor(
bno_cur_gt,
XFS_BTREE_NOERROR);
bno_cur_gt = NULL;
}
/*
* Right side is better.
*/
else {
xfs_btree_del_cursor(
bno_cur_lt,
XFS_BTREE_NOERROR);
bno_cur_lt = NULL;
}
break;
}
/*
* Fell off the left end.
*/
if ((error = xfs_btree_decrement(
bno_cur_lt, 0, &i)))
goto error0;
if (!i) {
xfs_btree_del_cursor(bno_cur_lt,
XFS_BTREE_NOERROR);
bno_cur_lt = NULL;
break;
}
}
}
/*
* The right side is perfect, trash the left side.
*/
else {
xfs_btree_del_cursor(bno_cur_lt,
XFS_BTREE_NOERROR);
bno_cur_lt = NULL;
}
error = xfs_alloc_find_best_extent(args,
&bno_cur_gt, &bno_cur_lt,
gtdiff, &ltbno, &ltlen, &ltlena,
1 /* search left */);
}
if (error)
goto error0;
}
/*
* If we couldn't get anything, give up.
*/
@ -1136,6 +1067,7 @@ xfs_alloc_ag_vextent_near(
args->agbno = NULLAGBLOCK;
return 0;
}
/*
* At this point we have selected a freespace entry, either to the
* left or to the right. If it's on the right, copy all the
@ -1152,6 +1084,7 @@ xfs_alloc_ag_vextent_near(
j = 1;
} else
j = 0;
/*
* Fix up the length and compute the useful address.
*/