18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. 48c2ecf20Sopenharmony_ci * All Rights Reserved. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include "xfs.h" 78c2ecf20Sopenharmony_ci#include "xfs_fs.h" 88c2ecf20Sopenharmony_ci#include "xfs_shared.h" 98c2ecf20Sopenharmony_ci#include "xfs_format.h" 108c2ecf20Sopenharmony_ci#include "xfs_log_format.h" 118c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h" 128c2ecf20Sopenharmony_ci#include "xfs_sb.h" 138c2ecf20Sopenharmony_ci#include "xfs_mount.h" 148c2ecf20Sopenharmony_ci#include "xfs_btree.h" 158c2ecf20Sopenharmony_ci#include "xfs_btree_staging.h" 168c2ecf20Sopenharmony_ci#include "xfs_alloc_btree.h" 178c2ecf20Sopenharmony_ci#include "xfs_alloc.h" 188c2ecf20Sopenharmony_ci#include "xfs_extent_busy.h" 198c2ecf20Sopenharmony_ci#include "xfs_error.h" 208c2ecf20Sopenharmony_ci#include "xfs_trace.h" 218c2ecf20Sopenharmony_ci#include "xfs_trans.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciSTATIC struct xfs_btree_cur * 258c2ecf20Sopenharmony_cixfs_allocbt_dup_cursor( 268c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp, 298c2ecf20Sopenharmony_ci cur->bc_ag.agbp, cur->bc_ag.agno, 308c2ecf20Sopenharmony_ci cur->bc_btnum); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciSTATIC void 348c2ecf20Sopenharmony_cixfs_allocbt_set_root( 358c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 368c2ecf20Sopenharmony_ci union xfs_btree_ptr *ptr, 378c2ecf20Sopenharmony_ci int inc) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct xfs_buf *agbp = cur->bc_ag.agbp; 408c2ecf20Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 418c2ecf20Sopenharmony_ci int btnum = cur->bc_btnum; 428c2ecf20Sopenharmony_ci struct xfs_perag *pag = agbp->b_pag; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci ASSERT(ptr->s != 0); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci agf->agf_roots[btnum] = ptr->s; 478c2ecf20Sopenharmony_ci be32_add_cpu(&agf->agf_levels[btnum], inc); 488c2ecf20Sopenharmony_ci pag->pagf_levels[btnum] += inc; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciSTATIC int 548c2ecf20Sopenharmony_cixfs_allocbt_alloc_block( 558c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 568c2ecf20Sopenharmony_ci union xfs_btree_ptr *start, 578c2ecf20Sopenharmony_ci union xfs_btree_ptr *new, 588c2ecf20Sopenharmony_ci int *stat) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci int error; 618c2ecf20Sopenharmony_ci xfs_agblock_t bno; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* Allocate the new block from the freelist. If we can't, give up. */ 648c2ecf20Sopenharmony_ci error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_ag.agbp, 658c2ecf20Sopenharmony_ci &bno, 1); 668c2ecf20Sopenharmony_ci if (error) 678c2ecf20Sopenharmony_ci return error; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (bno == NULLAGBLOCK) { 708c2ecf20Sopenharmony_ci *stat = 0; 718c2ecf20Sopenharmony_ci return 0; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agno, bno, 1, false); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci xfs_trans_agbtree_delta(cur->bc_tp, 1); 778c2ecf20Sopenharmony_ci new->s = cpu_to_be32(bno); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci *stat = 1; 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciSTATIC int 848c2ecf20Sopenharmony_cixfs_allocbt_free_block( 858c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 868c2ecf20Sopenharmony_ci struct xfs_buf *bp) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct xfs_buf *agbp = cur->bc_ag.agbp; 898c2ecf20Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 908c2ecf20Sopenharmony_ci xfs_agblock_t bno; 918c2ecf20Sopenharmony_ci int error; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp)); 948c2ecf20Sopenharmony_ci error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1); 958c2ecf20Sopenharmony_ci if (error) 968c2ecf20Sopenharmony_ci return error; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, 998c2ecf20Sopenharmony_ci XFS_EXTENT_BUSY_SKIP_DISCARD); 1008c2ecf20Sopenharmony_ci xfs_trans_agbtree_delta(cur->bc_tp, -1); 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* 1058c2ecf20Sopenharmony_ci * Update the longest extent in the AGF 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ciSTATIC void 1088c2ecf20Sopenharmony_cixfs_allocbt_update_lastrec( 1098c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 1108c2ecf20Sopenharmony_ci struct xfs_btree_block *block, 1118c2ecf20Sopenharmony_ci union xfs_btree_rec *rec, 1128c2ecf20Sopenharmony_ci int ptr, 1138c2ecf20Sopenharmony_ci int reason) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct xfs_agf *agf = cur->bc_ag.agbp->b_addr; 1168c2ecf20Sopenharmony_ci struct xfs_perag *pag; 1178c2ecf20Sopenharmony_ci __be32 len; 1188c2ecf20Sopenharmony_ci int numrecs; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci ASSERT(cur->bc_btnum == XFS_BTNUM_CNT); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci switch (reason) { 1238c2ecf20Sopenharmony_ci case LASTREC_UPDATE: 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * If this is the last leaf block and it's the last record, 1268c2ecf20Sopenharmony_ci * then update the size of the longest extent in the AG. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci if (ptr != xfs_btree_get_numrecs(block)) 1298c2ecf20Sopenharmony_ci return; 1308c2ecf20Sopenharmony_ci len = rec->alloc.ar_blockcount; 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci case LASTREC_INSREC: 1338c2ecf20Sopenharmony_ci if (be32_to_cpu(rec->alloc.ar_blockcount) <= 1348c2ecf20Sopenharmony_ci be32_to_cpu(agf->agf_longest)) 1358c2ecf20Sopenharmony_ci return; 1368c2ecf20Sopenharmony_ci len = rec->alloc.ar_blockcount; 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci case LASTREC_DELREC: 1398c2ecf20Sopenharmony_ci numrecs = xfs_btree_get_numrecs(block); 1408c2ecf20Sopenharmony_ci if (ptr <= numrecs) 1418c2ecf20Sopenharmony_ci return; 1428c2ecf20Sopenharmony_ci ASSERT(ptr == numrecs + 1); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (numrecs) { 1458c2ecf20Sopenharmony_ci xfs_alloc_rec_t *rrp; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci rrp = XFS_ALLOC_REC_ADDR(cur->bc_mp, block, numrecs); 1488c2ecf20Sopenharmony_ci len = rrp->ar_blockcount; 1498c2ecf20Sopenharmony_ci } else { 1508c2ecf20Sopenharmony_ci len = 0; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci default: 1558c2ecf20Sopenharmony_ci ASSERT(0); 1568c2ecf20Sopenharmony_ci return; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci agf->agf_longest = len; 1608c2ecf20Sopenharmony_ci pag = cur->bc_ag.agbp->b_pag; 1618c2ecf20Sopenharmony_ci pag->pagf_longest = be32_to_cpu(len); 1628c2ecf20Sopenharmony_ci xfs_alloc_log_agf(cur->bc_tp, cur->bc_ag.agbp, XFS_AGF_LONGEST); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ciSTATIC int 1668c2ecf20Sopenharmony_cixfs_allocbt_get_minrecs( 1678c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 1688c2ecf20Sopenharmony_ci int level) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci return cur->bc_mp->m_alloc_mnr[level != 0]; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ciSTATIC int 1748c2ecf20Sopenharmony_cixfs_allocbt_get_maxrecs( 1758c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 1768c2ecf20Sopenharmony_ci int level) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return cur->bc_mp->m_alloc_mxr[level != 0]; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ciSTATIC void 1828c2ecf20Sopenharmony_cixfs_allocbt_init_key_from_rec( 1838c2ecf20Sopenharmony_ci union xfs_btree_key *key, 1848c2ecf20Sopenharmony_ci union xfs_btree_rec *rec) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci key->alloc.ar_startblock = rec->alloc.ar_startblock; 1878c2ecf20Sopenharmony_ci key->alloc.ar_blockcount = rec->alloc.ar_blockcount; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ciSTATIC void 1918c2ecf20Sopenharmony_cixfs_bnobt_init_high_key_from_rec( 1928c2ecf20Sopenharmony_ci union xfs_btree_key *key, 1938c2ecf20Sopenharmony_ci union xfs_btree_rec *rec) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci __u32 x; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci x = be32_to_cpu(rec->alloc.ar_startblock); 1988c2ecf20Sopenharmony_ci x += be32_to_cpu(rec->alloc.ar_blockcount) - 1; 1998c2ecf20Sopenharmony_ci key->alloc.ar_startblock = cpu_to_be32(x); 2008c2ecf20Sopenharmony_ci key->alloc.ar_blockcount = 0; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ciSTATIC void 2048c2ecf20Sopenharmony_cixfs_cntbt_init_high_key_from_rec( 2058c2ecf20Sopenharmony_ci union xfs_btree_key *key, 2068c2ecf20Sopenharmony_ci union xfs_btree_rec *rec) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci key->alloc.ar_blockcount = rec->alloc.ar_blockcount; 2098c2ecf20Sopenharmony_ci key->alloc.ar_startblock = 0; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ciSTATIC void 2138c2ecf20Sopenharmony_cixfs_allocbt_init_rec_from_cur( 2148c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 2158c2ecf20Sopenharmony_ci union xfs_btree_rec *rec) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci rec->alloc.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock); 2188c2ecf20Sopenharmony_ci rec->alloc.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ciSTATIC void 2228c2ecf20Sopenharmony_cixfs_allocbt_init_ptr_from_cur( 2238c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 2248c2ecf20Sopenharmony_ci union xfs_btree_ptr *ptr) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct xfs_agf *agf = cur->bc_ag.agbp->b_addr; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno)); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci ptr->s = agf->agf_roots[cur->bc_btnum]; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ciSTATIC int64_t 2348c2ecf20Sopenharmony_cixfs_bnobt_key_diff( 2358c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 2368c2ecf20Sopenharmony_ci union xfs_btree_key *key) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci xfs_alloc_rec_incore_t *rec = &cur->bc_rec.a; 2398c2ecf20Sopenharmony_ci xfs_alloc_key_t *kp = &key->alloc; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return (int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ciSTATIC int64_t 2458c2ecf20Sopenharmony_cixfs_cntbt_key_diff( 2468c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 2478c2ecf20Sopenharmony_ci union xfs_btree_key *key) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci xfs_alloc_rec_incore_t *rec = &cur->bc_rec.a; 2508c2ecf20Sopenharmony_ci xfs_alloc_key_t *kp = &key->alloc; 2518c2ecf20Sopenharmony_ci int64_t diff; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci diff = (int64_t)be32_to_cpu(kp->ar_blockcount) - rec->ar_blockcount; 2548c2ecf20Sopenharmony_ci if (diff) 2558c2ecf20Sopenharmony_ci return diff; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return (int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ciSTATIC int64_t 2618c2ecf20Sopenharmony_cixfs_bnobt_diff_two_keys( 2628c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 2638c2ecf20Sopenharmony_ci union xfs_btree_key *k1, 2648c2ecf20Sopenharmony_ci union xfs_btree_key *k2) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci return (int64_t)be32_to_cpu(k1->alloc.ar_startblock) - 2678c2ecf20Sopenharmony_ci be32_to_cpu(k2->alloc.ar_startblock); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ciSTATIC int64_t 2718c2ecf20Sopenharmony_cixfs_cntbt_diff_two_keys( 2728c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 2738c2ecf20Sopenharmony_ci union xfs_btree_key *k1, 2748c2ecf20Sopenharmony_ci union xfs_btree_key *k2) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci int64_t diff; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci diff = be32_to_cpu(k1->alloc.ar_blockcount) - 2798c2ecf20Sopenharmony_ci be32_to_cpu(k2->alloc.ar_blockcount); 2808c2ecf20Sopenharmony_ci if (diff) 2818c2ecf20Sopenharmony_ci return diff; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci return be32_to_cpu(k1->alloc.ar_startblock) - 2848c2ecf20Sopenharmony_ci be32_to_cpu(k2->alloc.ar_startblock); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic xfs_failaddr_t 2888c2ecf20Sopenharmony_cixfs_allocbt_verify( 2898c2ecf20Sopenharmony_ci struct xfs_buf *bp) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct xfs_mount *mp = bp->b_mount; 2928c2ecf20Sopenharmony_ci struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 2938c2ecf20Sopenharmony_ci struct xfs_perag *pag = bp->b_pag; 2948c2ecf20Sopenharmony_ci xfs_failaddr_t fa; 2958c2ecf20Sopenharmony_ci unsigned int level; 2968c2ecf20Sopenharmony_ci xfs_btnum_t btnum = XFS_BTNUM_BNOi; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (!xfs_verify_magic(bp, block->bb_magic)) 2998c2ecf20Sopenharmony_ci return __this_address; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (xfs_sb_version_hascrc(&mp->m_sb)) { 3028c2ecf20Sopenharmony_ci fa = xfs_btree_sblock_v5hdr_verify(bp); 3038c2ecf20Sopenharmony_ci if (fa) 3048c2ecf20Sopenharmony_ci return fa; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* 3088c2ecf20Sopenharmony_ci * The perag may not be attached during grow operations or fully 3098c2ecf20Sopenharmony_ci * initialized from the AGF during log recovery. Therefore we can only 3108c2ecf20Sopenharmony_ci * check against maximum tree depth from those contexts. 3118c2ecf20Sopenharmony_ci * 3128c2ecf20Sopenharmony_ci * Otherwise check against the per-tree limit. Peek at one of the 3138c2ecf20Sopenharmony_ci * verifier magic values to determine the type of tree we're verifying 3148c2ecf20Sopenharmony_ci * against. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci level = be16_to_cpu(block->bb_level); 3178c2ecf20Sopenharmony_ci if (bp->b_ops->magic[0] == cpu_to_be32(XFS_ABTC_MAGIC)) 3188c2ecf20Sopenharmony_ci btnum = XFS_BTNUM_CNTi; 3198c2ecf20Sopenharmony_ci if (pag && pag->pagf_init) { 3208c2ecf20Sopenharmony_ci if (level >= pag->pagf_levels[btnum]) 3218c2ecf20Sopenharmony_ci return __this_address; 3228c2ecf20Sopenharmony_ci } else if (level >= mp->m_ag_maxlevels) 3238c2ecf20Sopenharmony_ci return __this_address; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return xfs_btree_sblock_verify(bp, mp->m_alloc_mxr[level != 0]); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic void 3298c2ecf20Sopenharmony_cixfs_allocbt_read_verify( 3308c2ecf20Sopenharmony_ci struct xfs_buf *bp) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci xfs_failaddr_t fa; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!xfs_btree_sblock_verify_crc(bp)) 3358c2ecf20Sopenharmony_ci xfs_verifier_error(bp, -EFSBADCRC, __this_address); 3368c2ecf20Sopenharmony_ci else { 3378c2ecf20Sopenharmony_ci fa = xfs_allocbt_verify(bp); 3388c2ecf20Sopenharmony_ci if (fa) 3398c2ecf20Sopenharmony_ci xfs_verifier_error(bp, -EFSCORRUPTED, fa); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (bp->b_error) 3438c2ecf20Sopenharmony_ci trace_xfs_btree_corrupt(bp, _RET_IP_); 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic void 3478c2ecf20Sopenharmony_cixfs_allocbt_write_verify( 3488c2ecf20Sopenharmony_ci struct xfs_buf *bp) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci xfs_failaddr_t fa; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci fa = xfs_allocbt_verify(bp); 3538c2ecf20Sopenharmony_ci if (fa) { 3548c2ecf20Sopenharmony_ci trace_xfs_btree_corrupt(bp, _RET_IP_); 3558c2ecf20Sopenharmony_ci xfs_verifier_error(bp, -EFSCORRUPTED, fa); 3568c2ecf20Sopenharmony_ci return; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci xfs_btree_sblock_calc_crc(bp); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ciconst struct xfs_buf_ops xfs_bnobt_buf_ops = { 3638c2ecf20Sopenharmony_ci .name = "xfs_bnobt", 3648c2ecf20Sopenharmony_ci .magic = { cpu_to_be32(XFS_ABTB_MAGIC), 3658c2ecf20Sopenharmony_ci cpu_to_be32(XFS_ABTB_CRC_MAGIC) }, 3668c2ecf20Sopenharmony_ci .verify_read = xfs_allocbt_read_verify, 3678c2ecf20Sopenharmony_ci .verify_write = xfs_allocbt_write_verify, 3688c2ecf20Sopenharmony_ci .verify_struct = xfs_allocbt_verify, 3698c2ecf20Sopenharmony_ci}; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ciconst struct xfs_buf_ops xfs_cntbt_buf_ops = { 3728c2ecf20Sopenharmony_ci .name = "xfs_cntbt", 3738c2ecf20Sopenharmony_ci .magic = { cpu_to_be32(XFS_ABTC_MAGIC), 3748c2ecf20Sopenharmony_ci cpu_to_be32(XFS_ABTC_CRC_MAGIC) }, 3758c2ecf20Sopenharmony_ci .verify_read = xfs_allocbt_read_verify, 3768c2ecf20Sopenharmony_ci .verify_write = xfs_allocbt_write_verify, 3778c2ecf20Sopenharmony_ci .verify_struct = xfs_allocbt_verify, 3788c2ecf20Sopenharmony_ci}; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ciSTATIC int 3818c2ecf20Sopenharmony_cixfs_bnobt_keys_inorder( 3828c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 3838c2ecf20Sopenharmony_ci union xfs_btree_key *k1, 3848c2ecf20Sopenharmony_ci union xfs_btree_key *k2) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci return be32_to_cpu(k1->alloc.ar_startblock) < 3878c2ecf20Sopenharmony_ci be32_to_cpu(k2->alloc.ar_startblock); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ciSTATIC int 3918c2ecf20Sopenharmony_cixfs_bnobt_recs_inorder( 3928c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 3938c2ecf20Sopenharmony_ci union xfs_btree_rec *r1, 3948c2ecf20Sopenharmony_ci union xfs_btree_rec *r2) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci return be32_to_cpu(r1->alloc.ar_startblock) + 3978c2ecf20Sopenharmony_ci be32_to_cpu(r1->alloc.ar_blockcount) <= 3988c2ecf20Sopenharmony_ci be32_to_cpu(r2->alloc.ar_startblock); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ciSTATIC int 4028c2ecf20Sopenharmony_cixfs_cntbt_keys_inorder( 4038c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 4048c2ecf20Sopenharmony_ci union xfs_btree_key *k1, 4058c2ecf20Sopenharmony_ci union xfs_btree_key *k2) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci return be32_to_cpu(k1->alloc.ar_blockcount) < 4088c2ecf20Sopenharmony_ci be32_to_cpu(k2->alloc.ar_blockcount) || 4098c2ecf20Sopenharmony_ci (k1->alloc.ar_blockcount == k2->alloc.ar_blockcount && 4108c2ecf20Sopenharmony_ci be32_to_cpu(k1->alloc.ar_startblock) < 4118c2ecf20Sopenharmony_ci be32_to_cpu(k2->alloc.ar_startblock)); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ciSTATIC int 4158c2ecf20Sopenharmony_cixfs_cntbt_recs_inorder( 4168c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 4178c2ecf20Sopenharmony_ci union xfs_btree_rec *r1, 4188c2ecf20Sopenharmony_ci union xfs_btree_rec *r2) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci return be32_to_cpu(r1->alloc.ar_blockcount) < 4218c2ecf20Sopenharmony_ci be32_to_cpu(r2->alloc.ar_blockcount) || 4228c2ecf20Sopenharmony_ci (r1->alloc.ar_blockcount == r2->alloc.ar_blockcount && 4238c2ecf20Sopenharmony_ci be32_to_cpu(r1->alloc.ar_startblock) < 4248c2ecf20Sopenharmony_ci be32_to_cpu(r2->alloc.ar_startblock)); 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic const struct xfs_btree_ops xfs_bnobt_ops = { 4288c2ecf20Sopenharmony_ci .rec_len = sizeof(xfs_alloc_rec_t), 4298c2ecf20Sopenharmony_ci .key_len = sizeof(xfs_alloc_key_t), 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci .dup_cursor = xfs_allocbt_dup_cursor, 4328c2ecf20Sopenharmony_ci .set_root = xfs_allocbt_set_root, 4338c2ecf20Sopenharmony_ci .alloc_block = xfs_allocbt_alloc_block, 4348c2ecf20Sopenharmony_ci .free_block = xfs_allocbt_free_block, 4358c2ecf20Sopenharmony_ci .update_lastrec = xfs_allocbt_update_lastrec, 4368c2ecf20Sopenharmony_ci .get_minrecs = xfs_allocbt_get_minrecs, 4378c2ecf20Sopenharmony_ci .get_maxrecs = xfs_allocbt_get_maxrecs, 4388c2ecf20Sopenharmony_ci .init_key_from_rec = xfs_allocbt_init_key_from_rec, 4398c2ecf20Sopenharmony_ci .init_high_key_from_rec = xfs_bnobt_init_high_key_from_rec, 4408c2ecf20Sopenharmony_ci .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, 4418c2ecf20Sopenharmony_ci .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, 4428c2ecf20Sopenharmony_ci .key_diff = xfs_bnobt_key_diff, 4438c2ecf20Sopenharmony_ci .buf_ops = &xfs_bnobt_buf_ops, 4448c2ecf20Sopenharmony_ci .diff_two_keys = xfs_bnobt_diff_two_keys, 4458c2ecf20Sopenharmony_ci .keys_inorder = xfs_bnobt_keys_inorder, 4468c2ecf20Sopenharmony_ci .recs_inorder = xfs_bnobt_recs_inorder, 4478c2ecf20Sopenharmony_ci}; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic const struct xfs_btree_ops xfs_cntbt_ops = { 4508c2ecf20Sopenharmony_ci .rec_len = sizeof(xfs_alloc_rec_t), 4518c2ecf20Sopenharmony_ci .key_len = sizeof(xfs_alloc_key_t), 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci .dup_cursor = xfs_allocbt_dup_cursor, 4548c2ecf20Sopenharmony_ci .set_root = xfs_allocbt_set_root, 4558c2ecf20Sopenharmony_ci .alloc_block = xfs_allocbt_alloc_block, 4568c2ecf20Sopenharmony_ci .free_block = xfs_allocbt_free_block, 4578c2ecf20Sopenharmony_ci .update_lastrec = xfs_allocbt_update_lastrec, 4588c2ecf20Sopenharmony_ci .get_minrecs = xfs_allocbt_get_minrecs, 4598c2ecf20Sopenharmony_ci .get_maxrecs = xfs_allocbt_get_maxrecs, 4608c2ecf20Sopenharmony_ci .init_key_from_rec = xfs_allocbt_init_key_from_rec, 4618c2ecf20Sopenharmony_ci .init_high_key_from_rec = xfs_cntbt_init_high_key_from_rec, 4628c2ecf20Sopenharmony_ci .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, 4638c2ecf20Sopenharmony_ci .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, 4648c2ecf20Sopenharmony_ci .key_diff = xfs_cntbt_key_diff, 4658c2ecf20Sopenharmony_ci .buf_ops = &xfs_cntbt_buf_ops, 4668c2ecf20Sopenharmony_ci .diff_two_keys = xfs_cntbt_diff_two_keys, 4678c2ecf20Sopenharmony_ci .keys_inorder = xfs_cntbt_keys_inorder, 4688c2ecf20Sopenharmony_ci .recs_inorder = xfs_cntbt_recs_inorder, 4698c2ecf20Sopenharmony_ci}; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/* Allocate most of a new allocation btree cursor. */ 4728c2ecf20Sopenharmony_ciSTATIC struct xfs_btree_cur * 4738c2ecf20Sopenharmony_cixfs_allocbt_init_common( 4748c2ecf20Sopenharmony_ci struct xfs_mount *mp, 4758c2ecf20Sopenharmony_ci struct xfs_trans *tp, 4768c2ecf20Sopenharmony_ci xfs_agnumber_t agno, 4778c2ecf20Sopenharmony_ci xfs_btnum_t btnum) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci cur = kmem_cache_zalloc(xfs_btree_cur_zone, GFP_NOFS | __GFP_NOFAIL); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci cur->bc_tp = tp; 4868c2ecf20Sopenharmony_ci cur->bc_mp = mp; 4878c2ecf20Sopenharmony_ci cur->bc_btnum = btnum; 4888c2ecf20Sopenharmony_ci cur->bc_blocklog = mp->m_sb.sb_blocklog; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (btnum == XFS_BTNUM_CNT) { 4918c2ecf20Sopenharmony_ci cur->bc_ops = &xfs_cntbt_ops; 4928c2ecf20Sopenharmony_ci cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtc_2); 4938c2ecf20Sopenharmony_ci cur->bc_flags = XFS_BTREE_LASTREC_UPDATE; 4948c2ecf20Sopenharmony_ci } else { 4958c2ecf20Sopenharmony_ci cur->bc_ops = &xfs_bnobt_ops; 4968c2ecf20Sopenharmony_ci cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2); 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci cur->bc_ag.agno = agno; 5008c2ecf20Sopenharmony_ci cur->bc_ag.abt.active = false; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (xfs_sb_version_hascrc(&mp->m_sb)) 5038c2ecf20Sopenharmony_ci cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return cur; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci/* 5098c2ecf20Sopenharmony_ci * Allocate a new allocation btree cursor. 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_cistruct xfs_btree_cur * /* new alloc btree cursor */ 5128c2ecf20Sopenharmony_cixfs_allocbt_init_cursor( 5138c2ecf20Sopenharmony_ci struct xfs_mount *mp, /* file system mount point */ 5148c2ecf20Sopenharmony_ci struct xfs_trans *tp, /* transaction pointer */ 5158c2ecf20Sopenharmony_ci struct xfs_buf *agbp, /* buffer for agf structure */ 5168c2ecf20Sopenharmony_ci xfs_agnumber_t agno, /* allocation group number */ 5178c2ecf20Sopenharmony_ci xfs_btnum_t btnum) /* btree identifier */ 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 5208c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci cur = xfs_allocbt_init_common(mp, tp, agno, btnum); 5238c2ecf20Sopenharmony_ci if (btnum == XFS_BTNUM_CNT) 5248c2ecf20Sopenharmony_ci cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]); 5258c2ecf20Sopenharmony_ci else 5268c2ecf20Sopenharmony_ci cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci cur->bc_ag.agbp = agbp; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return cur; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/* Create a free space btree cursor with a fake root for staging. */ 5348c2ecf20Sopenharmony_cistruct xfs_btree_cur * 5358c2ecf20Sopenharmony_cixfs_allocbt_stage_cursor( 5368c2ecf20Sopenharmony_ci struct xfs_mount *mp, 5378c2ecf20Sopenharmony_ci struct xbtree_afakeroot *afake, 5388c2ecf20Sopenharmony_ci xfs_agnumber_t agno, 5398c2ecf20Sopenharmony_ci xfs_btnum_t btnum) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci cur = xfs_allocbt_init_common(mp, NULL, agno, btnum); 5448c2ecf20Sopenharmony_ci xfs_btree_stage_afakeroot(cur, afake); 5458c2ecf20Sopenharmony_ci return cur; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci/* 5498c2ecf20Sopenharmony_ci * Install a new free space btree root. Caller is responsible for invalidating 5508c2ecf20Sopenharmony_ci * and freeing the old btree blocks. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_civoid 5538c2ecf20Sopenharmony_cixfs_allocbt_commit_staged_btree( 5548c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 5558c2ecf20Sopenharmony_ci struct xfs_trans *tp, 5568c2ecf20Sopenharmony_ci struct xfs_buf *agbp) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 5598c2ecf20Sopenharmony_ci struct xbtree_afakeroot *afake = cur->bc_ag.afake; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci ASSERT(cur->bc_flags & XFS_BTREE_STAGING); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci agf->agf_roots[cur->bc_btnum] = cpu_to_be32(afake->af_root); 5648c2ecf20Sopenharmony_ci agf->agf_levels[cur->bc_btnum] = cpu_to_be32(afake->af_levels); 5658c2ecf20Sopenharmony_ci xfs_alloc_log_agf(tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (cur->bc_btnum == XFS_BTNUM_BNO) { 5688c2ecf20Sopenharmony_ci xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_bnobt_ops); 5698c2ecf20Sopenharmony_ci } else { 5708c2ecf20Sopenharmony_ci cur->bc_flags |= XFS_BTREE_LASTREC_UPDATE; 5718c2ecf20Sopenharmony_ci xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_cntbt_ops); 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/* 5768c2ecf20Sopenharmony_ci * Calculate number of records in an alloc btree block. 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_ciint 5798c2ecf20Sopenharmony_cixfs_allocbt_maxrecs( 5808c2ecf20Sopenharmony_ci struct xfs_mount *mp, 5818c2ecf20Sopenharmony_ci int blocklen, 5828c2ecf20Sopenharmony_ci int leaf) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci blocklen -= XFS_ALLOC_BLOCK_LEN(mp); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (leaf) 5878c2ecf20Sopenharmony_ci return blocklen / sizeof(xfs_alloc_rec_t); 5888c2ecf20Sopenharmony_ci return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t)); 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci/* Calculate the freespace btree size for some records. */ 5928c2ecf20Sopenharmony_cixfs_extlen_t 5938c2ecf20Sopenharmony_cixfs_allocbt_calc_size( 5948c2ecf20Sopenharmony_ci struct xfs_mount *mp, 5958c2ecf20Sopenharmony_ci unsigned long long len) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci return xfs_btree_calc_size(mp->m_alloc_mnr, len); 5988c2ecf20Sopenharmony_ci} 599