162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014 Red Hat, Inc. 462306a36Sopenharmony_ci * All Rights Reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "xfs.h" 762306a36Sopenharmony_ci#include "xfs_fs.h" 862306a36Sopenharmony_ci#include "xfs_shared.h" 962306a36Sopenharmony_ci#include "xfs_format.h" 1062306a36Sopenharmony_ci#include "xfs_log_format.h" 1162306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1262306a36Sopenharmony_ci#include "xfs_mount.h" 1362306a36Sopenharmony_ci#include "xfs_trans.h" 1462306a36Sopenharmony_ci#include "xfs_alloc.h" 1562306a36Sopenharmony_ci#include "xfs_btree.h" 1662306a36Sopenharmony_ci#include "xfs_btree_staging.h" 1762306a36Sopenharmony_ci#include "xfs_rmap.h" 1862306a36Sopenharmony_ci#include "xfs_rmap_btree.h" 1962306a36Sopenharmony_ci#include "xfs_trace.h" 2062306a36Sopenharmony_ci#include "xfs_error.h" 2162306a36Sopenharmony_ci#include "xfs_extent_busy.h" 2262306a36Sopenharmony_ci#include "xfs_ag.h" 2362306a36Sopenharmony_ci#include "xfs_ag_resv.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic struct kmem_cache *xfs_rmapbt_cur_cache; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * Reverse map btree. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * This is a per-ag tree used to track the owner(s) of a given extent. With 3162306a36Sopenharmony_ci * reflink it is possible for there to be multiple owners, which is a departure 3262306a36Sopenharmony_ci * from classic XFS. Owner records for data extents are inserted when the 3362306a36Sopenharmony_ci * extent is mapped and removed when an extent is unmapped. Owner records for 3462306a36Sopenharmony_ci * all other block types (i.e. metadata) are inserted when an extent is 3562306a36Sopenharmony_ci * allocated and removed when an extent is freed. There can only be one owner 3662306a36Sopenharmony_ci * of a metadata extent, usually an inode or some other metadata structure like 3762306a36Sopenharmony_ci * an AG btree. 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * The rmap btree is part of the free space management, so blocks for the tree 4062306a36Sopenharmony_ci * are sourced from the agfl. Hence we need transaction reservation support for 4162306a36Sopenharmony_ci * this tree so that the freelist is always large enough. This also impacts on 4262306a36Sopenharmony_ci * the minimum space we need to leave free in the AG. 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * The tree is ordered by [ag block, owner, offset]. This is a large key size, 4562306a36Sopenharmony_ci * but it is the only way to enforce unique keys when a block can be owned by 4662306a36Sopenharmony_ci * multiple files at any offset. There's no need to order/search by extent 4762306a36Sopenharmony_ci * size for online updating/management of the tree. It is intended that most 4862306a36Sopenharmony_ci * reverse lookups will be to find the owner(s) of a particular block, or to 4962306a36Sopenharmony_ci * try to recover tree and file data from corrupt primary metadata. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic struct xfs_btree_cur * 5362306a36Sopenharmony_cixfs_rmapbt_dup_cursor( 5462306a36Sopenharmony_ci struct xfs_btree_cur *cur) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp, 5762306a36Sopenharmony_ci cur->bc_ag.agbp, cur->bc_ag.pag); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ciSTATIC void 6162306a36Sopenharmony_cixfs_rmapbt_set_root( 6262306a36Sopenharmony_ci struct xfs_btree_cur *cur, 6362306a36Sopenharmony_ci const union xfs_btree_ptr *ptr, 6462306a36Sopenharmony_ci int inc) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct xfs_buf *agbp = cur->bc_ag.agbp; 6762306a36Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 6862306a36Sopenharmony_ci int btnum = cur->bc_btnum; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci ASSERT(ptr->s != 0); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci agf->agf_roots[btnum] = ptr->s; 7362306a36Sopenharmony_ci be32_add_cpu(&agf->agf_levels[btnum], inc); 7462306a36Sopenharmony_ci cur->bc_ag.pag->pagf_levels[btnum] += inc; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciSTATIC int 8062306a36Sopenharmony_cixfs_rmapbt_alloc_block( 8162306a36Sopenharmony_ci struct xfs_btree_cur *cur, 8262306a36Sopenharmony_ci const union xfs_btree_ptr *start, 8362306a36Sopenharmony_ci union xfs_btree_ptr *new, 8462306a36Sopenharmony_ci int *stat) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct xfs_buf *agbp = cur->bc_ag.agbp; 8762306a36Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 8862306a36Sopenharmony_ci struct xfs_perag *pag = cur->bc_ag.pag; 8962306a36Sopenharmony_ci int error; 9062306a36Sopenharmony_ci xfs_agblock_t bno; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Allocate the new block from the freelist. If we can't, give up. */ 9362306a36Sopenharmony_ci error = xfs_alloc_get_freelist(pag, cur->bc_tp, cur->bc_ag.agbp, 9462306a36Sopenharmony_ci &bno, 1); 9562306a36Sopenharmony_ci if (error) 9662306a36Sopenharmony_ci return error; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci trace_xfs_rmapbt_alloc_block(cur->bc_mp, pag->pag_agno, bno, 1); 9962306a36Sopenharmony_ci if (bno == NULLAGBLOCK) { 10062306a36Sopenharmony_ci *stat = 0; 10162306a36Sopenharmony_ci return 0; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci xfs_extent_busy_reuse(cur->bc_mp, pag, bno, 1, false); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci new->s = cpu_to_be32(bno); 10762306a36Sopenharmony_ci be32_add_cpu(&agf->agf_rmap_blocks, 1); 10862306a36Sopenharmony_ci xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci xfs_ag_resv_rmapbt_alloc(cur->bc_mp, pag->pag_agno); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci *stat = 1; 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciSTATIC int 11762306a36Sopenharmony_cixfs_rmapbt_free_block( 11862306a36Sopenharmony_ci struct xfs_btree_cur *cur, 11962306a36Sopenharmony_ci struct xfs_buf *bp) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct xfs_buf *agbp = cur->bc_ag.agbp; 12262306a36Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 12362306a36Sopenharmony_ci struct xfs_perag *pag = cur->bc_ag.pag; 12462306a36Sopenharmony_ci xfs_agblock_t bno; 12562306a36Sopenharmony_ci int error; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci bno = xfs_daddr_to_agbno(cur->bc_mp, xfs_buf_daddr(bp)); 12862306a36Sopenharmony_ci trace_xfs_rmapbt_free_block(cur->bc_mp, pag->pag_agno, 12962306a36Sopenharmony_ci bno, 1); 13062306a36Sopenharmony_ci be32_add_cpu(&agf->agf_rmap_blocks, -1); 13162306a36Sopenharmony_ci xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS); 13262306a36Sopenharmony_ci error = xfs_alloc_put_freelist(pag, cur->bc_tp, agbp, NULL, bno, 1); 13362306a36Sopenharmony_ci if (error) 13462306a36Sopenharmony_ci return error; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci xfs_extent_busy_insert(cur->bc_tp, pag, bno, 1, 13762306a36Sopenharmony_ci XFS_EXTENT_BUSY_SKIP_DISCARD); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci xfs_ag_resv_free_extent(pag, XFS_AG_RESV_RMAPBT, NULL, 1); 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ciSTATIC int 14462306a36Sopenharmony_cixfs_rmapbt_get_minrecs( 14562306a36Sopenharmony_ci struct xfs_btree_cur *cur, 14662306a36Sopenharmony_ci int level) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci return cur->bc_mp->m_rmap_mnr[level != 0]; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ciSTATIC int 15262306a36Sopenharmony_cixfs_rmapbt_get_maxrecs( 15362306a36Sopenharmony_ci struct xfs_btree_cur *cur, 15462306a36Sopenharmony_ci int level) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci return cur->bc_mp->m_rmap_mxr[level != 0]; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* 16062306a36Sopenharmony_ci * Convert the ondisk record's offset field into the ondisk key's offset field. 16162306a36Sopenharmony_ci * Fork and bmbt are significant parts of the rmap record key, but written 16262306a36Sopenharmony_ci * status is merely a record attribute. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_cistatic inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ciSTATIC void 17062306a36Sopenharmony_cixfs_rmapbt_init_key_from_rec( 17162306a36Sopenharmony_ci union xfs_btree_key *key, 17262306a36Sopenharmony_ci const union xfs_btree_rec *rec) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci key->rmap.rm_startblock = rec->rmap.rm_startblock; 17562306a36Sopenharmony_ci key->rmap.rm_owner = rec->rmap.rm_owner; 17662306a36Sopenharmony_ci key->rmap.rm_offset = ondisk_rec_offset_to_key(rec); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* 18062306a36Sopenharmony_ci * The high key for a reverse mapping record can be computed by shifting 18162306a36Sopenharmony_ci * the startblock and offset to the highest value that would still map 18262306a36Sopenharmony_ci * to that record. In practice this means that we add blockcount-1 to 18362306a36Sopenharmony_ci * the startblock for all records, and if the record is for a data/attr 18462306a36Sopenharmony_ci * fork mapping, we add blockcount-1 to the offset too. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ciSTATIC void 18762306a36Sopenharmony_cixfs_rmapbt_init_high_key_from_rec( 18862306a36Sopenharmony_ci union xfs_btree_key *key, 18962306a36Sopenharmony_ci const union xfs_btree_rec *rec) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci uint64_t off; 19262306a36Sopenharmony_ci int adj; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci key->rmap.rm_startblock = rec->rmap.rm_startblock; 19762306a36Sopenharmony_ci be32_add_cpu(&key->rmap.rm_startblock, adj); 19862306a36Sopenharmony_ci key->rmap.rm_owner = rec->rmap.rm_owner; 19962306a36Sopenharmony_ci key->rmap.rm_offset = ondisk_rec_offset_to_key(rec); 20062306a36Sopenharmony_ci if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) || 20162306a36Sopenharmony_ci XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset))) 20262306a36Sopenharmony_ci return; 20362306a36Sopenharmony_ci off = be64_to_cpu(key->rmap.rm_offset); 20462306a36Sopenharmony_ci off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK); 20562306a36Sopenharmony_ci key->rmap.rm_offset = cpu_to_be64(off); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ciSTATIC void 20962306a36Sopenharmony_cixfs_rmapbt_init_rec_from_cur( 21062306a36Sopenharmony_ci struct xfs_btree_cur *cur, 21162306a36Sopenharmony_ci union xfs_btree_rec *rec) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock); 21462306a36Sopenharmony_ci rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount); 21562306a36Sopenharmony_ci rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner); 21662306a36Sopenharmony_ci rec->rmap.rm_offset = cpu_to_be64( 21762306a36Sopenharmony_ci xfs_rmap_irec_offset_pack(&cur->bc_rec.r)); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciSTATIC void 22162306a36Sopenharmony_cixfs_rmapbt_init_ptr_from_cur( 22262306a36Sopenharmony_ci struct xfs_btree_cur *cur, 22362306a36Sopenharmony_ci union xfs_btree_ptr *ptr) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct xfs_agf *agf = cur->bc_ag.agbp->b_addr; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno)); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ptr->s = agf->agf_roots[cur->bc_btnum]; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci/* 23362306a36Sopenharmony_ci * Mask the appropriate parts of the ondisk key field for a key comparison. 23462306a36Sopenharmony_ci * Fork and bmbt are significant parts of the rmap record key, but written 23562306a36Sopenharmony_ci * status is merely a record attribute. 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_cistatic inline uint64_t offset_keymask(uint64_t offset) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci return offset & ~XFS_RMAP_OFF_UNWRITTEN; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ciSTATIC int64_t 24362306a36Sopenharmony_cixfs_rmapbt_key_diff( 24462306a36Sopenharmony_ci struct xfs_btree_cur *cur, 24562306a36Sopenharmony_ci const union xfs_btree_key *key) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci struct xfs_rmap_irec *rec = &cur->bc_rec.r; 24862306a36Sopenharmony_ci const struct xfs_rmap_key *kp = &key->rmap; 24962306a36Sopenharmony_ci __u64 x, y; 25062306a36Sopenharmony_ci int64_t d; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci d = (int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock; 25362306a36Sopenharmony_ci if (d) 25462306a36Sopenharmony_ci return d; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci x = be64_to_cpu(kp->rm_owner); 25762306a36Sopenharmony_ci y = rec->rm_owner; 25862306a36Sopenharmony_ci if (x > y) 25962306a36Sopenharmony_ci return 1; 26062306a36Sopenharmony_ci else if (y > x) 26162306a36Sopenharmony_ci return -1; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci x = offset_keymask(be64_to_cpu(kp->rm_offset)); 26462306a36Sopenharmony_ci y = offset_keymask(xfs_rmap_irec_offset_pack(rec)); 26562306a36Sopenharmony_ci if (x > y) 26662306a36Sopenharmony_ci return 1; 26762306a36Sopenharmony_ci else if (y > x) 26862306a36Sopenharmony_ci return -1; 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ciSTATIC int64_t 27362306a36Sopenharmony_cixfs_rmapbt_diff_two_keys( 27462306a36Sopenharmony_ci struct xfs_btree_cur *cur, 27562306a36Sopenharmony_ci const union xfs_btree_key *k1, 27662306a36Sopenharmony_ci const union xfs_btree_key *k2, 27762306a36Sopenharmony_ci const union xfs_btree_key *mask) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci const struct xfs_rmap_key *kp1 = &k1->rmap; 28062306a36Sopenharmony_ci const struct xfs_rmap_key *kp2 = &k2->rmap; 28162306a36Sopenharmony_ci int64_t d; 28262306a36Sopenharmony_ci __u64 x, y; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Doesn't make sense to mask off the physical space part */ 28562306a36Sopenharmony_ci ASSERT(!mask || mask->rmap.rm_startblock); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci d = (int64_t)be32_to_cpu(kp1->rm_startblock) - 28862306a36Sopenharmony_ci be32_to_cpu(kp2->rm_startblock); 28962306a36Sopenharmony_ci if (d) 29062306a36Sopenharmony_ci return d; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (!mask || mask->rmap.rm_owner) { 29362306a36Sopenharmony_ci x = be64_to_cpu(kp1->rm_owner); 29462306a36Sopenharmony_ci y = be64_to_cpu(kp2->rm_owner); 29562306a36Sopenharmony_ci if (x > y) 29662306a36Sopenharmony_ci return 1; 29762306a36Sopenharmony_ci else if (y > x) 29862306a36Sopenharmony_ci return -1; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (!mask || mask->rmap.rm_offset) { 30262306a36Sopenharmony_ci /* Doesn't make sense to allow offset but not owner */ 30362306a36Sopenharmony_ci ASSERT(!mask || mask->rmap.rm_owner); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci x = offset_keymask(be64_to_cpu(kp1->rm_offset)); 30662306a36Sopenharmony_ci y = offset_keymask(be64_to_cpu(kp2->rm_offset)); 30762306a36Sopenharmony_ci if (x > y) 30862306a36Sopenharmony_ci return 1; 30962306a36Sopenharmony_ci else if (y > x) 31062306a36Sopenharmony_ci return -1; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic xfs_failaddr_t 31762306a36Sopenharmony_cixfs_rmapbt_verify( 31862306a36Sopenharmony_ci struct xfs_buf *bp) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct xfs_mount *mp = bp->b_mount; 32162306a36Sopenharmony_ci struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 32262306a36Sopenharmony_ci struct xfs_perag *pag = bp->b_pag; 32362306a36Sopenharmony_ci xfs_failaddr_t fa; 32462306a36Sopenharmony_ci unsigned int level; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* 32762306a36Sopenharmony_ci * magic number and level verification 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * During growfs operations, we can't verify the exact level or owner as 33062306a36Sopenharmony_ci * the perag is not fully initialised and hence not attached to the 33162306a36Sopenharmony_ci * buffer. In this case, check against the maximum tree depth. 33262306a36Sopenharmony_ci * 33362306a36Sopenharmony_ci * Similarly, during log recovery we will have a perag structure 33462306a36Sopenharmony_ci * attached, but the agf information will not yet have been initialised 33562306a36Sopenharmony_ci * from the on disk AGF. Again, we can only check against maximum limits 33662306a36Sopenharmony_ci * in this case. 33762306a36Sopenharmony_ci */ 33862306a36Sopenharmony_ci if (!xfs_verify_magic(bp, block->bb_magic)) 33962306a36Sopenharmony_ci return __this_address; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!xfs_has_rmapbt(mp)) 34262306a36Sopenharmony_ci return __this_address; 34362306a36Sopenharmony_ci fa = xfs_btree_sblock_v5hdr_verify(bp); 34462306a36Sopenharmony_ci if (fa) 34562306a36Sopenharmony_ci return fa; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci level = be16_to_cpu(block->bb_level); 34862306a36Sopenharmony_ci if (pag && xfs_perag_initialised_agf(pag)) { 34962306a36Sopenharmony_ci if (level >= pag->pagf_levels[XFS_BTNUM_RMAPi]) 35062306a36Sopenharmony_ci return __this_address; 35162306a36Sopenharmony_ci } else if (level >= mp->m_rmap_maxlevels) 35262306a36Sopenharmony_ci return __this_address; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci return xfs_btree_sblock_verify(bp, mp->m_rmap_mxr[level != 0]); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic void 35862306a36Sopenharmony_cixfs_rmapbt_read_verify( 35962306a36Sopenharmony_ci struct xfs_buf *bp) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci xfs_failaddr_t fa; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (!xfs_btree_sblock_verify_crc(bp)) 36462306a36Sopenharmony_ci xfs_verifier_error(bp, -EFSBADCRC, __this_address); 36562306a36Sopenharmony_ci else { 36662306a36Sopenharmony_ci fa = xfs_rmapbt_verify(bp); 36762306a36Sopenharmony_ci if (fa) 36862306a36Sopenharmony_ci xfs_verifier_error(bp, -EFSCORRUPTED, fa); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (bp->b_error) 37262306a36Sopenharmony_ci trace_xfs_btree_corrupt(bp, _RET_IP_); 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic void 37662306a36Sopenharmony_cixfs_rmapbt_write_verify( 37762306a36Sopenharmony_ci struct xfs_buf *bp) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci xfs_failaddr_t fa; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci fa = xfs_rmapbt_verify(bp); 38262306a36Sopenharmony_ci if (fa) { 38362306a36Sopenharmony_ci trace_xfs_btree_corrupt(bp, _RET_IP_); 38462306a36Sopenharmony_ci xfs_verifier_error(bp, -EFSCORRUPTED, fa); 38562306a36Sopenharmony_ci return; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci xfs_btree_sblock_calc_crc(bp); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ciconst struct xfs_buf_ops xfs_rmapbt_buf_ops = { 39262306a36Sopenharmony_ci .name = "xfs_rmapbt", 39362306a36Sopenharmony_ci .magic = { 0, cpu_to_be32(XFS_RMAP_CRC_MAGIC) }, 39462306a36Sopenharmony_ci .verify_read = xfs_rmapbt_read_verify, 39562306a36Sopenharmony_ci .verify_write = xfs_rmapbt_write_verify, 39662306a36Sopenharmony_ci .verify_struct = xfs_rmapbt_verify, 39762306a36Sopenharmony_ci}; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ciSTATIC int 40062306a36Sopenharmony_cixfs_rmapbt_keys_inorder( 40162306a36Sopenharmony_ci struct xfs_btree_cur *cur, 40262306a36Sopenharmony_ci const union xfs_btree_key *k1, 40362306a36Sopenharmony_ci const union xfs_btree_key *k2) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci uint32_t x; 40662306a36Sopenharmony_ci uint32_t y; 40762306a36Sopenharmony_ci uint64_t a; 40862306a36Sopenharmony_ci uint64_t b; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci x = be32_to_cpu(k1->rmap.rm_startblock); 41162306a36Sopenharmony_ci y = be32_to_cpu(k2->rmap.rm_startblock); 41262306a36Sopenharmony_ci if (x < y) 41362306a36Sopenharmony_ci return 1; 41462306a36Sopenharmony_ci else if (x > y) 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci a = be64_to_cpu(k1->rmap.rm_owner); 41762306a36Sopenharmony_ci b = be64_to_cpu(k2->rmap.rm_owner); 41862306a36Sopenharmony_ci if (a < b) 41962306a36Sopenharmony_ci return 1; 42062306a36Sopenharmony_ci else if (a > b) 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci a = offset_keymask(be64_to_cpu(k1->rmap.rm_offset)); 42362306a36Sopenharmony_ci b = offset_keymask(be64_to_cpu(k2->rmap.rm_offset)); 42462306a36Sopenharmony_ci if (a <= b) 42562306a36Sopenharmony_ci return 1; 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ciSTATIC int 43062306a36Sopenharmony_cixfs_rmapbt_recs_inorder( 43162306a36Sopenharmony_ci struct xfs_btree_cur *cur, 43262306a36Sopenharmony_ci const union xfs_btree_rec *r1, 43362306a36Sopenharmony_ci const union xfs_btree_rec *r2) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci uint32_t x; 43662306a36Sopenharmony_ci uint32_t y; 43762306a36Sopenharmony_ci uint64_t a; 43862306a36Sopenharmony_ci uint64_t b; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci x = be32_to_cpu(r1->rmap.rm_startblock); 44162306a36Sopenharmony_ci y = be32_to_cpu(r2->rmap.rm_startblock); 44262306a36Sopenharmony_ci if (x < y) 44362306a36Sopenharmony_ci return 1; 44462306a36Sopenharmony_ci else if (x > y) 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci a = be64_to_cpu(r1->rmap.rm_owner); 44762306a36Sopenharmony_ci b = be64_to_cpu(r2->rmap.rm_owner); 44862306a36Sopenharmony_ci if (a < b) 44962306a36Sopenharmony_ci return 1; 45062306a36Sopenharmony_ci else if (a > b) 45162306a36Sopenharmony_ci return 0; 45262306a36Sopenharmony_ci a = offset_keymask(be64_to_cpu(r1->rmap.rm_offset)); 45362306a36Sopenharmony_ci b = offset_keymask(be64_to_cpu(r2->rmap.rm_offset)); 45462306a36Sopenharmony_ci if (a <= b) 45562306a36Sopenharmony_ci return 1; 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ciSTATIC enum xbtree_key_contig 46062306a36Sopenharmony_cixfs_rmapbt_keys_contiguous( 46162306a36Sopenharmony_ci struct xfs_btree_cur *cur, 46262306a36Sopenharmony_ci const union xfs_btree_key *key1, 46362306a36Sopenharmony_ci const union xfs_btree_key *key2, 46462306a36Sopenharmony_ci const union xfs_btree_key *mask) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci ASSERT(!mask || mask->rmap.rm_startblock); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* 46962306a36Sopenharmony_ci * We only support checking contiguity of the physical space component. 47062306a36Sopenharmony_ci * If any callers ever need more specificity than that, they'll have to 47162306a36Sopenharmony_ci * implement it here. 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_ci ASSERT(!mask || (!mask->rmap.rm_owner && !mask->rmap.rm_offset)); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci return xbtree_key_contig(be32_to_cpu(key1->rmap.rm_startblock), 47662306a36Sopenharmony_ci be32_to_cpu(key2->rmap.rm_startblock)); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic const struct xfs_btree_ops xfs_rmapbt_ops = { 48062306a36Sopenharmony_ci .rec_len = sizeof(struct xfs_rmap_rec), 48162306a36Sopenharmony_ci .key_len = 2 * sizeof(struct xfs_rmap_key), 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci .dup_cursor = xfs_rmapbt_dup_cursor, 48462306a36Sopenharmony_ci .set_root = xfs_rmapbt_set_root, 48562306a36Sopenharmony_ci .alloc_block = xfs_rmapbt_alloc_block, 48662306a36Sopenharmony_ci .free_block = xfs_rmapbt_free_block, 48762306a36Sopenharmony_ci .get_minrecs = xfs_rmapbt_get_minrecs, 48862306a36Sopenharmony_ci .get_maxrecs = xfs_rmapbt_get_maxrecs, 48962306a36Sopenharmony_ci .init_key_from_rec = xfs_rmapbt_init_key_from_rec, 49062306a36Sopenharmony_ci .init_high_key_from_rec = xfs_rmapbt_init_high_key_from_rec, 49162306a36Sopenharmony_ci .init_rec_from_cur = xfs_rmapbt_init_rec_from_cur, 49262306a36Sopenharmony_ci .init_ptr_from_cur = xfs_rmapbt_init_ptr_from_cur, 49362306a36Sopenharmony_ci .key_diff = xfs_rmapbt_key_diff, 49462306a36Sopenharmony_ci .buf_ops = &xfs_rmapbt_buf_ops, 49562306a36Sopenharmony_ci .diff_two_keys = xfs_rmapbt_diff_two_keys, 49662306a36Sopenharmony_ci .keys_inorder = xfs_rmapbt_keys_inorder, 49762306a36Sopenharmony_ci .recs_inorder = xfs_rmapbt_recs_inorder, 49862306a36Sopenharmony_ci .keys_contiguous = xfs_rmapbt_keys_contiguous, 49962306a36Sopenharmony_ci}; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic struct xfs_btree_cur * 50262306a36Sopenharmony_cixfs_rmapbt_init_common( 50362306a36Sopenharmony_ci struct xfs_mount *mp, 50462306a36Sopenharmony_ci struct xfs_trans *tp, 50562306a36Sopenharmony_ci struct xfs_perag *pag) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct xfs_btree_cur *cur; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* Overlapping btree; 2 keys per pointer. */ 51062306a36Sopenharmony_ci cur = xfs_btree_alloc_cursor(mp, tp, XFS_BTNUM_RMAP, 51162306a36Sopenharmony_ci mp->m_rmap_maxlevels, xfs_rmapbt_cur_cache); 51262306a36Sopenharmony_ci cur->bc_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING; 51362306a36Sopenharmony_ci cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2); 51462306a36Sopenharmony_ci cur->bc_ops = &xfs_rmapbt_ops; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci cur->bc_ag.pag = xfs_perag_hold(pag); 51762306a36Sopenharmony_ci return cur; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci/* Create a new reverse mapping btree cursor. */ 52162306a36Sopenharmony_cistruct xfs_btree_cur * 52262306a36Sopenharmony_cixfs_rmapbt_init_cursor( 52362306a36Sopenharmony_ci struct xfs_mount *mp, 52462306a36Sopenharmony_ci struct xfs_trans *tp, 52562306a36Sopenharmony_ci struct xfs_buf *agbp, 52662306a36Sopenharmony_ci struct xfs_perag *pag) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 52962306a36Sopenharmony_ci struct xfs_btree_cur *cur; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci cur = xfs_rmapbt_init_common(mp, tp, pag); 53262306a36Sopenharmony_ci cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]); 53362306a36Sopenharmony_ci cur->bc_ag.agbp = agbp; 53462306a36Sopenharmony_ci return cur; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci/* Create a new reverse mapping btree cursor with a fake root for staging. */ 53862306a36Sopenharmony_cistruct xfs_btree_cur * 53962306a36Sopenharmony_cixfs_rmapbt_stage_cursor( 54062306a36Sopenharmony_ci struct xfs_mount *mp, 54162306a36Sopenharmony_ci struct xbtree_afakeroot *afake, 54262306a36Sopenharmony_ci struct xfs_perag *pag) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct xfs_btree_cur *cur; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci cur = xfs_rmapbt_init_common(mp, NULL, pag); 54762306a36Sopenharmony_ci xfs_btree_stage_afakeroot(cur, afake); 54862306a36Sopenharmony_ci return cur; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci/* 55262306a36Sopenharmony_ci * Install a new reverse mapping btree root. Caller is responsible for 55362306a36Sopenharmony_ci * invalidating and freeing the old btree blocks. 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_civoid 55662306a36Sopenharmony_cixfs_rmapbt_commit_staged_btree( 55762306a36Sopenharmony_ci struct xfs_btree_cur *cur, 55862306a36Sopenharmony_ci struct xfs_trans *tp, 55962306a36Sopenharmony_ci struct xfs_buf *agbp) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct xfs_agf *agf = agbp->b_addr; 56262306a36Sopenharmony_ci struct xbtree_afakeroot *afake = cur->bc_ag.afake; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci ASSERT(cur->bc_flags & XFS_BTREE_STAGING); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci agf->agf_roots[cur->bc_btnum] = cpu_to_be32(afake->af_root); 56762306a36Sopenharmony_ci agf->agf_levels[cur->bc_btnum] = cpu_to_be32(afake->af_levels); 56862306a36Sopenharmony_ci agf->agf_rmap_blocks = cpu_to_be32(afake->af_blocks); 56962306a36Sopenharmony_ci xfs_alloc_log_agf(tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS | 57062306a36Sopenharmony_ci XFS_AGF_RMAP_BLOCKS); 57162306a36Sopenharmony_ci xfs_btree_commit_afakeroot(cur, tp, agbp, &xfs_rmapbt_ops); 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci/* Calculate number of records in a reverse mapping btree block. */ 57562306a36Sopenharmony_cistatic inline unsigned int 57662306a36Sopenharmony_cixfs_rmapbt_block_maxrecs( 57762306a36Sopenharmony_ci unsigned int blocklen, 57862306a36Sopenharmony_ci bool leaf) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci if (leaf) 58162306a36Sopenharmony_ci return blocklen / sizeof(struct xfs_rmap_rec); 58262306a36Sopenharmony_ci return blocklen / 58362306a36Sopenharmony_ci (2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rmap_ptr_t)); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci/* 58762306a36Sopenharmony_ci * Calculate number of records in an rmap btree block. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_ciint 59062306a36Sopenharmony_cixfs_rmapbt_maxrecs( 59162306a36Sopenharmony_ci int blocklen, 59262306a36Sopenharmony_ci int leaf) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci blocklen -= XFS_RMAP_BLOCK_LEN; 59562306a36Sopenharmony_ci return xfs_rmapbt_block_maxrecs(blocklen, leaf); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/* Compute the max possible height for reverse mapping btrees. */ 59962306a36Sopenharmony_ciunsigned int 60062306a36Sopenharmony_cixfs_rmapbt_maxlevels_ondisk(void) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci unsigned int minrecs[2]; 60362306a36Sopenharmony_ci unsigned int blocklen; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_SBLOCK_CRC_LEN; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci minrecs[0] = xfs_rmapbt_block_maxrecs(blocklen, true) / 2; 60862306a36Sopenharmony_ci minrecs[1] = xfs_rmapbt_block_maxrecs(blocklen, false) / 2; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* 61162306a36Sopenharmony_ci * Compute the asymptotic maxlevels for an rmapbt on any reflink fs. 61262306a36Sopenharmony_ci * 61362306a36Sopenharmony_ci * On a reflink filesystem, each AG block can have up to 2^32 (per the 61462306a36Sopenharmony_ci * refcount record format) owners, which means that theoretically we 61562306a36Sopenharmony_ci * could face up to 2^64 rmap records. However, we're likely to run 61662306a36Sopenharmony_ci * out of blocks in the AG long before that happens, which means that 61762306a36Sopenharmony_ci * we must compute the max height based on what the btree will look 61862306a36Sopenharmony_ci * like if it consumes almost all the blocks in the AG due to maximal 61962306a36Sopenharmony_ci * sharing factor. 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_ci return xfs_btree_space_to_height(minrecs, XFS_MAX_CRC_AG_BLOCKS); 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci/* Compute the maximum height of an rmap btree. */ 62562306a36Sopenharmony_civoid 62662306a36Sopenharmony_cixfs_rmapbt_compute_maxlevels( 62762306a36Sopenharmony_ci struct xfs_mount *mp) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci if (!xfs_has_rmapbt(mp)) { 63062306a36Sopenharmony_ci mp->m_rmap_maxlevels = 0; 63162306a36Sopenharmony_ci return; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (xfs_has_reflink(mp)) { 63562306a36Sopenharmony_ci /* 63662306a36Sopenharmony_ci * Compute the asymptotic maxlevels for an rmap btree on a 63762306a36Sopenharmony_ci * filesystem that supports reflink. 63862306a36Sopenharmony_ci * 63962306a36Sopenharmony_ci * On a reflink filesystem, each AG block can have up to 2^32 64062306a36Sopenharmony_ci * (per the refcount record format) owners, which means that 64162306a36Sopenharmony_ci * theoretically we could face up to 2^64 rmap records. 64262306a36Sopenharmony_ci * However, we're likely to run out of blocks in the AG long 64362306a36Sopenharmony_ci * before that happens, which means that we must compute the 64462306a36Sopenharmony_ci * max height based on what the btree will look like if it 64562306a36Sopenharmony_ci * consumes almost all the blocks in the AG due to maximal 64662306a36Sopenharmony_ci * sharing factor. 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_ci mp->m_rmap_maxlevels = xfs_btree_space_to_height(mp->m_rmap_mnr, 64962306a36Sopenharmony_ci mp->m_sb.sb_agblocks); 65062306a36Sopenharmony_ci } else { 65162306a36Sopenharmony_ci /* 65262306a36Sopenharmony_ci * If there's no block sharing, compute the maximum rmapbt 65362306a36Sopenharmony_ci * height assuming one rmap record per AG block. 65462306a36Sopenharmony_ci */ 65562306a36Sopenharmony_ci mp->m_rmap_maxlevels = xfs_btree_compute_maxlevels( 65662306a36Sopenharmony_ci mp->m_rmap_mnr, mp->m_sb.sb_agblocks); 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci ASSERT(mp->m_rmap_maxlevels <= xfs_rmapbt_maxlevels_ondisk()); 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci/* Calculate the refcount btree size for some records. */ 66262306a36Sopenharmony_cixfs_extlen_t 66362306a36Sopenharmony_cixfs_rmapbt_calc_size( 66462306a36Sopenharmony_ci struct xfs_mount *mp, 66562306a36Sopenharmony_ci unsigned long long len) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci return xfs_btree_calc_size(mp->m_rmap_mnr, len); 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci/* 67162306a36Sopenharmony_ci * Calculate the maximum refcount btree size. 67262306a36Sopenharmony_ci */ 67362306a36Sopenharmony_cixfs_extlen_t 67462306a36Sopenharmony_cixfs_rmapbt_max_size( 67562306a36Sopenharmony_ci struct xfs_mount *mp, 67662306a36Sopenharmony_ci xfs_agblock_t agblocks) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci /* Bail out if we're uninitialized, which can happen in mkfs. */ 67962306a36Sopenharmony_ci if (mp->m_rmap_mxr[0] == 0) 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci return xfs_rmapbt_calc_size(mp, agblocks); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci/* 68662306a36Sopenharmony_ci * Figure out how many blocks to reserve and how many are used by this btree. 68762306a36Sopenharmony_ci */ 68862306a36Sopenharmony_ciint 68962306a36Sopenharmony_cixfs_rmapbt_calc_reserves( 69062306a36Sopenharmony_ci struct xfs_mount *mp, 69162306a36Sopenharmony_ci struct xfs_trans *tp, 69262306a36Sopenharmony_ci struct xfs_perag *pag, 69362306a36Sopenharmony_ci xfs_extlen_t *ask, 69462306a36Sopenharmony_ci xfs_extlen_t *used) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci struct xfs_buf *agbp; 69762306a36Sopenharmony_ci struct xfs_agf *agf; 69862306a36Sopenharmony_ci xfs_agblock_t agblocks; 69962306a36Sopenharmony_ci xfs_extlen_t tree_len; 70062306a36Sopenharmony_ci int error; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (!xfs_has_rmapbt(mp)) 70362306a36Sopenharmony_ci return 0; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci error = xfs_alloc_read_agf(pag, tp, 0, &agbp); 70662306a36Sopenharmony_ci if (error) 70762306a36Sopenharmony_ci return error; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci agf = agbp->b_addr; 71062306a36Sopenharmony_ci agblocks = be32_to_cpu(agf->agf_length); 71162306a36Sopenharmony_ci tree_len = be32_to_cpu(agf->agf_rmap_blocks); 71262306a36Sopenharmony_ci xfs_trans_brelse(tp, agbp); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* 71562306a36Sopenharmony_ci * The log is permanently allocated, so the space it occupies will 71662306a36Sopenharmony_ci * never be available for the kinds of things that would require btree 71762306a36Sopenharmony_ci * expansion. We therefore can pretend the space isn't there. 71862306a36Sopenharmony_ci */ 71962306a36Sopenharmony_ci if (xfs_ag_contains_log(mp, pag->pag_agno)) 72062306a36Sopenharmony_ci agblocks -= mp->m_sb.sb_logblocks; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* Reserve 1% of the AG or enough for 1 block per record. */ 72362306a36Sopenharmony_ci *ask += max(agblocks / 100, xfs_rmapbt_max_size(mp, agblocks)); 72462306a36Sopenharmony_ci *used += tree_len; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci return error; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ciint __init 73062306a36Sopenharmony_cixfs_rmapbt_init_cur_cache(void) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci xfs_rmapbt_cur_cache = kmem_cache_create("xfs_rmapbt_cur", 73362306a36Sopenharmony_ci xfs_btree_cur_sizeof(xfs_rmapbt_maxlevels_ondisk()), 73462306a36Sopenharmony_ci 0, 0, NULL); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (!xfs_rmapbt_cur_cache) 73762306a36Sopenharmony_ci return -ENOMEM; 73862306a36Sopenharmony_ci return 0; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_civoid 74262306a36Sopenharmony_cixfs_rmapbt_destroy_cur_cache(void) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci kmem_cache_destroy(xfs_rmapbt_cur_cache); 74562306a36Sopenharmony_ci xfs_rmapbt_cur_cache = NULL; 74662306a36Sopenharmony_ci} 747