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:
committed by
Alex Elder
parent
9f9baab38d
commit
489a150f64
@@ -664,6 +664,95 @@ error0:
|
|||||||
return error;
|
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.
|
* Allocate a variable extent near bno in the allocation group agno.
|
||||||
* Extent's length (returned in len) will be between minlen and maxlen,
|
* 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);
|
} while (bno_cur_lt || bno_cur_gt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Got both cursors still active, need to find better entry.
|
* Got both cursors still active, need to find better entry.
|
||||||
*/
|
*/
|
||||||
if (bno_cur_lt && bno_cur_gt) {
|
if (bno_cur_lt && bno_cur_gt) {
|
||||||
/*
|
|
||||||
* Left side is long enough, look for a right side entry.
|
|
||||||
*/
|
|
||||||
if (ltlena >= args->minlen) {
|
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);
|
args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
|
||||||
xfs_alloc_fix_len(args);
|
xfs_alloc_fix_len(args);
|
||||||
rlen = args->len;
|
ltdiff = xfs_alloc_compute_diff(args->agbno, args->len,
|
||||||
ltdiff = xfs_alloc_compute_diff(args->agbno, rlen,
|
|
||||||
args->alignment, ltbno, ltlen, <new);
|
args->alignment, ltbno, ltlen, <new);
|
||||||
|
|
||||||
|
error = xfs_alloc_find_best_extent(args,
|
||||||
|
&bno_cur_lt, &bno_cur_gt,
|
||||||
|
ltdiff, >bno, >len, >lena,
|
||||||
|
0 /* search right */);
|
||||||
|
} else {
|
||||||
|
ASSERT(gtlena >= args->minlen);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not perfect.
|
* Right side is good, look for a left side entry.
|
||||||
*/
|
|
||||||
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, >bno,
|
|
||||||
>len, &i)))
|
|
||||||
goto error0;
|
|
||||||
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
|
|
||||||
xfs_alloc_compute_aligned(gtbno, gtlen,
|
|
||||||
args->alignment, args->minlen,
|
|
||||||
>bnoa, >lena);
|
|
||||||
/*
|
|
||||||
* 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, >new);
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen);
|
args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen);
|
||||||
xfs_alloc_fix_len(args);
|
xfs_alloc_fix_len(args);
|
||||||
rlen = args->len;
|
gtdiff = xfs_alloc_compute_diff(args->agbno, args->len,
|
||||||
gtdiff = xfs_alloc_compute_diff(args->agbno, rlen,
|
|
||||||
args->alignment, gtbno, gtlen, >new);
|
args->alignment, gtbno, gtlen, >new);
|
||||||
/*
|
|
||||||
* Right side entry isn't perfect.
|
error = xfs_alloc_find_best_extent(args,
|
||||||
*/
|
&bno_cur_gt, &bno_cur_lt,
|
||||||
if (gtdiff) {
|
gtdiff, <bno, <len, <lena,
|
||||||
/*
|
1 /* search left */);
|
||||||
* 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, <bno,
|
|
||||||
<len, &i)))
|
|
||||||
goto error0;
|
|
||||||
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
|
|
||||||
xfs_alloc_compute_aligned(ltbno, ltlen,
|
|
||||||
args->alignment, args->minlen,
|
|
||||||
<bnoa, <lena);
|
|
||||||
/*
|
|
||||||
* 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, <new);
|
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
goto error0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we couldn't get anything, give up.
|
* If we couldn't get anything, give up.
|
||||||
*/
|
*/
|
||||||
@@ -1136,6 +1067,7 @@ xfs_alloc_ag_vextent_near(
|
|||||||
args->agbno = NULLAGBLOCK;
|
args->agbno = NULLAGBLOCK;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point we have selected a freespace entry, either to the
|
* 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
|
* 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;
|
j = 1;
|
||||||
} else
|
} else
|
||||||
j = 0;
|
j = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fix up the length and compute the useful address.
|
* Fix up the length and compute the useful address.
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user