/* * Size of the AGFL. For CRC-enabled filesystes we steal a couple of slots in * the beginning of the block for a proper header with the location information * and CRC.
*/ unsignedint
xfs_agfl_size( struct xfs_mount *mp)
{ unsignedint size = mp->m_sb.sb_sectsize;
if (xfs_has_crc(mp))
size -= sizeof(struct xfs_agfl);
xfs_extlen_t
xfs_prealloc_blocks( struct xfs_mount *mp)
{ if (xfs_has_reflink(mp)) return xfs_refc_block(mp) + 1; if (xfs_has_rmapbt(mp)) return XFS_RMAP_BLOCK(mp) + 1; if (xfs_has_finobt(mp)) return XFS_FIBT_BLOCK(mp) + 1; return XFS_IBT_BLOCK(mp) + 1;
}
/* * The number of blocks per AG that we withhold from xfs_dec_fdblocks to * guarantee that we can refill the AGFL prior to allocating space in a nearly * full AG. Although the space described by the free space btrees, the * blocks used by the freesp btrees themselves, and the blocks owned by the * AGFL are counted in the ondisk fdblocks, it's a mistake to let the ondisk * free space in the AG drop so low that the free space btrees cannot refill an * empty AGFL up to the minimum level. Rather than grind through empty AGs * until the fs goes down, we subtract this many AG blocks from the incore * fdblocks to ensure user allocation does not overcommit the space the * filesystem needs for the AGFLs. The rmap btree uses a per-AG reservation to * withhold space from xfs_dec_fdblocks, so we do not account for that here.
*/ #define XFS_ALLOCBT_AGFL_RESERVE 4
/* * Compute the number of blocks that we set aside to guarantee the ability to * refill the AGFL and handle a full bmap btree split. * * In order to avoid ENOSPC-related deadlock caused by out-of-order locking of * AGF buffer (PV 947395), we place constraints on the relationship among * actual allocations for data blocks, freelist blocks, and potential file data * bmap btree blocks. However, these restrictions may result in no actual space * allocated for a delayed extent, for example, a data block in a certain AG is * allocated but there is no additional block for the additional bmap btree * block due to a split of the bmap btree of the file. The result of this may * lead to an infinite loop when the file gets flushed to disk and all delayed * extents need to be actually allocated. To get around this, we explicitly set * aside a few blocks which will not be reserved in delayed allocation. * * For each AG, we need to reserve enough blocks to replenish a totally empty * AGFL and 4 more to handle a potential split of the file's bmap btree.
*/ unsignedint
xfs_alloc_set_aside( struct xfs_mount *mp)
{ return mp->m_sb.sb_agcount * (XFS_ALLOCBT_AGFL_RESERVE + 4);
}
/* * When deciding how much space to allocate out of an AG, we limit the * allocation maximum size to the size the AG. However, we cannot use all the * blocks in the AG - some are permanently used by metadata. These * blocks are generally: * - the AG superblock, AGF, AGI and AGFL * - the AGF (bno and cnt) and AGI btree root blocks, and optionally * the AGI free inode and rmap btree root blocks. * - blocks on the AGFL according to xfs_alloc_set_aside() limits * - the rmapbt root block * * The AG headers are sector sized, so the amount of space they take up is * dependent on filesystem geometry. The others are all single blocks.
*/ unsignedint
xfs_alloc_ag_max_usable( struct xfs_mount *mp)
{ unsignedint blocks;
/* * Lookup the record equal to [bno, len] in the btree given by cur.
*/ staticinlineint/* error */
xfs_alloc_lookup_eq( struct xfs_btree_cur *cur, /* btree cursor */
xfs_agblock_t bno, /* starting block of extent */
xfs_extlen_t len, /* length of extent */ int *stat) /* success/failure */
{ return xfs_alloc_lookup(cur, XFS_LOOKUP_EQ, bno, len, stat);
}
/* * Lookup the first record greater than or equal to [bno, len] * in the btree given by cur.
*/ int/* error */
xfs_alloc_lookup_ge( struct xfs_btree_cur *cur, /* btree cursor */
xfs_agblock_t bno, /* starting block of extent */
xfs_extlen_t len, /* length of extent */ int *stat) /* success/failure */
{ return xfs_alloc_lookup(cur, XFS_LOOKUP_GE, bno, len, stat);
}
/* * Lookup the first record less than or equal to [bno, len] * in the btree given by cur.
*/ int/* error */
xfs_alloc_lookup_le( struct xfs_btree_cur *cur, /* btree cursor */
xfs_agblock_t bno, /* starting block of extent */
xfs_extlen_t len, /* length of extent */ int *stat) /* success/failure */
{ return xfs_alloc_lookup(cur, XFS_LOOKUP_LE, bno, len, stat);
}
/* * Update the record referred to by cur to the value given * by [bno, len]. * This either works (return 0) or gets an EFSCORRUPTED error.
*/ STATICint/* error */
xfs_alloc_update( struct xfs_btree_cur *cur, /* btree cursor */
xfs_agblock_t bno, /* starting block of extent */
xfs_extlen_t len) /* length of extent */
{ union xfs_btree_rec rec;
/* * Compute aligned version of the found extent. * Takes alignment and min length into account.
*/ STATICbool
xfs_alloc_compute_aligned(
xfs_alloc_arg_t *args, /* allocation argument structure */
xfs_agblock_t foundbno, /* starting block in found extent */
xfs_extlen_t foundlen, /* length in found extent */
xfs_agblock_t *resbno, /* result block number */
xfs_extlen_t *reslen, /* result length */ unsigned *busy_gen)
{
xfs_agblock_t bno = foundbno;
xfs_extlen_t len = foundlen;
xfs_extlen_t diff; bool busy;
/* Trim busy sections out of found extent */
busy = xfs_extent_busy_trim(pag_group(args->pag), args->minlen,
args->maxlen, &bno, &len, busy_gen);
/* * If we have a largish extent that happens to start before min_agbno, * see if we can shift it into range...
*/ if (bno < args->min_agbno && bno + len > args->min_agbno) {
diff = args->min_agbno - bno; if (len > diff) {
bno += diff;
len -= diff;
}
}
if (args->alignment > 1 && len >= args->minlen) {
xfs_agblock_t aligned_bno = roundup(bno, args->alignment);
/* * Compute best start block and diff for "near" allocations. * freelen >= wantlen already checked by caller.
*/ STATIC xfs_extlen_t /* difference value (absolute) */
xfs_alloc_compute_diff(
xfs_agblock_t wantbno, /* target starting block */
xfs_extlen_t wantlen, /* target length */
xfs_extlen_t alignment, /* target alignment */ int datatype, /* are we allocating data? */
xfs_agblock_t freebno, /* freespace's starting block */
xfs_extlen_t freelen, /* freespace's length */
xfs_agblock_t *newbnop) /* result: best start block from free */
{
xfs_agblock_t freeend; /* end of freespace extent */
xfs_agblock_t newbno1; /* return block number */
xfs_agblock_t newbno2; /* other new block number */
xfs_extlen_t newlen1=0; /* length with newbno1 */
xfs_extlen_t newlen2=0; /* length with newbno2 */
xfs_agblock_t wantend; /* end of target extent */ bool userdata = datatype & XFS_ALLOC_USERDATA;
ASSERT(freelen >= wantlen);
freeend = freebno + freelen;
wantend = wantbno + wantlen; /* * We want to allocate from the start of a free extent if it is past * the desired block or if we are allocating user data and the free * extent is before desired block. The second case is there to allow * for contiguous allocation from the remaining free space if the file * grows in the short term.
*/ if (freebno >= wantbno || (userdata && freeend < wantend)) { if ((newbno1 = roundup(freebno, alignment)) >= freeend)
newbno1 = NULLAGBLOCK;
} elseif (freeend >= wantend && alignment > 1) {
newbno1 = roundup(wantbno, alignment);
newbno2 = newbno1 - alignment; if (newbno1 >= freeend)
newbno1 = NULLAGBLOCK; else
newlen1 = XFS_EXTLEN_MIN(wantlen, freeend - newbno1); if (newbno2 < freebno)
newbno2 = NULLAGBLOCK; else
newlen2 = XFS_EXTLEN_MIN(wantlen, freeend - newbno2); if (newbno1 != NULLAGBLOCK && newbno2 != NULLAGBLOCK) { if (newlen1 < newlen2 ||
(newlen1 == newlen2 &&
abs_diff(newbno1, wantbno) >
abs_diff(newbno2, wantbno)))
newbno1 = newbno2;
} elseif (newbno2 != NULLAGBLOCK)
newbno1 = newbno2;
} elseif (freeend >= wantend) {
newbno1 = wantbno;
} elseif (alignment > 1) {
newbno1 = roundup(freeend - wantlen, alignment); if (newbno1 > freeend - wantlen &&
newbno1 - alignment >= freebno)
newbno1 -= alignment; elseif (newbno1 >= freeend)
newbno1 = NULLAGBLOCK;
} else
newbno1 = freeend - wantlen;
*newbnop = newbno1; return newbno1 == NULLAGBLOCK ? 0 : abs_diff(newbno1, wantbno);
}
/* * Fix up the length, based on mod and prod. * len should be k * prod + mod for some k. * If len is too small it is returned unchanged. * If len hits maxlen it is left alone.
*/ STATICvoid
xfs_alloc_fix_len(
xfs_alloc_arg_t *args) /* allocation argument structure */
{
xfs_extlen_t k;
xfs_extlen_t rlen;
/* * Determine if the cursor points to the block that contains the right-most * block of records in the by-count btree. This block contains the largest * contiguous free extent in the AG, so if we modify a record in this block we * need to call xfs_alloc_fixup_longest() once the modifications are done to * ensure the agf->agf_longest field is kept up to date with the longest free * extent tracked by the by-count btree.
*/ staticbool
xfs_alloc_cursor_at_lastrec( struct xfs_btree_cur *cnt_cur)
{ struct xfs_btree_block *block; union xfs_btree_ptr ptr; struct xfs_buf *bp;
/* * Find the rightmost record of the cntbt, and return the longest free space * recorded in it. Simply set both the block number and the length to their * maximum values before searching.
*/ staticint
xfs_cntbt_longest( struct xfs_btree_cur *cnt_cur,
xfs_extlen_t *longest)
{ struct xfs_alloc_rec_incore irec; union xfs_btree_rec *rec; int stat = 0; int error;
memset(&cnt_cur->bc_rec, 0xFF, sizeof(cnt_cur->bc_rec));
error = xfs_btree_lookup(cnt_cur, XFS_LOOKUP_LE, &stat); if (error) return error; if (!stat) { /* totally empty tree */
*longest = 0; return 0;
}
error = xfs_btree_get_rec(cnt_cur, &rec, &stat); if (error) return error; if (XFS_IS_CORRUPT(cnt_cur->bc_mp, !stat)) {
xfs_btree_mark_sick(cnt_cur); return -EFSCORRUPTED;
}
/* * Update the longest contiguous free extent in the AG from the by-count cursor * that is passed to us. This should be done at the end of any allocation or * freeing operation that touches the longest extent in the btree. * * Needing to update the longest extent can be determined by calling * xfs_alloc_cursor_at_lastrec() after the cursor is positioned for record * modification but before the modification begins.
*/ staticint
xfs_alloc_fixup_longest( struct xfs_btree_cur *cnt_cur)
{ struct xfs_perag *pag = to_perag(cnt_cur->bc_group); struct xfs_buf *bp = cnt_cur->bc_ag.agbp; struct xfs_agf *agf = bp->b_addr;
xfs_extlen_t longest = 0; int error;
/* Lookup last rec in order to update AGF. */
error = xfs_cntbt_longest(cnt_cur, &longest); if (error) return error;
/* * Update the two btrees, logically removing from freespace the extent * starting at rbno, rlen blocks. The extent is contained within the * actual (current) free extent fbno for flen blocks. * Flags are passed in indicating whether the cursors are set to the * relevant records.
*/ STATICint/* error code */
xfs_alloc_fixup_trees( struct xfs_btree_cur *cnt_cur, /* cursor for by-size btree */ struct xfs_btree_cur *bno_cur, /* cursor for by-block btree */
xfs_agblock_t fbno, /* starting block of free extent */
xfs_extlen_t flen, /* length of free extent */
xfs_agblock_t rbno, /* starting block of returned extent */
xfs_extlen_t rlen, /* length of returned extent */ int flags) /* flags, XFSA_FIXUP_... */
{ int error; /* error code */ int i; /* operation results */
xfs_agblock_t nfbno1; /* first new free startblock */
xfs_agblock_t nfbno2; /* second new free startblock */
xfs_extlen_t nflen1=0; /* first new free length */
xfs_extlen_t nflen2=0; /* second new free length */ struct xfs_mount *mp; bool fixup_longest = false;
mp = cnt_cur->bc_mp;
/* * Look up the record in the by-size tree if necessary.
*/ if (flags & XFSA_FIXUP_CNT_OK) { #ifdef DEBUG if ((error = xfs_alloc_get_rec(cnt_cur, &nfbno1, &nflen1, &i))) return error; if (XFS_IS_CORRUPT(mp,
i != 1 ||
nfbno1 != fbno ||
nflen1 != flen)) {
xfs_btree_mark_sick(cnt_cur); return -EFSCORRUPTED;
} #endif
} else { if ((error = xfs_alloc_lookup_eq(cnt_cur, fbno, flen, &i))) return error; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur); return -EFSCORRUPTED;
}
} /* * Look up the record in the by-block tree if necessary.
*/ if (flags & XFSA_FIXUP_BNO_OK) { #ifdef DEBUG if ((error = xfs_alloc_get_rec(bno_cur, &nfbno1, &nflen1, &i))) return error; if (XFS_IS_CORRUPT(mp,
i != 1 ||
nfbno1 != fbno ||
nflen1 != flen)) {
xfs_btree_mark_sick(bno_cur); return -EFSCORRUPTED;
} #endif
} else { if ((error = xfs_alloc_lookup_eq(bno_cur, fbno, flen, &i))) return error; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(bno_cur); return -EFSCORRUPTED;
}
}
/* * Deal with all four cases: the allocated record is contained * within the freespace record, so we can have new freespace * at either (or both) end, or no freespace remaining.
*/ if (rbno == fbno && rlen == flen)
nfbno1 = nfbno2 = NULLAGBLOCK; elseif (rbno == fbno) {
nfbno1 = rbno + rlen;
nflen1 = flen - rlen;
nfbno2 = NULLAGBLOCK;
} elseif (rbno + rlen == fbno + flen) {
nfbno1 = fbno;
nflen1 = flen - rlen;
nfbno2 = NULLAGBLOCK;
} else {
nfbno1 = fbno;
nflen1 = rbno - fbno;
nfbno2 = rbno + rlen;
nflen2 = (fbno + flen) - nfbno2;
}
if (xfs_alloc_cursor_at_lastrec(cnt_cur))
fixup_longest = true;
/* * Delete the entry from the by-size btree.
*/ if ((error = xfs_btree_delete(cnt_cur, &i))) return error; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur); return -EFSCORRUPTED;
} /* * Add new by-size btree entry(s).
*/ if (nfbno1 != NULLAGBLOCK) { if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i))) return error; if (XFS_IS_CORRUPT(mp, i != 0)) {
xfs_btree_mark_sick(cnt_cur); return -EFSCORRUPTED;
} if ((error = xfs_btree_insert(cnt_cur, &i))) return error; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur); return -EFSCORRUPTED;
}
} if (nfbno2 != NULLAGBLOCK) { if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i))) return error; if (XFS_IS_CORRUPT(mp, i != 0)) {
xfs_btree_mark_sick(cnt_cur); return -EFSCORRUPTED;
} if ((error = xfs_btree_insert(cnt_cur, &i))) return error; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur); return -EFSCORRUPTED;
}
} /* * Fix up the by-block btree entry(s).
*/ if (nfbno1 == NULLAGBLOCK) { /* * No remaining freespace, just delete the by-block tree entry.
*/ if ((error = xfs_btree_delete(bno_cur, &i))) return error; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(bno_cur); return -EFSCORRUPTED;
}
} else { /* * Update the by-block entry to start later|be shorter.
*/ if ((error = xfs_alloc_update(bno_cur, nfbno1, nflen1))) return error;
} if (nfbno2 != NULLAGBLOCK) { /* * 2 resulting free entries, need to add one.
*/ if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i))) return error; if (XFS_IS_CORRUPT(mp, i != 0)) {
xfs_btree_mark_sick(bno_cur); return -EFSCORRUPTED;
} if ((error = xfs_btree_insert(bno_cur, &i))) return error; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(bno_cur); return -EFSCORRUPTED;
}
}
if (fixup_longest) return xfs_alloc_fixup_longest(cnt_cur);
return 0;
}
/* * We do not verify the AGFL contents against AGF-based index counters here, * even though we may have access to the perag that contains shadow copies. We * don't know if the AGF based counters have been checked, and if they have they * still may be inconsistent because they haven't yet been reset on the first * allocation after the AGF has been read in. * * This means we can only check that all agfl entries contain valid or null * values because we can't reliably determine the active range to exclude * NULLAGBNO as a valid value. * * However, we can't even do that for v4 format filesystems because there are * old versions of mkfs out there that does not initialise the AGFL to known, * verifiable values. HEnce we can't tell the difference between a AGFL block * allocated by mkfs and a corrupted AGFL block here on v4 filesystems. * * As a result, we can only fully validate AGFL block numbers when we pull them * from the freelist in xfs_alloc_get_freelist().
*/ static xfs_failaddr_t
xfs_agfl_verify( struct xfs_buf *bp)
{ struct xfs_mount *mp = bp->b_mount; struct xfs_agfl *agfl = XFS_BUF_TO_AGFL(bp);
__be32 *agfl_bno = xfs_buf_to_agfl_bno(bp); int i;
if (!xfs_has_crc(mp)) return NULL;
if (!xfs_verify_magic(bp, agfl->agfl_magicnum)) return __this_address; if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; /* * during growfs operations, the perag is not fully initialised, * so we can't use it for any useful checking. growfs ensures we can't * use it by using uncached buffers that don't have the perag attached * so we can detect and avoid this problem.
*/ if (bp->b_pag && be32_to_cpu(agfl->agfl_seqno) != pag_agno((bp->b_pag))) return __this_address;
for (i = 0; i < xfs_agfl_size(mp); i++) { if (be32_to_cpu(agfl_bno[i]) != NULLAGBLOCK &&
be32_to_cpu(agfl_bno[i]) >= mp->m_sb.sb_agblocks) return __this_address;
}
if (!xfs_log_check_lsn(mp, be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn))) return __this_address; return NULL;
}
/* * There is no verification of non-crc AGFLs because mkfs does not * initialise the AGFL to zero or NULL. Hence the only valid part of the * AGFL is what the AGF says is active. We can't get to the AGF, so we * can't verify just those entries are valid.
*/ if (!xfs_has_crc(mp)) return;
if (!xfs_buf_verify_cksum(bp, XFS_AGFL_CRC_OFF))
xfs_verifier_error(bp, -EFSBADCRC, __this_address); else {
fa = xfs_agfl_verify(bp); if (fa)
xfs_verifier_error(bp, -EFSCORRUPTED, fa);
}
}
/* * 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.
*/ staticint
xfs_alloc_cur_setup( struct xfs_alloc_arg *args, struct xfs_alloc_cur *acur)
{ int error; int i;
/* * 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_cntbt_init_cursor(args->mp, args->tp,
args->agbp, args->pag);
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_bnobt_init_cursor(args->mp, args->tp,
args->agbp, args->pag); if (!acur->bnogt)
acur->bnogt = xfs_bnobt_init_cursor(args->mp, args->tp,
args->agbp, args->pag); return i == 1 ? 0 : -ENOSPC;
}
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;
}
/* * Check an extent for allocation and track the best available candidate in the * allocation structure. The cursor is deactivated if it has entered an out of * range state based on allocation arguments. Optionally return the extent * extent geometry and allocation status if requested by the caller.
*/ staticint
xfs_alloc_cur_check( struct xfs_alloc_arg *args, struct xfs_alloc_cur *acur, struct xfs_btree_cur *cur, int *new)
{ int error, i;
xfs_agblock_t bno, bnoa, bnew;
xfs_extlen_t len, lena, diff = -1; bool busy; unsigned busy_gen = 0; bool deactivate = false; bool isbnobt = xfs_btree_is_bno(cur->bc_ops);
*new = 0;
error = xfs_alloc_get_rec(cur, &bno, &len, &i); if (error) return error; if (XFS_IS_CORRUPT(args->mp, i != 1)) {
xfs_btree_mark_sick(cur); return -EFSCORRUPTED;
}
/* * Check minlen and deactivate a cntbt cursor if out of acceptable size * range (i.e., walking backwards looking for a minlen extent).
*/ if (len < args->minlen) {
deactivate = !isbnobt; goto out;
}
busy = xfs_alloc_compute_aligned(args, bno, len, &bnoa, &lena,
&busy_gen);
acur->busy |= busy; if (busy)
acur->busy_gen = busy_gen; /* deactivate a bnobt cursor outside of locality range */ if (bnoa < args->min_agbno || bnoa > args->max_agbno) {
deactivate = isbnobt; goto out;
} if (lena < args->minlen) goto out;
/* * We have an aligned record that satisfies minlen and beats or matches * the candidate extent size. Compare locality for near allocation mode.
*/
diff = xfs_alloc_compute_diff(args->agbno, args->len,
args->alignment, args->datatype,
bnoa, lena, &bnew); if (bnew == NULLAGBLOCK) goto out;
/* * Deactivate a bnobt cursor with worse locality than the current best.
*/ if (diff > acur->diff) {
deactivate = isbnobt; goto out;
}
/* * We're done if we found a perfect allocation. This only deactivates * the current cursor, but this is just an optimization to terminate a * cntbt search that otherwise runs to the edge of the tree.
*/ if (acur->diff == 0 && acur->len == args->maxlen)
deactivate = true;
out: if (deactivate)
cur->bc_flags &= ~XFS_BTREE_ALLOCBT_ACTIVE;
trace_xfs_alloc_cur_check(cur, bno, len, diff, *new); return 0;
}
/* * Complete an allocation of a candidate extent. Remove the extent from both * trees and update the args structure.
*/ STATICint
xfs_alloc_cur_finish( struct xfs_alloc_arg *args, struct xfs_alloc_cur *acur)
{ int error;
/* * Locality allocation lookup algorithm. This expects a cntbt cursor and uses * bno optimized lookup to search for extents with ideal size and locality.
*/ STATICint
xfs_alloc_cntbt_iter( struct xfs_alloc_arg *args, struct xfs_alloc_cur *acur)
{ struct xfs_btree_cur *cur = acur->cnt;
xfs_agblock_t bno;
xfs_extlen_t len, cur_len; int error; int i;
if (!xfs_alloc_cur_active(cur)) return 0;
/* locality optimized lookup */
cur_len = acur->cur_len;
error = xfs_alloc_lookup_ge(cur, args->agbno, cur_len, &i); if (error) return error; if (i == 0) return 0;
error = xfs_alloc_get_rec(cur, &bno, &len, &i); if (error) return error;
/* check the current record and update search length from it */
error = xfs_alloc_cur_check(args, acur, cur, &i); if (error) return error;
ASSERT(len >= acur->cur_len);
acur->cur_len = len;
/* * We looked up the first record >= [agbno, len] above. The agbno is a * secondary key and so the current record may lie just before or after * agbno. If it is past agbno, check the previous record too so long as * the length matches as it may be closer. Don't check a smaller record * because that could deactivate our cursor.
*/ if (bno > args->agbno) {
error = xfs_btree_decrement(cur, 0, &i); if (!error && i) {
error = xfs_alloc_get_rec(cur, &bno, &len, &i); if (!error && i && len == acur->cur_len)
error = xfs_alloc_cur_check(args, acur, cur,
&i);
} if (error) return error;
}
/* * Increment the search key until we find at least one allocation * candidate or if the extent we found was larger. Otherwise, double the * search key to optimize the search. Efficiency is more important here * than absolute best locality.
*/
cur_len <<= 1; if (!acur->len || acur->cur_len >= cur_len)
acur->cur_len++; else
acur->cur_len = cur_len;
return error;
}
/* * Deal with the case where only small freespaces remain. Either return the * contents of the last freespace record, or allocate space from the freelist if * there is nothing in the tree.
*/ STATICint/* error */
xfs_alloc_ag_vextent_small( struct xfs_alloc_arg *args, /* allocation argument structure */ struct xfs_btree_cur *ccur, /* optional by-size cursor */
xfs_agblock_t *fbnop, /* result block number */
xfs_extlen_t *flenp, /* result length */ int *stat) /* status: 0-freelist, 1-normal/none */
{ struct xfs_agf *agf = args->agbp->b_addr; int error = 0;
xfs_agblock_t fbno = NULLAGBLOCK;
xfs_extlen_t flen = 0; int i = 0;
/* * If a cntbt cursor is provided, try to allocate the largest record in * the tree. Try the AGFL if the cntbt is empty, otherwise fail the * allocation. Make sure to respect minleft even when pulling from the * freelist.
*/ if (ccur)
error = xfs_btree_decrement(ccur, 0, &i); if (error) goto error; if (i) {
error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i); if (error) goto error; if (XFS_IS_CORRUPT(args->mp, i != 1)) {
xfs_btree_mark_sick(ccur);
error = -EFSCORRUPTED; goto error;
} goto out;
}
/* * If we're feeding an AGFL block to something that doesn't live in the * free space, we need to clear out the OWN_AG rmap.
*/
error = xfs_rmap_free(args->tp, args->agbp, args->pag, fbno, 1,
&XFS_RMAP_OINFO_AG); if (error) goto error;
*stat = 0; return 0;
out: /* * Can't do the allocation, give up.
*/ if (flen < args->minlen) {
args->agbno = NULLAGBLOCK;
trace_xfs_alloc_small_notenough(args);
flen = 0;
}
*fbnop = fbno;
*flenp = flen;
*stat = 1;
trace_xfs_alloc_small_done(args); return 0;
/* * Allocate a variable extent at exactly agno/bno. * Extent's length (returned in *len) will be between minlen and maxlen, * and of the form k * prod + mod unless there's nothing that large. * Return the starting a.g. block (bno), or NULLAGBLOCK if we can't do it.
*/ STATICint/* error */
xfs_alloc_ag_vextent_exact(
xfs_alloc_arg_t *args) /* allocation argument structure */
{ struct xfs_btree_cur *bno_cur;/* by block-number btree cursor */ struct xfs_btree_cur *cnt_cur;/* by count btree cursor */ int error;
xfs_agblock_t fbno; /* start block of found extent */
xfs_extlen_t flen; /* length of found extent */
xfs_agblock_t tbno; /* start block of busy extent */
xfs_extlen_t tlen; /* length of busy extent */
xfs_agblock_t tend; /* end block of busy extent */ int i; /* success/failure of operation */ unsigned busy_gen;
ASSERT(args->alignment == 1);
/* * Allocate/initialize a cursor for the by-number freespace btree.
*/
bno_cur = xfs_bnobt_init_cursor(args->mp, args->tp, args->agbp,
args->pag);
/* * Lookup bno and minlen in the btree (minlen is irrelevant, really). * Look for the closest free block <= bno, it must contain bno * if any free block does.
*/
error = xfs_alloc_lookup_le(bno_cur, args->agbno, args->minlen, &i); if (error) goto error0; if (!i) goto not_found;
/* * Grab the freespace record.
*/
error = xfs_alloc_get_rec(bno_cur, &fbno, &flen, &i); if (error) goto error0; if (XFS_IS_CORRUPT(args->mp, i != 1)) {
xfs_btree_mark_sick(bno_cur);
error = -EFSCORRUPTED; goto error0;
}
ASSERT(fbno <= args->agbno);
/* * Give up if the start of the extent is busy, or the freespace isn't * long enough for the minimum request.
*/ if (tbno > args->agbno) goto not_found; if (tlen < args->minlen) goto not_found;
tend = tbno + tlen; if (tend < args->agbno + args->minlen) goto not_found;
/* * End of extent will be smaller of the freespace end and the * maximal requested end. * * Fix the length according to mod and prod if given.
*/
args->len = XFS_AGBLOCK_MIN(tend, args->agbno + args->maxlen)
- args->agbno;
xfs_alloc_fix_len(args);
ASSERT(args->agbno + args->len <= tend);
/* * We are allocating agbno for args->len * Allocate/initialize a cursor for the by-size btree.
*/
cnt_cur = xfs_cntbt_init_cursor(args->mp, args->tp, args->agbp,
args->pag);
ASSERT(xfs_verify_agbext(args->pag, args->agbno, args->len));
error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno,
args->len, XFSA_FIXUP_BNO_OK); if (error) {
xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); goto error0;
}
/* * Search a given number of btree records in a given direction. Check each * record against the good extent we've already found.
*/ STATICint
xfs_alloc_walk_iter( struct xfs_alloc_arg *args, struct xfs_alloc_cur *acur, struct xfs_btree_cur *cur, bool increment, bool find_one, /* quit on first candidate */ int count, /* rec count (-1 for infinite) */ int *stat)
{ int error; int i;
*stat = 0;
/* * Search so long as the cursor is active or we find a better extent. * The cursor is deactivated if it extends beyond the range of the * current allocation candidate.
*/ while (xfs_alloc_cur_active(cur) && count) {
error = xfs_alloc_cur_check(args, acur, cur, &i); if (error) return error; if (i == 1) {
*stat = 1; if (find_one) break;
} if (!xfs_alloc_cur_active(cur)) break;
if (increment)
error = xfs_btree_increment(cur, 0, &i); else
error = xfs_btree_decrement(cur, 0, &i); if (error) return error; if (i == 0)
cur->bc_flags &= ~XFS_BTREE_ALLOCBT_ACTIVE;
if (count > 0)
count--;
}
return 0;
}
/* * Search the by-bno and by-size btrees in parallel in search of an extent with * ideal locality based on the NEAR mode ->agbno locality hint.
*/ STATICint
xfs_alloc_ag_vextent_locality( struct xfs_alloc_arg *args, struct xfs_alloc_cur *acur, int *stat)
{ struct xfs_btree_cur *fbcur = NULL; int error; int i; bool fbinc;
ASSERT(acur->len == 0);
*stat = 0;
error = xfs_alloc_lookup_ge(acur->cnt, args->agbno, acur->cur_len, &i); if (error) return error;
error = xfs_alloc_lookup_le(acur->bnolt, args->agbno, 0, &i); if (error) return error;
error = xfs_alloc_lookup_ge(acur->bnogt, args->agbno, 0, &i); if (error) return error;
/* * Search the bnobt and cntbt in parallel. Search the bnobt left and * right and lookup the closest extent to the locality hint for each * extent size key in the cntbt. The entire search terminates * immediately on a bnobt hit because that means we've found best case * locality. Otherwise the search continues until the cntbt cursor runs * off the end of the tree. If no allocation candidate is found at this * point, give up on locality, walk backwards from the end of the cntbt * and take the first available extent. * * The parallel tree searches balance each other out to provide fairly * consistent performance for various situations. The bnobt search can * have pathological behavior in the worst case scenario of larger * allocation requests and fragmented free space. On the other hand, the * bnobt is able to satisfy most smaller allocation requests much more * quickly than the cntbt. The cntbt search can sift through fragmented * free space and sets of free extents for larger allocation requests * more quickly than the bnobt. Since the locality hint is just a hint * and we don't want to scan the entire bnobt for perfect locality, the * cntbt search essentially bounds the bnobt search such that we can * find good enough locality at reasonable performance in most cases.
*/ while (xfs_alloc_cur_active(acur->bnolt) ||
xfs_alloc_cur_active(acur->bnogt) ||
xfs_alloc_cur_active(acur->cnt)) {
trace_xfs_alloc_cur_lookup(args);
/* * Search the bnobt left and right. In the case of a hit, finish * the search in the opposite direction and we're done.
*/
error = xfs_alloc_walk_iter(args, acur, acur->bnolt, false, true, 1, &i); if (error) return error; if (i == 1) {
trace_xfs_alloc_cur_left(args);
fbcur = acur->bnogt;
fbinc = true; break;
}
error = xfs_alloc_walk_iter(args, acur, acur->bnogt, true, true,
1, &i); if (error) return error; if (i == 1) {
trace_xfs_alloc_cur_right(args);
fbcur = acur->bnolt;
fbinc = false; break;
}
/* * Check the extent with best locality based on the current * extent size search key and keep track of the best candidate.
*/
error = xfs_alloc_cntbt_iter(args, acur); if (error) return error; if (!xfs_alloc_cur_active(acur->cnt)) {
trace_xfs_alloc_cur_lookup_done(args); break;
}
}
/* * If we failed to find anything due to busy extents, return empty * handed so the caller can flush and retry. If no busy extents were * found, walk backwards from the end of the cntbt as a last resort.
*/ if (!xfs_alloc_cur_active(acur->cnt) && !acur->len && !acur->busy) {
error = xfs_btree_decrement(acur->cnt, 0, &i); if (error) return error; if (i) {
acur->cnt->bc_flags |= XFS_BTREE_ALLOCBT_ACTIVE;
fbcur = acur->cnt;
fbinc = false;
}
}
/* * Search in the opposite direction for a better entry in the case of * a bnobt hit or walk backwards from the end of the cntbt.
*/ if (fbcur) {
error = xfs_alloc_walk_iter(args, acur, fbcur, fbinc, true, -1,
&i); if (error) return error;
}
if (acur->len)
*stat = 1;
return 0;
}
/* Check the last block of the cnt btree for allocations. */ staticint
xfs_alloc_ag_vextent_lastblock( struct xfs_alloc_arg *args, struct xfs_alloc_cur *acur,
xfs_agblock_t *bno,
xfs_extlen_t *len, bool *allocated)
{ int error; int i;
#ifdef DEBUG /* Randomly don't execute the first algorithm. */ if (get_random_u32_below(2)) return 0; #endif
/* * Start from the entry that lookup found, sequence through all larger * free blocks. If we're actually pointing at a record smaller than * maxlen, go to the start of this block, and skip all those smaller * than minlen.
*/ if (*len || args->alignment > 1) {
acur->cnt->bc_levels[0].ptr = 1; do {
error = xfs_alloc_get_rec(acur->cnt, bno, len, &i); if (error) return error; if (XFS_IS_CORRUPT(args->mp, i != 1)) {
xfs_btree_mark_sick(acur->cnt); return -EFSCORRUPTED;
} if (*len >= args->minlen) break;
error = xfs_btree_increment(acur->cnt, 0, &i); if (error) return error;
} while (i);
ASSERT(*len >= args->minlen); if (!i) return 0;
}
/* * Allocate a variable extent near bno in the allocation group agno. * Extent's length (returned in len) will be between minlen and maxlen, * 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.
*/ STATICint
xfs_alloc_ag_vextent_near( struct xfs_alloc_arg *args,
uint32_t alloc_flags)
{ struct xfs_alloc_cur acur = {}; int error; /* error code */ int i; /* result code, temporary */
xfs_agblock_t bno;
xfs_extlen_t len;
/* handle uninitialized agbno range so caller doesn't have to */ if (!args->min_agbno && !args->max_agbno)
args->max_agbno = args->mp->m_sb.sb_agblocks - 1;
ASSERT(args->min_agbno <= args->max_agbno);
/* clamp agbno to the range if it's outside */ if (args->agbno < args->min_agbno)
args->agbno = args->min_agbno; if (args->agbno > args->max_agbno)
args->agbno = args->max_agbno;
/* Retry once quickly if we find busy extents before blocking. */
alloc_flags |= XFS_ALLOC_FLAG_TRYFLUSH;
restart:
len = 0;
/* * 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.
*/
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 || len == 0) {
trace_xfs_alloc_near_noentry(args); goto out;
}
ASSERT(i == 1);
} elseif (error) { goto out;
}
/* * First algorithm. * If the requested extent is large wrt the freespaces available * in this a.g., then the cursor will be pointing to a btree entry * near the right edge of the tree. If it's in the last btree leaf * block, then we just examine all the entries in that block * that are big enough, and pick the best one.
*/ if (xfs_btree_islastblock(acur.cnt, 0)) { bool allocated = false;
error = xfs_alloc_ag_vextent_lastblock(args, &acur, &bno, &len,
&allocated); if (error) goto out; if (allocated) goto alloc_finish;
}
/* * Second algorithm. Combined cntbt and bnobt search to find ideal * locality.
*/
error = xfs_alloc_ag_vextent_locality(args, &acur, &i); if (error) goto out;
/* * If we couldn't get anything, give up.
*/ if (!acur.len) { if (acur.busy) { /* * Our only valid extents must have been busy. Flush and * retry the allocation again. If we get an -EAGAIN * error, we're being told that a deadlock was avoided * and the current transaction needs committing before * the allocation can be retried.
*/
trace_xfs_alloc_near_busy(args);
error = xfs_extent_busy_flush(args->tp,
pag_group(args->pag), acur.busy_gen,
alloc_flags); if (error) goto out;
/* * Allocate a variable extent anywhere in the allocation group agno. * Extent's length (returned in len) will be between minlen and maxlen, * 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.
*/ staticint
xfs_alloc_ag_vextent_size( struct xfs_alloc_arg *args,
uint32_t alloc_flags)
{ struct xfs_agf *agf = args->agbp->b_addr; struct xfs_btree_cur *bno_cur; struct xfs_btree_cur *cnt_cur;
xfs_agblock_t fbno; /* start of found freespace */
xfs_extlen_t flen; /* length of found freespace */
xfs_agblock_t rbno; /* returned block number */
xfs_extlen_t rlen; /* length of returned extent */ bool busy; unsigned busy_gen; int error; int i;
/* Retry once quickly if we find busy extents before blocking. */
alloc_flags |= XFS_ALLOC_FLAG_TRYFLUSH;
restart: /* * Allocate and initialize a cursor for the by-size btree.
*/
cnt_cur = xfs_cntbt_init_cursor(args->mp, args->tp, args->agbp,
args->pag);
bno_cur = NULL;
/* * Look for an entry >= maxlen+alignment-1 blocks.
*/ if ((error = xfs_alloc_lookup_ge(cnt_cur, 0,
args->maxlen + args->alignment - 1, &i))) goto error0;
/* * If none then we have to settle for a smaller extent. In the case that * there are no large extents, this will return the last entry in the * tree unless the tree is empty. In the case that there are only busy * large extents, this will return the largest small extent unless there * are no smaller extents available.
*/ if (!i) {
error = xfs_alloc_ag_vextent_small(args, cnt_cur,
&fbno, &flen, &i); if (error) goto error0; if (i == 0 || flen == 0) {
xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
trace_xfs_alloc_size_noentry(args); return 0;
}
ASSERT(i == 1);
busy = xfs_alloc_compute_aligned(args, fbno, flen, &rbno,
&rlen, &busy_gen);
} else { /* * Search for a non-busy extent that is large enough.
*/ for (;;) {
error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i); if (error) goto error0; if (XFS_IS_CORRUPT(args->mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
}
error = xfs_btree_increment(cnt_cur, 0, &i); if (error) goto error0; if (i) continue;
/* * Our only valid extents must have been busy. Flush and * retry the allocation again. If we get an -EAGAIN * error, we're being told that a deadlock was avoided * and the current transaction needs committing before * the allocation can be retried.
*/
trace_xfs_alloc_size_busy(args);
error = xfs_extent_busy_flush(args->tp,
pag_group(args->pag), busy_gen,
alloc_flags); if (error) goto error0;
/* * In the first case above, we got the last entry in the * by-size btree. Now we check to see if the space hits maxlen * once aligned; if not, we search left for something better. * This can't happen in the second case above.
*/
rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); if (XFS_IS_CORRUPT(args->mp,
rlen != 0 &&
(rlen > flen ||
rbno + rlen > fbno + flen))) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} if (rlen < args->maxlen) {
xfs_agblock_t bestfbno;
xfs_extlen_t bestflen;
xfs_agblock_t bestrbno;
xfs_extlen_t bestrlen;
bestrlen = rlen;
bestrbno = rbno;
bestflen = flen;
bestfbno = fbno; for (;;) { if ((error = xfs_btree_decrement(cnt_cur, 0, &i))) goto error0; if (i == 0) break; if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen,
&i))) goto error0; if (XFS_IS_CORRUPT(args->mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} if (flen <= bestrlen) break;
busy = xfs_alloc_compute_aligned(args, fbno, flen,
&rbno, &rlen, &busy_gen);
rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); if (XFS_IS_CORRUPT(args->mp,
rlen != 0 &&
(rlen > flen ||
rbno + rlen > fbno + flen))) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} if (rlen > bestrlen) {
bestrlen = rlen;
bestrbno = rbno;
bestflen = flen;
bestfbno = fbno; if (rlen == args->maxlen) break;
}
} if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen,
&i))) goto error0; if (XFS_IS_CORRUPT(args->mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
}
rlen = bestrlen;
rbno = bestrbno;
flen = bestflen;
fbno = bestfbno;
}
args->wasfromfl = 0; /* * Fix up the length.
*/
args->len = rlen; if (rlen < args->minlen) { if (busy) { /* * Our only valid extents must have been busy. Flush and * retry the allocation again. If we get an -EAGAIN * error, we're being told that a deadlock was avoided * and the current transaction needs committing before * the allocation can be retried.
*/
trace_xfs_alloc_size_busy(args);
error = xfs_extent_busy_flush(args->tp,
pag_group(args->pag), busy_gen,
alloc_flags); if (error) goto error0;
/* * Free the extent starting at agno/bno for length.
*/ int
xfs_free_ag_extent( struct xfs_trans *tp, struct xfs_buf *agbp,
xfs_agblock_t bno,
xfs_extlen_t len, conststruct xfs_owner_info *oinfo, enum xfs_ag_resv_type type)
{ struct xfs_mount *mp; struct xfs_btree_cur *bno_cur; struct xfs_btree_cur *cnt_cur;
xfs_agblock_t gtbno; /* start of right neighbor */
xfs_extlen_t gtlen; /* length of right neighbor */
xfs_agblock_t ltbno; /* start of left neighbor */
xfs_extlen_t ltlen; /* length of left neighbor */
xfs_agblock_t nbno; /* new starting block of freesp */
xfs_extlen_t nlen; /* new length of freespace */ int haveleft; /* have a left neighbor */ int haveright; /* have a right neighbor */ int i; int error; struct xfs_perag *pag = agbp->b_pag; bool fixup_longest = false;
bno_cur = cnt_cur = NULL;
mp = tp->t_mountp;
if (!xfs_rmap_should_skip_owner_update(oinfo)) {
error = xfs_rmap_free(tp, agbp, pag, bno, len, oinfo); if (error) goto error0;
}
/* * Allocate and initialize a cursor for the by-block btree.
*/
bno_cur = xfs_bnobt_init_cursor(mp, tp, agbp, pag); /* * Look for a neighboring block on the left (lower block numbers) * that is contiguous with this space.
*/ if ((error = xfs_alloc_lookup_le(bno_cur, bno, len, &haveleft))) goto error0; if (haveleft) { /* * There is a block to our left.
*/ if ((error = xfs_alloc_get_rec(bno_cur, <bno, <len, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(bno_cur);
error = -EFSCORRUPTED; goto error0;
} /* * It's not contiguous, though.
*/ if (ltbno + ltlen < bno)
haveleft = 0; else { /* * If this failure happens the request to free this * space was invalid, it's (partly) already free. * Very bad.
*/ if (XFS_IS_CORRUPT(mp, ltbno + ltlen > bno)) {
xfs_btree_mark_sick(bno_cur);
error = -EFSCORRUPTED; goto error0;
}
}
} /* * Look for a neighboring block on the right (higher block numbers) * that is contiguous with this space.
*/ if ((error = xfs_btree_increment(bno_cur, 0, &haveright))) goto error0; if (haveright) { /* * There is a block to our right.
*/ if ((error = xfs_alloc_get_rec(bno_cur, >bno, >len, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(bno_cur);
error = -EFSCORRUPTED; goto error0;
} /* * It's not contiguous, though.
*/ if (bno + len < gtbno)
haveright = 0; else { /* * If this failure happens the request to free this * space was invalid, it's (partly) already free. * Very bad.
*/ if (XFS_IS_CORRUPT(mp, bno + len > gtbno)) {
xfs_btree_mark_sick(bno_cur);
error = -EFSCORRUPTED; goto error0;
}
}
} /* * Now allocate and initialize a cursor for the by-size tree.
*/
cnt_cur = xfs_cntbt_init_cursor(mp, tp, agbp, pag); /* * Have both left and right contiguous neighbors. * Merge all three into a single free block.
*/ if (haveleft && haveright) { /* * Delete the old by-size entry on the left.
*/ if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} /* * Delete the old by-size entry on the right.
*/ if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} /* * Delete the old by-block entry for the right block.
*/ if ((error = xfs_btree_delete(bno_cur, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(bno_cur);
error = -EFSCORRUPTED; goto error0;
} /* * Move the by-block cursor back to the left neighbor.
*/ if ((error = xfs_btree_decrement(bno_cur, 0, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(bno_cur);
error = -EFSCORRUPTED; goto error0;
} #ifdef DEBUG /* * Check that this is the right record: delete didn't * mangle the cursor.
*/
{
xfs_agblock_t xxbno;
xfs_extlen_t xxlen;
if ((error = xfs_alloc_get_rec(bno_cur, &xxbno, &xxlen,
&i))) goto error0; if (XFS_IS_CORRUPT(mp,
i != 1 ||
xxbno != ltbno ||
xxlen != ltlen)) {
xfs_btree_mark_sick(bno_cur);
error = -EFSCORRUPTED; goto error0;
}
} #endif /* * Update remaining by-block entry to the new, joined block.
*/
nbno = ltbno;
nlen = len + ltlen + gtlen; if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) goto error0;
} /* * Have only a left contiguous neighbor. * Merge it together with the new freespace.
*/ elseif (haveleft) { /* * Delete the old by-size entry on the left.
*/ if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} /* * Back up the by-block cursor to the left neighbor, and * update its length.
*/ if ((error = xfs_btree_decrement(bno_cur, 0, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(bno_cur);
error = -EFSCORRUPTED; goto error0;
}
nbno = ltbno;
nlen = len + ltlen; if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) goto error0;
} /* * Have only a right contiguous neighbor. * Merge it together with the new freespace.
*/ elseif (haveright) { /* * Delete the old by-size entry on the right.
*/ if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} if ((error = xfs_btree_delete(cnt_cur, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} /* * Update the starting block and length of the right * neighbor in the by-block tree.
*/
nbno = bno;
nlen = len + gtlen; if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) goto error0;
} /* * No contiguous neighbors. * Insert the new freespace into the by-block tree.
*/ else {
nbno = bno;
nlen = len; if ((error = xfs_btree_insert(bno_cur, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(bno_cur);
error = -EFSCORRUPTED; goto error0;
}
}
xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR);
bno_cur = NULL;
/* * In all cases we need to insert the new freespace in the by-size tree. * * If this new freespace is being inserted in the block that contains * the largest free space in the btree, make sure we also fix up the * agf->agf-longest tracker field.
*/ if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 0)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} if (xfs_alloc_cursor_at_lastrec(cnt_cur))
fixup_longest = true; if ((error = xfs_btree_insert(cnt_cur, &i))) goto error0; if (XFS_IS_CORRUPT(mp, i != 1)) {
xfs_btree_mark_sick(cnt_cur);
error = -EFSCORRUPTED; goto error0;
} if (fixup_longest) {
error = xfs_alloc_fixup_longest(cnt_cur); if (error) goto error0;
}
/* * Update the freespace totals in the ag and superblock.
*/
error = xfs_alloc_update_counters(tp, agbp, len);
xfs_ag_resv_free_extent(pag, type, tp, len); if (error) goto error0;
error0:
trace_xfs_free_extent(pag, bno, len, type, -1, -1); if (bno_cur)
xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); if (cnt_cur)
xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); return error;
}
/* * Visible (exported) allocation/free functions. * Some of these are used just by xfs_alloc_btree.c and this file.
*/
/* * Compute and fill in value of m_alloc_maxlevels.
*/ void
xfs_alloc_compute_maxlevels(
xfs_mount_t *mp) /* file system mount structure */
{
mp->m_alloc_maxlevels = xfs_btree_compute_maxlevels(mp->m_alloc_mnr,
(mp->m_sb.sb_agblocks + 1) / 2);
ASSERT(mp->m_alloc_maxlevels <= xfs_allocbt_maxlevels_ondisk());
}
/* * Find the length of the longest extent in an AG. The 'need' parameter * specifies how much space we're going to need for the AGFL and the * 'reserved' parameter tells us how many blocks in this AG are reserved for * other callers.
*/
xfs_extlen_t
xfs_alloc_longest_free_extent( struct xfs_perag *pag,
xfs_extlen_t need,
xfs_extlen_t reserved)
{
xfs_extlen_t delta = 0;
/* * If the AGFL needs a recharge, we'll have to subtract that from the * longest extent.
*/ if (need > pag->pagf_flcount)
delta = need - pag->pagf_flcount;
/* * If we cannot maintain others' reservations with space from the * not-longest freesp extents, we'll have to subtract /that/ from * the longest extent too.
*/ if (pag->pagf_freeblks - pag->pagf_longest < reserved)
delta += reserved - (pag->pagf_freeblks - pag->pagf_longest);
/* * If the longest extent is long enough to satisfy all the * reservations and AGFL rules in place, we can return this extent.
*/ if (pag->pagf_longest > delta) return min_t(xfs_extlen_t, pag_mount(pag)->m_ag_max_usable,
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.