10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0 230f712c9SDave Chinner /* 330f712c9SDave Chinner * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. 430f712c9SDave Chinner * All Rights Reserved. 530f712c9SDave Chinner */ 630f712c9SDave Chinner #include "xfs.h" 730f712c9SDave Chinner #include "xfs_fs.h" 830f712c9SDave Chinner #include "xfs_shared.h" 930f712c9SDave Chinner #include "xfs_format.h" 1030f712c9SDave Chinner #include "xfs_log_format.h" 1130f712c9SDave Chinner #include "xfs_trans_resv.h" 1230f712c9SDave Chinner #include "xfs_bit.h" 1330f712c9SDave Chinner #include "xfs_mount.h" 1430f712c9SDave Chinner #include "xfs_btree.h" 15c29ce8f4SDarrick J. Wong #include "xfs_btree_staging.h" 1630f712c9SDave Chinner #include "xfs_ialloc.h" 1730f712c9SDave Chinner #include "xfs_ialloc_btree.h" 1830f712c9SDave Chinner #include "xfs_alloc.h" 1930f712c9SDave Chinner #include "xfs_error.h" 2030f712c9SDave Chinner #include "xfs_trace.h" 2130f712c9SDave Chinner #include "xfs_trans.h" 22340785ccSDarrick J. Wong #include "xfs_rmap.h" 2330933120SDave Chinner #include "xfs_ag.h" 2430f712c9SDave Chinner 25e7720afaSDarrick J. Wong static struct kmem_cache *xfs_inobt_cur_cache; 269fa47bdcSDarrick J. Wong 2730f712c9SDave Chinner STATIC int 2830f712c9SDave Chinner xfs_inobt_get_minrecs( 2930f712c9SDave Chinner struct xfs_btree_cur *cur, 3030f712c9SDave Chinner int level) 3130f712c9SDave Chinner { 32ef325959SDarrick J. Wong return M_IGEO(cur->bc_mp)->inobt_mnr[level != 0]; 3330f712c9SDave Chinner } 3430f712c9SDave Chinner 3530f712c9SDave Chinner STATIC struct xfs_btree_cur * 3630f712c9SDave Chinner xfs_inobt_dup_cursor( 3730f712c9SDave Chinner struct xfs_btree_cur *cur) 3830f712c9SDave Chinner { 39bab8b795SDave Chinner return xfs_inobt_init_cursor(cur->bc_ag.pag, cur->bc_tp, 40bab8b795SDave Chinner cur->bc_ag.agbp, cur->bc_btnum); 4130f712c9SDave Chinner } 4230f712c9SDave Chinner 4330f712c9SDave Chinner STATIC void 4430f712c9SDave Chinner xfs_inobt_set_root( 4530f712c9SDave Chinner struct xfs_btree_cur *cur, 46b5a6e5feSDarrick J. Wong const union xfs_btree_ptr *nptr, 4730f712c9SDave Chinner int inc) /* level change */ 4830f712c9SDave Chinner { 49576af732SDave Chinner struct xfs_buf *agbp = cur->bc_ag.agbp; 50370c782bSChristoph Hellwig struct xfs_agi *agi = agbp->b_addr; 5130f712c9SDave Chinner 5230f712c9SDave Chinner agi->agi_root = nptr->s; 5330f712c9SDave Chinner be32_add_cpu(&agi->agi_level, inc); 5430f712c9SDave Chinner xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL); 5530f712c9SDave Chinner } 5630f712c9SDave Chinner 5730f712c9SDave Chinner STATIC void 5830f712c9SDave Chinner xfs_finobt_set_root( 5930f712c9SDave Chinner struct xfs_btree_cur *cur, 60b5a6e5feSDarrick J. Wong const union xfs_btree_ptr *nptr, 6130f712c9SDave Chinner int inc) /* level change */ 6230f712c9SDave Chinner { 63576af732SDave Chinner struct xfs_buf *agbp = cur->bc_ag.agbp; 64370c782bSChristoph Hellwig struct xfs_agi *agi = agbp->b_addr; 6530f712c9SDave Chinner 6630f712c9SDave Chinner agi->agi_free_root = nptr->s; 6730f712c9SDave Chinner be32_add_cpu(&agi->agi_free_level, inc); 6830f712c9SDave Chinner xfs_ialloc_log_agi(cur->bc_tp, agbp, 6930f712c9SDave Chinner XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL); 7030f712c9SDave Chinner } 7130f712c9SDave Chinner 722a39946cSDarrick J. Wong /* Update the inode btree block counter for this btree. */ 732a39946cSDarrick J. Wong static inline void 742a39946cSDarrick J. Wong xfs_inobt_mod_blockcount( 752a39946cSDarrick J. Wong struct xfs_btree_cur *cur, 762a39946cSDarrick J. Wong int howmuch) 772a39946cSDarrick J. Wong { 782a39946cSDarrick J. Wong struct xfs_buf *agbp = cur->bc_ag.agbp; 792a39946cSDarrick J. Wong struct xfs_agi *agi = agbp->b_addr; 802a39946cSDarrick J. Wong 81ebd9027dSDave Chinner if (!xfs_has_inobtcounts(cur->bc_mp)) 822a39946cSDarrick J. Wong return; 832a39946cSDarrick J. Wong 842a39946cSDarrick J. Wong if (cur->bc_btnum == XFS_BTNUM_FINO) 852a39946cSDarrick J. Wong be32_add_cpu(&agi->agi_fblocks, howmuch); 862a39946cSDarrick J. Wong else if (cur->bc_btnum == XFS_BTNUM_INO) 872a39946cSDarrick J. Wong be32_add_cpu(&agi->agi_iblocks, howmuch); 882a39946cSDarrick J. Wong xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_IBLOCKS); 892a39946cSDarrick J. Wong } 902a39946cSDarrick J. Wong 9130f712c9SDave Chinner STATIC int 9276d771b4SChristoph Hellwig __xfs_inobt_alloc_block( 9330f712c9SDave Chinner struct xfs_btree_cur *cur, 94deb06b9aSDarrick J. Wong const union xfs_btree_ptr *start, 9530f712c9SDave Chinner union xfs_btree_ptr *new, 9676d771b4SChristoph Hellwig int *stat, 9776d771b4SChristoph Hellwig enum xfs_ag_resv_type resv) 9830f712c9SDave Chinner { 9930f712c9SDave Chinner xfs_alloc_arg_t args; /* block allocation args */ 10030f712c9SDave Chinner int error; /* error return value */ 10130f712c9SDave Chinner xfs_agblock_t sbno = be32_to_cpu(start->s); 10230f712c9SDave Chinner 10330f712c9SDave Chinner memset(&args, 0, sizeof(args)); 10430f712c9SDave Chinner args.tp = cur->bc_tp; 10530f712c9SDave Chinner args.mp = cur->bc_mp; 10674c36a86SDave Chinner args.pag = cur->bc_ag.pag; 1077280fedaSDarrick J. Wong args.oinfo = XFS_RMAP_OINFO_INOBT; 10830f712c9SDave Chinner args.minlen = 1; 10930f712c9SDave Chinner args.maxlen = 1; 11030f712c9SDave Chinner args.prod = 1; 11176d771b4SChristoph Hellwig args.resv = resv; 11230f712c9SDave Chinner 113db4710fdSDave Chinner error = xfs_alloc_vextent_near_bno(&args, 114db4710fdSDave Chinner XFS_AGB_TO_FSB(args.mp, args.pag->pag_agno, sbno)); 115e157ebdcSCarlos Maiolino if (error) 11630f712c9SDave Chinner return error; 117e157ebdcSCarlos Maiolino 11830f712c9SDave Chinner if (args.fsbno == NULLFSBLOCK) { 11930f712c9SDave Chinner *stat = 0; 12030f712c9SDave Chinner return 0; 12130f712c9SDave Chinner } 12230f712c9SDave Chinner ASSERT(args.len == 1); 12330f712c9SDave Chinner 12430f712c9SDave Chinner new->s = cpu_to_be32(XFS_FSB_TO_AGBNO(args.mp, args.fsbno)); 12530f712c9SDave Chinner *stat = 1; 1262a39946cSDarrick J. Wong xfs_inobt_mod_blockcount(cur, 1); 12730f712c9SDave Chinner return 0; 12830f712c9SDave Chinner } 12930f712c9SDave Chinner 13030f712c9SDave Chinner STATIC int 13176d771b4SChristoph Hellwig xfs_inobt_alloc_block( 13276d771b4SChristoph Hellwig struct xfs_btree_cur *cur, 133deb06b9aSDarrick J. Wong const union xfs_btree_ptr *start, 13476d771b4SChristoph Hellwig union xfs_btree_ptr *new, 13576d771b4SChristoph Hellwig int *stat) 13676d771b4SChristoph Hellwig { 13776d771b4SChristoph Hellwig return __xfs_inobt_alloc_block(cur, start, new, stat, XFS_AG_RESV_NONE); 13876d771b4SChristoph Hellwig } 13976d771b4SChristoph Hellwig 14076d771b4SChristoph Hellwig STATIC int 14176d771b4SChristoph Hellwig xfs_finobt_alloc_block( 14276d771b4SChristoph Hellwig struct xfs_btree_cur *cur, 143deb06b9aSDarrick J. Wong const union xfs_btree_ptr *start, 14476d771b4SChristoph Hellwig union xfs_btree_ptr *new, 14576d771b4SChristoph Hellwig int *stat) 14676d771b4SChristoph Hellwig { 147e1f6ca11SDarrick J. Wong if (cur->bc_mp->m_finobt_nores) 148ad90bb58SBrian Foster return xfs_inobt_alloc_block(cur, start, new, stat); 14976d771b4SChristoph Hellwig return __xfs_inobt_alloc_block(cur, start, new, stat, 15076d771b4SChristoph Hellwig XFS_AG_RESV_METADATA); 15176d771b4SChristoph Hellwig } 15276d771b4SChristoph Hellwig 15376d771b4SChristoph Hellwig STATIC int 154ad90bb58SBrian Foster __xfs_inobt_free_block( 155ad90bb58SBrian Foster struct xfs_btree_cur *cur, 156ad90bb58SBrian Foster struct xfs_buf *bp, 157ad90bb58SBrian Foster enum xfs_ag_resv_type resv) 158ad90bb58SBrian Foster { 159b2ccab31SDarrick J. Wong xfs_fsblock_t fsbno; 160b2ccab31SDarrick J. Wong 1612a39946cSDarrick J. Wong xfs_inobt_mod_blockcount(cur, -1); 162b2ccab31SDarrick J. Wong fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, xfs_buf_daddr(bp)); 163b2ccab31SDarrick J. Wong return xfs_free_extent(cur->bc_tp, cur->bc_ag.pag, 164b2ccab31SDarrick J. Wong XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1, 1657280fedaSDarrick J. Wong &XFS_RMAP_OINFO_INOBT, resv); 166ad90bb58SBrian Foster } 167ad90bb58SBrian Foster 168ad90bb58SBrian Foster STATIC int 16930f712c9SDave Chinner xfs_inobt_free_block( 17030f712c9SDave Chinner struct xfs_btree_cur *cur, 17130f712c9SDave Chinner struct xfs_buf *bp) 17230f712c9SDave Chinner { 173ad90bb58SBrian Foster return __xfs_inobt_free_block(cur, bp, XFS_AG_RESV_NONE); 174ad90bb58SBrian Foster } 175340785ccSDarrick J. Wong 176ad90bb58SBrian Foster STATIC int 177ad90bb58SBrian Foster xfs_finobt_free_block( 178ad90bb58SBrian Foster struct xfs_btree_cur *cur, 179ad90bb58SBrian Foster struct xfs_buf *bp) 180ad90bb58SBrian Foster { 181e1f6ca11SDarrick J. Wong if (cur->bc_mp->m_finobt_nores) 182ad90bb58SBrian Foster return xfs_inobt_free_block(cur, bp); 183ad90bb58SBrian Foster return __xfs_inobt_free_block(cur, bp, XFS_AG_RESV_METADATA); 18430f712c9SDave Chinner } 18530f712c9SDave Chinner 18630f712c9SDave Chinner STATIC int 18730f712c9SDave Chinner xfs_inobt_get_maxrecs( 18830f712c9SDave Chinner struct xfs_btree_cur *cur, 18930f712c9SDave Chinner int level) 19030f712c9SDave Chinner { 191ef325959SDarrick J. Wong return M_IGEO(cur->bc_mp)->inobt_mxr[level != 0]; 19230f712c9SDave Chinner } 19330f712c9SDave Chinner 19430f712c9SDave Chinner STATIC void 19530f712c9SDave Chinner xfs_inobt_init_key_from_rec( 19630f712c9SDave Chinner union xfs_btree_key *key, 19723825cd1SDarrick J. Wong const union xfs_btree_rec *rec) 19830f712c9SDave Chinner { 19930f712c9SDave Chinner key->inobt.ir_startino = rec->inobt.ir_startino; 20030f712c9SDave Chinner } 20130f712c9SDave Chinner 20230f712c9SDave Chinner STATIC void 203118bb47eSDarrick J. Wong xfs_inobt_init_high_key_from_rec( 204118bb47eSDarrick J. Wong union xfs_btree_key *key, 20523825cd1SDarrick J. Wong const union xfs_btree_rec *rec) 206118bb47eSDarrick J. Wong { 207118bb47eSDarrick J. Wong __u32 x; 208118bb47eSDarrick J. Wong 209118bb47eSDarrick J. Wong x = be32_to_cpu(rec->inobt.ir_startino); 210118bb47eSDarrick J. Wong x += XFS_INODES_PER_CHUNK - 1; 211118bb47eSDarrick J. Wong key->inobt.ir_startino = cpu_to_be32(x); 212118bb47eSDarrick J. Wong } 213118bb47eSDarrick J. Wong 214118bb47eSDarrick J. Wong STATIC void 21530f712c9SDave Chinner xfs_inobt_init_rec_from_cur( 21630f712c9SDave Chinner struct xfs_btree_cur *cur, 21730f712c9SDave Chinner union xfs_btree_rec *rec) 21830f712c9SDave Chinner { 21930f712c9SDave Chinner rec->inobt.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino); 22038c26bfdSDave Chinner if (xfs_has_sparseinodes(cur->bc_mp)) { 2215419040fSBrian Foster rec->inobt.ir_u.sp.ir_holemask = 2225419040fSBrian Foster cpu_to_be16(cur->bc_rec.i.ir_holemask); 2235419040fSBrian Foster rec->inobt.ir_u.sp.ir_count = cur->bc_rec.i.ir_count; 2245419040fSBrian Foster rec->inobt.ir_u.sp.ir_freecount = cur->bc_rec.i.ir_freecount; 2255419040fSBrian Foster } else { 2265419040fSBrian Foster /* ir_holemask/ir_count not supported on-disk */ 2275419040fSBrian Foster rec->inobt.ir_u.f.ir_freecount = 2285419040fSBrian Foster cpu_to_be32(cur->bc_rec.i.ir_freecount); 2295419040fSBrian Foster } 23030f712c9SDave Chinner rec->inobt.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free); 23130f712c9SDave Chinner } 23230f712c9SDave Chinner 23330f712c9SDave Chinner /* 23430f712c9SDave Chinner * initial value of ptr for lookup 23530f712c9SDave Chinner */ 23630f712c9SDave Chinner STATIC void 23730f712c9SDave Chinner xfs_inobt_init_ptr_from_cur( 23830f712c9SDave Chinner struct xfs_btree_cur *cur, 23930f712c9SDave Chinner union xfs_btree_ptr *ptr) 24030f712c9SDave Chinner { 241576af732SDave Chinner struct xfs_agi *agi = cur->bc_ag.agbp->b_addr; 24230f712c9SDave Chinner 24350f02fe3SDave Chinner ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agi->agi_seqno)); 24430f712c9SDave Chinner 24530f712c9SDave Chinner ptr->s = agi->agi_root; 24630f712c9SDave Chinner } 24730f712c9SDave Chinner 24830f712c9SDave Chinner STATIC void 24930f712c9SDave Chinner xfs_finobt_init_ptr_from_cur( 25030f712c9SDave Chinner struct xfs_btree_cur *cur, 25130f712c9SDave Chinner union xfs_btree_ptr *ptr) 25230f712c9SDave Chinner { 253576af732SDave Chinner struct xfs_agi *agi = cur->bc_ag.agbp->b_addr; 25430f712c9SDave Chinner 25550f02fe3SDave Chinner ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agi->agi_seqno)); 25630f712c9SDave Chinner ptr->s = agi->agi_free_root; 25730f712c9SDave Chinner } 25830f712c9SDave Chinner 259c8ce540dSDarrick J. Wong STATIC int64_t 26030f712c9SDave Chinner xfs_inobt_key_diff( 26130f712c9SDave Chinner struct xfs_btree_cur *cur, 262d29d5577SDarrick J. Wong const union xfs_btree_key *key) 26330f712c9SDave Chinner { 264c8ce540dSDarrick J. Wong return (int64_t)be32_to_cpu(key->inobt.ir_startino) - 26530f712c9SDave Chinner cur->bc_rec.i.ir_startino; 26630f712c9SDave Chinner } 26730f712c9SDave Chinner 268118bb47eSDarrick J. Wong STATIC int64_t 269118bb47eSDarrick J. Wong xfs_inobt_diff_two_keys( 270118bb47eSDarrick J. Wong struct xfs_btree_cur *cur, 271d29d5577SDarrick J. Wong const union xfs_btree_key *k1, 272d29d5577SDarrick J. Wong const union xfs_btree_key *k2) 273118bb47eSDarrick J. Wong { 274118bb47eSDarrick J. Wong return (int64_t)be32_to_cpu(k1->inobt.ir_startino) - 275118bb47eSDarrick J. Wong be32_to_cpu(k2->inobt.ir_startino); 276118bb47eSDarrick J. Wong } 277118bb47eSDarrick J. Wong 278a6a781a5SDarrick J. Wong static xfs_failaddr_t 27930f712c9SDave Chinner xfs_inobt_verify( 28030f712c9SDave Chinner struct xfs_buf *bp) 28130f712c9SDave Chinner { 282dbd329f1SChristoph Hellwig struct xfs_mount *mp = bp->b_mount; 28330f712c9SDave Chinner struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 284a6a781a5SDarrick J. Wong xfs_failaddr_t fa; 28530f712c9SDave Chinner unsigned int level; 28630f712c9SDave Chinner 2878473fee3SBrian Foster if (!xfs_verify_magic(bp, block->bb_magic)) 2888473fee3SBrian Foster return __this_address; 2898473fee3SBrian Foster 29030f712c9SDave Chinner /* 29130f712c9SDave Chinner * During growfs operations, we can't verify the exact owner as the 29230f712c9SDave Chinner * perag is not fully initialised and hence not attached to the buffer. 29330f712c9SDave Chinner * 29430f712c9SDave Chinner * Similarly, during log recovery we will have a perag structure 29530f712c9SDave Chinner * attached, but the agi information will not yet have been initialised 29630f712c9SDave Chinner * from the on disk AGI. We don't currently use any of this information, 2977ac2ff8bSDave Chinner * but beware of the landmine (i.e. need to check 2987ac2ff8bSDave Chinner * xfs_perag_initialised_agi(pag)) if we ever do. 29930f712c9SDave Chinner */ 300ebd9027dSDave Chinner if (xfs_has_crc(mp)) { 301a6a781a5SDarrick J. Wong fa = xfs_btree_sblock_v5hdr_verify(bp); 302a6a781a5SDarrick J. Wong if (fa) 303a6a781a5SDarrick J. Wong return fa; 30430f712c9SDave Chinner } 30530f712c9SDave Chinner 306c5ab131bSDarrick J. Wong /* level verification */ 30730f712c9SDave Chinner level = be16_to_cpu(block->bb_level); 308ef325959SDarrick J. Wong if (level >= M_IGEO(mp)->inobt_maxlevels) 309a6a781a5SDarrick J. Wong return __this_address; 31030f712c9SDave Chinner 311ef325959SDarrick J. Wong return xfs_btree_sblock_verify(bp, 312ef325959SDarrick J. Wong M_IGEO(mp)->inobt_mxr[level != 0]); 31330f712c9SDave Chinner } 31430f712c9SDave Chinner 31530f712c9SDave Chinner static void 31630f712c9SDave Chinner xfs_inobt_read_verify( 31730f712c9SDave Chinner struct xfs_buf *bp) 31830f712c9SDave Chinner { 319bc1a09b8SDarrick J. Wong xfs_failaddr_t fa; 320bc1a09b8SDarrick J. Wong 32130f712c9SDave Chinner if (!xfs_btree_sblock_verify_crc(bp)) 322bc1a09b8SDarrick J. Wong xfs_verifier_error(bp, -EFSBADCRC, __this_address); 323bc1a09b8SDarrick J. Wong else { 324bc1a09b8SDarrick J. Wong fa = xfs_inobt_verify(bp); 325bc1a09b8SDarrick J. Wong if (fa) 326bc1a09b8SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 327bc1a09b8SDarrick J. Wong } 32830f712c9SDave Chinner 32931ca03c9SDarrick J. Wong if (bp->b_error) 33030f712c9SDave Chinner trace_xfs_btree_corrupt(bp, _RET_IP_); 33130f712c9SDave Chinner } 33230f712c9SDave Chinner 33330f712c9SDave Chinner static void 33430f712c9SDave Chinner xfs_inobt_write_verify( 33530f712c9SDave Chinner struct xfs_buf *bp) 33630f712c9SDave Chinner { 337bc1a09b8SDarrick J. Wong xfs_failaddr_t fa; 338bc1a09b8SDarrick J. Wong 339bc1a09b8SDarrick J. Wong fa = xfs_inobt_verify(bp); 340bc1a09b8SDarrick J. Wong if (fa) { 34130f712c9SDave Chinner trace_xfs_btree_corrupt(bp, _RET_IP_); 342bc1a09b8SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 34330f712c9SDave Chinner return; 34430f712c9SDave Chinner } 34530f712c9SDave Chinner xfs_btree_sblock_calc_crc(bp); 34630f712c9SDave Chinner 34730f712c9SDave Chinner } 34830f712c9SDave Chinner 34930f712c9SDave Chinner const struct xfs_buf_ops xfs_inobt_buf_ops = { 350233135b7SEric Sandeen .name = "xfs_inobt", 3518473fee3SBrian Foster .magic = { cpu_to_be32(XFS_IBT_MAGIC), cpu_to_be32(XFS_IBT_CRC_MAGIC) }, 35230f712c9SDave Chinner .verify_read = xfs_inobt_read_verify, 35330f712c9SDave Chinner .verify_write = xfs_inobt_write_verify, 354b5572597SDarrick J. Wong .verify_struct = xfs_inobt_verify, 35530f712c9SDave Chinner }; 35630f712c9SDave Chinner 35701e68f40SBrian Foster const struct xfs_buf_ops xfs_finobt_buf_ops = { 35801e68f40SBrian Foster .name = "xfs_finobt", 3598473fee3SBrian Foster .magic = { cpu_to_be32(XFS_FIBT_MAGIC), 3608473fee3SBrian Foster cpu_to_be32(XFS_FIBT_CRC_MAGIC) }, 36101e68f40SBrian Foster .verify_read = xfs_inobt_read_verify, 36201e68f40SBrian Foster .verify_write = xfs_inobt_write_verify, 36301e68f40SBrian Foster .verify_struct = xfs_inobt_verify, 36401e68f40SBrian Foster }; 36501e68f40SBrian Foster 36630f712c9SDave Chinner STATIC int 36730f712c9SDave Chinner xfs_inobt_keys_inorder( 36830f712c9SDave Chinner struct xfs_btree_cur *cur, 3698e38dc88SDarrick J. Wong const union xfs_btree_key *k1, 3708e38dc88SDarrick J. Wong const union xfs_btree_key *k2) 37130f712c9SDave Chinner { 37230f712c9SDave Chinner return be32_to_cpu(k1->inobt.ir_startino) < 37330f712c9SDave Chinner be32_to_cpu(k2->inobt.ir_startino); 37430f712c9SDave Chinner } 37530f712c9SDave Chinner 37630f712c9SDave Chinner STATIC int 37730f712c9SDave Chinner xfs_inobt_recs_inorder( 37830f712c9SDave Chinner struct xfs_btree_cur *cur, 3798e38dc88SDarrick J. Wong const union xfs_btree_rec *r1, 3808e38dc88SDarrick J. Wong const union xfs_btree_rec *r2) 38130f712c9SDave Chinner { 38230f712c9SDave Chinner return be32_to_cpu(r1->inobt.ir_startino) + XFS_INODES_PER_CHUNK <= 38330f712c9SDave Chinner be32_to_cpu(r2->inobt.ir_startino); 38430f712c9SDave Chinner } 38530f712c9SDave Chinner 38630f712c9SDave Chinner static const struct xfs_btree_ops xfs_inobt_ops = { 38730f712c9SDave Chinner .rec_len = sizeof(xfs_inobt_rec_t), 38830f712c9SDave Chinner .key_len = sizeof(xfs_inobt_key_t), 38930f712c9SDave Chinner 39030f712c9SDave Chinner .dup_cursor = xfs_inobt_dup_cursor, 39130f712c9SDave Chinner .set_root = xfs_inobt_set_root, 39230f712c9SDave Chinner .alloc_block = xfs_inobt_alloc_block, 39330f712c9SDave Chinner .free_block = xfs_inobt_free_block, 39430f712c9SDave Chinner .get_minrecs = xfs_inobt_get_minrecs, 39530f712c9SDave Chinner .get_maxrecs = xfs_inobt_get_maxrecs, 39630f712c9SDave Chinner .init_key_from_rec = xfs_inobt_init_key_from_rec, 397118bb47eSDarrick J. Wong .init_high_key_from_rec = xfs_inobt_init_high_key_from_rec, 39830f712c9SDave Chinner .init_rec_from_cur = xfs_inobt_init_rec_from_cur, 39930f712c9SDave Chinner .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, 40030f712c9SDave Chinner .key_diff = xfs_inobt_key_diff, 40130f712c9SDave Chinner .buf_ops = &xfs_inobt_buf_ops, 402118bb47eSDarrick J. Wong .diff_two_keys = xfs_inobt_diff_two_keys, 40330f712c9SDave Chinner .keys_inorder = xfs_inobt_keys_inorder, 40430f712c9SDave Chinner .recs_inorder = xfs_inobt_recs_inorder, 40530f712c9SDave Chinner }; 40630f712c9SDave Chinner 40730f712c9SDave Chinner static const struct xfs_btree_ops xfs_finobt_ops = { 40830f712c9SDave Chinner .rec_len = sizeof(xfs_inobt_rec_t), 40930f712c9SDave Chinner .key_len = sizeof(xfs_inobt_key_t), 41030f712c9SDave Chinner 41130f712c9SDave Chinner .dup_cursor = xfs_inobt_dup_cursor, 41230f712c9SDave Chinner .set_root = xfs_finobt_set_root, 41376d771b4SChristoph Hellwig .alloc_block = xfs_finobt_alloc_block, 414ad90bb58SBrian Foster .free_block = xfs_finobt_free_block, 41530f712c9SDave Chinner .get_minrecs = xfs_inobt_get_minrecs, 41630f712c9SDave Chinner .get_maxrecs = xfs_inobt_get_maxrecs, 41730f712c9SDave Chinner .init_key_from_rec = xfs_inobt_init_key_from_rec, 418118bb47eSDarrick J. Wong .init_high_key_from_rec = xfs_inobt_init_high_key_from_rec, 41930f712c9SDave Chinner .init_rec_from_cur = xfs_inobt_init_rec_from_cur, 42030f712c9SDave Chinner .init_ptr_from_cur = xfs_finobt_init_ptr_from_cur, 42130f712c9SDave Chinner .key_diff = xfs_inobt_key_diff, 42201e68f40SBrian Foster .buf_ops = &xfs_finobt_buf_ops, 423118bb47eSDarrick J. Wong .diff_two_keys = xfs_inobt_diff_two_keys, 42430f712c9SDave Chinner .keys_inorder = xfs_inobt_keys_inorder, 42530f712c9SDave Chinner .recs_inorder = xfs_inobt_recs_inorder, 42630f712c9SDave Chinner }; 42730f712c9SDave Chinner 42830f712c9SDave Chinner /* 429c29ce8f4SDarrick J. Wong * Initialize a new inode btree cursor. 43030f712c9SDave Chinner */ 431c29ce8f4SDarrick J. Wong static struct xfs_btree_cur * 432c29ce8f4SDarrick J. Wong xfs_inobt_init_common( 433be9fb17dSDave Chinner struct xfs_perag *pag, 434bab8b795SDave Chinner struct xfs_trans *tp, /* transaction pointer */ 43530f712c9SDave Chinner xfs_btnum_t btnum) /* ialloc or free ino btree */ 43630f712c9SDave Chinner { 437bab8b795SDave Chinner struct xfs_mount *mp = pag->pag_mount; 43830f712c9SDave Chinner struct xfs_btree_cur *cur; 43930f712c9SDave Chinner 440c940a0c5SDarrick J. Wong cur = xfs_btree_alloc_cursor(mp, tp, btnum, 4419fa47bdcSDarrick J. Wong M_IGEO(mp)->inobt_maxlevels, xfs_inobt_cur_cache); 44230f712c9SDave Chinner if (btnum == XFS_BTNUM_INO) { 44311ef38afSDave Chinner cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_ibt_2); 444c29ce8f4SDarrick J. Wong cur->bc_ops = &xfs_inobt_ops; 44530f712c9SDave Chinner } else { 44611ef38afSDave Chinner cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_fibt_2); 447c29ce8f4SDarrick J. Wong cur->bc_ops = &xfs_finobt_ops; 44830f712c9SDave Chinner } 44930f712c9SDave Chinner 45038c26bfdSDave Chinner if (xfs_has_crc(mp)) 45130f712c9SDave Chinner cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; 45230f712c9SDave Chinner 453*9b2e5a23SDarrick J. Wong cur->bc_ag.pag = xfs_perag_hold(pag); 45430f712c9SDave Chinner return cur; 45530f712c9SDave Chinner } 45630f712c9SDave Chinner 457c29ce8f4SDarrick J. Wong /* Create an inode btree cursor. */ 458c29ce8f4SDarrick J. Wong struct xfs_btree_cur * 459c29ce8f4SDarrick J. Wong xfs_inobt_init_cursor( 460bab8b795SDave Chinner struct xfs_perag *pag, 461c29ce8f4SDarrick J. Wong struct xfs_trans *tp, 462c29ce8f4SDarrick J. Wong struct xfs_buf *agbp, 463c29ce8f4SDarrick J. Wong xfs_btnum_t btnum) 464c29ce8f4SDarrick J. Wong { 465c29ce8f4SDarrick J. Wong struct xfs_btree_cur *cur; 466c29ce8f4SDarrick J. Wong struct xfs_agi *agi = agbp->b_addr; 467c29ce8f4SDarrick J. Wong 468bab8b795SDave Chinner cur = xfs_inobt_init_common(pag, tp, btnum); 469c29ce8f4SDarrick J. Wong if (btnum == XFS_BTNUM_INO) 470c29ce8f4SDarrick J. Wong cur->bc_nlevels = be32_to_cpu(agi->agi_level); 471c29ce8f4SDarrick J. Wong else 472c29ce8f4SDarrick J. Wong cur->bc_nlevels = be32_to_cpu(agi->agi_free_level); 473c29ce8f4SDarrick J. Wong cur->bc_ag.agbp = agbp; 474c29ce8f4SDarrick J. Wong return cur; 475c29ce8f4SDarrick J. Wong } 476c29ce8f4SDarrick J. Wong 477c29ce8f4SDarrick J. Wong /* Create an inode btree cursor with a fake root for staging. */ 478c29ce8f4SDarrick J. Wong struct xfs_btree_cur * 479c29ce8f4SDarrick J. Wong xfs_inobt_stage_cursor( 4807b13c515SDave Chinner struct xfs_perag *pag, 481bab8b795SDave Chinner struct xbtree_afakeroot *afake, 482c29ce8f4SDarrick J. Wong xfs_btnum_t btnum) 483c29ce8f4SDarrick J. Wong { 484c29ce8f4SDarrick J. Wong struct xfs_btree_cur *cur; 485c29ce8f4SDarrick J. Wong 486bab8b795SDave Chinner cur = xfs_inobt_init_common(pag, NULL, btnum); 487c29ce8f4SDarrick J. Wong xfs_btree_stage_afakeroot(cur, afake); 488c29ce8f4SDarrick J. Wong return cur; 489c29ce8f4SDarrick J. Wong } 490c29ce8f4SDarrick J. Wong 491c29ce8f4SDarrick J. Wong /* 492c29ce8f4SDarrick J. Wong * Install a new inobt btree root. Caller is responsible for invalidating 493c29ce8f4SDarrick J. Wong * and freeing the old btree blocks. 494c29ce8f4SDarrick J. Wong */ 495c29ce8f4SDarrick J. Wong void 496c29ce8f4SDarrick J. Wong xfs_inobt_commit_staged_btree( 497c29ce8f4SDarrick J. Wong struct xfs_btree_cur *cur, 498c29ce8f4SDarrick J. Wong struct xfs_trans *tp, 499c29ce8f4SDarrick J. Wong struct xfs_buf *agbp) 500c29ce8f4SDarrick J. Wong { 501c29ce8f4SDarrick J. Wong struct xfs_agi *agi = agbp->b_addr; 502c29ce8f4SDarrick J. Wong struct xbtree_afakeroot *afake = cur->bc_ag.afake; 50311f74423SDarrick J. Wong int fields; 504c29ce8f4SDarrick J. Wong 505c29ce8f4SDarrick J. Wong ASSERT(cur->bc_flags & XFS_BTREE_STAGING); 506c29ce8f4SDarrick J. Wong 507c29ce8f4SDarrick J. Wong if (cur->bc_btnum == XFS_BTNUM_INO) { 50811f74423SDarrick J. Wong fields = XFS_AGI_ROOT | XFS_AGI_LEVEL; 509c29ce8f4SDarrick J. Wong agi->agi_root = cpu_to_be32(afake->af_root); 510c29ce8f4SDarrick J. Wong agi->agi_level = cpu_to_be32(afake->af_levels); 511ebd9027dSDave Chinner if (xfs_has_inobtcounts(cur->bc_mp)) { 51211f74423SDarrick J. Wong agi->agi_iblocks = cpu_to_be32(afake->af_blocks); 51311f74423SDarrick J. Wong fields |= XFS_AGI_IBLOCKS; 51411f74423SDarrick J. Wong } 51511f74423SDarrick J. Wong xfs_ialloc_log_agi(tp, agbp, fields); 516c29ce8f4SDarrick J. Wong xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_inobt_ops); 517c29ce8f4SDarrick J. Wong } else { 51811f74423SDarrick J. Wong fields = XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL; 519c29ce8f4SDarrick J. Wong agi->agi_free_root = cpu_to_be32(afake->af_root); 520c29ce8f4SDarrick J. Wong agi->agi_free_level = cpu_to_be32(afake->af_levels); 521ebd9027dSDave Chinner if (xfs_has_inobtcounts(cur->bc_mp)) { 52211f74423SDarrick J. Wong agi->agi_fblocks = cpu_to_be32(afake->af_blocks); 52311f74423SDarrick J. Wong fields |= XFS_AGI_IBLOCKS; 52411f74423SDarrick J. Wong } 52511f74423SDarrick J. Wong xfs_ialloc_log_agi(tp, agbp, fields); 526c29ce8f4SDarrick J. Wong xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_finobt_ops); 527c29ce8f4SDarrick J. Wong } 528c29ce8f4SDarrick J. Wong } 529c29ce8f4SDarrick J. Wong 5300ed5f735SDarrick J. Wong /* Calculate number of records in an inode btree block. */ 5310ed5f735SDarrick J. Wong static inline unsigned int 5320ed5f735SDarrick J. Wong xfs_inobt_block_maxrecs( 5330ed5f735SDarrick J. Wong unsigned int blocklen, 5340ed5f735SDarrick J. Wong bool leaf) 5350ed5f735SDarrick J. Wong { 5360ed5f735SDarrick J. Wong if (leaf) 5370ed5f735SDarrick J. Wong return blocklen / sizeof(xfs_inobt_rec_t); 5380ed5f735SDarrick J. Wong return blocklen / (sizeof(xfs_inobt_key_t) + sizeof(xfs_inobt_ptr_t)); 5390ed5f735SDarrick J. Wong } 5400ed5f735SDarrick J. Wong 54130f712c9SDave Chinner /* 54230f712c9SDave Chinner * Calculate number of records in an inobt btree block. 54330f712c9SDave Chinner */ 54430f712c9SDave Chinner int 54530f712c9SDave Chinner xfs_inobt_maxrecs( 54630f712c9SDave Chinner struct xfs_mount *mp, 54730f712c9SDave Chinner int blocklen, 54830f712c9SDave Chinner int leaf) 54930f712c9SDave Chinner { 55030f712c9SDave Chinner blocklen -= XFS_INOBT_BLOCK_LEN(mp); 5510ed5f735SDarrick J. Wong return xfs_inobt_block_maxrecs(blocklen, leaf); 5520ed5f735SDarrick J. Wong } 55330f712c9SDave Chinner 5540ed5f735SDarrick J. Wong /* 5550ed5f735SDarrick J. Wong * Maximum number of inode btree records per AG. Pretend that we can fill an 5560ed5f735SDarrick J. Wong * entire AG completely full of inodes except for the AG headers. 5570ed5f735SDarrick J. Wong */ 5580ed5f735SDarrick J. Wong #define XFS_MAX_INODE_RECORDS \ 5590ed5f735SDarrick J. Wong ((XFS_MAX_AG_BYTES - (4 * BBSIZE)) / XFS_DINODE_MIN_SIZE) / \ 5600ed5f735SDarrick J. Wong XFS_INODES_PER_CHUNK 5610ed5f735SDarrick J. Wong 5620ed5f735SDarrick J. Wong /* Compute the max possible height for the inode btree. */ 5630ed5f735SDarrick J. Wong static inline unsigned int 5640ed5f735SDarrick J. Wong xfs_inobt_maxlevels_ondisk(void) 5650ed5f735SDarrick J. Wong { 5660ed5f735SDarrick J. Wong unsigned int minrecs[2]; 5670ed5f735SDarrick J. Wong unsigned int blocklen; 5680ed5f735SDarrick J. Wong 5690ed5f735SDarrick J. Wong blocklen = min(XFS_MIN_BLOCKSIZE - XFS_BTREE_SBLOCK_LEN, 5700ed5f735SDarrick J. Wong XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN); 5710ed5f735SDarrick J. Wong 5720ed5f735SDarrick J. Wong minrecs[0] = xfs_inobt_block_maxrecs(blocklen, true) / 2; 5730ed5f735SDarrick J. Wong minrecs[1] = xfs_inobt_block_maxrecs(blocklen, false) / 2; 5740ed5f735SDarrick J. Wong 5750ed5f735SDarrick J. Wong return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_INODE_RECORDS); 5760ed5f735SDarrick J. Wong } 5770ed5f735SDarrick J. Wong 5780ed5f735SDarrick J. Wong /* Compute the max possible height for the free inode btree. */ 5790ed5f735SDarrick J. Wong static inline unsigned int 5800ed5f735SDarrick J. Wong xfs_finobt_maxlevels_ondisk(void) 5810ed5f735SDarrick J. Wong { 5820ed5f735SDarrick J. Wong unsigned int minrecs[2]; 5830ed5f735SDarrick J. Wong unsigned int blocklen; 5840ed5f735SDarrick J. Wong 5850ed5f735SDarrick J. Wong blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN; 5860ed5f735SDarrick J. Wong 5870ed5f735SDarrick J. Wong minrecs[0] = xfs_inobt_block_maxrecs(blocklen, true) / 2; 5880ed5f735SDarrick J. Wong minrecs[1] = xfs_inobt_block_maxrecs(blocklen, false) / 2; 5890ed5f735SDarrick J. Wong 5900ed5f735SDarrick J. Wong return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_INODE_RECORDS); 5910ed5f735SDarrick J. Wong } 5920ed5f735SDarrick J. Wong 5930ed5f735SDarrick J. Wong /* Compute the max possible height for either inode btree. */ 5940ed5f735SDarrick J. Wong unsigned int 5950ed5f735SDarrick J. Wong xfs_iallocbt_maxlevels_ondisk(void) 5960ed5f735SDarrick J. Wong { 5970ed5f735SDarrick J. Wong return max(xfs_inobt_maxlevels_ondisk(), 5980ed5f735SDarrick J. Wong xfs_finobt_maxlevels_ondisk()); 59930f712c9SDave Chinner } 6004148c347SBrian Foster 6014148c347SBrian Foster /* 6024148c347SBrian Foster * Convert the inode record holemask to an inode allocation bitmap. The inode 6034148c347SBrian Foster * allocation bitmap is inode granularity and specifies whether an inode is 6044148c347SBrian Foster * physically allocated on disk (not whether the inode is considered allocated 6054148c347SBrian Foster * or free by the fs). 6064148c347SBrian Foster * 6074148c347SBrian Foster * A bit value of 1 means the inode is allocated, a value of 0 means it is free. 6084148c347SBrian Foster */ 6094148c347SBrian Foster uint64_t 6104148c347SBrian Foster xfs_inobt_irec_to_allocmask( 6114148c347SBrian Foster struct xfs_inobt_rec_incore *rec) 6124148c347SBrian Foster { 6134148c347SBrian Foster uint64_t bitmap = 0; 6144148c347SBrian Foster uint64_t inodespbit; 6154148c347SBrian Foster int nextbit; 6164148c347SBrian Foster uint allocbitmap; 6174148c347SBrian Foster 6184148c347SBrian Foster /* 6194148c347SBrian Foster * The holemask has 16-bits for a 64 inode record. Therefore each 6204148c347SBrian Foster * holemask bit represents multiple inodes. Create a mask of bits to set 6214148c347SBrian Foster * in the allocmask for each holemask bit. 6224148c347SBrian Foster */ 6234148c347SBrian Foster inodespbit = (1 << XFS_INODES_PER_HOLEMASK_BIT) - 1; 6244148c347SBrian Foster 6254148c347SBrian Foster /* 6264148c347SBrian Foster * Allocated inodes are represented by 0 bits in holemask. Invert the 0 6274148c347SBrian Foster * bits to 1 and convert to a uint so we can use xfs_next_bit(). Mask 6284148c347SBrian Foster * anything beyond the 16 holemask bits since this casts to a larger 6294148c347SBrian Foster * type. 6304148c347SBrian Foster */ 6314148c347SBrian Foster allocbitmap = ~rec->ir_holemask & ((1 << XFS_INOBT_HOLEMASK_BITS) - 1); 6324148c347SBrian Foster 6334148c347SBrian Foster /* 6344148c347SBrian Foster * allocbitmap is the inverted holemask so every set bit represents 6354148c347SBrian Foster * allocated inodes. To expand from 16-bit holemask granularity to 6364148c347SBrian Foster * 64-bit (e.g., bit-per-inode), set inodespbit bits in the target 6374148c347SBrian Foster * bitmap for every holemask bit. 6384148c347SBrian Foster */ 6394148c347SBrian Foster nextbit = xfs_next_bit(&allocbitmap, 1, 0); 6404148c347SBrian Foster while (nextbit != -1) { 6414148c347SBrian Foster ASSERT(nextbit < (sizeof(rec->ir_holemask) * NBBY)); 6424148c347SBrian Foster 6434148c347SBrian Foster bitmap |= (inodespbit << 6444148c347SBrian Foster (nextbit * XFS_INODES_PER_HOLEMASK_BIT)); 6454148c347SBrian Foster 6464148c347SBrian Foster nextbit = xfs_next_bit(&allocbitmap, 1, nextbit + 1); 6474148c347SBrian Foster } 6484148c347SBrian Foster 6494148c347SBrian Foster return bitmap; 6504148c347SBrian Foster } 65156d1115cSBrian Foster 65256d1115cSBrian Foster #if defined(DEBUG) || defined(XFS_WARN) 65356d1115cSBrian Foster /* 65456d1115cSBrian Foster * Verify that an in-core inode record has a valid inode count. 65556d1115cSBrian Foster */ 65656d1115cSBrian Foster int 65756d1115cSBrian Foster xfs_inobt_rec_check_count( 65856d1115cSBrian Foster struct xfs_mount *mp, 65956d1115cSBrian Foster struct xfs_inobt_rec_incore *rec) 66056d1115cSBrian Foster { 66156d1115cSBrian Foster int inocount = 0; 66256d1115cSBrian Foster int nextbit = 0; 66356d1115cSBrian Foster uint64_t allocbmap; 66456d1115cSBrian Foster int wordsz; 66556d1115cSBrian Foster 66656d1115cSBrian Foster wordsz = sizeof(allocbmap) / sizeof(unsigned int); 66756d1115cSBrian Foster allocbmap = xfs_inobt_irec_to_allocmask(rec); 66856d1115cSBrian Foster 66956d1115cSBrian Foster nextbit = xfs_next_bit((uint *) &allocbmap, wordsz, nextbit); 67056d1115cSBrian Foster while (nextbit != -1) { 67156d1115cSBrian Foster inocount++; 67256d1115cSBrian Foster nextbit = xfs_next_bit((uint *) &allocbmap, wordsz, 67356d1115cSBrian Foster nextbit + 1); 67456d1115cSBrian Foster } 67556d1115cSBrian Foster 67656d1115cSBrian Foster if (inocount != rec->ir_count) 67756d1115cSBrian Foster return -EFSCORRUPTED; 67856d1115cSBrian Foster 67956d1115cSBrian Foster return 0; 68056d1115cSBrian Foster } 68156d1115cSBrian Foster #endif /* DEBUG */ 68276d771b4SChristoph Hellwig 68376d771b4SChristoph Hellwig static xfs_extlen_t 68476d771b4SChristoph Hellwig xfs_inobt_max_size( 6853829c9a1SDave Chinner struct xfs_perag *pag) 68676d771b4SChristoph Hellwig { 6873829c9a1SDave Chinner struct xfs_mount *mp = pag->pag_mount; 6883829c9a1SDave Chinner xfs_agblock_t agblocks = pag->block_count; 689c0876897SDave Chinner 69076d771b4SChristoph Hellwig /* Bail out if we're uninitialized, which can happen in mkfs. */ 691ef325959SDarrick J. Wong if (M_IGEO(mp)->inobt_mxr[0] == 0) 69276d771b4SChristoph Hellwig return 0; 69376d771b4SChristoph Hellwig 6945cd213b0SDarrick J. Wong /* 6955cd213b0SDarrick J. Wong * The log is permanently allocated, so the space it occupies will 6965cd213b0SDarrick J. Wong * never be available for the kinds of things that would require btree 6975cd213b0SDarrick J. Wong * expansion. We therefore can pretend the space isn't there. 6985cd213b0SDarrick J. Wong */ 69936029deeSDave Chinner if (xfs_ag_contains_log(mp, pag->pag_agno)) 7005cd213b0SDarrick J. Wong agblocks -= mp->m_sb.sb_logblocks; 7015cd213b0SDarrick J. Wong 702ef325959SDarrick J. Wong return xfs_btree_calc_size(M_IGEO(mp)->inobt_mnr, 703c0876897SDave Chinner (uint64_t)agblocks * mp->m_sb.sb_inopblock / 70476d771b4SChristoph Hellwig XFS_INODES_PER_CHUNK); 70576d771b4SChristoph Hellwig } 70676d771b4SChristoph Hellwig 707a211432cSDarrick J. Wong /* Read AGI and create inobt cursor. */ 708a211432cSDarrick J. Wong int 709a211432cSDarrick J. Wong xfs_inobt_cur( 7107b13c515SDave Chinner struct xfs_perag *pag, 711bab8b795SDave Chinner struct xfs_trans *tp, 712a211432cSDarrick J. Wong xfs_btnum_t which, 713a211432cSDarrick J. Wong struct xfs_btree_cur **curpp, 714a211432cSDarrick J. Wong struct xfs_buf **agi_bpp) 715a211432cSDarrick J. Wong { 716a211432cSDarrick J. Wong struct xfs_btree_cur *cur; 717a211432cSDarrick J. Wong int error; 718a211432cSDarrick J. Wong 719a211432cSDarrick J. Wong ASSERT(*agi_bpp == NULL); 720a211432cSDarrick J. Wong ASSERT(*curpp == NULL); 721a211432cSDarrick J. Wong 72299b13c7fSDave Chinner error = xfs_ialloc_read_agi(pag, tp, agi_bpp); 723a211432cSDarrick J. Wong if (error) 724a211432cSDarrick J. Wong return error; 725a211432cSDarrick J. Wong 726bab8b795SDave Chinner cur = xfs_inobt_init_cursor(pag, tp, *agi_bpp, which); 727a211432cSDarrick J. Wong *curpp = cur; 728a211432cSDarrick J. Wong return 0; 729a211432cSDarrick J. Wong } 730a211432cSDarrick J. Wong 73176d771b4SChristoph Hellwig static int 73276d771b4SChristoph Hellwig xfs_inobt_count_blocks( 73330933120SDave Chinner struct xfs_perag *pag, 734bab8b795SDave Chinner struct xfs_trans *tp, 73576d771b4SChristoph Hellwig xfs_btnum_t btnum, 73676d771b4SChristoph Hellwig xfs_extlen_t *tree_blocks) 73776d771b4SChristoph Hellwig { 738a211432cSDarrick J. Wong struct xfs_buf *agbp = NULL; 739a211432cSDarrick J. Wong struct xfs_btree_cur *cur = NULL; 74076d771b4SChristoph Hellwig int error; 74176d771b4SChristoph Hellwig 742bab8b795SDave Chinner error = xfs_inobt_cur(pag, tp, btnum, &cur, &agbp); 74376d771b4SChristoph Hellwig if (error) 74476d771b4SChristoph Hellwig return error; 74576d771b4SChristoph Hellwig 74676d771b4SChristoph Hellwig error = xfs_btree_count_blocks(cur, tree_blocks); 7470b04b6b8SDarrick J. Wong xfs_btree_del_cursor(cur, error); 748ebcbef3aSDarrick J. Wong xfs_trans_brelse(tp, agbp); 74976d771b4SChristoph Hellwig 75076d771b4SChristoph Hellwig return error; 75176d771b4SChristoph Hellwig } 75276d771b4SChristoph Hellwig 7531ac35f06SDarrick J. Wong /* Read finobt block count from AGI header. */ 7541ac35f06SDarrick J. Wong static int 7551ac35f06SDarrick J. Wong xfs_finobt_read_blocks( 75630933120SDave Chinner struct xfs_perag *pag, 75799b13c7fSDave Chinner struct xfs_trans *tp, 7581ac35f06SDarrick J. Wong xfs_extlen_t *tree_blocks) 7591ac35f06SDarrick J. Wong { 7601ac35f06SDarrick J. Wong struct xfs_buf *agbp; 7611ac35f06SDarrick J. Wong struct xfs_agi *agi; 7621ac35f06SDarrick J. Wong int error; 7631ac35f06SDarrick J. Wong 76499b13c7fSDave Chinner error = xfs_ialloc_read_agi(pag, tp, &agbp); 7651ac35f06SDarrick J. Wong if (error) 7661ac35f06SDarrick J. Wong return error; 7671ac35f06SDarrick J. Wong 7681ac35f06SDarrick J. Wong agi = agbp->b_addr; 7691ac35f06SDarrick J. Wong *tree_blocks = be32_to_cpu(agi->agi_fblocks); 7701ac35f06SDarrick J. Wong xfs_trans_brelse(tp, agbp); 7711ac35f06SDarrick J. Wong return 0; 7721ac35f06SDarrick J. Wong } 7731ac35f06SDarrick J. Wong 77476d771b4SChristoph Hellwig /* 77576d771b4SChristoph Hellwig * Figure out how many blocks to reserve and how many are used by this btree. 77676d771b4SChristoph Hellwig */ 77776d771b4SChristoph Hellwig int 77876d771b4SChristoph Hellwig xfs_finobt_calc_reserves( 77930933120SDave Chinner struct xfs_perag *pag, 780bab8b795SDave Chinner struct xfs_trans *tp, 78176d771b4SChristoph Hellwig xfs_extlen_t *ask, 78276d771b4SChristoph Hellwig xfs_extlen_t *used) 78376d771b4SChristoph Hellwig { 78476d771b4SChristoph Hellwig xfs_extlen_t tree_len = 0; 78576d771b4SChristoph Hellwig int error; 78676d771b4SChristoph Hellwig 787bab8b795SDave Chinner if (!xfs_has_finobt(pag->pag_mount)) 78876d771b4SChristoph Hellwig return 0; 78976d771b4SChristoph Hellwig 790bab8b795SDave Chinner if (xfs_has_inobtcounts(pag->pag_mount)) 79199b13c7fSDave Chinner error = xfs_finobt_read_blocks(pag, tp, &tree_len); 7921ac35f06SDarrick J. Wong else 793bab8b795SDave Chinner error = xfs_inobt_count_blocks(pag, tp, XFS_BTNUM_FINO, 7941ac35f06SDarrick J. Wong &tree_len); 79576d771b4SChristoph Hellwig if (error) 79676d771b4SChristoph Hellwig return error; 79776d771b4SChristoph Hellwig 7983829c9a1SDave Chinner *ask += xfs_inobt_max_size(pag); 79976d771b4SChristoph Hellwig *used += tree_len; 80076d771b4SChristoph Hellwig return 0; 80176d771b4SChristoph Hellwig } 80214861c47SDarrick J. Wong 80314861c47SDarrick J. Wong /* Calculate the inobt btree size for some records. */ 80414861c47SDarrick J. Wong xfs_extlen_t 80514861c47SDarrick J. Wong xfs_iallocbt_calc_size( 80614861c47SDarrick J. Wong struct xfs_mount *mp, 80714861c47SDarrick J. Wong unsigned long long len) 80814861c47SDarrick J. Wong { 809ef325959SDarrick J. Wong return xfs_btree_calc_size(M_IGEO(mp)->inobt_mnr, len); 81014861c47SDarrick J. Wong } 8119fa47bdcSDarrick J. Wong 8129fa47bdcSDarrick J. Wong int __init 8139fa47bdcSDarrick J. Wong xfs_inobt_init_cur_cache(void) 8149fa47bdcSDarrick J. Wong { 8159fa47bdcSDarrick J. Wong xfs_inobt_cur_cache = kmem_cache_create("xfs_inobt_cur", 8169fa47bdcSDarrick J. Wong xfs_btree_cur_sizeof(xfs_inobt_maxlevels_ondisk()), 8179fa47bdcSDarrick J. Wong 0, 0, NULL); 8189fa47bdcSDarrick J. Wong 8199fa47bdcSDarrick J. Wong if (!xfs_inobt_cur_cache) 8209fa47bdcSDarrick J. Wong return -ENOMEM; 8219fa47bdcSDarrick J. Wong return 0; 8229fa47bdcSDarrick J. Wong } 8239fa47bdcSDarrick J. Wong 8249fa47bdcSDarrick J. Wong void 8259fa47bdcSDarrick J. Wong xfs_inobt_destroy_cur_cache(void) 8269fa47bdcSDarrick J. Wong { 8279fa47bdcSDarrick J. Wong kmem_cache_destroy(xfs_inobt_cur_cache); 8289fa47bdcSDarrick J. Wong xfs_inobt_cur_cache = NULL; 8299fa47bdcSDarrick J. Wong } 830