162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. 462306a36Sopenharmony_ci * All Rights Reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "xfs.h" 762306a36Sopenharmony_ci#include "xfs_fs.h" 862306a36Sopenharmony_ci#include "xfs_shared.h" 962306a36Sopenharmony_ci#include "xfs_format.h" 1062306a36Sopenharmony_ci#include "xfs_log_format.h" 1162306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1262306a36Sopenharmony_ci#include "xfs_mount.h" 1362306a36Sopenharmony_ci#include "xfs_btree.h" 1462306a36Sopenharmony_ci#include "xfs_btree_staging.h" 1562306a36Sopenharmony_ci#include "xfs_alloc_btree.h" 1662306a36Sopenharmony_ci#include "xfs_alloc.h" 1762306a36Sopenharmony_ci#include "xfs_extent_busy.h" 1862306a36Sopenharmony_ci#include "xfs_error.h" 1962306a36Sopenharmony_ci#include "xfs_trace.h" 2062306a36Sopenharmony_ci#include "xfs_trans.h" 2162306a36Sopenharmony_ci#include "xfs_ag.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic struct kmem_cache *xfs_allocbt_cur_cache; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciSTATIC struct xfs_btree_cur * 2662306a36Sopenharmony_cixfs_allocbt_dup_cursor( 2762306a36Sopenharmony_ci struct xfs_btree_cur *cur) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp, 3062306a36Sopenharmony_ci cur->bc_ag.agbp, cur->bc_ag.pag, cur->bc_btnum); 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciSTATIC void 3462306a36Sopenharmony_cixfs_allocbt_set_root( 3562306a36Sopenharmony_ci struct xfs_btree_cur *cur, 3662306a36Sopenharmony_ci const union xfs_btree_ptr *ptr, 3762306a36Sopenharmony_ci int inc) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct xfs_buf *agbp = cur->bc_ag.agbp; 4062306a36Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 4162306a36Sopenharmony_ci int btnum = cur->bc_btnum; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci ASSERT(ptr->s != 0); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci agf->agf_roots[btnum] = ptr->s; 4662306a36Sopenharmony_ci be32_add_cpu(&agf->agf_levels[btnum], inc); 4762306a36Sopenharmony_ci cur->bc_ag.pag->pagf_levels[btnum] += inc; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ciSTATIC int 5362306a36Sopenharmony_cixfs_allocbt_alloc_block( 5462306a36Sopenharmony_ci struct xfs_btree_cur *cur, 5562306a36Sopenharmony_ci const union xfs_btree_ptr *start, 5662306a36Sopenharmony_ci union xfs_btree_ptr *new, 5762306a36Sopenharmony_ci int *stat) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci int error; 6062306a36Sopenharmony_ci xfs_agblock_t bno; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Allocate the new block from the freelist. If we can't, give up. */ 6362306a36Sopenharmony_ci error = xfs_alloc_get_freelist(cur->bc_ag.pag, cur->bc_tp, 6462306a36Sopenharmony_ci cur->bc_ag.agbp, &bno, 1); 6562306a36Sopenharmony_ci if (error) 6662306a36Sopenharmony_ci return error; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (bno == NULLAGBLOCK) { 6962306a36Sopenharmony_ci *stat = 0; 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci atomic64_inc(&cur->bc_mp->m_allocbt_blks); 7462306a36Sopenharmony_ci xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.pag, bno, 1, false); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci new->s = cpu_to_be32(bno); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci *stat = 1; 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciSTATIC int 8362306a36Sopenharmony_cixfs_allocbt_free_block( 8462306a36Sopenharmony_ci struct xfs_btree_cur *cur, 8562306a36Sopenharmony_ci struct xfs_buf *bp) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct xfs_buf *agbp = cur->bc_ag.agbp; 8862306a36Sopenharmony_ci xfs_agblock_t bno; 8962306a36Sopenharmony_ci int error; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci bno = xfs_daddr_to_agbno(cur->bc_mp, xfs_buf_daddr(bp)); 9262306a36Sopenharmony_ci error = xfs_alloc_put_freelist(cur->bc_ag.pag, cur->bc_tp, agbp, NULL, 9362306a36Sopenharmony_ci bno, 1); 9462306a36Sopenharmony_ci if (error) 9562306a36Sopenharmony_ci return error; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci atomic64_dec(&cur->bc_mp->m_allocbt_blks); 9862306a36Sopenharmony_ci xfs_extent_busy_insert(cur->bc_tp, agbp->b_pag, bno, 1, 9962306a36Sopenharmony_ci XFS_EXTENT_BUSY_SKIP_DISCARD); 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * Update the longest extent in the AGF 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ciSTATIC void 10762306a36Sopenharmony_cixfs_allocbt_update_lastrec( 10862306a36Sopenharmony_ci struct xfs_btree_cur *cur, 10962306a36Sopenharmony_ci const struct xfs_btree_block *block, 11062306a36Sopenharmony_ci const union xfs_btree_rec *rec, 11162306a36Sopenharmony_ci int ptr, 11262306a36Sopenharmony_ci int reason) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct xfs_agf *agf = cur->bc_ag.agbp->b_addr; 11562306a36Sopenharmony_ci struct xfs_perag *pag; 11662306a36Sopenharmony_ci __be32 len; 11762306a36Sopenharmony_ci int numrecs; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci ASSERT(cur->bc_btnum == XFS_BTNUM_CNT); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci switch (reason) { 12262306a36Sopenharmony_ci case LASTREC_UPDATE: 12362306a36Sopenharmony_ci /* 12462306a36Sopenharmony_ci * If this is the last leaf block and it's the last record, 12562306a36Sopenharmony_ci * then update the size of the longest extent in the AG. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci if (ptr != xfs_btree_get_numrecs(block)) 12862306a36Sopenharmony_ci return; 12962306a36Sopenharmony_ci len = rec->alloc.ar_blockcount; 13062306a36Sopenharmony_ci break; 13162306a36Sopenharmony_ci case LASTREC_INSREC: 13262306a36Sopenharmony_ci if (be32_to_cpu(rec->alloc.ar_blockcount) <= 13362306a36Sopenharmony_ci be32_to_cpu(agf->agf_longest)) 13462306a36Sopenharmony_ci return; 13562306a36Sopenharmony_ci len = rec->alloc.ar_blockcount; 13662306a36Sopenharmony_ci break; 13762306a36Sopenharmony_ci case LASTREC_DELREC: 13862306a36Sopenharmony_ci numrecs = xfs_btree_get_numrecs(block); 13962306a36Sopenharmony_ci if (ptr <= numrecs) 14062306a36Sopenharmony_ci return; 14162306a36Sopenharmony_ci ASSERT(ptr == numrecs + 1); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (numrecs) { 14462306a36Sopenharmony_ci xfs_alloc_rec_t *rrp; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci rrp = XFS_ALLOC_REC_ADDR(cur->bc_mp, block, numrecs); 14762306a36Sopenharmony_ci len = rrp->ar_blockcount; 14862306a36Sopenharmony_ci } else { 14962306a36Sopenharmony_ci len = 0; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci default: 15462306a36Sopenharmony_ci ASSERT(0); 15562306a36Sopenharmony_ci return; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci agf->agf_longest = len; 15962306a36Sopenharmony_ci pag = cur->bc_ag.agbp->b_pag; 16062306a36Sopenharmony_ci pag->pagf_longest = be32_to_cpu(len); 16162306a36Sopenharmony_ci xfs_alloc_log_agf(cur->bc_tp, cur->bc_ag.agbp, XFS_AGF_LONGEST); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ciSTATIC int 16562306a36Sopenharmony_cixfs_allocbt_get_minrecs( 16662306a36Sopenharmony_ci struct xfs_btree_cur *cur, 16762306a36Sopenharmony_ci int level) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci return cur->bc_mp->m_alloc_mnr[level != 0]; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ciSTATIC int 17362306a36Sopenharmony_cixfs_allocbt_get_maxrecs( 17462306a36Sopenharmony_ci struct xfs_btree_cur *cur, 17562306a36Sopenharmony_ci int level) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci return cur->bc_mp->m_alloc_mxr[level != 0]; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ciSTATIC void 18162306a36Sopenharmony_cixfs_allocbt_init_key_from_rec( 18262306a36Sopenharmony_ci union xfs_btree_key *key, 18362306a36Sopenharmony_ci const union xfs_btree_rec *rec) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci key->alloc.ar_startblock = rec->alloc.ar_startblock; 18662306a36Sopenharmony_ci key->alloc.ar_blockcount = rec->alloc.ar_blockcount; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ciSTATIC void 19062306a36Sopenharmony_cixfs_bnobt_init_high_key_from_rec( 19162306a36Sopenharmony_ci union xfs_btree_key *key, 19262306a36Sopenharmony_ci const union xfs_btree_rec *rec) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci __u32 x; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci x = be32_to_cpu(rec->alloc.ar_startblock); 19762306a36Sopenharmony_ci x += be32_to_cpu(rec->alloc.ar_blockcount) - 1; 19862306a36Sopenharmony_ci key->alloc.ar_startblock = cpu_to_be32(x); 19962306a36Sopenharmony_ci key->alloc.ar_blockcount = 0; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ciSTATIC void 20362306a36Sopenharmony_cixfs_cntbt_init_high_key_from_rec( 20462306a36Sopenharmony_ci union xfs_btree_key *key, 20562306a36Sopenharmony_ci const union xfs_btree_rec *rec) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci key->alloc.ar_blockcount = rec->alloc.ar_blockcount; 20862306a36Sopenharmony_ci key->alloc.ar_startblock = 0; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ciSTATIC void 21262306a36Sopenharmony_cixfs_allocbt_init_rec_from_cur( 21362306a36Sopenharmony_ci struct xfs_btree_cur *cur, 21462306a36Sopenharmony_ci union xfs_btree_rec *rec) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci rec->alloc.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock); 21762306a36Sopenharmony_ci rec->alloc.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciSTATIC void 22162306a36Sopenharmony_cixfs_allocbt_init_ptr_from_cur( 22262306a36Sopenharmony_ci struct xfs_btree_cur *cur, 22362306a36Sopenharmony_ci union xfs_btree_ptr *ptr) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct xfs_agf *agf = cur->bc_ag.agbp->b_addr; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno)); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ptr->s = agf->agf_roots[cur->bc_btnum]; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ciSTATIC int64_t 23362306a36Sopenharmony_cixfs_bnobt_key_diff( 23462306a36Sopenharmony_ci struct xfs_btree_cur *cur, 23562306a36Sopenharmony_ci const union xfs_btree_key *key) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct xfs_alloc_rec_incore *rec = &cur->bc_rec.a; 23862306a36Sopenharmony_ci const struct xfs_alloc_rec *kp = &key->alloc; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci return (int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ciSTATIC int64_t 24462306a36Sopenharmony_cixfs_cntbt_key_diff( 24562306a36Sopenharmony_ci struct xfs_btree_cur *cur, 24662306a36Sopenharmony_ci const union xfs_btree_key *key) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct xfs_alloc_rec_incore *rec = &cur->bc_rec.a; 24962306a36Sopenharmony_ci const struct xfs_alloc_rec *kp = &key->alloc; 25062306a36Sopenharmony_ci int64_t diff; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci diff = (int64_t)be32_to_cpu(kp->ar_blockcount) - rec->ar_blockcount; 25362306a36Sopenharmony_ci if (diff) 25462306a36Sopenharmony_ci return diff; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return (int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ciSTATIC int64_t 26062306a36Sopenharmony_cixfs_bnobt_diff_two_keys( 26162306a36Sopenharmony_ci struct xfs_btree_cur *cur, 26262306a36Sopenharmony_ci const union xfs_btree_key *k1, 26362306a36Sopenharmony_ci const union xfs_btree_key *k2, 26462306a36Sopenharmony_ci const union xfs_btree_key *mask) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci ASSERT(!mask || mask->alloc.ar_startblock); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return (int64_t)be32_to_cpu(k1->alloc.ar_startblock) - 26962306a36Sopenharmony_ci be32_to_cpu(k2->alloc.ar_startblock); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ciSTATIC int64_t 27362306a36Sopenharmony_cixfs_cntbt_diff_two_keys( 27462306a36Sopenharmony_ci struct xfs_btree_cur *cur, 27562306a36Sopenharmony_ci const union xfs_btree_key *k1, 27662306a36Sopenharmony_ci const union xfs_btree_key *k2, 27762306a36Sopenharmony_ci const union xfs_btree_key *mask) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci int64_t diff; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ASSERT(!mask || (mask->alloc.ar_blockcount && 28262306a36Sopenharmony_ci mask->alloc.ar_startblock)); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci diff = be32_to_cpu(k1->alloc.ar_blockcount) - 28562306a36Sopenharmony_ci be32_to_cpu(k2->alloc.ar_blockcount); 28662306a36Sopenharmony_ci if (diff) 28762306a36Sopenharmony_ci return diff; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return be32_to_cpu(k1->alloc.ar_startblock) - 29062306a36Sopenharmony_ci be32_to_cpu(k2->alloc.ar_startblock); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic xfs_failaddr_t 29462306a36Sopenharmony_cixfs_allocbt_verify( 29562306a36Sopenharmony_ci struct xfs_buf *bp) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct xfs_mount *mp = bp->b_mount; 29862306a36Sopenharmony_ci struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 29962306a36Sopenharmony_ci struct xfs_perag *pag = bp->b_pag; 30062306a36Sopenharmony_ci xfs_failaddr_t fa; 30162306a36Sopenharmony_ci unsigned int level; 30262306a36Sopenharmony_ci xfs_btnum_t btnum = XFS_BTNUM_BNOi; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (!xfs_verify_magic(bp, block->bb_magic)) 30562306a36Sopenharmony_ci return __this_address; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (xfs_has_crc(mp)) { 30862306a36Sopenharmony_ci fa = xfs_btree_sblock_v5hdr_verify(bp); 30962306a36Sopenharmony_ci if (fa) 31062306a36Sopenharmony_ci return fa; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* 31462306a36Sopenharmony_ci * The perag may not be attached during grow operations or fully 31562306a36Sopenharmony_ci * initialized from the AGF during log recovery. Therefore we can only 31662306a36Sopenharmony_ci * check against maximum tree depth from those contexts. 31762306a36Sopenharmony_ci * 31862306a36Sopenharmony_ci * Otherwise check against the per-tree limit. Peek at one of the 31962306a36Sopenharmony_ci * verifier magic values to determine the type of tree we're verifying 32062306a36Sopenharmony_ci * against. 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci level = be16_to_cpu(block->bb_level); 32362306a36Sopenharmony_ci if (bp->b_ops->magic[0] == cpu_to_be32(XFS_ABTC_MAGIC)) 32462306a36Sopenharmony_ci btnum = XFS_BTNUM_CNTi; 32562306a36Sopenharmony_ci if (pag && xfs_perag_initialised_agf(pag)) { 32662306a36Sopenharmony_ci if (level >= pag->pagf_levels[btnum]) 32762306a36Sopenharmony_ci return __this_address; 32862306a36Sopenharmony_ci } else if (level >= mp->m_alloc_maxlevels) 32962306a36Sopenharmony_ci return __this_address; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return xfs_btree_sblock_verify(bp, mp->m_alloc_mxr[level != 0]); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void 33562306a36Sopenharmony_cixfs_allocbt_read_verify( 33662306a36Sopenharmony_ci struct xfs_buf *bp) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci xfs_failaddr_t fa; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (!xfs_btree_sblock_verify_crc(bp)) 34162306a36Sopenharmony_ci xfs_verifier_error(bp, -EFSBADCRC, __this_address); 34262306a36Sopenharmony_ci else { 34362306a36Sopenharmony_ci fa = xfs_allocbt_verify(bp); 34462306a36Sopenharmony_ci if (fa) 34562306a36Sopenharmony_ci xfs_verifier_error(bp, -EFSCORRUPTED, fa); 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (bp->b_error) 34962306a36Sopenharmony_ci trace_xfs_btree_corrupt(bp, _RET_IP_); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic void 35362306a36Sopenharmony_cixfs_allocbt_write_verify( 35462306a36Sopenharmony_ci struct xfs_buf *bp) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci xfs_failaddr_t fa; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci fa = xfs_allocbt_verify(bp); 35962306a36Sopenharmony_ci if (fa) { 36062306a36Sopenharmony_ci trace_xfs_btree_corrupt(bp, _RET_IP_); 36162306a36Sopenharmony_ci xfs_verifier_error(bp, -EFSCORRUPTED, fa); 36262306a36Sopenharmony_ci return; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci xfs_btree_sblock_calc_crc(bp); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ciconst struct xfs_buf_ops xfs_bnobt_buf_ops = { 36962306a36Sopenharmony_ci .name = "xfs_bnobt", 37062306a36Sopenharmony_ci .magic = { cpu_to_be32(XFS_ABTB_MAGIC), 37162306a36Sopenharmony_ci cpu_to_be32(XFS_ABTB_CRC_MAGIC) }, 37262306a36Sopenharmony_ci .verify_read = xfs_allocbt_read_verify, 37362306a36Sopenharmony_ci .verify_write = xfs_allocbt_write_verify, 37462306a36Sopenharmony_ci .verify_struct = xfs_allocbt_verify, 37562306a36Sopenharmony_ci}; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ciconst struct xfs_buf_ops xfs_cntbt_buf_ops = { 37862306a36Sopenharmony_ci .name = "xfs_cntbt", 37962306a36Sopenharmony_ci .magic = { cpu_to_be32(XFS_ABTC_MAGIC), 38062306a36Sopenharmony_ci cpu_to_be32(XFS_ABTC_CRC_MAGIC) }, 38162306a36Sopenharmony_ci .verify_read = xfs_allocbt_read_verify, 38262306a36Sopenharmony_ci .verify_write = xfs_allocbt_write_verify, 38362306a36Sopenharmony_ci .verify_struct = xfs_allocbt_verify, 38462306a36Sopenharmony_ci}; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ciSTATIC int 38762306a36Sopenharmony_cixfs_bnobt_keys_inorder( 38862306a36Sopenharmony_ci struct xfs_btree_cur *cur, 38962306a36Sopenharmony_ci const union xfs_btree_key *k1, 39062306a36Sopenharmony_ci const union xfs_btree_key *k2) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci return be32_to_cpu(k1->alloc.ar_startblock) < 39362306a36Sopenharmony_ci be32_to_cpu(k2->alloc.ar_startblock); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ciSTATIC int 39762306a36Sopenharmony_cixfs_bnobt_recs_inorder( 39862306a36Sopenharmony_ci struct xfs_btree_cur *cur, 39962306a36Sopenharmony_ci const union xfs_btree_rec *r1, 40062306a36Sopenharmony_ci const union xfs_btree_rec *r2) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci return be32_to_cpu(r1->alloc.ar_startblock) + 40362306a36Sopenharmony_ci be32_to_cpu(r1->alloc.ar_blockcount) <= 40462306a36Sopenharmony_ci be32_to_cpu(r2->alloc.ar_startblock); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ciSTATIC int 40862306a36Sopenharmony_cixfs_cntbt_keys_inorder( 40962306a36Sopenharmony_ci struct xfs_btree_cur *cur, 41062306a36Sopenharmony_ci const union xfs_btree_key *k1, 41162306a36Sopenharmony_ci const union xfs_btree_key *k2) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci return be32_to_cpu(k1->alloc.ar_blockcount) < 41462306a36Sopenharmony_ci be32_to_cpu(k2->alloc.ar_blockcount) || 41562306a36Sopenharmony_ci (k1->alloc.ar_blockcount == k2->alloc.ar_blockcount && 41662306a36Sopenharmony_ci be32_to_cpu(k1->alloc.ar_startblock) < 41762306a36Sopenharmony_ci be32_to_cpu(k2->alloc.ar_startblock)); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ciSTATIC int 42162306a36Sopenharmony_cixfs_cntbt_recs_inorder( 42262306a36Sopenharmony_ci struct xfs_btree_cur *cur, 42362306a36Sopenharmony_ci const union xfs_btree_rec *r1, 42462306a36Sopenharmony_ci const union xfs_btree_rec *r2) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci return be32_to_cpu(r1->alloc.ar_blockcount) < 42762306a36Sopenharmony_ci be32_to_cpu(r2->alloc.ar_blockcount) || 42862306a36Sopenharmony_ci (r1->alloc.ar_blockcount == r2->alloc.ar_blockcount && 42962306a36Sopenharmony_ci be32_to_cpu(r1->alloc.ar_startblock) < 43062306a36Sopenharmony_ci be32_to_cpu(r2->alloc.ar_startblock)); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ciSTATIC enum xbtree_key_contig 43462306a36Sopenharmony_cixfs_allocbt_keys_contiguous( 43562306a36Sopenharmony_ci struct xfs_btree_cur *cur, 43662306a36Sopenharmony_ci const union xfs_btree_key *key1, 43762306a36Sopenharmony_ci const union xfs_btree_key *key2, 43862306a36Sopenharmony_ci const union xfs_btree_key *mask) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci ASSERT(!mask || mask->alloc.ar_startblock); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return xbtree_key_contig(be32_to_cpu(key1->alloc.ar_startblock), 44362306a36Sopenharmony_ci be32_to_cpu(key2->alloc.ar_startblock)); 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic const struct xfs_btree_ops xfs_bnobt_ops = { 44762306a36Sopenharmony_ci .rec_len = sizeof(xfs_alloc_rec_t), 44862306a36Sopenharmony_ci .key_len = sizeof(xfs_alloc_key_t), 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci .dup_cursor = xfs_allocbt_dup_cursor, 45162306a36Sopenharmony_ci .set_root = xfs_allocbt_set_root, 45262306a36Sopenharmony_ci .alloc_block = xfs_allocbt_alloc_block, 45362306a36Sopenharmony_ci .free_block = xfs_allocbt_free_block, 45462306a36Sopenharmony_ci .update_lastrec = xfs_allocbt_update_lastrec, 45562306a36Sopenharmony_ci .get_minrecs = xfs_allocbt_get_minrecs, 45662306a36Sopenharmony_ci .get_maxrecs = xfs_allocbt_get_maxrecs, 45762306a36Sopenharmony_ci .init_key_from_rec = xfs_allocbt_init_key_from_rec, 45862306a36Sopenharmony_ci .init_high_key_from_rec = xfs_bnobt_init_high_key_from_rec, 45962306a36Sopenharmony_ci .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, 46062306a36Sopenharmony_ci .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, 46162306a36Sopenharmony_ci .key_diff = xfs_bnobt_key_diff, 46262306a36Sopenharmony_ci .buf_ops = &xfs_bnobt_buf_ops, 46362306a36Sopenharmony_ci .diff_two_keys = xfs_bnobt_diff_two_keys, 46462306a36Sopenharmony_ci .keys_inorder = xfs_bnobt_keys_inorder, 46562306a36Sopenharmony_ci .recs_inorder = xfs_bnobt_recs_inorder, 46662306a36Sopenharmony_ci .keys_contiguous = xfs_allocbt_keys_contiguous, 46762306a36Sopenharmony_ci}; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic const struct xfs_btree_ops xfs_cntbt_ops = { 47062306a36Sopenharmony_ci .rec_len = sizeof(xfs_alloc_rec_t), 47162306a36Sopenharmony_ci .key_len = sizeof(xfs_alloc_key_t), 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci .dup_cursor = xfs_allocbt_dup_cursor, 47462306a36Sopenharmony_ci .set_root = xfs_allocbt_set_root, 47562306a36Sopenharmony_ci .alloc_block = xfs_allocbt_alloc_block, 47662306a36Sopenharmony_ci .free_block = xfs_allocbt_free_block, 47762306a36Sopenharmony_ci .update_lastrec = xfs_allocbt_update_lastrec, 47862306a36Sopenharmony_ci .get_minrecs = xfs_allocbt_get_minrecs, 47962306a36Sopenharmony_ci .get_maxrecs = xfs_allocbt_get_maxrecs, 48062306a36Sopenharmony_ci .init_key_from_rec = xfs_allocbt_init_key_from_rec, 48162306a36Sopenharmony_ci .init_high_key_from_rec = xfs_cntbt_init_high_key_from_rec, 48262306a36Sopenharmony_ci .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, 48362306a36Sopenharmony_ci .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, 48462306a36Sopenharmony_ci .key_diff = xfs_cntbt_key_diff, 48562306a36Sopenharmony_ci .buf_ops = &xfs_cntbt_buf_ops, 48662306a36Sopenharmony_ci .diff_two_keys = xfs_cntbt_diff_two_keys, 48762306a36Sopenharmony_ci .keys_inorder = xfs_cntbt_keys_inorder, 48862306a36Sopenharmony_ci .recs_inorder = xfs_cntbt_recs_inorder, 48962306a36Sopenharmony_ci .keys_contiguous = NULL, /* not needed right now */ 49062306a36Sopenharmony_ci}; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci/* Allocate most of a new allocation btree cursor. */ 49362306a36Sopenharmony_ciSTATIC struct xfs_btree_cur * 49462306a36Sopenharmony_cixfs_allocbt_init_common( 49562306a36Sopenharmony_ci struct xfs_mount *mp, 49662306a36Sopenharmony_ci struct xfs_trans *tp, 49762306a36Sopenharmony_ci struct xfs_perag *pag, 49862306a36Sopenharmony_ci xfs_btnum_t btnum) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct xfs_btree_cur *cur; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci cur = xfs_btree_alloc_cursor(mp, tp, btnum, mp->m_alloc_maxlevels, 50562306a36Sopenharmony_ci xfs_allocbt_cur_cache); 50662306a36Sopenharmony_ci cur->bc_ag.abt.active = false; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (btnum == XFS_BTNUM_CNT) { 50962306a36Sopenharmony_ci cur->bc_ops = &xfs_cntbt_ops; 51062306a36Sopenharmony_ci cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtc_2); 51162306a36Sopenharmony_ci cur->bc_flags = XFS_BTREE_LASTREC_UPDATE; 51262306a36Sopenharmony_ci } else { 51362306a36Sopenharmony_ci cur->bc_ops = &xfs_bnobt_ops; 51462306a36Sopenharmony_ci cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2); 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci cur->bc_ag.pag = xfs_perag_hold(pag); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (xfs_has_crc(mp)) 52062306a36Sopenharmony_ci cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return cur; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci/* 52662306a36Sopenharmony_ci * Allocate a new allocation btree cursor. 52762306a36Sopenharmony_ci */ 52862306a36Sopenharmony_cistruct xfs_btree_cur * /* new alloc btree cursor */ 52962306a36Sopenharmony_cixfs_allocbt_init_cursor( 53062306a36Sopenharmony_ci struct xfs_mount *mp, /* file system mount point */ 53162306a36Sopenharmony_ci struct xfs_trans *tp, /* transaction pointer */ 53262306a36Sopenharmony_ci struct xfs_buf *agbp, /* buffer for agf structure */ 53362306a36Sopenharmony_ci struct xfs_perag *pag, 53462306a36Sopenharmony_ci xfs_btnum_t btnum) /* btree identifier */ 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 53762306a36Sopenharmony_ci struct xfs_btree_cur *cur; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci cur = xfs_allocbt_init_common(mp, tp, pag, btnum); 54062306a36Sopenharmony_ci if (btnum == XFS_BTNUM_CNT) 54162306a36Sopenharmony_ci cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]); 54262306a36Sopenharmony_ci else 54362306a36Sopenharmony_ci cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci cur->bc_ag.agbp = agbp; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci return cur; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci/* Create a free space btree cursor with a fake root for staging. */ 55162306a36Sopenharmony_cistruct xfs_btree_cur * 55262306a36Sopenharmony_cixfs_allocbt_stage_cursor( 55362306a36Sopenharmony_ci struct xfs_mount *mp, 55462306a36Sopenharmony_ci struct xbtree_afakeroot *afake, 55562306a36Sopenharmony_ci struct xfs_perag *pag, 55662306a36Sopenharmony_ci xfs_btnum_t btnum) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct xfs_btree_cur *cur; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci cur = xfs_allocbt_init_common(mp, NULL, pag, btnum); 56162306a36Sopenharmony_ci xfs_btree_stage_afakeroot(cur, afake); 56262306a36Sopenharmony_ci return cur; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci/* 56662306a36Sopenharmony_ci * Install a new free space btree root. Caller is responsible for invalidating 56762306a36Sopenharmony_ci * and freeing the old btree blocks. 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_civoid 57062306a36Sopenharmony_cixfs_allocbt_commit_staged_btree( 57162306a36Sopenharmony_ci struct xfs_btree_cur *cur, 57262306a36Sopenharmony_ci struct xfs_trans *tp, 57362306a36Sopenharmony_ci struct xfs_buf *agbp) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 57662306a36Sopenharmony_ci struct xbtree_afakeroot *afake = cur->bc_ag.afake; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci ASSERT(cur->bc_flags & XFS_BTREE_STAGING); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci agf->agf_roots[cur->bc_btnum] = cpu_to_be32(afake->af_root); 58162306a36Sopenharmony_ci agf->agf_levels[cur->bc_btnum] = cpu_to_be32(afake->af_levels); 58262306a36Sopenharmony_ci xfs_alloc_log_agf(tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (cur->bc_btnum == XFS_BTNUM_BNO) { 58562306a36Sopenharmony_ci xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_bnobt_ops); 58662306a36Sopenharmony_ci } else { 58762306a36Sopenharmony_ci cur->bc_flags |= XFS_BTREE_LASTREC_UPDATE; 58862306a36Sopenharmony_ci xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_cntbt_ops); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci/* Calculate number of records in an alloc btree block. */ 59362306a36Sopenharmony_cistatic inline unsigned int 59462306a36Sopenharmony_cixfs_allocbt_block_maxrecs( 59562306a36Sopenharmony_ci unsigned int blocklen, 59662306a36Sopenharmony_ci bool leaf) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci if (leaf) 59962306a36Sopenharmony_ci return blocklen / sizeof(xfs_alloc_rec_t); 60062306a36Sopenharmony_ci return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t)); 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci/* 60462306a36Sopenharmony_ci * Calculate number of records in an alloc btree block. 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_ciint 60762306a36Sopenharmony_cixfs_allocbt_maxrecs( 60862306a36Sopenharmony_ci struct xfs_mount *mp, 60962306a36Sopenharmony_ci int blocklen, 61062306a36Sopenharmony_ci int leaf) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci blocklen -= XFS_ALLOC_BLOCK_LEN(mp); 61362306a36Sopenharmony_ci return xfs_allocbt_block_maxrecs(blocklen, leaf); 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci/* Free space btrees are at their largest when every other block is free. */ 61762306a36Sopenharmony_ci#define XFS_MAX_FREESP_RECORDS ((XFS_MAX_AG_BLOCKS + 1) / 2) 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci/* Compute the max possible height for free space btrees. */ 62062306a36Sopenharmony_ciunsigned int 62162306a36Sopenharmony_cixfs_allocbt_maxlevels_ondisk(void) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci unsigned int minrecs[2]; 62462306a36Sopenharmony_ci unsigned int blocklen; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci blocklen = min(XFS_MIN_BLOCKSIZE - XFS_BTREE_SBLOCK_LEN, 62762306a36Sopenharmony_ci XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci minrecs[0] = xfs_allocbt_block_maxrecs(blocklen, true) / 2; 63062306a36Sopenharmony_ci minrecs[1] = xfs_allocbt_block_maxrecs(blocklen, false) / 2; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_FREESP_RECORDS); 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci/* Calculate the freespace btree size for some records. */ 63662306a36Sopenharmony_cixfs_extlen_t 63762306a36Sopenharmony_cixfs_allocbt_calc_size( 63862306a36Sopenharmony_ci struct xfs_mount *mp, 63962306a36Sopenharmony_ci unsigned long long len) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci return xfs_btree_calc_size(mp->m_alloc_mnr, len); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ciint __init 64562306a36Sopenharmony_cixfs_allocbt_init_cur_cache(void) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci xfs_allocbt_cur_cache = kmem_cache_create("xfs_bnobt_cur", 64862306a36Sopenharmony_ci xfs_btree_cur_sizeof(xfs_allocbt_maxlevels_ondisk()), 64962306a36Sopenharmony_ci 0, 0, NULL); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (!xfs_allocbt_cur_cache) 65262306a36Sopenharmony_ci return -ENOMEM; 65362306a36Sopenharmony_ci return 0; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_civoid 65762306a36Sopenharmony_cixfs_allocbt_destroy_cur_cache(void) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci kmem_cache_destroy(xfs_allocbt_cur_cache); 66062306a36Sopenharmony_ci xfs_allocbt_cur_cache = NULL; 66162306a36Sopenharmony_ci} 662