1fc6856c6SDarrick J. Wong // SPDX-License-Identifier: GPL-2.0-or-later 2fc6856c6SDarrick J. Wong /* 3fc6856c6SDarrick J. Wong * Copyright (c) 2018-2024 Oracle. All Rights Reserved. 4fc6856c6SDarrick J. Wong * Author: Darrick J. Wong <djwong@kernel.org> 5fc6856c6SDarrick J. Wong */ 6fc6856c6SDarrick J. Wong #include "xfs.h" 7fc6856c6SDarrick J. Wong #include "xfs_fs.h" 8fc6856c6SDarrick J. Wong #include "xfs_shared.h" 9fc6856c6SDarrick J. Wong #include "xfs_format.h" 10fc6856c6SDarrick J. Wong #include "xfs_log_format.h" 11fc6856c6SDarrick J. Wong #include "xfs_trans_resv.h" 12fc6856c6SDarrick J. Wong #include "xfs_bit.h" 13fc6856c6SDarrick J. Wong #include "xfs_sb.h" 14fc6856c6SDarrick J. Wong #include "xfs_mount.h" 15fc6856c6SDarrick J. Wong #include "xfs_defer.h" 16fc6856c6SDarrick J. Wong #include "xfs_inode.h" 17fc6856c6SDarrick J. Wong #include "xfs_trans.h" 18fc6856c6SDarrick J. Wong #include "xfs_alloc.h" 19fc6856c6SDarrick J. Wong #include "xfs_btree.h" 20fc6856c6SDarrick J. Wong #include "xfs_btree_staging.h" 21*d386b402SDarrick J. Wong #include "xfs_rmap.h" 22fc6856c6SDarrick J. Wong #include "xfs_rtrmap_btree.h" 23fc6856c6SDarrick J. Wong #include "xfs_trace.h" 24fc6856c6SDarrick J. Wong #include "xfs_cksum.h" 25fc6856c6SDarrick J. Wong #include "xfs_error.h" 26fc6856c6SDarrick J. Wong #include "xfs_extent_busy.h" 27fc6856c6SDarrick J. Wong #include "xfs_rtgroup.h" 28*d386b402SDarrick J. Wong #include "xfs_bmap.h" 29fc6856c6SDarrick J. Wong 30fc6856c6SDarrick J. Wong static struct kmem_cache *xfs_rtrmapbt_cur_cache; 31fc6856c6SDarrick J. Wong 32fc6856c6SDarrick J. Wong /* 33fc6856c6SDarrick J. Wong * Realtime Reverse Map btree. 34fc6856c6SDarrick J. Wong * 35fc6856c6SDarrick J. Wong * This is a btree used to track the owner(s) of a given extent in the realtime 36fc6856c6SDarrick J. Wong * device. See the comments in xfs_rmap_btree.c for more information. 37fc6856c6SDarrick J. Wong * 38fc6856c6SDarrick J. Wong * This tree is basically the same as the regular rmap btree except that it 39fc6856c6SDarrick J. Wong * is rooted in an inode and does not live in free space. 40fc6856c6SDarrick J. Wong */ 41fc6856c6SDarrick J. Wong 42fc6856c6SDarrick J. Wong static struct xfs_btree_cur * 43fc6856c6SDarrick J. Wong xfs_rtrmapbt_dup_cursor( 44fc6856c6SDarrick J. Wong struct xfs_btree_cur *cur) 45fc6856c6SDarrick J. Wong { 46fc6856c6SDarrick J. Wong return xfs_rtrmapbt_init_cursor(cur->bc_tp, to_rtg(cur->bc_group)); 47fc6856c6SDarrick J. Wong } 48fc6856c6SDarrick J. Wong 49*d386b402SDarrick J. Wong STATIC int 50*d386b402SDarrick J. Wong xfs_rtrmapbt_get_minrecs( 51*d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 52*d386b402SDarrick J. Wong int level) 53*d386b402SDarrick J. Wong { 54*d386b402SDarrick J. Wong if (level == cur->bc_nlevels - 1) { 55*d386b402SDarrick J. Wong struct xfs_ifork *ifp = xfs_btree_ifork_ptr(cur); 56*d386b402SDarrick J. Wong 57*d386b402SDarrick J. Wong return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes, 58*d386b402SDarrick J. Wong level == 0) / 2; 59*d386b402SDarrick J. Wong } 60*d386b402SDarrick J. Wong 61*d386b402SDarrick J. Wong return cur->bc_mp->m_rtrmap_mnr[level != 0]; 62*d386b402SDarrick J. Wong } 63*d386b402SDarrick J. Wong 64*d386b402SDarrick J. Wong STATIC int 65*d386b402SDarrick J. Wong xfs_rtrmapbt_get_maxrecs( 66*d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 67*d386b402SDarrick J. Wong int level) 68*d386b402SDarrick J. Wong { 69*d386b402SDarrick J. Wong if (level == cur->bc_nlevels - 1) { 70*d386b402SDarrick J. Wong struct xfs_ifork *ifp = xfs_btree_ifork_ptr(cur); 71*d386b402SDarrick J. Wong 72*d386b402SDarrick J. Wong return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes, 73*d386b402SDarrick J. Wong level == 0); 74*d386b402SDarrick J. Wong } 75*d386b402SDarrick J. Wong 76*d386b402SDarrick J. Wong return cur->bc_mp->m_rtrmap_mxr[level != 0]; 77*d386b402SDarrick J. Wong } 78*d386b402SDarrick J. Wong 79*d386b402SDarrick J. Wong /* 80*d386b402SDarrick J. Wong * Convert the ondisk record's offset field into the ondisk key's offset field. 81*d386b402SDarrick J. Wong * Fork and bmbt are significant parts of the rmap record key, but written 82*d386b402SDarrick J. Wong * status is merely a record attribute. 83*d386b402SDarrick J. Wong */ 84*d386b402SDarrick J. Wong static inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec) 85*d386b402SDarrick J. Wong { 86*d386b402SDarrick J. Wong return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN); 87*d386b402SDarrick J. Wong } 88*d386b402SDarrick J. Wong 89*d386b402SDarrick J. Wong STATIC void 90*d386b402SDarrick J. Wong xfs_rtrmapbt_init_key_from_rec( 91*d386b402SDarrick J. Wong union xfs_btree_key *key, 92*d386b402SDarrick J. Wong const union xfs_btree_rec *rec) 93*d386b402SDarrick J. Wong { 94*d386b402SDarrick J. Wong key->rmap.rm_startblock = rec->rmap.rm_startblock; 95*d386b402SDarrick J. Wong key->rmap.rm_owner = rec->rmap.rm_owner; 96*d386b402SDarrick J. Wong key->rmap.rm_offset = ondisk_rec_offset_to_key(rec); 97*d386b402SDarrick J. Wong } 98*d386b402SDarrick J. Wong 99*d386b402SDarrick J. Wong STATIC void 100*d386b402SDarrick J. Wong xfs_rtrmapbt_init_high_key_from_rec( 101*d386b402SDarrick J. Wong union xfs_btree_key *key, 102*d386b402SDarrick J. Wong const union xfs_btree_rec *rec) 103*d386b402SDarrick J. Wong { 104*d386b402SDarrick J. Wong uint64_t off; 105*d386b402SDarrick J. Wong int adj; 106*d386b402SDarrick J. Wong 107*d386b402SDarrick J. Wong adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1; 108*d386b402SDarrick J. Wong 109*d386b402SDarrick J. Wong key->rmap.rm_startblock = rec->rmap.rm_startblock; 110*d386b402SDarrick J. Wong be32_add_cpu(&key->rmap.rm_startblock, adj); 111*d386b402SDarrick J. Wong key->rmap.rm_owner = rec->rmap.rm_owner; 112*d386b402SDarrick J. Wong key->rmap.rm_offset = ondisk_rec_offset_to_key(rec); 113*d386b402SDarrick J. Wong if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) || 114*d386b402SDarrick J. Wong XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset))) 115*d386b402SDarrick J. Wong return; 116*d386b402SDarrick J. Wong off = be64_to_cpu(key->rmap.rm_offset); 117*d386b402SDarrick J. Wong off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK); 118*d386b402SDarrick J. Wong key->rmap.rm_offset = cpu_to_be64(off); 119*d386b402SDarrick J. Wong } 120*d386b402SDarrick J. Wong 121*d386b402SDarrick J. Wong STATIC void 122*d386b402SDarrick J. Wong xfs_rtrmapbt_init_rec_from_cur( 123*d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 124*d386b402SDarrick J. Wong union xfs_btree_rec *rec) 125*d386b402SDarrick J. Wong { 126*d386b402SDarrick J. Wong rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock); 127*d386b402SDarrick J. Wong rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount); 128*d386b402SDarrick J. Wong rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner); 129*d386b402SDarrick J. Wong rec->rmap.rm_offset = cpu_to_be64( 130*d386b402SDarrick J. Wong xfs_rmap_irec_offset_pack(&cur->bc_rec.r)); 131*d386b402SDarrick J. Wong } 132*d386b402SDarrick J. Wong 133*d386b402SDarrick J. Wong STATIC void 134*d386b402SDarrick J. Wong xfs_rtrmapbt_init_ptr_from_cur( 135*d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 136*d386b402SDarrick J. Wong union xfs_btree_ptr *ptr) 137*d386b402SDarrick J. Wong { 138*d386b402SDarrick J. Wong ptr->l = 0; 139*d386b402SDarrick J. Wong } 140*d386b402SDarrick J. Wong 141*d386b402SDarrick J. Wong /* 142*d386b402SDarrick J. Wong * Mask the appropriate parts of the ondisk key field for a key comparison. 143*d386b402SDarrick J. Wong * Fork and bmbt are significant parts of the rmap record key, but written 144*d386b402SDarrick J. Wong * status is merely a record attribute. 145*d386b402SDarrick J. Wong */ 146*d386b402SDarrick J. Wong static inline uint64_t offset_keymask(uint64_t offset) 147*d386b402SDarrick J. Wong { 148*d386b402SDarrick J. Wong return offset & ~XFS_RMAP_OFF_UNWRITTEN; 149*d386b402SDarrick J. Wong } 150*d386b402SDarrick J. Wong 151*d386b402SDarrick J. Wong STATIC int64_t 152*d386b402SDarrick J. Wong xfs_rtrmapbt_key_diff( 153*d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 154*d386b402SDarrick J. Wong const union xfs_btree_key *key) 155*d386b402SDarrick J. Wong { 156*d386b402SDarrick J. Wong struct xfs_rmap_irec *rec = &cur->bc_rec.r; 157*d386b402SDarrick J. Wong const struct xfs_rmap_key *kp = &key->rmap; 158*d386b402SDarrick J. Wong __u64 x, y; 159*d386b402SDarrick J. Wong int64_t d; 160*d386b402SDarrick J. Wong 161*d386b402SDarrick J. Wong d = (int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock; 162*d386b402SDarrick J. Wong if (d) 163*d386b402SDarrick J. Wong return d; 164*d386b402SDarrick J. Wong 165*d386b402SDarrick J. Wong x = be64_to_cpu(kp->rm_owner); 166*d386b402SDarrick J. Wong y = rec->rm_owner; 167*d386b402SDarrick J. Wong if (x > y) 168*d386b402SDarrick J. Wong return 1; 169*d386b402SDarrick J. Wong else if (y > x) 170*d386b402SDarrick J. Wong return -1; 171*d386b402SDarrick J. Wong 172*d386b402SDarrick J. Wong x = offset_keymask(be64_to_cpu(kp->rm_offset)); 173*d386b402SDarrick J. Wong y = offset_keymask(xfs_rmap_irec_offset_pack(rec)); 174*d386b402SDarrick J. Wong if (x > y) 175*d386b402SDarrick J. Wong return 1; 176*d386b402SDarrick J. Wong else if (y > x) 177*d386b402SDarrick J. Wong return -1; 178*d386b402SDarrick J. Wong return 0; 179*d386b402SDarrick J. Wong } 180*d386b402SDarrick J. Wong 181*d386b402SDarrick J. Wong STATIC int64_t 182*d386b402SDarrick J. Wong xfs_rtrmapbt_diff_two_keys( 183*d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 184*d386b402SDarrick J. Wong const union xfs_btree_key *k1, 185*d386b402SDarrick J. Wong const union xfs_btree_key *k2, 186*d386b402SDarrick J. Wong const union xfs_btree_key *mask) 187*d386b402SDarrick J. Wong { 188*d386b402SDarrick J. Wong const struct xfs_rmap_key *kp1 = &k1->rmap; 189*d386b402SDarrick J. Wong const struct xfs_rmap_key *kp2 = &k2->rmap; 190*d386b402SDarrick J. Wong int64_t d; 191*d386b402SDarrick J. Wong __u64 x, y; 192*d386b402SDarrick J. Wong 193*d386b402SDarrick J. Wong /* Doesn't make sense to mask off the physical space part */ 194*d386b402SDarrick J. Wong ASSERT(!mask || mask->rmap.rm_startblock); 195*d386b402SDarrick J. Wong 196*d386b402SDarrick J. Wong d = (int64_t)be32_to_cpu(kp1->rm_startblock) - 197*d386b402SDarrick J. Wong be32_to_cpu(kp2->rm_startblock); 198*d386b402SDarrick J. Wong if (d) 199*d386b402SDarrick J. Wong return d; 200*d386b402SDarrick J. Wong 201*d386b402SDarrick J. Wong if (!mask || mask->rmap.rm_owner) { 202*d386b402SDarrick J. Wong x = be64_to_cpu(kp1->rm_owner); 203*d386b402SDarrick J. Wong y = be64_to_cpu(kp2->rm_owner); 204*d386b402SDarrick J. Wong if (x > y) 205*d386b402SDarrick J. Wong return 1; 206*d386b402SDarrick J. Wong else if (y > x) 207*d386b402SDarrick J. Wong return -1; 208*d386b402SDarrick J. Wong } 209*d386b402SDarrick J. Wong 210*d386b402SDarrick J. Wong if (!mask || mask->rmap.rm_offset) { 211*d386b402SDarrick J. Wong /* Doesn't make sense to allow offset but not owner */ 212*d386b402SDarrick J. Wong ASSERT(!mask || mask->rmap.rm_owner); 213*d386b402SDarrick J. Wong 214*d386b402SDarrick J. Wong x = offset_keymask(be64_to_cpu(kp1->rm_offset)); 215*d386b402SDarrick J. Wong y = offset_keymask(be64_to_cpu(kp2->rm_offset)); 216*d386b402SDarrick J. Wong if (x > y) 217*d386b402SDarrick J. Wong return 1; 218*d386b402SDarrick J. Wong else if (y > x) 219*d386b402SDarrick J. Wong return -1; 220*d386b402SDarrick J. Wong } 221*d386b402SDarrick J. Wong 222*d386b402SDarrick J. Wong return 0; 223*d386b402SDarrick J. Wong } 224*d386b402SDarrick J. Wong 225fc6856c6SDarrick J. Wong static xfs_failaddr_t 226fc6856c6SDarrick J. Wong xfs_rtrmapbt_verify( 227fc6856c6SDarrick J. Wong struct xfs_buf *bp) 228fc6856c6SDarrick J. Wong { 229fc6856c6SDarrick J. Wong struct xfs_mount *mp = bp->b_target->bt_mount; 230fc6856c6SDarrick J. Wong struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 231fc6856c6SDarrick J. Wong xfs_failaddr_t fa; 232fc6856c6SDarrick J. Wong int level; 233fc6856c6SDarrick J. Wong 234fc6856c6SDarrick J. Wong if (!xfs_verify_magic(bp, block->bb_magic)) 235fc6856c6SDarrick J. Wong return __this_address; 236fc6856c6SDarrick J. Wong 237fc6856c6SDarrick J. Wong if (!xfs_has_rmapbt(mp)) 238fc6856c6SDarrick J. Wong return __this_address; 239fc6856c6SDarrick J. Wong fa = xfs_btree_fsblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN); 240fc6856c6SDarrick J. Wong if (fa) 241fc6856c6SDarrick J. Wong return fa; 242fc6856c6SDarrick J. Wong level = be16_to_cpu(block->bb_level); 243fc6856c6SDarrick J. Wong if (level > mp->m_rtrmap_maxlevels) 244fc6856c6SDarrick J. Wong return __this_address; 245fc6856c6SDarrick J. Wong 246fc6856c6SDarrick J. Wong return xfs_btree_fsblock_verify(bp, mp->m_rtrmap_mxr[level != 0]); 247fc6856c6SDarrick J. Wong } 248fc6856c6SDarrick J. Wong 249fc6856c6SDarrick J. Wong static void 250fc6856c6SDarrick J. Wong xfs_rtrmapbt_read_verify( 251fc6856c6SDarrick J. Wong struct xfs_buf *bp) 252fc6856c6SDarrick J. Wong { 253fc6856c6SDarrick J. Wong xfs_failaddr_t fa; 254fc6856c6SDarrick J. Wong 255fc6856c6SDarrick J. Wong if (!xfs_btree_fsblock_verify_crc(bp)) 256fc6856c6SDarrick J. Wong xfs_verifier_error(bp, -EFSBADCRC, __this_address); 257fc6856c6SDarrick J. Wong else { 258fc6856c6SDarrick J. Wong fa = xfs_rtrmapbt_verify(bp); 259fc6856c6SDarrick J. Wong if (fa) 260fc6856c6SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 261fc6856c6SDarrick J. Wong } 262fc6856c6SDarrick J. Wong 263fc6856c6SDarrick J. Wong if (bp->b_error) 264fc6856c6SDarrick J. Wong trace_xfs_btree_corrupt(bp, _RET_IP_); 265fc6856c6SDarrick J. Wong } 266fc6856c6SDarrick J. Wong 267fc6856c6SDarrick J. Wong static void 268fc6856c6SDarrick J. Wong xfs_rtrmapbt_write_verify( 269fc6856c6SDarrick J. Wong struct xfs_buf *bp) 270fc6856c6SDarrick J. Wong { 271fc6856c6SDarrick J. Wong xfs_failaddr_t fa; 272fc6856c6SDarrick J. Wong 273fc6856c6SDarrick J. Wong fa = xfs_rtrmapbt_verify(bp); 274fc6856c6SDarrick J. Wong if (fa) { 275fc6856c6SDarrick J. Wong trace_xfs_btree_corrupt(bp, _RET_IP_); 276fc6856c6SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 277fc6856c6SDarrick J. Wong return; 278fc6856c6SDarrick J. Wong } 279fc6856c6SDarrick J. Wong xfs_btree_fsblock_calc_crc(bp); 280fc6856c6SDarrick J. Wong 281fc6856c6SDarrick J. Wong } 282fc6856c6SDarrick J. Wong 283fc6856c6SDarrick J. Wong const struct xfs_buf_ops xfs_rtrmapbt_buf_ops = { 284fc6856c6SDarrick J. Wong .name = "xfs_rtrmapbt", 285fc6856c6SDarrick J. Wong .magic = { 0, cpu_to_be32(XFS_RTRMAP_CRC_MAGIC) }, 286fc6856c6SDarrick J. Wong .verify_read = xfs_rtrmapbt_read_verify, 287fc6856c6SDarrick J. Wong .verify_write = xfs_rtrmapbt_write_verify, 288fc6856c6SDarrick J. Wong .verify_struct = xfs_rtrmapbt_verify, 289fc6856c6SDarrick J. Wong }; 290fc6856c6SDarrick J. Wong 291*d386b402SDarrick J. Wong STATIC int 292*d386b402SDarrick J. Wong xfs_rtrmapbt_keys_inorder( 293*d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 294*d386b402SDarrick J. Wong const union xfs_btree_key *k1, 295*d386b402SDarrick J. Wong const union xfs_btree_key *k2) 296*d386b402SDarrick J. Wong { 297*d386b402SDarrick J. Wong uint32_t x; 298*d386b402SDarrick J. Wong uint32_t y; 299*d386b402SDarrick J. Wong uint64_t a; 300*d386b402SDarrick J. Wong uint64_t b; 301*d386b402SDarrick J. Wong 302*d386b402SDarrick J. Wong x = be32_to_cpu(k1->rmap.rm_startblock); 303*d386b402SDarrick J. Wong y = be32_to_cpu(k2->rmap.rm_startblock); 304*d386b402SDarrick J. Wong if (x < y) 305*d386b402SDarrick J. Wong return 1; 306*d386b402SDarrick J. Wong else if (x > y) 307*d386b402SDarrick J. Wong return 0; 308*d386b402SDarrick J. Wong a = be64_to_cpu(k1->rmap.rm_owner); 309*d386b402SDarrick J. Wong b = be64_to_cpu(k2->rmap.rm_owner); 310*d386b402SDarrick J. Wong if (a < b) 311*d386b402SDarrick J. Wong return 1; 312*d386b402SDarrick J. Wong else if (a > b) 313*d386b402SDarrick J. Wong return 0; 314*d386b402SDarrick J. Wong a = offset_keymask(be64_to_cpu(k1->rmap.rm_offset)); 315*d386b402SDarrick J. Wong b = offset_keymask(be64_to_cpu(k2->rmap.rm_offset)); 316*d386b402SDarrick J. Wong if (a <= b) 317*d386b402SDarrick J. Wong return 1; 318*d386b402SDarrick J. Wong return 0; 319*d386b402SDarrick J. Wong } 320*d386b402SDarrick J. Wong 321*d386b402SDarrick J. Wong STATIC int 322*d386b402SDarrick J. Wong xfs_rtrmapbt_recs_inorder( 323*d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 324*d386b402SDarrick J. Wong const union xfs_btree_rec *r1, 325*d386b402SDarrick J. Wong const union xfs_btree_rec *r2) 326*d386b402SDarrick J. Wong { 327*d386b402SDarrick J. Wong uint32_t x; 328*d386b402SDarrick J. Wong uint32_t y; 329*d386b402SDarrick J. Wong uint64_t a; 330*d386b402SDarrick J. Wong uint64_t b; 331*d386b402SDarrick J. Wong 332*d386b402SDarrick J. Wong x = be32_to_cpu(r1->rmap.rm_startblock); 333*d386b402SDarrick J. Wong y = be32_to_cpu(r2->rmap.rm_startblock); 334*d386b402SDarrick J. Wong if (x < y) 335*d386b402SDarrick J. Wong return 1; 336*d386b402SDarrick J. Wong else if (x > y) 337*d386b402SDarrick J. Wong return 0; 338*d386b402SDarrick J. Wong a = be64_to_cpu(r1->rmap.rm_owner); 339*d386b402SDarrick J. Wong b = be64_to_cpu(r2->rmap.rm_owner); 340*d386b402SDarrick J. Wong if (a < b) 341*d386b402SDarrick J. Wong return 1; 342*d386b402SDarrick J. Wong else if (a > b) 343*d386b402SDarrick J. Wong return 0; 344*d386b402SDarrick J. Wong a = offset_keymask(be64_to_cpu(r1->rmap.rm_offset)); 345*d386b402SDarrick J. Wong b = offset_keymask(be64_to_cpu(r2->rmap.rm_offset)); 346*d386b402SDarrick J. Wong if (a <= b) 347*d386b402SDarrick J. Wong return 1; 348*d386b402SDarrick J. Wong return 0; 349*d386b402SDarrick J. Wong } 350*d386b402SDarrick J. Wong 351*d386b402SDarrick J. Wong STATIC enum xbtree_key_contig 352*d386b402SDarrick J. Wong xfs_rtrmapbt_keys_contiguous( 353*d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 354*d386b402SDarrick J. Wong const union xfs_btree_key *key1, 355*d386b402SDarrick J. Wong const union xfs_btree_key *key2, 356*d386b402SDarrick J. Wong const union xfs_btree_key *mask) 357*d386b402SDarrick J. Wong { 358*d386b402SDarrick J. Wong ASSERT(!mask || mask->rmap.rm_startblock); 359*d386b402SDarrick J. Wong 360*d386b402SDarrick J. Wong /* 361*d386b402SDarrick J. Wong * We only support checking contiguity of the physical space component. 362*d386b402SDarrick J. Wong * If any callers ever need more specificity than that, they'll have to 363*d386b402SDarrick J. Wong * implement it here. 364*d386b402SDarrick J. Wong */ 365*d386b402SDarrick J. Wong ASSERT(!mask || (!mask->rmap.rm_owner && !mask->rmap.rm_offset)); 366*d386b402SDarrick J. Wong 367*d386b402SDarrick J. Wong return xbtree_key_contig(be32_to_cpu(key1->rmap.rm_startblock), 368*d386b402SDarrick J. Wong be32_to_cpu(key2->rmap.rm_startblock)); 369*d386b402SDarrick J. Wong } 370*d386b402SDarrick J. Wong 371fc6856c6SDarrick J. Wong const struct xfs_btree_ops xfs_rtrmapbt_ops = { 372fc6856c6SDarrick J. Wong .name = "rtrmap", 373fc6856c6SDarrick J. Wong .type = XFS_BTREE_TYPE_INODE, 374fc6856c6SDarrick J. Wong .geom_flags = XFS_BTGEO_OVERLAPPING | 375fc6856c6SDarrick J. Wong XFS_BTGEO_IROOT_RECORDS, 376fc6856c6SDarrick J. Wong 377fc6856c6SDarrick J. Wong .rec_len = sizeof(struct xfs_rmap_rec), 378fc6856c6SDarrick J. Wong /* Overlapping btree; 2 keys per pointer. */ 379fc6856c6SDarrick J. Wong .key_len = 2 * sizeof(struct xfs_rmap_key), 380fc6856c6SDarrick J. Wong .ptr_len = XFS_BTREE_LONG_PTR_LEN, 381fc6856c6SDarrick J. Wong 382fc6856c6SDarrick J. Wong .lru_refs = XFS_RMAP_BTREE_REF, 383fc6856c6SDarrick J. Wong .statoff = XFS_STATS_CALC_INDEX(xs_rtrmap_2), 384fc6856c6SDarrick J. Wong 385fc6856c6SDarrick J. Wong .dup_cursor = xfs_rtrmapbt_dup_cursor, 386*d386b402SDarrick J. Wong .alloc_block = xfs_btree_alloc_metafile_block, 387*d386b402SDarrick J. Wong .free_block = xfs_btree_free_metafile_block, 388*d386b402SDarrick J. Wong .get_minrecs = xfs_rtrmapbt_get_minrecs, 389*d386b402SDarrick J. Wong .get_maxrecs = xfs_rtrmapbt_get_maxrecs, 390*d386b402SDarrick J. Wong .init_key_from_rec = xfs_rtrmapbt_init_key_from_rec, 391*d386b402SDarrick J. Wong .init_high_key_from_rec = xfs_rtrmapbt_init_high_key_from_rec, 392*d386b402SDarrick J. Wong .init_rec_from_cur = xfs_rtrmapbt_init_rec_from_cur, 393*d386b402SDarrick J. Wong .init_ptr_from_cur = xfs_rtrmapbt_init_ptr_from_cur, 394*d386b402SDarrick J. Wong .key_diff = xfs_rtrmapbt_key_diff, 395fc6856c6SDarrick J. Wong .buf_ops = &xfs_rtrmapbt_buf_ops, 396*d386b402SDarrick J. Wong .diff_two_keys = xfs_rtrmapbt_diff_two_keys, 397*d386b402SDarrick J. Wong .keys_inorder = xfs_rtrmapbt_keys_inorder, 398*d386b402SDarrick J. Wong .recs_inorder = xfs_rtrmapbt_recs_inorder, 399*d386b402SDarrick J. Wong .keys_contiguous = xfs_rtrmapbt_keys_contiguous, 400fc6856c6SDarrick J. Wong }; 401fc6856c6SDarrick J. Wong 402fc6856c6SDarrick J. Wong /* Allocate a new rt rmap btree cursor. */ 403fc6856c6SDarrick J. Wong struct xfs_btree_cur * 404fc6856c6SDarrick J. Wong xfs_rtrmapbt_init_cursor( 405fc6856c6SDarrick J. Wong struct xfs_trans *tp, 406fc6856c6SDarrick J. Wong struct xfs_rtgroup *rtg) 407fc6856c6SDarrick J. Wong { 408fc6856c6SDarrick J. Wong struct xfs_inode *ip = NULL; 409fc6856c6SDarrick J. Wong struct xfs_mount *mp = rtg_mount(rtg); 410fc6856c6SDarrick J. Wong struct xfs_btree_cur *cur; 411fc6856c6SDarrick J. Wong 412fc6856c6SDarrick J. Wong return NULL; /* XXX */ 413fc6856c6SDarrick J. Wong 414fc6856c6SDarrick J. Wong xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL); 415fc6856c6SDarrick J. Wong 416fc6856c6SDarrick J. Wong cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rtrmapbt_ops, 417fc6856c6SDarrick J. Wong mp->m_rtrmap_maxlevels, xfs_rtrmapbt_cur_cache); 418fc6856c6SDarrick J. Wong 419fc6856c6SDarrick J. Wong cur->bc_ino.ip = ip; 420fc6856c6SDarrick J. Wong cur->bc_group = xfs_group_hold(rtg_group(rtg)); 421fc6856c6SDarrick J. Wong cur->bc_ino.whichfork = XFS_DATA_FORK; 422fc6856c6SDarrick J. Wong cur->bc_nlevels = be16_to_cpu(ip->i_df.if_broot->bb_level) + 1; 423fc6856c6SDarrick J. Wong cur->bc_ino.forksize = xfs_inode_fork_size(ip, XFS_DATA_FORK); 424fc6856c6SDarrick J. Wong 425fc6856c6SDarrick J. Wong return cur; 426fc6856c6SDarrick J. Wong } 427fc6856c6SDarrick J. Wong 428fc6856c6SDarrick J. Wong /* 429fc6856c6SDarrick J. Wong * Install a new rt reverse mapping btree root. Caller is responsible for 430fc6856c6SDarrick J. Wong * invalidating and freeing the old btree blocks. 431fc6856c6SDarrick J. Wong */ 432fc6856c6SDarrick J. Wong void 433fc6856c6SDarrick J. Wong xfs_rtrmapbt_commit_staged_btree( 434fc6856c6SDarrick J. Wong struct xfs_btree_cur *cur, 435fc6856c6SDarrick J. Wong struct xfs_trans *tp) 436fc6856c6SDarrick J. Wong { 437fc6856c6SDarrick J. Wong struct xbtree_ifakeroot *ifake = cur->bc_ino.ifake; 438fc6856c6SDarrick J. Wong struct xfs_ifork *ifp; 439fc6856c6SDarrick J. Wong int flags = XFS_ILOG_CORE | XFS_ILOG_DBROOT; 440fc6856c6SDarrick J. Wong 441fc6856c6SDarrick J. Wong ASSERT(cur->bc_flags & XFS_BTREE_STAGING); 442fc6856c6SDarrick J. Wong 443fc6856c6SDarrick J. Wong /* 444fc6856c6SDarrick J. Wong * Free any resources hanging off the real fork, then shallow-copy the 445fc6856c6SDarrick J. Wong * staging fork's contents into the real fork to transfer everything 446fc6856c6SDarrick J. Wong * we just built. 447fc6856c6SDarrick J. Wong */ 448fc6856c6SDarrick J. Wong ifp = xfs_ifork_ptr(cur->bc_ino.ip, XFS_DATA_FORK); 449fc6856c6SDarrick J. Wong xfs_idestroy_fork(ifp); 450fc6856c6SDarrick J. Wong memcpy(ifp, ifake->if_fork, sizeof(struct xfs_ifork)); 451fc6856c6SDarrick J. Wong 452fc6856c6SDarrick J. Wong cur->bc_ino.ip->i_projid = cur->bc_group->xg_gno; 453fc6856c6SDarrick J. Wong xfs_trans_log_inode(tp, cur->bc_ino.ip, flags); 454fc6856c6SDarrick J. Wong xfs_btree_commit_ifakeroot(cur, tp, XFS_DATA_FORK); 455fc6856c6SDarrick J. Wong } 456fc6856c6SDarrick J. Wong 457fc6856c6SDarrick J. Wong /* Calculate number of records in a rt reverse mapping btree block. */ 458fc6856c6SDarrick J. Wong static inline unsigned int 459fc6856c6SDarrick J. Wong xfs_rtrmapbt_block_maxrecs( 460fc6856c6SDarrick J. Wong unsigned int blocklen, 461fc6856c6SDarrick J. Wong bool leaf) 462fc6856c6SDarrick J. Wong { 463fc6856c6SDarrick J. Wong if (leaf) 464fc6856c6SDarrick J. Wong return blocklen / sizeof(struct xfs_rmap_rec); 465fc6856c6SDarrick J. Wong return blocklen / 466fc6856c6SDarrick J. Wong (2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rtrmap_ptr_t)); 467fc6856c6SDarrick J. Wong } 468fc6856c6SDarrick J. Wong 469fc6856c6SDarrick J. Wong /* 470fc6856c6SDarrick J. Wong * Calculate number of records in an rt reverse mapping btree block. 471fc6856c6SDarrick J. Wong */ 472fc6856c6SDarrick J. Wong unsigned int 473fc6856c6SDarrick J. Wong xfs_rtrmapbt_maxrecs( 474fc6856c6SDarrick J. Wong struct xfs_mount *mp, 475fc6856c6SDarrick J. Wong unsigned int blocklen, 476fc6856c6SDarrick J. Wong bool leaf) 477fc6856c6SDarrick J. Wong { 478fc6856c6SDarrick J. Wong blocklen -= XFS_RTRMAP_BLOCK_LEN; 479fc6856c6SDarrick J. Wong return xfs_rtrmapbt_block_maxrecs(blocklen, leaf); 480fc6856c6SDarrick J. Wong } 481fc6856c6SDarrick J. Wong 482fc6856c6SDarrick J. Wong /* Compute the max possible height for realtime reverse mapping btrees. */ 483fc6856c6SDarrick J. Wong unsigned int 484fc6856c6SDarrick J. Wong xfs_rtrmapbt_maxlevels_ondisk(void) 485fc6856c6SDarrick J. Wong { 486fc6856c6SDarrick J. Wong unsigned int minrecs[2]; 487fc6856c6SDarrick J. Wong unsigned int blocklen; 488fc6856c6SDarrick J. Wong 489fc6856c6SDarrick J. Wong blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN; 490fc6856c6SDarrick J. Wong 491fc6856c6SDarrick J. Wong minrecs[0] = xfs_rtrmapbt_block_maxrecs(blocklen, true) / 2; 492fc6856c6SDarrick J. Wong minrecs[1] = xfs_rtrmapbt_block_maxrecs(blocklen, false) / 2; 493fc6856c6SDarrick J. Wong 494fc6856c6SDarrick J. Wong /* We need at most one record for every block in an rt group. */ 495fc6856c6SDarrick J. Wong return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_RGBLOCKS); 496fc6856c6SDarrick J. Wong } 497fc6856c6SDarrick J. Wong 498fc6856c6SDarrick J. Wong int __init 499fc6856c6SDarrick J. Wong xfs_rtrmapbt_init_cur_cache(void) 500fc6856c6SDarrick J. Wong { 501fc6856c6SDarrick J. Wong xfs_rtrmapbt_cur_cache = kmem_cache_create("xfs_rtrmapbt_cur", 502fc6856c6SDarrick J. Wong xfs_btree_cur_sizeof(xfs_rtrmapbt_maxlevels_ondisk()), 503fc6856c6SDarrick J. Wong 0, 0, NULL); 504fc6856c6SDarrick J. Wong 505fc6856c6SDarrick J. Wong if (!xfs_rtrmapbt_cur_cache) 506fc6856c6SDarrick J. Wong return -ENOMEM; 507fc6856c6SDarrick J. Wong return 0; 508fc6856c6SDarrick J. Wong } 509fc6856c6SDarrick J. Wong 510fc6856c6SDarrick J. Wong void 511fc6856c6SDarrick J. Wong xfs_rtrmapbt_destroy_cur_cache(void) 512fc6856c6SDarrick J. Wong { 513fc6856c6SDarrick J. Wong kmem_cache_destroy(xfs_rtrmapbt_cur_cache); 514fc6856c6SDarrick J. Wong xfs_rtrmapbt_cur_cache = NULL; 515fc6856c6SDarrick J. Wong } 516fc6856c6SDarrick J. Wong 517fc6856c6SDarrick J. Wong /* Compute the maximum height of an rt reverse mapping btree. */ 518fc6856c6SDarrick J. Wong void 519fc6856c6SDarrick J. Wong xfs_rtrmapbt_compute_maxlevels( 520fc6856c6SDarrick J. Wong struct xfs_mount *mp) 521fc6856c6SDarrick J. Wong { 522fc6856c6SDarrick J. Wong unsigned int d_maxlevels, r_maxlevels; 523fc6856c6SDarrick J. Wong 524fc6856c6SDarrick J. Wong if (!xfs_has_rtrmapbt(mp)) { 525fc6856c6SDarrick J. Wong mp->m_rtrmap_maxlevels = 0; 526fc6856c6SDarrick J. Wong return; 527fc6856c6SDarrick J. Wong } 528fc6856c6SDarrick J. Wong 529fc6856c6SDarrick J. Wong /* 530fc6856c6SDarrick J. Wong * The realtime rmapbt lives on the data device, which means that its 531fc6856c6SDarrick J. Wong * maximum height is constrained by the size of the data device and 532fc6856c6SDarrick J. Wong * the height required to store one rmap record for each block in an 533fc6856c6SDarrick J. Wong * rt group. 534fc6856c6SDarrick J. Wong */ 535fc6856c6SDarrick J. Wong d_maxlevels = xfs_btree_space_to_height(mp->m_rtrmap_mnr, 536fc6856c6SDarrick J. Wong mp->m_sb.sb_dblocks); 537fc6856c6SDarrick J. Wong r_maxlevels = xfs_btree_compute_maxlevels(mp->m_rtrmap_mnr, 538fc6856c6SDarrick J. Wong mp->m_groups[XG_TYPE_RTG].blocks); 539fc6856c6SDarrick J. Wong 540fc6856c6SDarrick J. Wong /* Add one level to handle the inode root level. */ 541fc6856c6SDarrick J. Wong mp->m_rtrmap_maxlevels = min(d_maxlevels, r_maxlevels) + 1; 542fc6856c6SDarrick J. Wong } 543