Skip to content

Commit ebf5587

Browse files
Christoph Hellwigdjwong
authored andcommitted
xfs: improve handling of busy extents in the low-level allocator
Currently we force the log and simply try again if we hit a busy extent, but especially with online discard enabled it might take a while after the log force for the busy extents to disappear, and we might have already completed our second pass. So instead we add a new waitqueue and a generation counter to the pag structure so that we can do wakeups once we've removed busy extents, and we replace the single retry with an unconditional one - after all we hold the AGF buffer lock, so no other allocations or frees can be racing with us in this AG. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
1 parent 5e30c23 commit ebf5587

File tree

5 files changed

+166
-73
lines changed

5 files changed

+166
-73
lines changed

fs/xfs/libxfs/xfs_alloc.c

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -221,20 +221,22 @@ xfs_alloc_get_rec(
221221
* Compute aligned version of the found extent.
222222
* Takes alignment and min length into account.
223223
*/
224-
STATIC void
224+
STATIC bool
225225
xfs_alloc_compute_aligned(
226226
xfs_alloc_arg_t *args, /* allocation argument structure */
227227
xfs_agblock_t foundbno, /* starting block in found extent */
228228
xfs_extlen_t foundlen, /* length in found extent */
229229
xfs_agblock_t *resbno, /* result block number */
230-
xfs_extlen_t *reslen) /* result length */
230+
xfs_extlen_t *reslen, /* result length */
231+
unsigned *busy_gen)
231232
{
232-
xfs_agblock_t bno;
233-
xfs_extlen_t len;
233+
xfs_agblock_t bno = foundbno;
234+
xfs_extlen_t len = foundlen;
234235
xfs_extlen_t diff;
236+
bool busy;
235237

236238
/* Trim busy sections out of found extent */
237-
xfs_extent_busy_trim(args, foundbno, foundlen, &bno, &len);
239+
busy = xfs_extent_busy_trim(args, &bno, &len, busy_gen);
238240

239241
/*
240242
* If we have a largish extent that happens to start before min_agbno,
@@ -259,6 +261,8 @@ xfs_alloc_compute_aligned(
259261
*resbno = bno;
260262
*reslen = len;
261263
}
264+
265+
return busy;
262266
}
263267

264268
/*
@@ -737,10 +741,11 @@ xfs_alloc_ag_vextent_exact(
737741
int error;
738742
xfs_agblock_t fbno; /* start block of found extent */
739743
xfs_extlen_t flen; /* length of found extent */
740-
xfs_agblock_t tbno; /* start block of trimmed extent */
741-
xfs_extlen_t tlen; /* length of trimmed extent */
742-
xfs_agblock_t tend; /* end block of trimmed extent */
744+
xfs_agblock_t tbno; /* start block of busy extent */
745+
xfs_extlen_t tlen; /* length of busy extent */
746+
xfs_agblock_t tend; /* end block of busy extent */
743747
int i; /* success/failure of operation */
748+
unsigned busy_gen;
744749

745750
ASSERT(args->alignment == 1);
746751

@@ -773,7 +778,9 @@ xfs_alloc_ag_vextent_exact(
773778
/*
774779
* Check for overlapping busy extents.
775780
*/
776-
xfs_extent_busy_trim(args, fbno, flen, &tbno, &tlen);
781+
tbno = fbno;
782+
tlen = flen;
783+
xfs_extent_busy_trim(args, &tbno, &tlen, &busy_gen);
777784

778785
/*
779786
* Give up if the start of the extent is busy, or the freespace isn't
@@ -853,6 +860,7 @@ xfs_alloc_find_best_extent(
853860
xfs_agblock_t sdiff;
854861
int error;
855862
int i;
863+
unsigned busy_gen;
856864

857865
/* The good extent is perfect, no need to search. */
858866
if (!gdiff)
@@ -866,7 +874,8 @@ xfs_alloc_find_best_extent(
866874
if (error)
867875
goto error0;
868876
XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
869-
xfs_alloc_compute_aligned(args, *sbno, *slen, sbnoa, slena);
877+
xfs_alloc_compute_aligned(args, *sbno, *slen,
878+
sbnoa, slena, &busy_gen);
870879

871880
/*
872881
* The good extent is closer than this one.
@@ -955,7 +964,8 @@ xfs_alloc_ag_vextent_near(
955964
xfs_extlen_t ltlena; /* aligned ... */
956965
xfs_agblock_t ltnew; /* useful start bno of left side */
957966
xfs_extlen_t rlen; /* length of returned extent */
958-
int forced = 0;
967+
bool busy;
968+
unsigned busy_gen;
959969
#ifdef DEBUG
960970
/*
961971
* Randomly don't execute the first algorithm.
@@ -982,6 +992,7 @@ xfs_alloc_ag_vextent_near(
982992
ltlen = 0;
983993
gtlena = 0;
984994
ltlena = 0;
995+
busy = false;
985996

986997
/*
987998
* Get a cursor for the by-size btree.
@@ -1064,8 +1075,8 @@ xfs_alloc_ag_vextent_near(
10641075
if ((error = xfs_alloc_get_rec(cnt_cur, &ltbno, &ltlen, &i)))
10651076
goto error0;
10661077
XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
1067-
xfs_alloc_compute_aligned(args, ltbno, ltlen,
1068-
&ltbnoa, &ltlena);
1078+
busy = xfs_alloc_compute_aligned(args, ltbno, ltlen,
1079+
&ltbnoa, &ltlena, &busy_gen);
10691080
if (ltlena < args->minlen)
10701081
continue;
10711082
if (ltbnoa < args->min_agbno || ltbnoa > args->max_agbno)
@@ -1183,8 +1194,8 @@ xfs_alloc_ag_vextent_near(
11831194
if ((error = xfs_alloc_get_rec(bno_cur_lt, &ltbno, &ltlen, &i)))
11841195
goto error0;
11851196
XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
1186-
xfs_alloc_compute_aligned(args, ltbno, ltlen,
1187-
&ltbnoa, &ltlena);
1197+
busy |= xfs_alloc_compute_aligned(args, ltbno, ltlen,
1198+
&ltbnoa, &ltlena, &busy_gen);
11881199
if (ltlena >= args->minlen && ltbnoa >= args->min_agbno)
11891200
break;
11901201
if ((error = xfs_btree_decrement(bno_cur_lt, 0, &i)))
@@ -1199,8 +1210,8 @@ xfs_alloc_ag_vextent_near(
11991210
if ((error = xfs_alloc_get_rec(bno_cur_gt, &gtbno, &gtlen, &i)))
12001211
goto error0;
12011212
XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
1202-
xfs_alloc_compute_aligned(args, gtbno, gtlen,
1203-
&gtbnoa, &gtlena);
1213+
busy |= xfs_alloc_compute_aligned(args, gtbno, gtlen,
1214+
&gtbnoa, &gtlena, &busy_gen);
12041215
if (gtlena >= args->minlen && gtbnoa <= args->max_agbno)
12051216
break;
12061217
if ((error = xfs_btree_increment(bno_cur_gt, 0, &i)))
@@ -1261,9 +1272,9 @@ xfs_alloc_ag_vextent_near(
12611272
if (bno_cur_lt == NULL && bno_cur_gt == NULL) {
12621273
xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
12631274

1264-
if (!forced++) {
1275+
if (busy) {
12651276
trace_xfs_alloc_near_busy(args);
1266-
xfs_log_force(args->mp, XFS_LOG_SYNC);
1277+
xfs_extent_busy_flush(args->mp, args->pag, busy_gen);
12671278
goto restart;
12681279
}
12691280
trace_xfs_alloc_size_neither(args);
@@ -1344,7 +1355,8 @@ xfs_alloc_ag_vextent_size(
13441355
int i; /* temp status variable */
13451356
xfs_agblock_t rbno; /* returned block number */
13461357
xfs_extlen_t rlen; /* length of returned extent */
1347-
int forced = 0;
1358+
bool busy;
1359+
unsigned busy_gen;
13481360

13491361
restart:
13501362
/*
@@ -1353,6 +1365,7 @@ xfs_alloc_ag_vextent_size(
13531365
cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
13541366
args->agno, XFS_BTNUM_CNT);
13551367
bno_cur = NULL;
1368+
busy = false;
13561369

13571370
/*
13581371
* Look for an entry >= maxlen+alignment-1 blocks.
@@ -1362,14 +1375,13 @@ xfs_alloc_ag_vextent_size(
13621375
goto error0;
13631376

13641377
/*
1365-
* If none or we have busy extents that we cannot allocate from, then
1366-
* we have to settle for a smaller extent. In the case that there are
1367-
* no large extents, this will return the last entry in the tree unless
1368-
* the tree is empty. In the case that there are only busy large
1369-
* extents, this will return the largest small extent unless there
1378+
* If none then we have to settle for a smaller extent. In the case that
1379+
* there are no large extents, this will return the last entry in the
1380+
* tree unless the tree is empty. In the case that there are only busy
1381+
* large extents, this will return the largest small extent unless there
13701382
* are no smaller extents available.
13711383
*/
1372-
if (!i || forced > 1) {
1384+
if (!i) {
13731385
error = xfs_alloc_ag_vextent_small(args, cnt_cur,
13741386
&fbno, &flen, &i);
13751387
if (error)
@@ -1380,22 +1392,20 @@ xfs_alloc_ag_vextent_size(
13801392
return 0;
13811393
}
13821394
ASSERT(i == 1);
1383-
xfs_alloc_compute_aligned(args, fbno, flen, &rbno, &rlen);
1395+
busy = xfs_alloc_compute_aligned(args, fbno, flen, &rbno,
1396+
&rlen, &busy_gen);
13841397
} else {
13851398
/*
13861399
* Search for a non-busy extent that is large enough.
1387-
* If we are at low space, don't check, or if we fall of
1388-
* the end of the btree, turn off the busy check and
1389-
* restart.
13901400
*/
13911401
for (;;) {
13921402
error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i);
13931403
if (error)
13941404
goto error0;
13951405
XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
13961406

1397-
xfs_alloc_compute_aligned(args, fbno, flen,
1398-
&rbno, &rlen);
1407+
busy = xfs_alloc_compute_aligned(args, fbno, flen,
1408+
&rbno, &rlen, &busy_gen);
13991409

14001410
if (rlen >= args->maxlen)
14011411
break;
@@ -1407,18 +1417,13 @@ xfs_alloc_ag_vextent_size(
14071417
/*
14081418
* Our only valid extents must have been busy.
14091419
* Make it unbusy by forcing the log out and
1410-
* retrying. If we've been here before, forcing
1411-
* the log isn't making the extents available,
1412-
* which means they have probably been freed in
1413-
* this transaction. In that case, we have to
1414-
* give up on them and we'll attempt a minlen
1415-
* allocation the next time around.
1420+
* retrying.
14161421
*/
14171422
xfs_btree_del_cursor(cnt_cur,
14181423
XFS_BTREE_NOERROR);
14191424
trace_xfs_alloc_size_busy(args);
1420-
if (!forced++)
1421-
xfs_log_force(args->mp, XFS_LOG_SYNC);
1425+
xfs_extent_busy_flush(args->mp,
1426+
args->pag, busy_gen);
14221427
goto restart;
14231428
}
14241429
}
@@ -1454,8 +1459,8 @@ xfs_alloc_ag_vextent_size(
14541459
XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
14551460
if (flen < bestrlen)
14561461
break;
1457-
xfs_alloc_compute_aligned(args, fbno, flen,
1458-
&rbno, &rlen);
1462+
busy = xfs_alloc_compute_aligned(args, fbno, flen,
1463+
&rbno, &rlen, &busy_gen);
14591464
rlen = XFS_EXTLEN_MIN(args->maxlen, rlen);
14601465
XFS_WANT_CORRUPTED_GOTO(args->mp, rlen == 0 ||
14611466
(rlen <= flen && rbno + rlen <= fbno + flen),
@@ -1484,10 +1489,10 @@ xfs_alloc_ag_vextent_size(
14841489
*/
14851490
args->len = rlen;
14861491
if (rlen < args->minlen) {
1487-
if (!forced++) {
1492+
if (busy) {
14881493
xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
14891494
trace_xfs_alloc_size_busy(args);
1490-
xfs_log_force(args->mp, XFS_LOG_SYNC);
1495+
xfs_extent_busy_flush(args->mp, args->pag, busy_gen);
14911496
goto restart;
14921497
}
14931498
goto out_nominleft;

0 commit comments

Comments
 (0)