diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index 0ecc142c833b..664e2ad72542 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -710,8 +710,71 @@ xfs_alloc_update_counters( } /* - * Allocation group level functions. + * Block allocation algorithm and data structures. */ +struct xfs_alloc_cur { + struct xfs_btree_cur *cnt; /* btree cursors */ + struct xfs_btree_cur *bnolt; + struct xfs_btree_cur *bnogt; +}; + +/* + * Set up cursors, etc. in the extent allocation cursor. This function can be + * called multiple times to reset an initialized structure without having to + * reallocate cursors. + */ +static int +xfs_alloc_cur_setup( + struct xfs_alloc_arg *args, + struct xfs_alloc_cur *acur) +{ + int error; + int i; + + ASSERT(args->alignment == 1 || args->type != XFS_ALLOCTYPE_THIS_BNO); + + /* + * Perform an initial cntbt lookup to check for availability of maxlen + * extents. If this fails, we'll return -ENOSPC to signal the caller to + * attempt a small allocation. + */ + if (!acur->cnt) + acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp, + args->agbp, args->agno, XFS_BTNUM_CNT); + error = xfs_alloc_lookup_ge(acur->cnt, 0, args->maxlen, &i); + if (error) + return error; + + /* + * Allocate the bnobt left and right search cursors. + */ + if (!acur->bnolt) + acur->bnolt = xfs_allocbt_init_cursor(args->mp, args->tp, + args->agbp, args->agno, XFS_BTNUM_BNO); + if (!acur->bnogt) + acur->bnogt = xfs_allocbt_init_cursor(args->mp, args->tp, + args->agbp, args->agno, XFS_BTNUM_BNO); + return i == 1 ? 0 : -ENOSPC; +} + +static void +xfs_alloc_cur_close( + struct xfs_alloc_cur *acur, + bool error) +{ + int cur_error = XFS_BTREE_NOERROR; + + if (error) + cur_error = XFS_BTREE_ERROR; + + if (acur->cnt) + xfs_btree_del_cursor(acur->cnt, cur_error); + if (acur->bnolt) + xfs_btree_del_cursor(acur->bnolt, cur_error); + if (acur->bnogt) + xfs_btree_del_cursor(acur->bnogt, cur_error); + acur->cnt = acur->bnolt = acur->bnogt = NULL; +} /* * Deal with the case where only small freespaces remain. Either return the @@ -1008,8 +1071,8 @@ error0: 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 */ + 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, /* extent length */ @@ -1031,7 +1094,7 @@ xfs_alloc_find_best_extent( * 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); + error = xfs_alloc_get_rec(scur, sbno, slen, &i); if (error) goto error0; XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); @@ -1074,21 +1137,19 @@ xfs_alloc_find_best_extent( } if (!dir) - error = xfs_btree_increment(*scur, 0, &i); + error = xfs_btree_increment(scur, 0, &i); else - error = xfs_btree_decrement(*scur, 0, &i); + 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; + scur->bc_private.a.priv.abt.active = false; return 0; out_use_search: - xfs_btree_del_cursor(*gcur, XFS_BTREE_NOERROR); - *gcur = NULL; + gcur->bc_private.a.priv.abt.active = false; return 0; error0: @@ -1102,13 +1163,12 @@ error0: * and of the form k * prod + mod unless there's nothing that large. * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. */ -STATIC int /* error */ +STATIC int xfs_alloc_ag_vextent_near( - xfs_alloc_arg_t *args) /* allocation argument structure */ + struct xfs_alloc_arg *args) { - xfs_btree_cur_t *bno_cur_gt; /* cursor for bno btree, right side */ - xfs_btree_cur_t *bno_cur_lt; /* cursor for bno btree, left side */ - xfs_btree_cur_t *cnt_cur; /* cursor for count btree */ + struct xfs_alloc_cur acur = {}; + struct xfs_btree_cur *bno_cur; xfs_agblock_t gtbno; /* start bno of right side entry */ xfs_agblock_t gtbnoa; /* aligned ... */ xfs_extlen_t gtdiff; /* difference to right side entry */ @@ -1148,38 +1208,29 @@ xfs_alloc_ag_vextent_near( args->agbno = args->max_agbno; restart: - bno_cur_lt = NULL; - bno_cur_gt = NULL; ltlen = 0; gtlena = 0; ltlena = 0; busy = false; /* - * Get a cursor for the by-size btree. + * Set up cursors and see if there are any free extents as big as + * maxlen. If not, pick the last entry in the tree unless the tree is + * empty. */ - cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_CNT); - - /* - * See if there are any free extents as big as maxlen. - */ - if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, args->maxlen, &i))) - goto error0; - /* - * If none, then pick up the last entry in the tree unless the - * tree is empty. - */ - if (!i) { - if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, <bno, - <len, &i))) - goto error0; + error = xfs_alloc_cur_setup(args, &acur); + if (error == -ENOSPC) { + error = xfs_alloc_ag_vextent_small(args, acur.cnt, <bno, + <len, &i); + if (error) + goto out; if (i == 0 || ltlen == 0) { - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); trace_xfs_alloc_near_noentry(args); - return 0; + goto out; } ASSERT(i == 1); + } else if (error) { + goto out; } args->wasfromfl = 0; @@ -1193,7 +1244,7 @@ restart: * This is written as a while loop so we can break out of it, * but we never loop back to the top. */ - while (xfs_btree_islastblock(cnt_cur, 0)) { + while (xfs_btree_islastblock(acur.cnt, 0)) { xfs_extlen_t bdiff; int besti=0; xfs_extlen_t blen=0; @@ -1210,32 +1261,35 @@ restart: * and skip all those smaller than minlen. */ if (ltlen || args->alignment > 1) { - cnt_cur->bc_ptrs[0] = 1; + acur.cnt->bc_ptrs[0] = 1; do { - if ((error = xfs_alloc_get_rec(cnt_cur, <bno, - <len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); + error = xfs_alloc_get_rec(acur.cnt, <bno, + <len, &i); + if (error) + goto out; + XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, out); if (ltlen >= args->minlen) break; - if ((error = xfs_btree_increment(cnt_cur, 0, &i))) - goto error0; + error = xfs_btree_increment(acur.cnt, 0, &i); + if (error) + goto out; } while (i); ASSERT(ltlen >= args->minlen); if (!i) break; } - i = cnt_cur->bc_ptrs[0]; + i = acur.cnt->bc_ptrs[0]; for (j = 1, blen = 0, bdiff = 0; !error && j && (blen < args->maxlen || bdiff > 0); - error = xfs_btree_increment(cnt_cur, 0, &j)) { + error = xfs_btree_increment(acur.cnt, 0, &j)) { /* * For each entry, decide if it's better than * the previous best entry. */ - if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); + error = xfs_alloc_get_rec(acur.cnt, <bno, <len, &i); + if (error) + goto out; + XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, out); busy = xfs_alloc_compute_aligned(args, ltbno, ltlen, <bnoa, <lena, &busy_gen); if (ltlena < args->minlen) @@ -1255,7 +1309,7 @@ restart: bdiff = ltdiff; bnew = ltnew; blen = args->len; - besti = cnt_cur->bc_ptrs[0]; + besti = acur.cnt->bc_ptrs[0]; } } /* @@ -1267,10 +1321,11 @@ restart: /* * Point at the best entry, and retrieve it again. */ - cnt_cur->bc_ptrs[0] = besti; - if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); + acur.cnt->bc_ptrs[0] = besti; + error = xfs_alloc_get_rec(acur.cnt, <bno, <len, &i); + if (error) + goto out; + XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, out); ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); args->len = blen; @@ -1280,23 +1335,14 @@ restart: args->agbno = bnew; ASSERT(bnew >= ltbno); ASSERT(bnew + blen <= ltbno + ltlen); - /* - * Set up a cursor for the by-bno tree. - */ - bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp, - args->agbp, args->agno, XFS_BTNUM_BNO); - /* - * Fix up the btree entries. - */ - if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, - ltlen, bnew, blen, XFSA_FIXUP_CNT_OK))) - goto error0; - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); - + error = xfs_alloc_fixup_trees(acur.cnt, acur.bnolt, ltbno, + ltlen, bnew, blen, XFSA_FIXUP_CNT_OK); + if (error) + goto out; trace_xfs_alloc_near_first(args); - return 0; + goto out; } + /* * Second algorithm. * Search in the by-bno tree to the left and to the right @@ -1309,86 +1355,57 @@ restart: * level algorithm that picks allocation groups for allocations * is not supposed to do this. */ - /* - * Allocate and initialize the cursor for the leftward search. - */ - bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_BNO); - /* - * Lookup <= bno to find the leftward search's starting point. - */ - if ((error = xfs_alloc_lookup_le(bno_cur_lt, args->agbno, args->maxlen, &i))) - goto error0; - if (!i) { - /* - * Didn't find anything; use this cursor for the rightward - * search. - */ - bno_cur_gt = bno_cur_lt; - bno_cur_lt = NULL; - } - /* - * Found something. Duplicate the cursor for the rightward search. - */ - else if ((error = xfs_btree_dup_cursor(bno_cur_lt, &bno_cur_gt))) - goto error0; - /* - * Increment the cursor, so we will point at the entry just right - * of the leftward entry if any, or to the leftmost entry. - */ - if ((error = xfs_btree_increment(bno_cur_gt, 0, &i))) - goto error0; - if (!i) { - /* - * It failed, there are no rightward entries. - */ - xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_NOERROR); - bno_cur_gt = NULL; - } + error = xfs_alloc_lookup_le(acur.bnolt, args->agbno, 0, &i); + if (error) + goto out; + error = xfs_alloc_lookup_ge(acur.bnogt, args->agbno, 0, &i); + if (error) + goto out; + /* * Loop going left with the leftward cursor, right with the * rightward cursor, until either both directions give up or * we find an entry at least as big as minlen. */ do { - if (bno_cur_lt) { - if ((error = xfs_alloc_get_rec(bno_cur_lt, <bno, <len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); + if (xfs_alloc_cur_active(acur.bnolt)) { + error = xfs_alloc_get_rec(acur.bnolt, <bno, <len, &i); + if (error) + goto out; + XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, out); busy |= xfs_alloc_compute_aligned(args, ltbno, ltlen, <bnoa, <lena, &busy_gen); if (ltlena >= args->minlen && ltbnoa >= args->min_agbno) break; - if ((error = xfs_btree_decrement(bno_cur_lt, 0, &i))) - goto error0; - if (!i || ltbnoa < args->min_agbno) { - xfs_btree_del_cursor(bno_cur_lt, - XFS_BTREE_NOERROR); - bno_cur_lt = NULL; - } + error = xfs_btree_decrement(acur.bnolt, 0, &i); + if (error) + goto out; + if (!i || ltbnoa < args->min_agbno) + acur.bnolt->bc_private.a.priv.abt.active = false; } - if (bno_cur_gt) { - if ((error = xfs_alloc_get_rec(bno_cur_gt, >bno, >len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); + if (xfs_alloc_cur_active(acur.bnogt)) { + error = xfs_alloc_get_rec(acur.bnogt, >bno, >len, &i); + if (error) + goto out; + XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, out); busy |= xfs_alloc_compute_aligned(args, gtbno, gtlen, >bnoa, >lena, &busy_gen); if (gtlena >= args->minlen && gtbnoa <= args->max_agbno) break; - if ((error = xfs_btree_increment(bno_cur_gt, 0, &i))) - goto error0; - if (!i || gtbnoa > args->max_agbno) { - xfs_btree_del_cursor(bno_cur_gt, - XFS_BTREE_NOERROR); - bno_cur_gt = NULL; - } + error = xfs_btree_increment(acur.bnogt, 0, &i); + if (error) + goto out; + if (!i || gtbnoa > args->max_agbno) + acur.bnogt->bc_private.a.priv.abt.active = false; } - } while (bno_cur_lt || bno_cur_gt); + } while (xfs_alloc_cur_active(acur.bnolt) || + xfs_alloc_cur_active(acur.bnogt)); /* * Got both cursors still active, need to find better entry. */ - if (bno_cur_lt && bno_cur_gt) { + if (xfs_alloc_cur_active(acur.bnolt) && + xfs_alloc_cur_active(acur.bnogt)) { if (ltlena >= args->minlen) { /* * Left side is good, look for a right side entry. @@ -1400,7 +1417,7 @@ restart: ltlena, <new); error = xfs_alloc_find_best_extent(args, - &bno_cur_lt, &bno_cur_gt, + acur.bnolt, acur.bnogt, ltdiff, >bno, >len, >bnoa, >lena, 0 /* search right */); @@ -1417,22 +1434,21 @@ restart: gtlena, >new); error = xfs_alloc_find_best_extent(args, - &bno_cur_gt, &bno_cur_lt, + acur.bnogt, acur.bnolt, gtdiff, <bno, <len, <bnoa, <lena, 1 /* search left */); } if (error) - goto error0; + goto out; } /* * If we couldn't get anything, give up. */ - if (bno_cur_lt == NULL && bno_cur_gt == NULL) { - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - + if (!xfs_alloc_cur_active(acur.bnolt) && + !xfs_alloc_cur_active(acur.bnogt)) { if (busy) { trace_xfs_alloc_near_busy(args); xfs_extent_busy_flush(args->mp, args->pag, busy_gen); @@ -1440,7 +1456,7 @@ restart: } trace_xfs_alloc_size_neither(args); args->agbno = NULLAGBLOCK; - return 0; + goto out; } /* @@ -1449,16 +1465,17 @@ restart: * useful variables to the "left" set so we only have one * copy of this code. */ - if (bno_cur_gt) { - bno_cur_lt = bno_cur_gt; - bno_cur_gt = NULL; + if (xfs_alloc_cur_active(acur.bnogt)) { + bno_cur = acur.bnogt; ltbno = gtbno; ltbnoa = gtbnoa; ltlen = gtlen; ltlena = gtlena; j = 1; - } else + } else { + bno_cur = acur.bnolt; j = 0; + } /* * Fix up the length and compute the useful address. @@ -1474,27 +1491,18 @@ restart: ASSERT(ltnew >= args->min_agbno && ltnew <= args->max_agbno); args->agbno = ltnew; - if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen, - ltnew, rlen, XFSA_FIXUP_BNO_OK))) - goto error0; + error = xfs_alloc_fixup_trees(acur.cnt, bno_cur, ltbno, ltlen, ltnew, + rlen, XFSA_FIXUP_BNO_OK); + if (error) + goto out; if (j) trace_xfs_alloc_near_greater(args); else trace_xfs_alloc_near_lesser(args); - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); - return 0; - - error0: - trace_xfs_alloc_near_error(args); - if (cnt_cur != NULL) - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); - if (bno_cur_lt != NULL) - xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_ERROR); - if (bno_cur_gt != NULL) - xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_ERROR); +out: + xfs_alloc_cur_close(&acur, error); return error; }