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" 216b08901aSDarrick J. Wong #include "xfs_metafile.h" 22d386b402SDarrick J. Wong #include "xfs_rmap.h" 23fc6856c6SDarrick J. Wong #include "xfs_rtrmap_btree.h" 24fc6856c6SDarrick J. Wong #include "xfs_trace.h" 25fc6856c6SDarrick J. Wong #include "xfs_cksum.h" 26fc6856c6SDarrick J. Wong #include "xfs_error.h" 27fc6856c6SDarrick J. Wong #include "xfs_extent_busy.h" 28fc6856c6SDarrick J. Wong #include "xfs_rtgroup.h" 29d386b402SDarrick J. Wong #include "xfs_bmap.h" 30fc6856c6SDarrick J. Wong 31fc6856c6SDarrick J. Wong static struct kmem_cache *xfs_rtrmapbt_cur_cache; 32fc6856c6SDarrick J. Wong 33fc6856c6SDarrick J. Wong /* 34fc6856c6SDarrick J. Wong * Realtime Reverse Map btree. 35fc6856c6SDarrick J. Wong * 36fc6856c6SDarrick J. Wong * This is a btree used to track the owner(s) of a given extent in the realtime 37fc6856c6SDarrick J. Wong * device. See the comments in xfs_rmap_btree.c for more information. 38fc6856c6SDarrick J. Wong * 39fc6856c6SDarrick J. Wong * This tree is basically the same as the regular rmap btree except that it 40fc6856c6SDarrick J. Wong * is rooted in an inode and does not live in free space. 41fc6856c6SDarrick J. Wong */ 42fc6856c6SDarrick J. Wong 43fc6856c6SDarrick J. Wong static struct xfs_btree_cur * 44fc6856c6SDarrick J. Wong xfs_rtrmapbt_dup_cursor( 45fc6856c6SDarrick J. Wong struct xfs_btree_cur *cur) 46fc6856c6SDarrick J. Wong { 47fc6856c6SDarrick J. Wong return xfs_rtrmapbt_init_cursor(cur->bc_tp, to_rtg(cur->bc_group)); 48fc6856c6SDarrick J. Wong } 49fc6856c6SDarrick J. Wong 50d386b402SDarrick J. Wong STATIC int 51d386b402SDarrick J. Wong xfs_rtrmapbt_get_minrecs( 52d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 53d386b402SDarrick J. Wong int level) 54d386b402SDarrick J. Wong { 55d386b402SDarrick J. Wong if (level == cur->bc_nlevels - 1) { 56d386b402SDarrick J. Wong struct xfs_ifork *ifp = xfs_btree_ifork_ptr(cur); 57d386b402SDarrick J. Wong 58d386b402SDarrick J. Wong return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes, 59d386b402SDarrick J. Wong level == 0) / 2; 60d386b402SDarrick J. Wong } 61d386b402SDarrick J. Wong 62d386b402SDarrick J. Wong return cur->bc_mp->m_rtrmap_mnr[level != 0]; 63d386b402SDarrick J. Wong } 64d386b402SDarrick J. Wong 65d386b402SDarrick J. Wong STATIC int 66d386b402SDarrick J. Wong xfs_rtrmapbt_get_maxrecs( 67d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 68d386b402SDarrick J. Wong int level) 69d386b402SDarrick J. Wong { 70d386b402SDarrick J. Wong if (level == cur->bc_nlevels - 1) { 71d386b402SDarrick J. Wong struct xfs_ifork *ifp = xfs_btree_ifork_ptr(cur); 72d386b402SDarrick J. Wong 73d386b402SDarrick J. Wong return xfs_rtrmapbt_maxrecs(cur->bc_mp, ifp->if_broot_bytes, 74d386b402SDarrick J. Wong level == 0); 75d386b402SDarrick J. Wong } 76d386b402SDarrick J. Wong 77d386b402SDarrick J. Wong return cur->bc_mp->m_rtrmap_mxr[level != 0]; 78d386b402SDarrick J. Wong } 79d386b402SDarrick J. Wong 80d386b402SDarrick J. Wong /* 81d386b402SDarrick J. Wong * Convert the ondisk record's offset field into the ondisk key's offset field. 82d386b402SDarrick J. Wong * Fork and bmbt are significant parts of the rmap record key, but written 83d386b402SDarrick J. Wong * status is merely a record attribute. 84d386b402SDarrick J. Wong */ 85d386b402SDarrick J. Wong static inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec) 86d386b402SDarrick J. Wong { 87d386b402SDarrick J. Wong return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN); 88d386b402SDarrick J. Wong } 89d386b402SDarrick J. Wong 90d386b402SDarrick J. Wong STATIC void 91d386b402SDarrick J. Wong xfs_rtrmapbt_init_key_from_rec( 92d386b402SDarrick J. Wong union xfs_btree_key *key, 93d386b402SDarrick J. Wong const union xfs_btree_rec *rec) 94d386b402SDarrick J. Wong { 95d386b402SDarrick J. Wong key->rmap.rm_startblock = rec->rmap.rm_startblock; 96d386b402SDarrick J. Wong key->rmap.rm_owner = rec->rmap.rm_owner; 97d386b402SDarrick J. Wong key->rmap.rm_offset = ondisk_rec_offset_to_key(rec); 98d386b402SDarrick J. Wong } 99d386b402SDarrick J. Wong 100d386b402SDarrick J. Wong STATIC void 101d386b402SDarrick J. Wong xfs_rtrmapbt_init_high_key_from_rec( 102d386b402SDarrick J. Wong union xfs_btree_key *key, 103d386b402SDarrick J. Wong const union xfs_btree_rec *rec) 104d386b402SDarrick J. Wong { 105d386b402SDarrick J. Wong uint64_t off; 106d386b402SDarrick J. Wong int adj; 107d386b402SDarrick J. Wong 108d386b402SDarrick J. Wong adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1; 109d386b402SDarrick J. Wong 110d386b402SDarrick J. Wong key->rmap.rm_startblock = rec->rmap.rm_startblock; 111d386b402SDarrick J. Wong be32_add_cpu(&key->rmap.rm_startblock, adj); 112d386b402SDarrick J. Wong key->rmap.rm_owner = rec->rmap.rm_owner; 113d386b402SDarrick J. Wong key->rmap.rm_offset = ondisk_rec_offset_to_key(rec); 114d386b402SDarrick J. Wong if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) || 115d386b402SDarrick J. Wong XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset))) 116d386b402SDarrick J. Wong return; 117d386b402SDarrick J. Wong off = be64_to_cpu(key->rmap.rm_offset); 118d386b402SDarrick J. Wong off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK); 119d386b402SDarrick J. Wong key->rmap.rm_offset = cpu_to_be64(off); 120d386b402SDarrick J. Wong } 121d386b402SDarrick J. Wong 122d386b402SDarrick J. Wong STATIC void 123d386b402SDarrick J. Wong xfs_rtrmapbt_init_rec_from_cur( 124d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 125d386b402SDarrick J. Wong union xfs_btree_rec *rec) 126d386b402SDarrick J. Wong { 127d386b402SDarrick J. Wong rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock); 128d386b402SDarrick J. Wong rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount); 129d386b402SDarrick J. Wong rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner); 130d386b402SDarrick J. Wong rec->rmap.rm_offset = cpu_to_be64( 131d386b402SDarrick J. Wong xfs_rmap_irec_offset_pack(&cur->bc_rec.r)); 132d386b402SDarrick J. Wong } 133d386b402SDarrick J. Wong 134d386b402SDarrick J. Wong STATIC void 135d386b402SDarrick J. Wong xfs_rtrmapbt_init_ptr_from_cur( 136d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 137d386b402SDarrick J. Wong union xfs_btree_ptr *ptr) 138d386b402SDarrick J. Wong { 139d386b402SDarrick J. Wong ptr->l = 0; 140d386b402SDarrick J. Wong } 141d386b402SDarrick J. Wong 142d386b402SDarrick J. Wong /* 143d386b402SDarrick J. Wong * Mask the appropriate parts of the ondisk key field for a key comparison. 144d386b402SDarrick J. Wong * Fork and bmbt are significant parts of the rmap record key, but written 145d386b402SDarrick J. Wong * status is merely a record attribute. 146d386b402SDarrick J. Wong */ 147d386b402SDarrick J. Wong static inline uint64_t offset_keymask(uint64_t offset) 148d386b402SDarrick J. Wong { 149d386b402SDarrick J. Wong return offset & ~XFS_RMAP_OFF_UNWRITTEN; 150d386b402SDarrick J. Wong } 151d386b402SDarrick J. Wong 152d386b402SDarrick J. Wong STATIC int64_t 153d386b402SDarrick J. Wong xfs_rtrmapbt_key_diff( 154d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 155d386b402SDarrick J. Wong const union xfs_btree_key *key) 156d386b402SDarrick J. Wong { 157d386b402SDarrick J. Wong struct xfs_rmap_irec *rec = &cur->bc_rec.r; 158d386b402SDarrick J. Wong const struct xfs_rmap_key *kp = &key->rmap; 159d386b402SDarrick J. Wong __u64 x, y; 160d386b402SDarrick J. Wong int64_t d; 161d386b402SDarrick J. Wong 162d386b402SDarrick J. Wong d = (int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock; 163d386b402SDarrick J. Wong if (d) 164d386b402SDarrick J. Wong return d; 165d386b402SDarrick J. Wong 166d386b402SDarrick J. Wong x = be64_to_cpu(kp->rm_owner); 167d386b402SDarrick J. Wong y = rec->rm_owner; 168d386b402SDarrick J. Wong if (x > y) 169d386b402SDarrick J. Wong return 1; 170d386b402SDarrick J. Wong else if (y > x) 171d386b402SDarrick J. Wong return -1; 172d386b402SDarrick J. Wong 173d386b402SDarrick J. Wong x = offset_keymask(be64_to_cpu(kp->rm_offset)); 174d386b402SDarrick J. Wong y = offset_keymask(xfs_rmap_irec_offset_pack(rec)); 175d386b402SDarrick J. Wong if (x > y) 176d386b402SDarrick J. Wong return 1; 177d386b402SDarrick J. Wong else if (y > x) 178d386b402SDarrick J. Wong return -1; 179d386b402SDarrick J. Wong return 0; 180d386b402SDarrick J. Wong } 181d386b402SDarrick J. Wong 182d386b402SDarrick J. Wong STATIC int64_t 183d386b402SDarrick J. Wong xfs_rtrmapbt_diff_two_keys( 184d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 185d386b402SDarrick J. Wong const union xfs_btree_key *k1, 186d386b402SDarrick J. Wong const union xfs_btree_key *k2, 187d386b402SDarrick J. Wong const union xfs_btree_key *mask) 188d386b402SDarrick J. Wong { 189d386b402SDarrick J. Wong const struct xfs_rmap_key *kp1 = &k1->rmap; 190d386b402SDarrick J. Wong const struct xfs_rmap_key *kp2 = &k2->rmap; 191d386b402SDarrick J. Wong int64_t d; 192d386b402SDarrick J. Wong __u64 x, y; 193d386b402SDarrick J. Wong 194d386b402SDarrick J. Wong /* Doesn't make sense to mask off the physical space part */ 195d386b402SDarrick J. Wong ASSERT(!mask || mask->rmap.rm_startblock); 196d386b402SDarrick J. Wong 197d386b402SDarrick J. Wong d = (int64_t)be32_to_cpu(kp1->rm_startblock) - 198d386b402SDarrick J. Wong be32_to_cpu(kp2->rm_startblock); 199d386b402SDarrick J. Wong if (d) 200d386b402SDarrick J. Wong return d; 201d386b402SDarrick J. Wong 202d386b402SDarrick J. Wong if (!mask || mask->rmap.rm_owner) { 203d386b402SDarrick J. Wong x = be64_to_cpu(kp1->rm_owner); 204d386b402SDarrick J. Wong y = be64_to_cpu(kp2->rm_owner); 205d386b402SDarrick J. Wong if (x > y) 206d386b402SDarrick J. Wong return 1; 207d386b402SDarrick J. Wong else if (y > x) 208d386b402SDarrick J. Wong return -1; 209d386b402SDarrick J. Wong } 210d386b402SDarrick J. Wong 211d386b402SDarrick J. Wong if (!mask || mask->rmap.rm_offset) { 212d386b402SDarrick J. Wong /* Doesn't make sense to allow offset but not owner */ 213d386b402SDarrick J. Wong ASSERT(!mask || mask->rmap.rm_owner); 214d386b402SDarrick J. Wong 215d386b402SDarrick J. Wong x = offset_keymask(be64_to_cpu(kp1->rm_offset)); 216d386b402SDarrick J. Wong y = offset_keymask(be64_to_cpu(kp2->rm_offset)); 217d386b402SDarrick J. Wong if (x > y) 218d386b402SDarrick J. Wong return 1; 219d386b402SDarrick J. Wong else if (y > x) 220d386b402SDarrick J. Wong return -1; 221d386b402SDarrick J. Wong } 222d386b402SDarrick J. Wong 223d386b402SDarrick J. Wong return 0; 224d386b402SDarrick J. Wong } 225d386b402SDarrick J. Wong 226fc6856c6SDarrick J. Wong static xfs_failaddr_t 227fc6856c6SDarrick J. Wong xfs_rtrmapbt_verify( 228fc6856c6SDarrick J. Wong struct xfs_buf *bp) 229fc6856c6SDarrick J. Wong { 230fc6856c6SDarrick J. Wong struct xfs_mount *mp = bp->b_target->bt_mount; 231fc6856c6SDarrick J. Wong struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 232fc6856c6SDarrick J. Wong xfs_failaddr_t fa; 233fc6856c6SDarrick J. Wong int level; 234fc6856c6SDarrick J. Wong 235fc6856c6SDarrick J. Wong if (!xfs_verify_magic(bp, block->bb_magic)) 236fc6856c6SDarrick J. Wong return __this_address; 237fc6856c6SDarrick J. Wong 238fc6856c6SDarrick J. Wong if (!xfs_has_rmapbt(mp)) 239fc6856c6SDarrick J. Wong return __this_address; 240fc6856c6SDarrick J. Wong fa = xfs_btree_fsblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN); 241fc6856c6SDarrick J. Wong if (fa) 242fc6856c6SDarrick J. Wong return fa; 243fc6856c6SDarrick J. Wong level = be16_to_cpu(block->bb_level); 244fc6856c6SDarrick J. Wong if (level > mp->m_rtrmap_maxlevels) 245fc6856c6SDarrick J. Wong return __this_address; 246fc6856c6SDarrick J. Wong 247fc6856c6SDarrick J. Wong return xfs_btree_fsblock_verify(bp, mp->m_rtrmap_mxr[level != 0]); 248fc6856c6SDarrick J. Wong } 249fc6856c6SDarrick J. Wong 250fc6856c6SDarrick J. Wong static void 251fc6856c6SDarrick J. Wong xfs_rtrmapbt_read_verify( 252fc6856c6SDarrick J. Wong struct xfs_buf *bp) 253fc6856c6SDarrick J. Wong { 254fc6856c6SDarrick J. Wong xfs_failaddr_t fa; 255fc6856c6SDarrick J. Wong 256fc6856c6SDarrick J. Wong if (!xfs_btree_fsblock_verify_crc(bp)) 257fc6856c6SDarrick J. Wong xfs_verifier_error(bp, -EFSBADCRC, __this_address); 258fc6856c6SDarrick J. Wong else { 259fc6856c6SDarrick J. Wong fa = xfs_rtrmapbt_verify(bp); 260fc6856c6SDarrick J. Wong if (fa) 261fc6856c6SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 262fc6856c6SDarrick J. Wong } 263fc6856c6SDarrick J. Wong 264fc6856c6SDarrick J. Wong if (bp->b_error) 265fc6856c6SDarrick J. Wong trace_xfs_btree_corrupt(bp, _RET_IP_); 266fc6856c6SDarrick J. Wong } 267fc6856c6SDarrick J. Wong 268fc6856c6SDarrick J. Wong static void 269fc6856c6SDarrick J. Wong xfs_rtrmapbt_write_verify( 270fc6856c6SDarrick J. Wong struct xfs_buf *bp) 271fc6856c6SDarrick J. Wong { 272fc6856c6SDarrick J. Wong xfs_failaddr_t fa; 273fc6856c6SDarrick J. Wong 274fc6856c6SDarrick J. Wong fa = xfs_rtrmapbt_verify(bp); 275fc6856c6SDarrick J. Wong if (fa) { 276fc6856c6SDarrick J. Wong trace_xfs_btree_corrupt(bp, _RET_IP_); 277fc6856c6SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 278fc6856c6SDarrick J. Wong return; 279fc6856c6SDarrick J. Wong } 280fc6856c6SDarrick J. Wong xfs_btree_fsblock_calc_crc(bp); 281fc6856c6SDarrick J. Wong 282fc6856c6SDarrick J. Wong } 283fc6856c6SDarrick J. Wong 284fc6856c6SDarrick J. Wong const struct xfs_buf_ops xfs_rtrmapbt_buf_ops = { 285fc6856c6SDarrick J. Wong .name = "xfs_rtrmapbt", 286fc6856c6SDarrick J. Wong .magic = { 0, cpu_to_be32(XFS_RTRMAP_CRC_MAGIC) }, 287fc6856c6SDarrick J. Wong .verify_read = xfs_rtrmapbt_read_verify, 288fc6856c6SDarrick J. Wong .verify_write = xfs_rtrmapbt_write_verify, 289fc6856c6SDarrick J. Wong .verify_struct = xfs_rtrmapbt_verify, 290fc6856c6SDarrick J. Wong }; 291fc6856c6SDarrick J. Wong 292d386b402SDarrick J. Wong STATIC int 293d386b402SDarrick J. Wong xfs_rtrmapbt_keys_inorder( 294d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 295d386b402SDarrick J. Wong const union xfs_btree_key *k1, 296d386b402SDarrick J. Wong const union xfs_btree_key *k2) 297d386b402SDarrick J. Wong { 298d386b402SDarrick J. Wong uint32_t x; 299d386b402SDarrick J. Wong uint32_t y; 300d386b402SDarrick J. Wong uint64_t a; 301d386b402SDarrick J. Wong uint64_t b; 302d386b402SDarrick J. Wong 303d386b402SDarrick J. Wong x = be32_to_cpu(k1->rmap.rm_startblock); 304d386b402SDarrick J. Wong y = be32_to_cpu(k2->rmap.rm_startblock); 305d386b402SDarrick J. Wong if (x < y) 306d386b402SDarrick J. Wong return 1; 307d386b402SDarrick J. Wong else if (x > y) 308d386b402SDarrick J. Wong return 0; 309d386b402SDarrick J. Wong a = be64_to_cpu(k1->rmap.rm_owner); 310d386b402SDarrick J. Wong b = be64_to_cpu(k2->rmap.rm_owner); 311d386b402SDarrick J. Wong if (a < b) 312d386b402SDarrick J. Wong return 1; 313d386b402SDarrick J. Wong else if (a > b) 314d386b402SDarrick J. Wong return 0; 315d386b402SDarrick J. Wong a = offset_keymask(be64_to_cpu(k1->rmap.rm_offset)); 316d386b402SDarrick J. Wong b = offset_keymask(be64_to_cpu(k2->rmap.rm_offset)); 317d386b402SDarrick J. Wong if (a <= b) 318d386b402SDarrick J. Wong return 1; 319d386b402SDarrick J. Wong return 0; 320d386b402SDarrick J. Wong } 321d386b402SDarrick J. Wong 322d386b402SDarrick J. Wong STATIC int 323d386b402SDarrick J. Wong xfs_rtrmapbt_recs_inorder( 324d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 325d386b402SDarrick J. Wong const union xfs_btree_rec *r1, 326d386b402SDarrick J. Wong const union xfs_btree_rec *r2) 327d386b402SDarrick J. Wong { 328d386b402SDarrick J. Wong uint32_t x; 329d386b402SDarrick J. Wong uint32_t y; 330d386b402SDarrick J. Wong uint64_t a; 331d386b402SDarrick J. Wong uint64_t b; 332d386b402SDarrick J. Wong 333d386b402SDarrick J. Wong x = be32_to_cpu(r1->rmap.rm_startblock); 334d386b402SDarrick J. Wong y = be32_to_cpu(r2->rmap.rm_startblock); 335d386b402SDarrick J. Wong if (x < y) 336d386b402SDarrick J. Wong return 1; 337d386b402SDarrick J. Wong else if (x > y) 338d386b402SDarrick J. Wong return 0; 339d386b402SDarrick J. Wong a = be64_to_cpu(r1->rmap.rm_owner); 340d386b402SDarrick J. Wong b = be64_to_cpu(r2->rmap.rm_owner); 341d386b402SDarrick J. Wong if (a < b) 342d386b402SDarrick J. Wong return 1; 343d386b402SDarrick J. Wong else if (a > b) 344d386b402SDarrick J. Wong return 0; 345d386b402SDarrick J. Wong a = offset_keymask(be64_to_cpu(r1->rmap.rm_offset)); 346d386b402SDarrick J. Wong b = offset_keymask(be64_to_cpu(r2->rmap.rm_offset)); 347d386b402SDarrick J. Wong if (a <= b) 348d386b402SDarrick J. Wong return 1; 349d386b402SDarrick J. Wong return 0; 350d386b402SDarrick J. Wong } 351d386b402SDarrick J. Wong 352d386b402SDarrick J. Wong STATIC enum xbtree_key_contig 353d386b402SDarrick J. Wong xfs_rtrmapbt_keys_contiguous( 354d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 355d386b402SDarrick J. Wong const union xfs_btree_key *key1, 356d386b402SDarrick J. Wong const union xfs_btree_key *key2, 357d386b402SDarrick J. Wong const union xfs_btree_key *mask) 358d386b402SDarrick J. Wong { 359d386b402SDarrick J. Wong ASSERT(!mask || mask->rmap.rm_startblock); 360d386b402SDarrick J. Wong 361d386b402SDarrick J. Wong /* 362d386b402SDarrick J. Wong * We only support checking contiguity of the physical space component. 363d386b402SDarrick J. Wong * If any callers ever need more specificity than that, they'll have to 364d386b402SDarrick J. Wong * implement it here. 365d386b402SDarrick J. Wong */ 366d386b402SDarrick J. Wong ASSERT(!mask || (!mask->rmap.rm_owner && !mask->rmap.rm_offset)); 367d386b402SDarrick J. Wong 368d386b402SDarrick J. Wong return xbtree_key_contig(be32_to_cpu(key1->rmap.rm_startblock), 369d386b402SDarrick J. Wong be32_to_cpu(key2->rmap.rm_startblock)); 370d386b402SDarrick J. Wong } 371d386b402SDarrick J. Wong 372fc6856c6SDarrick J. Wong const struct xfs_btree_ops xfs_rtrmapbt_ops = { 373fc6856c6SDarrick J. Wong .name = "rtrmap", 374fc6856c6SDarrick J. Wong .type = XFS_BTREE_TYPE_INODE, 375fc6856c6SDarrick J. Wong .geom_flags = XFS_BTGEO_OVERLAPPING | 376fc6856c6SDarrick J. Wong XFS_BTGEO_IROOT_RECORDS, 377fc6856c6SDarrick J. Wong 378fc6856c6SDarrick J. Wong .rec_len = sizeof(struct xfs_rmap_rec), 379fc6856c6SDarrick J. Wong /* Overlapping btree; 2 keys per pointer. */ 380fc6856c6SDarrick J. Wong .key_len = 2 * sizeof(struct xfs_rmap_key), 381fc6856c6SDarrick J. Wong .ptr_len = XFS_BTREE_LONG_PTR_LEN, 382fc6856c6SDarrick J. Wong 383fc6856c6SDarrick J. Wong .lru_refs = XFS_RMAP_BTREE_REF, 384fc6856c6SDarrick J. Wong .statoff = XFS_STATS_CALC_INDEX(xs_rtrmap_2), 385fc6856c6SDarrick J. Wong 386fc6856c6SDarrick J. Wong .dup_cursor = xfs_rtrmapbt_dup_cursor, 387d386b402SDarrick J. Wong .alloc_block = xfs_btree_alloc_metafile_block, 388d386b402SDarrick J. Wong .free_block = xfs_btree_free_metafile_block, 389d386b402SDarrick J. Wong .get_minrecs = xfs_rtrmapbt_get_minrecs, 390d386b402SDarrick J. Wong .get_maxrecs = xfs_rtrmapbt_get_maxrecs, 391d386b402SDarrick J. Wong .init_key_from_rec = xfs_rtrmapbt_init_key_from_rec, 392d386b402SDarrick J. Wong .init_high_key_from_rec = xfs_rtrmapbt_init_high_key_from_rec, 393d386b402SDarrick J. Wong .init_rec_from_cur = xfs_rtrmapbt_init_rec_from_cur, 394d386b402SDarrick J. Wong .init_ptr_from_cur = xfs_rtrmapbt_init_ptr_from_cur, 395d386b402SDarrick J. Wong .key_diff = xfs_rtrmapbt_key_diff, 396fc6856c6SDarrick J. Wong .buf_ops = &xfs_rtrmapbt_buf_ops, 397d386b402SDarrick J. Wong .diff_two_keys = xfs_rtrmapbt_diff_two_keys, 398d386b402SDarrick J. Wong .keys_inorder = xfs_rtrmapbt_keys_inorder, 399d386b402SDarrick J. Wong .recs_inorder = xfs_rtrmapbt_recs_inorder, 400d386b402SDarrick J. Wong .keys_contiguous = xfs_rtrmapbt_keys_contiguous, 401fc6856c6SDarrick J. Wong }; 402fc6856c6SDarrick J. Wong 403fc6856c6SDarrick J. Wong /* Allocate a new rt rmap btree cursor. */ 404fc6856c6SDarrick J. Wong struct xfs_btree_cur * 405fc6856c6SDarrick J. Wong xfs_rtrmapbt_init_cursor( 406fc6856c6SDarrick J. Wong struct xfs_trans *tp, 407fc6856c6SDarrick J. Wong struct xfs_rtgroup *rtg) 408fc6856c6SDarrick J. Wong { 4096b08901aSDarrick J. Wong struct xfs_inode *ip = rtg_rmap(rtg); 410fc6856c6SDarrick J. Wong struct xfs_mount *mp = rtg_mount(rtg); 411fc6856c6SDarrick J. Wong struct xfs_btree_cur *cur; 412fc6856c6SDarrick J. Wong 413fc6856c6SDarrick J. Wong xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL); 414fc6856c6SDarrick J. Wong 415fc6856c6SDarrick J. Wong cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rtrmapbt_ops, 416fc6856c6SDarrick J. Wong mp->m_rtrmap_maxlevels, xfs_rtrmapbt_cur_cache); 417fc6856c6SDarrick J. Wong 418fc6856c6SDarrick J. Wong cur->bc_ino.ip = ip; 419fc6856c6SDarrick J. Wong cur->bc_group = xfs_group_hold(rtg_group(rtg)); 420fc6856c6SDarrick J. Wong cur->bc_ino.whichfork = XFS_DATA_FORK; 421fc6856c6SDarrick J. Wong cur->bc_nlevels = be16_to_cpu(ip->i_df.if_broot->bb_level) + 1; 422fc6856c6SDarrick J. Wong cur->bc_ino.forksize = xfs_inode_fork_size(ip, XFS_DATA_FORK); 423fc6856c6SDarrick J. Wong 424fc6856c6SDarrick J. Wong return cur; 425fc6856c6SDarrick J. Wong } 426fc6856c6SDarrick J. Wong 427fc6856c6SDarrick J. Wong /* 428fc6856c6SDarrick J. Wong * Install a new rt reverse mapping btree root. Caller is responsible for 429fc6856c6SDarrick J. Wong * invalidating and freeing the old btree blocks. 430fc6856c6SDarrick J. Wong */ 431fc6856c6SDarrick J. Wong void 432fc6856c6SDarrick J. Wong xfs_rtrmapbt_commit_staged_btree( 433fc6856c6SDarrick J. Wong struct xfs_btree_cur *cur, 434fc6856c6SDarrick J. Wong struct xfs_trans *tp) 435fc6856c6SDarrick J. Wong { 436fc6856c6SDarrick J. Wong struct xbtree_ifakeroot *ifake = cur->bc_ino.ifake; 437fc6856c6SDarrick J. Wong struct xfs_ifork *ifp; 438fc6856c6SDarrick J. Wong int flags = XFS_ILOG_CORE | XFS_ILOG_DBROOT; 439fc6856c6SDarrick J. Wong 440fc6856c6SDarrick J. Wong ASSERT(cur->bc_flags & XFS_BTREE_STAGING); 4416b08901aSDarrick J. Wong ASSERT(ifake->if_fork->if_format == XFS_DINODE_FMT_META_BTREE); 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*8491a55cSDarrick J. Wong 544*8491a55cSDarrick J. Wong /* Calculate the rtrmap btree size for some records. */ 545*8491a55cSDarrick J. Wong static unsigned long long 546*8491a55cSDarrick J. Wong xfs_rtrmapbt_calc_size( 547*8491a55cSDarrick J. Wong struct xfs_mount *mp, 548*8491a55cSDarrick J. Wong unsigned long long len) 549*8491a55cSDarrick J. Wong { 550*8491a55cSDarrick J. Wong return xfs_btree_calc_size(mp->m_rtrmap_mnr, len); 551*8491a55cSDarrick J. Wong } 552*8491a55cSDarrick J. Wong 553*8491a55cSDarrick J. Wong /* 554*8491a55cSDarrick J. Wong * Calculate the maximum rmap btree size. 555*8491a55cSDarrick J. Wong */ 556*8491a55cSDarrick J. Wong static unsigned long long 557*8491a55cSDarrick J. Wong xfs_rtrmapbt_max_size( 558*8491a55cSDarrick J. Wong struct xfs_mount *mp, 559*8491a55cSDarrick J. Wong xfs_rtblock_t rtblocks) 560*8491a55cSDarrick J. Wong { 561*8491a55cSDarrick J. Wong /* Bail out if we're uninitialized, which can happen in mkfs. */ 562*8491a55cSDarrick J. Wong if (mp->m_rtrmap_mxr[0] == 0) 563*8491a55cSDarrick J. Wong return 0; 564*8491a55cSDarrick J. Wong 565*8491a55cSDarrick J. Wong return xfs_rtrmapbt_calc_size(mp, rtblocks); 566*8491a55cSDarrick J. Wong } 567*8491a55cSDarrick J. Wong 568*8491a55cSDarrick J. Wong /* 569*8491a55cSDarrick J. Wong * Figure out how many blocks to reserve and how many are used by this btree. 570*8491a55cSDarrick J. Wong */ 571*8491a55cSDarrick J. Wong xfs_filblks_t 572*8491a55cSDarrick J. Wong xfs_rtrmapbt_calc_reserves( 573*8491a55cSDarrick J. Wong struct xfs_mount *mp) 574*8491a55cSDarrick J. Wong { 575*8491a55cSDarrick J. Wong uint32_t blocks = mp->m_groups[XG_TYPE_RTG].blocks; 576*8491a55cSDarrick J. Wong 577*8491a55cSDarrick J. Wong if (!xfs_has_rtrmapbt(mp)) 578*8491a55cSDarrick J. Wong return 0; 579*8491a55cSDarrick J. Wong 580*8491a55cSDarrick J. Wong /* Reserve 1% of the rtgroup or enough for 1 block per record. */ 581*8491a55cSDarrick J. Wong return max_t(xfs_filblks_t, blocks / 100, 582*8491a55cSDarrick J. Wong xfs_rtrmapbt_max_size(mp, blocks)); 583*8491a55cSDarrick J. Wong } 584