18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Oracle. All Rights Reserved. 48c2ecf20Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com> 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_refcount_btree.h" 178c2ecf20Sopenharmony_ci#include "xfs_alloc.h" 188c2ecf20Sopenharmony_ci#include "xfs_error.h" 198c2ecf20Sopenharmony_ci#include "xfs_trace.h" 208c2ecf20Sopenharmony_ci#include "xfs_trans.h" 218c2ecf20Sopenharmony_ci#include "xfs_bit.h" 228c2ecf20Sopenharmony_ci#include "xfs_rmap.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic struct xfs_btree_cur * 258c2ecf20Sopenharmony_cixfs_refcountbt_dup_cursor( 268c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp, 298c2ecf20Sopenharmony_ci cur->bc_ag.agbp, cur->bc_ag.agno); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciSTATIC void 338c2ecf20Sopenharmony_cixfs_refcountbt_set_root( 348c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 358c2ecf20Sopenharmony_ci union xfs_btree_ptr *ptr, 368c2ecf20Sopenharmony_ci int inc) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct xfs_buf *agbp = cur->bc_ag.agbp; 398c2ecf20Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 408c2ecf20Sopenharmony_ci struct xfs_perag *pag = agbp->b_pag; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci ASSERT(ptr->s != 0); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci agf->agf_refcount_root = ptr->s; 458c2ecf20Sopenharmony_ci be32_add_cpu(&agf->agf_refcount_level, inc); 468c2ecf20Sopenharmony_ci pag->pagf_refcount_level += inc; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci xfs_alloc_log_agf(cur->bc_tp, agbp, 498c2ecf20Sopenharmony_ci XFS_AGF_REFCOUNT_ROOT | XFS_AGF_REFCOUNT_LEVEL); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciSTATIC int 538c2ecf20Sopenharmony_cixfs_refcountbt_alloc_block( 548c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 558c2ecf20Sopenharmony_ci union xfs_btree_ptr *start, 568c2ecf20Sopenharmony_ci union xfs_btree_ptr *new, 578c2ecf20Sopenharmony_ci int *stat) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct xfs_buf *agbp = cur->bc_ag.agbp; 608c2ecf20Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 618c2ecf20Sopenharmony_ci struct xfs_alloc_arg args; /* block allocation args */ 628c2ecf20Sopenharmony_ci int error; /* error return value */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci memset(&args, 0, sizeof(args)); 658c2ecf20Sopenharmony_ci args.tp = cur->bc_tp; 668c2ecf20Sopenharmony_ci args.mp = cur->bc_mp; 678c2ecf20Sopenharmony_ci args.type = XFS_ALLOCTYPE_NEAR_BNO; 688c2ecf20Sopenharmony_ci args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.agno, 698c2ecf20Sopenharmony_ci xfs_refc_block(args.mp)); 708c2ecf20Sopenharmony_ci args.oinfo = XFS_RMAP_OINFO_REFC; 718c2ecf20Sopenharmony_ci args.minlen = args.maxlen = args.prod = 1; 728c2ecf20Sopenharmony_ci args.resv = XFS_AG_RESV_METADATA; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci error = xfs_alloc_vextent(&args); 758c2ecf20Sopenharmony_ci if (error) 768c2ecf20Sopenharmony_ci goto out_error; 778c2ecf20Sopenharmony_ci trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_ag.agno, 788c2ecf20Sopenharmony_ci args.agbno, 1); 798c2ecf20Sopenharmony_ci if (args.fsbno == NULLFSBLOCK) { 808c2ecf20Sopenharmony_ci *stat = 0; 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci ASSERT(args.agno == cur->bc_ag.agno); 848c2ecf20Sopenharmony_ci ASSERT(args.len == 1); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci new->s = cpu_to_be32(args.agbno); 878c2ecf20Sopenharmony_ci be32_add_cpu(&agf->agf_refcount_blocks, 1); 888c2ecf20Sopenharmony_ci xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci *stat = 1; 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciout_error: 948c2ecf20Sopenharmony_ci return error; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciSTATIC int 988c2ecf20Sopenharmony_cixfs_refcountbt_free_block( 998c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 1008c2ecf20Sopenharmony_ci struct xfs_buf *bp) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct xfs_mount *mp = cur->bc_mp; 1038c2ecf20Sopenharmony_ci struct xfs_buf *agbp = cur->bc_ag.agbp; 1048c2ecf20Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 1058c2ecf20Sopenharmony_ci xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); 1068c2ecf20Sopenharmony_ci int error; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_ag.agno, 1098c2ecf20Sopenharmony_ci XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1); 1108c2ecf20Sopenharmony_ci be32_add_cpu(&agf->agf_refcount_blocks, -1); 1118c2ecf20Sopenharmony_ci xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS); 1128c2ecf20Sopenharmony_ci error = xfs_free_extent(cur->bc_tp, fsbno, 1, &XFS_RMAP_OINFO_REFC, 1138c2ecf20Sopenharmony_ci XFS_AG_RESV_METADATA); 1148c2ecf20Sopenharmony_ci if (error) 1158c2ecf20Sopenharmony_ci return error; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return error; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciSTATIC int 1218c2ecf20Sopenharmony_cixfs_refcountbt_get_minrecs( 1228c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 1238c2ecf20Sopenharmony_ci int level) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci return cur->bc_mp->m_refc_mnr[level != 0]; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ciSTATIC int 1298c2ecf20Sopenharmony_cixfs_refcountbt_get_maxrecs( 1308c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 1318c2ecf20Sopenharmony_ci int level) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci return cur->bc_mp->m_refc_mxr[level != 0]; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciSTATIC void 1378c2ecf20Sopenharmony_cixfs_refcountbt_init_key_from_rec( 1388c2ecf20Sopenharmony_ci union xfs_btree_key *key, 1398c2ecf20Sopenharmony_ci union xfs_btree_rec *rec) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci key->refc.rc_startblock = rec->refc.rc_startblock; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ciSTATIC void 1458c2ecf20Sopenharmony_cixfs_refcountbt_init_high_key_from_rec( 1468c2ecf20Sopenharmony_ci union xfs_btree_key *key, 1478c2ecf20Sopenharmony_ci union xfs_btree_rec *rec) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci __u32 x; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci x = be32_to_cpu(rec->refc.rc_startblock); 1528c2ecf20Sopenharmony_ci x += be32_to_cpu(rec->refc.rc_blockcount) - 1; 1538c2ecf20Sopenharmony_ci key->refc.rc_startblock = cpu_to_be32(x); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ciSTATIC void 1578c2ecf20Sopenharmony_cixfs_refcountbt_init_rec_from_cur( 1588c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 1598c2ecf20Sopenharmony_ci union xfs_btree_rec *rec) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci rec->refc.rc_startblock = cpu_to_be32(cur->bc_rec.rc.rc_startblock); 1628c2ecf20Sopenharmony_ci rec->refc.rc_blockcount = cpu_to_be32(cur->bc_rec.rc.rc_blockcount); 1638c2ecf20Sopenharmony_ci rec->refc.rc_refcount = cpu_to_be32(cur->bc_rec.rc.rc_refcount); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ciSTATIC void 1678c2ecf20Sopenharmony_cixfs_refcountbt_init_ptr_from_cur( 1688c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 1698c2ecf20Sopenharmony_ci union xfs_btree_ptr *ptr) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct xfs_agf *agf = cur->bc_ag.agbp->b_addr; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno)); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci ptr->s = agf->agf_refcount_root; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ciSTATIC int64_t 1798c2ecf20Sopenharmony_cixfs_refcountbt_key_diff( 1808c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 1818c2ecf20Sopenharmony_ci union xfs_btree_key *key) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct xfs_refcount_irec *rec = &cur->bc_rec.rc; 1848c2ecf20Sopenharmony_ci struct xfs_refcount_key *kp = &key->refc; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return (int64_t)be32_to_cpu(kp->rc_startblock) - rec->rc_startblock; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ciSTATIC int64_t 1908c2ecf20Sopenharmony_cixfs_refcountbt_diff_two_keys( 1918c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 1928c2ecf20Sopenharmony_ci union xfs_btree_key *k1, 1938c2ecf20Sopenharmony_ci union xfs_btree_key *k2) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci return (int64_t)be32_to_cpu(k1->refc.rc_startblock) - 1968c2ecf20Sopenharmony_ci be32_to_cpu(k2->refc.rc_startblock); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ciSTATIC xfs_failaddr_t 2008c2ecf20Sopenharmony_cixfs_refcountbt_verify( 2018c2ecf20Sopenharmony_ci struct xfs_buf *bp) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct xfs_mount *mp = bp->b_mount; 2048c2ecf20Sopenharmony_ci struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 2058c2ecf20Sopenharmony_ci struct xfs_perag *pag = bp->b_pag; 2068c2ecf20Sopenharmony_ci xfs_failaddr_t fa; 2078c2ecf20Sopenharmony_ci unsigned int level; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (!xfs_verify_magic(bp, block->bb_magic)) 2108c2ecf20Sopenharmony_ci return __this_address; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (!xfs_sb_version_hasreflink(&mp->m_sb)) 2138c2ecf20Sopenharmony_ci return __this_address; 2148c2ecf20Sopenharmony_ci fa = xfs_btree_sblock_v5hdr_verify(bp); 2158c2ecf20Sopenharmony_ci if (fa) 2168c2ecf20Sopenharmony_ci return fa; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci level = be16_to_cpu(block->bb_level); 2198c2ecf20Sopenharmony_ci if (pag && pag->pagf_init) { 2208c2ecf20Sopenharmony_ci if (level >= pag->pagf_refcount_level) 2218c2ecf20Sopenharmony_ci return __this_address; 2228c2ecf20Sopenharmony_ci } else if (level >= mp->m_refc_maxlevels) 2238c2ecf20Sopenharmony_ci return __this_address; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return xfs_btree_sblock_verify(bp, mp->m_refc_mxr[level != 0]); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciSTATIC void 2298c2ecf20Sopenharmony_cixfs_refcountbt_read_verify( 2308c2ecf20Sopenharmony_ci struct xfs_buf *bp) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci xfs_failaddr_t fa; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (!xfs_btree_sblock_verify_crc(bp)) 2358c2ecf20Sopenharmony_ci xfs_verifier_error(bp, -EFSBADCRC, __this_address); 2368c2ecf20Sopenharmony_ci else { 2378c2ecf20Sopenharmony_ci fa = xfs_refcountbt_verify(bp); 2388c2ecf20Sopenharmony_ci if (fa) 2398c2ecf20Sopenharmony_ci xfs_verifier_error(bp, -EFSCORRUPTED, fa); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (bp->b_error) 2438c2ecf20Sopenharmony_ci trace_xfs_btree_corrupt(bp, _RET_IP_); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciSTATIC void 2478c2ecf20Sopenharmony_cixfs_refcountbt_write_verify( 2488c2ecf20Sopenharmony_ci struct xfs_buf *bp) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci xfs_failaddr_t fa; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci fa = xfs_refcountbt_verify(bp); 2538c2ecf20Sopenharmony_ci if (fa) { 2548c2ecf20Sopenharmony_ci trace_xfs_btree_corrupt(bp, _RET_IP_); 2558c2ecf20Sopenharmony_ci xfs_verifier_error(bp, -EFSCORRUPTED, fa); 2568c2ecf20Sopenharmony_ci return; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci xfs_btree_sblock_calc_crc(bp); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ciconst struct xfs_buf_ops xfs_refcountbt_buf_ops = { 2638c2ecf20Sopenharmony_ci .name = "xfs_refcountbt", 2648c2ecf20Sopenharmony_ci .magic = { 0, cpu_to_be32(XFS_REFC_CRC_MAGIC) }, 2658c2ecf20Sopenharmony_ci .verify_read = xfs_refcountbt_read_verify, 2668c2ecf20Sopenharmony_ci .verify_write = xfs_refcountbt_write_verify, 2678c2ecf20Sopenharmony_ci .verify_struct = xfs_refcountbt_verify, 2688c2ecf20Sopenharmony_ci}; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ciSTATIC int 2718c2ecf20Sopenharmony_cixfs_refcountbt_keys_inorder( 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 return be32_to_cpu(k1->refc.rc_startblock) < 2778c2ecf20Sopenharmony_ci be32_to_cpu(k2->refc.rc_startblock); 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ciSTATIC int 2818c2ecf20Sopenharmony_cixfs_refcountbt_recs_inorder( 2828c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 2838c2ecf20Sopenharmony_ci union xfs_btree_rec *r1, 2848c2ecf20Sopenharmony_ci union xfs_btree_rec *r2) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci return be32_to_cpu(r1->refc.rc_startblock) + 2878c2ecf20Sopenharmony_ci be32_to_cpu(r1->refc.rc_blockcount) <= 2888c2ecf20Sopenharmony_ci be32_to_cpu(r2->refc.rc_startblock); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic const struct xfs_btree_ops xfs_refcountbt_ops = { 2928c2ecf20Sopenharmony_ci .rec_len = sizeof(struct xfs_refcount_rec), 2938c2ecf20Sopenharmony_ci .key_len = sizeof(struct xfs_refcount_key), 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci .dup_cursor = xfs_refcountbt_dup_cursor, 2968c2ecf20Sopenharmony_ci .set_root = xfs_refcountbt_set_root, 2978c2ecf20Sopenharmony_ci .alloc_block = xfs_refcountbt_alloc_block, 2988c2ecf20Sopenharmony_ci .free_block = xfs_refcountbt_free_block, 2998c2ecf20Sopenharmony_ci .get_minrecs = xfs_refcountbt_get_minrecs, 3008c2ecf20Sopenharmony_ci .get_maxrecs = xfs_refcountbt_get_maxrecs, 3018c2ecf20Sopenharmony_ci .init_key_from_rec = xfs_refcountbt_init_key_from_rec, 3028c2ecf20Sopenharmony_ci .init_high_key_from_rec = xfs_refcountbt_init_high_key_from_rec, 3038c2ecf20Sopenharmony_ci .init_rec_from_cur = xfs_refcountbt_init_rec_from_cur, 3048c2ecf20Sopenharmony_ci .init_ptr_from_cur = xfs_refcountbt_init_ptr_from_cur, 3058c2ecf20Sopenharmony_ci .key_diff = xfs_refcountbt_key_diff, 3068c2ecf20Sopenharmony_ci .buf_ops = &xfs_refcountbt_buf_ops, 3078c2ecf20Sopenharmony_ci .diff_two_keys = xfs_refcountbt_diff_two_keys, 3088c2ecf20Sopenharmony_ci .keys_inorder = xfs_refcountbt_keys_inorder, 3098c2ecf20Sopenharmony_ci .recs_inorder = xfs_refcountbt_recs_inorder, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci/* 3138c2ecf20Sopenharmony_ci * Initialize a new refcount btree cursor. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_cistatic struct xfs_btree_cur * 3168c2ecf20Sopenharmony_cixfs_refcountbt_init_common( 3178c2ecf20Sopenharmony_ci struct xfs_mount *mp, 3188c2ecf20Sopenharmony_ci struct xfs_trans *tp, 3198c2ecf20Sopenharmony_ci xfs_agnumber_t agno) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci ASSERT(agno != NULLAGNUMBER); 3248c2ecf20Sopenharmony_ci ASSERT(agno < mp->m_sb.sb_agcount); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci cur = kmem_cache_zalloc(xfs_btree_cur_zone, GFP_NOFS | __GFP_NOFAIL); 3278c2ecf20Sopenharmony_ci cur->bc_tp = tp; 3288c2ecf20Sopenharmony_ci cur->bc_mp = mp; 3298c2ecf20Sopenharmony_ci cur->bc_btnum = XFS_BTNUM_REFC; 3308c2ecf20Sopenharmony_ci cur->bc_blocklog = mp->m_sb.sb_blocklog; 3318c2ecf20Sopenharmony_ci cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci cur->bc_ag.agno = agno; 3348c2ecf20Sopenharmony_ci cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci cur->bc_ag.refc.nr_ops = 0; 3378c2ecf20Sopenharmony_ci cur->bc_ag.refc.shape_changes = 0; 3388c2ecf20Sopenharmony_ci cur->bc_ops = &xfs_refcountbt_ops; 3398c2ecf20Sopenharmony_ci return cur; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci/* Create a btree cursor. */ 3438c2ecf20Sopenharmony_cistruct xfs_btree_cur * 3448c2ecf20Sopenharmony_cixfs_refcountbt_init_cursor( 3458c2ecf20Sopenharmony_ci struct xfs_mount *mp, 3468c2ecf20Sopenharmony_ci struct xfs_trans *tp, 3478c2ecf20Sopenharmony_ci struct xfs_buf *agbp, 3488c2ecf20Sopenharmony_ci xfs_agnumber_t agno) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 3518c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci cur = xfs_refcountbt_init_common(mp, tp, agno); 3548c2ecf20Sopenharmony_ci cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level); 3558c2ecf20Sopenharmony_ci cur->bc_ag.agbp = agbp; 3568c2ecf20Sopenharmony_ci return cur; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/* Create a btree cursor with a fake root for staging. */ 3608c2ecf20Sopenharmony_cistruct xfs_btree_cur * 3618c2ecf20Sopenharmony_cixfs_refcountbt_stage_cursor( 3628c2ecf20Sopenharmony_ci struct xfs_mount *mp, 3638c2ecf20Sopenharmony_ci struct xbtree_afakeroot *afake, 3648c2ecf20Sopenharmony_ci xfs_agnumber_t agno) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci cur = xfs_refcountbt_init_common(mp, NULL, agno); 3698c2ecf20Sopenharmony_ci xfs_btree_stage_afakeroot(cur, afake); 3708c2ecf20Sopenharmony_ci return cur; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci/* 3748c2ecf20Sopenharmony_ci * Swap in the new btree root. Once we pass this point the newly rebuilt btree 3758c2ecf20Sopenharmony_ci * is in place and we have to kill off all the old btree blocks. 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_civoid 3788c2ecf20Sopenharmony_cixfs_refcountbt_commit_staged_btree( 3798c2ecf20Sopenharmony_ci struct xfs_btree_cur *cur, 3808c2ecf20Sopenharmony_ci struct xfs_trans *tp, 3818c2ecf20Sopenharmony_ci struct xfs_buf *agbp) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 3848c2ecf20Sopenharmony_ci struct xbtree_afakeroot *afake = cur->bc_ag.afake; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ASSERT(cur->bc_flags & XFS_BTREE_STAGING); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci agf->agf_refcount_root = cpu_to_be32(afake->af_root); 3898c2ecf20Sopenharmony_ci agf->agf_refcount_level = cpu_to_be32(afake->af_levels); 3908c2ecf20Sopenharmony_ci agf->agf_refcount_blocks = cpu_to_be32(afake->af_blocks); 3918c2ecf20Sopenharmony_ci xfs_alloc_log_agf(tp, agbp, XFS_AGF_REFCOUNT_BLOCKS | 3928c2ecf20Sopenharmony_ci XFS_AGF_REFCOUNT_ROOT | 3938c2ecf20Sopenharmony_ci XFS_AGF_REFCOUNT_LEVEL); 3948c2ecf20Sopenharmony_ci xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_refcountbt_ops); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/* 3988c2ecf20Sopenharmony_ci * Calculate the number of records in a refcount btree block. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_ciint 4018c2ecf20Sopenharmony_cixfs_refcountbt_maxrecs( 4028c2ecf20Sopenharmony_ci int blocklen, 4038c2ecf20Sopenharmony_ci bool leaf) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci blocklen -= XFS_REFCOUNT_BLOCK_LEN; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (leaf) 4088c2ecf20Sopenharmony_ci return blocklen / sizeof(struct xfs_refcount_rec); 4098c2ecf20Sopenharmony_ci return blocklen / (sizeof(struct xfs_refcount_key) + 4108c2ecf20Sopenharmony_ci sizeof(xfs_refcount_ptr_t)); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci/* Compute the maximum height of a refcount btree. */ 4148c2ecf20Sopenharmony_civoid 4158c2ecf20Sopenharmony_cixfs_refcountbt_compute_maxlevels( 4168c2ecf20Sopenharmony_ci struct xfs_mount *mp) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci mp->m_refc_maxlevels = xfs_btree_compute_maxlevels( 4198c2ecf20Sopenharmony_ci mp->m_refc_mnr, mp->m_sb.sb_agblocks); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci/* Calculate the refcount btree size for some records. */ 4238c2ecf20Sopenharmony_cixfs_extlen_t 4248c2ecf20Sopenharmony_cixfs_refcountbt_calc_size( 4258c2ecf20Sopenharmony_ci struct xfs_mount *mp, 4268c2ecf20Sopenharmony_ci unsigned long long len) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci return xfs_btree_calc_size(mp->m_refc_mnr, len); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci/* 4328c2ecf20Sopenharmony_ci * Calculate the maximum refcount btree size. 4338c2ecf20Sopenharmony_ci */ 4348c2ecf20Sopenharmony_cixfs_extlen_t 4358c2ecf20Sopenharmony_cixfs_refcountbt_max_size( 4368c2ecf20Sopenharmony_ci struct xfs_mount *mp, 4378c2ecf20Sopenharmony_ci xfs_agblock_t agblocks) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci /* Bail out if we're uninitialized, which can happen in mkfs. */ 4408c2ecf20Sopenharmony_ci if (mp->m_refc_mxr[0] == 0) 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return xfs_refcountbt_calc_size(mp, agblocks); 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* 4478c2ecf20Sopenharmony_ci * Figure out how many blocks to reserve and how many are used by this btree. 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ciint 4508c2ecf20Sopenharmony_cixfs_refcountbt_calc_reserves( 4518c2ecf20Sopenharmony_ci struct xfs_mount *mp, 4528c2ecf20Sopenharmony_ci struct xfs_trans *tp, 4538c2ecf20Sopenharmony_ci xfs_agnumber_t agno, 4548c2ecf20Sopenharmony_ci xfs_extlen_t *ask, 4558c2ecf20Sopenharmony_ci xfs_extlen_t *used) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci struct xfs_buf *agbp; 4588c2ecf20Sopenharmony_ci struct xfs_agf *agf; 4598c2ecf20Sopenharmony_ci xfs_agblock_t agblocks; 4608c2ecf20Sopenharmony_ci xfs_extlen_t tree_len; 4618c2ecf20Sopenharmony_ci int error; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (!xfs_sb_version_hasreflink(&mp->m_sb)) 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); 4688c2ecf20Sopenharmony_ci if (error) 4698c2ecf20Sopenharmony_ci return error; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci agf = agbp->b_addr; 4728c2ecf20Sopenharmony_ci agblocks = be32_to_cpu(agf->agf_length); 4738c2ecf20Sopenharmony_ci tree_len = be32_to_cpu(agf->agf_refcount_blocks); 4748c2ecf20Sopenharmony_ci xfs_trans_brelse(tp, agbp); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* 4778c2ecf20Sopenharmony_ci * The log is permanently allocated, so the space it occupies will 4788c2ecf20Sopenharmony_ci * never be available for the kinds of things that would require btree 4798c2ecf20Sopenharmony_ci * expansion. We therefore can pretend the space isn't there. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_ci if (mp->m_sb.sb_logstart && 4828c2ecf20Sopenharmony_ci XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno) 4838c2ecf20Sopenharmony_ci agblocks -= mp->m_sb.sb_logblocks; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci *ask += xfs_refcountbt_max_size(mp, agblocks); 4868c2ecf20Sopenharmony_ci *used += tree_len; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci return error; 4898c2ecf20Sopenharmony_ci} 490