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 80f33659e8SDarrick J. Wong /* Calculate number of records in the ondisk realtime rmap btree inode root. */ 81f33659e8SDarrick J. Wong unsigned int 82f33659e8SDarrick J. Wong xfs_rtrmapbt_droot_maxrecs( 83f33659e8SDarrick J. Wong unsigned int blocklen, 84f33659e8SDarrick J. Wong bool leaf) 85f33659e8SDarrick J. Wong { 86f33659e8SDarrick J. Wong blocklen -= sizeof(struct xfs_rtrmap_root); 87f33659e8SDarrick J. Wong 88f33659e8SDarrick J. Wong if (leaf) 89f33659e8SDarrick J. Wong return blocklen / sizeof(struct xfs_rmap_rec); 90f33659e8SDarrick J. Wong return blocklen / (2 * sizeof(struct xfs_rmap_key) + 91f33659e8SDarrick J. Wong sizeof(xfs_rtrmap_ptr_t)); 92f33659e8SDarrick J. Wong } 93f33659e8SDarrick J. Wong 94f33659e8SDarrick J. Wong /* 95f33659e8SDarrick J. Wong * Get the maximum records we could store in the on-disk format. 96f33659e8SDarrick J. Wong * 97f33659e8SDarrick J. Wong * For non-root nodes this is equivalent to xfs_rtrmapbt_get_maxrecs, but 98f33659e8SDarrick J. Wong * for the root node this checks the available space in the dinode fork 99f33659e8SDarrick J. Wong * so that we can resize the in-memory buffer to match it. After a 100f33659e8SDarrick J. Wong * resize to the maximum size this function returns the same value 101f33659e8SDarrick J. Wong * as xfs_rtrmapbt_get_maxrecs for the root node, too. 102f33659e8SDarrick J. Wong */ 103f33659e8SDarrick J. Wong STATIC int 104f33659e8SDarrick J. Wong xfs_rtrmapbt_get_dmaxrecs( 105f33659e8SDarrick J. Wong struct xfs_btree_cur *cur, 106f33659e8SDarrick J. Wong int level) 107f33659e8SDarrick J. Wong { 108f33659e8SDarrick J. Wong if (level != cur->bc_nlevels - 1) 109f33659e8SDarrick J. Wong return cur->bc_mp->m_rtrmap_mxr[level != 0]; 110f33659e8SDarrick J. Wong return xfs_rtrmapbt_droot_maxrecs(cur->bc_ino.forksize, level == 0); 111f33659e8SDarrick J. Wong } 112f33659e8SDarrick J. Wong 113d386b402SDarrick J. Wong /* 114d386b402SDarrick J. Wong * Convert the ondisk record's offset field into the ondisk key's offset field. 115d386b402SDarrick J. Wong * Fork and bmbt are significant parts of the rmap record key, but written 116d386b402SDarrick J. Wong * status is merely a record attribute. 117d386b402SDarrick J. Wong */ 118d386b402SDarrick J. Wong static inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec) 119d386b402SDarrick J. Wong { 120d386b402SDarrick J. Wong return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN); 121d386b402SDarrick J. Wong } 122d386b402SDarrick J. Wong 123d386b402SDarrick J. Wong STATIC void 124d386b402SDarrick J. Wong xfs_rtrmapbt_init_key_from_rec( 125d386b402SDarrick J. Wong union xfs_btree_key *key, 126d386b402SDarrick J. Wong const union xfs_btree_rec *rec) 127d386b402SDarrick J. Wong { 128d386b402SDarrick J. Wong key->rmap.rm_startblock = rec->rmap.rm_startblock; 129d386b402SDarrick J. Wong key->rmap.rm_owner = rec->rmap.rm_owner; 130d386b402SDarrick J. Wong key->rmap.rm_offset = ondisk_rec_offset_to_key(rec); 131d386b402SDarrick J. Wong } 132d386b402SDarrick J. Wong 133d386b402SDarrick J. Wong STATIC void 134d386b402SDarrick J. Wong xfs_rtrmapbt_init_high_key_from_rec( 135d386b402SDarrick J. Wong union xfs_btree_key *key, 136d386b402SDarrick J. Wong const union xfs_btree_rec *rec) 137d386b402SDarrick J. Wong { 138d386b402SDarrick J. Wong uint64_t off; 139d386b402SDarrick J. Wong int adj; 140d386b402SDarrick J. Wong 141d386b402SDarrick J. Wong adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1; 142d386b402SDarrick J. Wong 143d386b402SDarrick J. Wong key->rmap.rm_startblock = rec->rmap.rm_startblock; 144d386b402SDarrick J. Wong be32_add_cpu(&key->rmap.rm_startblock, adj); 145d386b402SDarrick J. Wong key->rmap.rm_owner = rec->rmap.rm_owner; 146d386b402SDarrick J. Wong key->rmap.rm_offset = ondisk_rec_offset_to_key(rec); 147d386b402SDarrick J. Wong if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) || 148d386b402SDarrick J. Wong XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset))) 149d386b402SDarrick J. Wong return; 150d386b402SDarrick J. Wong off = be64_to_cpu(key->rmap.rm_offset); 151d386b402SDarrick J. Wong off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK); 152d386b402SDarrick J. Wong key->rmap.rm_offset = cpu_to_be64(off); 153d386b402SDarrick J. Wong } 154d386b402SDarrick J. Wong 155d386b402SDarrick J. Wong STATIC void 156d386b402SDarrick J. Wong xfs_rtrmapbt_init_rec_from_cur( 157d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 158d386b402SDarrick J. Wong union xfs_btree_rec *rec) 159d386b402SDarrick J. Wong { 160d386b402SDarrick J. Wong rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock); 161d386b402SDarrick J. Wong rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount); 162d386b402SDarrick J. Wong rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner); 163d386b402SDarrick J. Wong rec->rmap.rm_offset = cpu_to_be64( 164d386b402SDarrick J. Wong xfs_rmap_irec_offset_pack(&cur->bc_rec.r)); 165d386b402SDarrick J. Wong } 166d386b402SDarrick J. Wong 167d386b402SDarrick J. Wong STATIC void 168d386b402SDarrick J. Wong xfs_rtrmapbt_init_ptr_from_cur( 169d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 170d386b402SDarrick J. Wong union xfs_btree_ptr *ptr) 171d386b402SDarrick J. Wong { 172d386b402SDarrick J. Wong ptr->l = 0; 173d386b402SDarrick J. Wong } 174d386b402SDarrick J. Wong 175d386b402SDarrick J. Wong /* 176d386b402SDarrick J. Wong * Mask the appropriate parts of the ondisk key field for a key comparison. 177d386b402SDarrick J. Wong * Fork and bmbt are significant parts of the rmap record key, but written 178d386b402SDarrick J. Wong * status is merely a record attribute. 179d386b402SDarrick J. Wong */ 180d386b402SDarrick J. Wong static inline uint64_t offset_keymask(uint64_t offset) 181d386b402SDarrick J. Wong { 182d386b402SDarrick J. Wong return offset & ~XFS_RMAP_OFF_UNWRITTEN; 183d386b402SDarrick J. Wong } 184d386b402SDarrick J. Wong 185d386b402SDarrick J. Wong STATIC int64_t 186d386b402SDarrick J. Wong xfs_rtrmapbt_key_diff( 187d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 188d386b402SDarrick J. Wong const union xfs_btree_key *key) 189d386b402SDarrick J. Wong { 190d386b402SDarrick J. Wong struct xfs_rmap_irec *rec = &cur->bc_rec.r; 191d386b402SDarrick J. Wong const struct xfs_rmap_key *kp = &key->rmap; 192d386b402SDarrick J. Wong __u64 x, y; 193d386b402SDarrick J. Wong int64_t d; 194d386b402SDarrick J. Wong 195d386b402SDarrick J. Wong d = (int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock; 196d386b402SDarrick J. Wong if (d) 197d386b402SDarrick J. Wong return d; 198d386b402SDarrick J. Wong 199d386b402SDarrick J. Wong x = be64_to_cpu(kp->rm_owner); 200d386b402SDarrick J. Wong y = rec->rm_owner; 201d386b402SDarrick J. Wong if (x > y) 202d386b402SDarrick J. Wong return 1; 203d386b402SDarrick J. Wong else if (y > x) 204d386b402SDarrick J. Wong return -1; 205d386b402SDarrick J. Wong 206d386b402SDarrick J. Wong x = offset_keymask(be64_to_cpu(kp->rm_offset)); 207d386b402SDarrick J. Wong y = offset_keymask(xfs_rmap_irec_offset_pack(rec)); 208d386b402SDarrick J. Wong if (x > y) 209d386b402SDarrick J. Wong return 1; 210d386b402SDarrick J. Wong else if (y > x) 211d386b402SDarrick J. Wong return -1; 212d386b402SDarrick J. Wong return 0; 213d386b402SDarrick J. Wong } 214d386b402SDarrick J. Wong 215d386b402SDarrick J. Wong STATIC int64_t 216d386b402SDarrick J. Wong xfs_rtrmapbt_diff_two_keys( 217d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 218d386b402SDarrick J. Wong const union xfs_btree_key *k1, 219d386b402SDarrick J. Wong const union xfs_btree_key *k2, 220d386b402SDarrick J. Wong const union xfs_btree_key *mask) 221d386b402SDarrick J. Wong { 222d386b402SDarrick J. Wong const struct xfs_rmap_key *kp1 = &k1->rmap; 223d386b402SDarrick J. Wong const struct xfs_rmap_key *kp2 = &k2->rmap; 224d386b402SDarrick J. Wong int64_t d; 225d386b402SDarrick J. Wong __u64 x, y; 226d386b402SDarrick J. Wong 227d386b402SDarrick J. Wong /* Doesn't make sense to mask off the physical space part */ 228d386b402SDarrick J. Wong ASSERT(!mask || mask->rmap.rm_startblock); 229d386b402SDarrick J. Wong 230d386b402SDarrick J. Wong d = (int64_t)be32_to_cpu(kp1->rm_startblock) - 231d386b402SDarrick J. Wong be32_to_cpu(kp2->rm_startblock); 232d386b402SDarrick J. Wong if (d) 233d386b402SDarrick J. Wong return d; 234d386b402SDarrick J. Wong 235d386b402SDarrick J. Wong if (!mask || mask->rmap.rm_owner) { 236d386b402SDarrick J. Wong x = be64_to_cpu(kp1->rm_owner); 237d386b402SDarrick J. Wong y = be64_to_cpu(kp2->rm_owner); 238d386b402SDarrick J. Wong if (x > y) 239d386b402SDarrick J. Wong return 1; 240d386b402SDarrick J. Wong else if (y > x) 241d386b402SDarrick J. Wong return -1; 242d386b402SDarrick J. Wong } 243d386b402SDarrick J. Wong 244d386b402SDarrick J. Wong if (!mask || mask->rmap.rm_offset) { 245d386b402SDarrick J. Wong /* Doesn't make sense to allow offset but not owner */ 246d386b402SDarrick J. Wong ASSERT(!mask || mask->rmap.rm_owner); 247d386b402SDarrick J. Wong 248d386b402SDarrick J. Wong x = offset_keymask(be64_to_cpu(kp1->rm_offset)); 249d386b402SDarrick J. Wong y = offset_keymask(be64_to_cpu(kp2->rm_offset)); 250d386b402SDarrick J. Wong if (x > y) 251d386b402SDarrick J. Wong return 1; 252d386b402SDarrick J. Wong else if (y > x) 253d386b402SDarrick J. Wong return -1; 254d386b402SDarrick J. Wong } 255d386b402SDarrick J. Wong 256d386b402SDarrick J. Wong return 0; 257d386b402SDarrick J. Wong } 258d386b402SDarrick J. Wong 259fc6856c6SDarrick J. Wong static xfs_failaddr_t 260fc6856c6SDarrick J. Wong xfs_rtrmapbt_verify( 261fc6856c6SDarrick J. Wong struct xfs_buf *bp) 262fc6856c6SDarrick J. Wong { 263fc6856c6SDarrick J. Wong struct xfs_mount *mp = bp->b_target->bt_mount; 264fc6856c6SDarrick J. Wong struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 265fc6856c6SDarrick J. Wong xfs_failaddr_t fa; 266fc6856c6SDarrick J. Wong int level; 267fc6856c6SDarrick J. Wong 268fc6856c6SDarrick J. Wong if (!xfs_verify_magic(bp, block->bb_magic)) 269fc6856c6SDarrick J. Wong return __this_address; 270fc6856c6SDarrick J. Wong 271fc6856c6SDarrick J. Wong if (!xfs_has_rmapbt(mp)) 272fc6856c6SDarrick J. Wong return __this_address; 273fc6856c6SDarrick J. Wong fa = xfs_btree_fsblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN); 274fc6856c6SDarrick J. Wong if (fa) 275fc6856c6SDarrick J. Wong return fa; 276fc6856c6SDarrick J. Wong level = be16_to_cpu(block->bb_level); 277fc6856c6SDarrick J. Wong if (level > mp->m_rtrmap_maxlevels) 278fc6856c6SDarrick J. Wong return __this_address; 279fc6856c6SDarrick J. Wong 280fc6856c6SDarrick J. Wong return xfs_btree_fsblock_verify(bp, mp->m_rtrmap_mxr[level != 0]); 281fc6856c6SDarrick J. Wong } 282fc6856c6SDarrick J. Wong 283fc6856c6SDarrick J. Wong static void 284fc6856c6SDarrick J. Wong xfs_rtrmapbt_read_verify( 285fc6856c6SDarrick J. Wong struct xfs_buf *bp) 286fc6856c6SDarrick J. Wong { 287fc6856c6SDarrick J. Wong xfs_failaddr_t fa; 288fc6856c6SDarrick J. Wong 289fc6856c6SDarrick J. Wong if (!xfs_btree_fsblock_verify_crc(bp)) 290fc6856c6SDarrick J. Wong xfs_verifier_error(bp, -EFSBADCRC, __this_address); 291fc6856c6SDarrick J. Wong else { 292fc6856c6SDarrick J. Wong fa = xfs_rtrmapbt_verify(bp); 293fc6856c6SDarrick J. Wong if (fa) 294fc6856c6SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 295fc6856c6SDarrick J. Wong } 296fc6856c6SDarrick J. Wong 297fc6856c6SDarrick J. Wong if (bp->b_error) 298fc6856c6SDarrick J. Wong trace_xfs_btree_corrupt(bp, _RET_IP_); 299fc6856c6SDarrick J. Wong } 300fc6856c6SDarrick J. Wong 301fc6856c6SDarrick J. Wong static void 302fc6856c6SDarrick J. Wong xfs_rtrmapbt_write_verify( 303fc6856c6SDarrick J. Wong struct xfs_buf *bp) 304fc6856c6SDarrick J. Wong { 305fc6856c6SDarrick J. Wong xfs_failaddr_t fa; 306fc6856c6SDarrick J. Wong 307fc6856c6SDarrick J. Wong fa = xfs_rtrmapbt_verify(bp); 308fc6856c6SDarrick J. Wong if (fa) { 309fc6856c6SDarrick J. Wong trace_xfs_btree_corrupt(bp, _RET_IP_); 310fc6856c6SDarrick J. Wong xfs_verifier_error(bp, -EFSCORRUPTED, fa); 311fc6856c6SDarrick J. Wong return; 312fc6856c6SDarrick J. Wong } 313fc6856c6SDarrick J. Wong xfs_btree_fsblock_calc_crc(bp); 314fc6856c6SDarrick J. Wong 315fc6856c6SDarrick J. Wong } 316fc6856c6SDarrick J. Wong 317fc6856c6SDarrick J. Wong const struct xfs_buf_ops xfs_rtrmapbt_buf_ops = { 318fc6856c6SDarrick J. Wong .name = "xfs_rtrmapbt", 319fc6856c6SDarrick J. Wong .magic = { 0, cpu_to_be32(XFS_RTRMAP_CRC_MAGIC) }, 320fc6856c6SDarrick J. Wong .verify_read = xfs_rtrmapbt_read_verify, 321fc6856c6SDarrick J. Wong .verify_write = xfs_rtrmapbt_write_verify, 322fc6856c6SDarrick J. Wong .verify_struct = xfs_rtrmapbt_verify, 323fc6856c6SDarrick J. Wong }; 324fc6856c6SDarrick J. Wong 325d386b402SDarrick J. Wong STATIC int 326d386b402SDarrick J. Wong xfs_rtrmapbt_keys_inorder( 327d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 328d386b402SDarrick J. Wong const union xfs_btree_key *k1, 329d386b402SDarrick J. Wong const union xfs_btree_key *k2) 330d386b402SDarrick J. Wong { 331d386b402SDarrick J. Wong uint32_t x; 332d386b402SDarrick J. Wong uint32_t y; 333d386b402SDarrick J. Wong uint64_t a; 334d386b402SDarrick J. Wong uint64_t b; 335d386b402SDarrick J. Wong 336d386b402SDarrick J. Wong x = be32_to_cpu(k1->rmap.rm_startblock); 337d386b402SDarrick J. Wong y = be32_to_cpu(k2->rmap.rm_startblock); 338d386b402SDarrick J. Wong if (x < y) 339d386b402SDarrick J. Wong return 1; 340d386b402SDarrick J. Wong else if (x > y) 341d386b402SDarrick J. Wong return 0; 342d386b402SDarrick J. Wong a = be64_to_cpu(k1->rmap.rm_owner); 343d386b402SDarrick J. Wong b = be64_to_cpu(k2->rmap.rm_owner); 344d386b402SDarrick J. Wong if (a < b) 345d386b402SDarrick J. Wong return 1; 346d386b402SDarrick J. Wong else if (a > b) 347d386b402SDarrick J. Wong return 0; 348d386b402SDarrick J. Wong a = offset_keymask(be64_to_cpu(k1->rmap.rm_offset)); 349d386b402SDarrick J. Wong b = offset_keymask(be64_to_cpu(k2->rmap.rm_offset)); 350d386b402SDarrick J. Wong if (a <= b) 351d386b402SDarrick J. Wong return 1; 352d386b402SDarrick J. Wong return 0; 353d386b402SDarrick J. Wong } 354d386b402SDarrick J. Wong 355d386b402SDarrick J. Wong STATIC int 356d386b402SDarrick J. Wong xfs_rtrmapbt_recs_inorder( 357d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 358d386b402SDarrick J. Wong const union xfs_btree_rec *r1, 359d386b402SDarrick J. Wong const union xfs_btree_rec *r2) 360d386b402SDarrick J. Wong { 361d386b402SDarrick J. Wong uint32_t x; 362d386b402SDarrick J. Wong uint32_t y; 363d386b402SDarrick J. Wong uint64_t a; 364d386b402SDarrick J. Wong uint64_t b; 365d386b402SDarrick J. Wong 366d386b402SDarrick J. Wong x = be32_to_cpu(r1->rmap.rm_startblock); 367d386b402SDarrick J. Wong y = be32_to_cpu(r2->rmap.rm_startblock); 368d386b402SDarrick J. Wong if (x < y) 369d386b402SDarrick J. Wong return 1; 370d386b402SDarrick J. Wong else if (x > y) 371d386b402SDarrick J. Wong return 0; 372d386b402SDarrick J. Wong a = be64_to_cpu(r1->rmap.rm_owner); 373d386b402SDarrick J. Wong b = be64_to_cpu(r2->rmap.rm_owner); 374d386b402SDarrick J. Wong if (a < b) 375d386b402SDarrick J. Wong return 1; 376d386b402SDarrick J. Wong else if (a > b) 377d386b402SDarrick J. Wong return 0; 378d386b402SDarrick J. Wong a = offset_keymask(be64_to_cpu(r1->rmap.rm_offset)); 379d386b402SDarrick J. Wong b = offset_keymask(be64_to_cpu(r2->rmap.rm_offset)); 380d386b402SDarrick J. Wong if (a <= b) 381d386b402SDarrick J. Wong return 1; 382d386b402SDarrick J. Wong return 0; 383d386b402SDarrick J. Wong } 384d386b402SDarrick J. Wong 385d386b402SDarrick J. Wong STATIC enum xbtree_key_contig 386d386b402SDarrick J. Wong xfs_rtrmapbt_keys_contiguous( 387d386b402SDarrick J. Wong struct xfs_btree_cur *cur, 388d386b402SDarrick J. Wong const union xfs_btree_key *key1, 389d386b402SDarrick J. Wong const union xfs_btree_key *key2, 390d386b402SDarrick J. Wong const union xfs_btree_key *mask) 391d386b402SDarrick J. Wong { 392d386b402SDarrick J. Wong ASSERT(!mask || mask->rmap.rm_startblock); 393d386b402SDarrick J. Wong 394d386b402SDarrick J. Wong /* 395d386b402SDarrick J. Wong * We only support checking contiguity of the physical space component. 396d386b402SDarrick J. Wong * If any callers ever need more specificity than that, they'll have to 397d386b402SDarrick J. Wong * implement it here. 398d386b402SDarrick J. Wong */ 399d386b402SDarrick J. Wong ASSERT(!mask || (!mask->rmap.rm_owner && !mask->rmap.rm_offset)); 400d386b402SDarrick J. Wong 401d386b402SDarrick J. Wong return xbtree_key_contig(be32_to_cpu(key1->rmap.rm_startblock), 402d386b402SDarrick J. Wong be32_to_cpu(key2->rmap.rm_startblock)); 403d386b402SDarrick J. Wong } 404d386b402SDarrick J. Wong 405f33659e8SDarrick J. Wong static inline void 406f33659e8SDarrick J. Wong xfs_rtrmapbt_move_ptrs( 407f33659e8SDarrick J. Wong struct xfs_mount *mp, 408f33659e8SDarrick J. Wong struct xfs_btree_block *broot, 409f33659e8SDarrick J. Wong short old_size, 410f33659e8SDarrick J. Wong size_t new_size, 411f33659e8SDarrick J. Wong unsigned int numrecs) 412f33659e8SDarrick J. Wong { 413f33659e8SDarrick J. Wong void *dptr; 414f33659e8SDarrick J. Wong void *sptr; 415f33659e8SDarrick J. Wong 416f33659e8SDarrick J. Wong sptr = xfs_rtrmap_broot_ptr_addr(mp, broot, 1, old_size); 417f33659e8SDarrick J. Wong dptr = xfs_rtrmap_broot_ptr_addr(mp, broot, 1, new_size); 418f33659e8SDarrick J. Wong memmove(dptr, sptr, numrecs * sizeof(xfs_rtrmap_ptr_t)); 419f33659e8SDarrick J. Wong } 420f33659e8SDarrick J. Wong 421f33659e8SDarrick J. Wong static struct xfs_btree_block * 422f33659e8SDarrick J. Wong xfs_rtrmapbt_broot_realloc( 423f33659e8SDarrick J. Wong struct xfs_btree_cur *cur, 424f33659e8SDarrick J. Wong unsigned int new_numrecs) 425f33659e8SDarrick J. Wong { 426f33659e8SDarrick J. Wong struct xfs_mount *mp = cur->bc_mp; 427f33659e8SDarrick J. Wong struct xfs_ifork *ifp = xfs_btree_ifork_ptr(cur); 428f33659e8SDarrick J. Wong struct xfs_btree_block *broot; 429f33659e8SDarrick J. Wong unsigned int new_size; 430f33659e8SDarrick J. Wong unsigned int old_size = ifp->if_broot_bytes; 431f33659e8SDarrick J. Wong const unsigned int level = cur->bc_nlevels - 1; 432f33659e8SDarrick J. Wong 433f33659e8SDarrick J. Wong new_size = xfs_rtrmap_broot_space_calc(mp, level, new_numrecs); 434f33659e8SDarrick J. Wong 435f33659e8SDarrick J. Wong /* Handle the nop case quietly. */ 436f33659e8SDarrick J. Wong if (new_size == old_size) 437f33659e8SDarrick J. Wong return ifp->if_broot; 438f33659e8SDarrick J. Wong 439f33659e8SDarrick J. Wong if (new_size > old_size) { 440f33659e8SDarrick J. Wong unsigned int old_numrecs; 441f33659e8SDarrick J. Wong 442f33659e8SDarrick J. Wong /* 443f33659e8SDarrick J. Wong * If there wasn't any memory allocated before, just allocate 444f33659e8SDarrick J. Wong * it now and get out. 445f33659e8SDarrick J. Wong */ 446f33659e8SDarrick J. Wong if (old_size == 0) 447f33659e8SDarrick J. Wong return xfs_broot_realloc(ifp, new_size); 448f33659e8SDarrick J. Wong 449f33659e8SDarrick J. Wong /* 450f33659e8SDarrick J. Wong * If there is already an existing if_broot, then we need to 451f33659e8SDarrick J. Wong * realloc it and possibly move the node block pointers because 452f33659e8SDarrick J. Wong * those are not butted up against the btree block header. 453f33659e8SDarrick J. Wong */ 454f33659e8SDarrick J. Wong old_numrecs = xfs_rtrmapbt_maxrecs(mp, old_size, level == 0); 455f33659e8SDarrick J. Wong broot = xfs_broot_realloc(ifp, new_size); 456f33659e8SDarrick J. Wong if (level > 0) 457f33659e8SDarrick J. Wong xfs_rtrmapbt_move_ptrs(mp, broot, old_size, new_size, 458f33659e8SDarrick J. Wong old_numrecs); 459f33659e8SDarrick J. Wong goto out_broot; 460f33659e8SDarrick J. Wong } 461f33659e8SDarrick J. Wong 462f33659e8SDarrick J. Wong /* 463f33659e8SDarrick J. Wong * We're reducing numrecs. If we're going all the way to zero, just 464f33659e8SDarrick J. Wong * free the block. 465f33659e8SDarrick J. Wong */ 466f33659e8SDarrick J. Wong ASSERT(ifp->if_broot != NULL && old_size > 0); 467f33659e8SDarrick J. Wong if (new_size == 0) 468f33659e8SDarrick J. Wong return xfs_broot_realloc(ifp, 0); 469f33659e8SDarrick J. Wong 470f33659e8SDarrick J. Wong /* 471f33659e8SDarrick J. Wong * Shrink the btree root by possibly moving the rtrmapbt pointers, 472f33659e8SDarrick J. Wong * since they are not butted up against the btree block header. Then 473f33659e8SDarrick J. Wong * reallocate broot. 474f33659e8SDarrick J. Wong */ 475f33659e8SDarrick J. Wong if (level > 0) 476f33659e8SDarrick J. Wong xfs_rtrmapbt_move_ptrs(mp, ifp->if_broot, old_size, new_size, 477f33659e8SDarrick J. Wong new_numrecs); 478f33659e8SDarrick J. Wong broot = xfs_broot_realloc(ifp, new_size); 479f33659e8SDarrick J. Wong 480f33659e8SDarrick J. Wong out_broot: 481f33659e8SDarrick J. Wong ASSERT(xfs_rtrmap_droot_space(broot) <= 482f33659e8SDarrick J. Wong xfs_inode_fork_size(cur->bc_ino.ip, cur->bc_ino.whichfork)); 483f33659e8SDarrick J. Wong return broot; 484f33659e8SDarrick J. Wong } 485f33659e8SDarrick J. Wong 486fc6856c6SDarrick J. Wong const struct xfs_btree_ops xfs_rtrmapbt_ops = { 487fc6856c6SDarrick J. Wong .name = "rtrmap", 488fc6856c6SDarrick J. Wong .type = XFS_BTREE_TYPE_INODE, 489fc6856c6SDarrick J. Wong .geom_flags = XFS_BTGEO_OVERLAPPING | 490fc6856c6SDarrick J. Wong XFS_BTGEO_IROOT_RECORDS, 491fc6856c6SDarrick J. Wong 492fc6856c6SDarrick J. Wong .rec_len = sizeof(struct xfs_rmap_rec), 493fc6856c6SDarrick J. Wong /* Overlapping btree; 2 keys per pointer. */ 494fc6856c6SDarrick J. Wong .key_len = 2 * sizeof(struct xfs_rmap_key), 495fc6856c6SDarrick J. Wong .ptr_len = XFS_BTREE_LONG_PTR_LEN, 496fc6856c6SDarrick J. Wong 497fc6856c6SDarrick J. Wong .lru_refs = XFS_RMAP_BTREE_REF, 498fc6856c6SDarrick J. Wong .statoff = XFS_STATS_CALC_INDEX(xs_rtrmap_2), 499fc6856c6SDarrick J. Wong 500fc6856c6SDarrick J. Wong .dup_cursor = xfs_rtrmapbt_dup_cursor, 501d386b402SDarrick J. Wong .alloc_block = xfs_btree_alloc_metafile_block, 502d386b402SDarrick J. Wong .free_block = xfs_btree_free_metafile_block, 503d386b402SDarrick J. Wong .get_minrecs = xfs_rtrmapbt_get_minrecs, 504d386b402SDarrick J. Wong .get_maxrecs = xfs_rtrmapbt_get_maxrecs, 505f33659e8SDarrick J. Wong .get_dmaxrecs = xfs_rtrmapbt_get_dmaxrecs, 506d386b402SDarrick J. Wong .init_key_from_rec = xfs_rtrmapbt_init_key_from_rec, 507d386b402SDarrick J. Wong .init_high_key_from_rec = xfs_rtrmapbt_init_high_key_from_rec, 508d386b402SDarrick J. Wong .init_rec_from_cur = xfs_rtrmapbt_init_rec_from_cur, 509d386b402SDarrick J. Wong .init_ptr_from_cur = xfs_rtrmapbt_init_ptr_from_cur, 510d386b402SDarrick J. Wong .key_diff = xfs_rtrmapbt_key_diff, 511fc6856c6SDarrick J. Wong .buf_ops = &xfs_rtrmapbt_buf_ops, 512d386b402SDarrick J. Wong .diff_two_keys = xfs_rtrmapbt_diff_two_keys, 513d386b402SDarrick J. Wong .keys_inorder = xfs_rtrmapbt_keys_inorder, 514d386b402SDarrick J. Wong .recs_inorder = xfs_rtrmapbt_recs_inorder, 515d386b402SDarrick J. Wong .keys_contiguous = xfs_rtrmapbt_keys_contiguous, 516f33659e8SDarrick J. Wong .broot_realloc = xfs_rtrmapbt_broot_realloc, 517fc6856c6SDarrick J. Wong }; 518fc6856c6SDarrick J. Wong 519fc6856c6SDarrick J. Wong /* Allocate a new rt rmap btree cursor. */ 520fc6856c6SDarrick J. Wong struct xfs_btree_cur * 521fc6856c6SDarrick J. Wong xfs_rtrmapbt_init_cursor( 522fc6856c6SDarrick J. Wong struct xfs_trans *tp, 523fc6856c6SDarrick J. Wong struct xfs_rtgroup *rtg) 524fc6856c6SDarrick J. Wong { 5256b08901aSDarrick J. Wong struct xfs_inode *ip = rtg_rmap(rtg); 526fc6856c6SDarrick J. Wong struct xfs_mount *mp = rtg_mount(rtg); 527fc6856c6SDarrick J. Wong struct xfs_btree_cur *cur; 528fc6856c6SDarrick J. Wong 529fc6856c6SDarrick J. Wong xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL); 530fc6856c6SDarrick J. Wong 531fc6856c6SDarrick J. Wong cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rtrmapbt_ops, 532fc6856c6SDarrick J. Wong mp->m_rtrmap_maxlevels, xfs_rtrmapbt_cur_cache); 533fc6856c6SDarrick J. Wong 534fc6856c6SDarrick J. Wong cur->bc_ino.ip = ip; 535fc6856c6SDarrick J. Wong cur->bc_group = xfs_group_hold(rtg_group(rtg)); 536fc6856c6SDarrick J. Wong cur->bc_ino.whichfork = XFS_DATA_FORK; 537fc6856c6SDarrick J. Wong cur->bc_nlevels = be16_to_cpu(ip->i_df.if_broot->bb_level) + 1; 538fc6856c6SDarrick J. Wong cur->bc_ino.forksize = xfs_inode_fork_size(ip, XFS_DATA_FORK); 539fc6856c6SDarrick J. Wong 540fc6856c6SDarrick J. Wong return cur; 541fc6856c6SDarrick J. Wong } 542fc6856c6SDarrick J. Wong 543fc6856c6SDarrick J. Wong /* 544fc6856c6SDarrick J. Wong * Install a new rt reverse mapping btree root. Caller is responsible for 545fc6856c6SDarrick J. Wong * invalidating and freeing the old btree blocks. 546fc6856c6SDarrick J. Wong */ 547fc6856c6SDarrick J. Wong void 548fc6856c6SDarrick J. Wong xfs_rtrmapbt_commit_staged_btree( 549fc6856c6SDarrick J. Wong struct xfs_btree_cur *cur, 550fc6856c6SDarrick J. Wong struct xfs_trans *tp) 551fc6856c6SDarrick J. Wong { 552fc6856c6SDarrick J. Wong struct xbtree_ifakeroot *ifake = cur->bc_ino.ifake; 553fc6856c6SDarrick J. Wong struct xfs_ifork *ifp; 554fc6856c6SDarrick J. Wong int flags = XFS_ILOG_CORE | XFS_ILOG_DBROOT; 555fc6856c6SDarrick J. Wong 556fc6856c6SDarrick J. Wong ASSERT(cur->bc_flags & XFS_BTREE_STAGING); 5576b08901aSDarrick J. Wong ASSERT(ifake->if_fork->if_format == XFS_DINODE_FMT_META_BTREE); 558fc6856c6SDarrick J. Wong 559fc6856c6SDarrick J. Wong /* 560fc6856c6SDarrick J. Wong * Free any resources hanging off the real fork, then shallow-copy the 561fc6856c6SDarrick J. Wong * staging fork's contents into the real fork to transfer everything 562fc6856c6SDarrick J. Wong * we just built. 563fc6856c6SDarrick J. Wong */ 564fc6856c6SDarrick J. Wong ifp = xfs_ifork_ptr(cur->bc_ino.ip, XFS_DATA_FORK); 565fc6856c6SDarrick J. Wong xfs_idestroy_fork(ifp); 566fc6856c6SDarrick J. Wong memcpy(ifp, ifake->if_fork, sizeof(struct xfs_ifork)); 567fc6856c6SDarrick J. Wong 568fc6856c6SDarrick J. Wong cur->bc_ino.ip->i_projid = cur->bc_group->xg_gno; 569fc6856c6SDarrick J. Wong xfs_trans_log_inode(tp, cur->bc_ino.ip, flags); 570fc6856c6SDarrick J. Wong xfs_btree_commit_ifakeroot(cur, tp, XFS_DATA_FORK); 571fc6856c6SDarrick J. Wong } 572fc6856c6SDarrick J. Wong 573fc6856c6SDarrick J. Wong /* Calculate number of records in a rt reverse mapping btree block. */ 574fc6856c6SDarrick J. Wong static inline unsigned int 575fc6856c6SDarrick J. Wong xfs_rtrmapbt_block_maxrecs( 576fc6856c6SDarrick J. Wong unsigned int blocklen, 577fc6856c6SDarrick J. Wong bool leaf) 578fc6856c6SDarrick J. Wong { 579fc6856c6SDarrick J. Wong if (leaf) 580fc6856c6SDarrick J. Wong return blocklen / sizeof(struct xfs_rmap_rec); 581fc6856c6SDarrick J. Wong return blocklen / 582fc6856c6SDarrick J. Wong (2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rtrmap_ptr_t)); 583fc6856c6SDarrick J. Wong } 584fc6856c6SDarrick J. Wong 585fc6856c6SDarrick J. Wong /* 586fc6856c6SDarrick J. Wong * Calculate number of records in an rt reverse mapping btree block. 587fc6856c6SDarrick J. Wong */ 588fc6856c6SDarrick J. Wong unsigned int 589fc6856c6SDarrick J. Wong xfs_rtrmapbt_maxrecs( 590fc6856c6SDarrick J. Wong struct xfs_mount *mp, 591fc6856c6SDarrick J. Wong unsigned int blocklen, 592fc6856c6SDarrick J. Wong bool leaf) 593fc6856c6SDarrick J. Wong { 594fc6856c6SDarrick J. Wong blocklen -= XFS_RTRMAP_BLOCK_LEN; 595fc6856c6SDarrick J. Wong return xfs_rtrmapbt_block_maxrecs(blocklen, leaf); 596fc6856c6SDarrick J. Wong } 597fc6856c6SDarrick J. Wong 598fc6856c6SDarrick J. Wong /* Compute the max possible height for realtime reverse mapping btrees. */ 599fc6856c6SDarrick J. Wong unsigned int 600fc6856c6SDarrick J. Wong xfs_rtrmapbt_maxlevels_ondisk(void) 601fc6856c6SDarrick J. Wong { 602fc6856c6SDarrick J. Wong unsigned int minrecs[2]; 603fc6856c6SDarrick J. Wong unsigned int blocklen; 604fc6856c6SDarrick J. Wong 605fc6856c6SDarrick J. Wong blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN; 606fc6856c6SDarrick J. Wong 607fc6856c6SDarrick J. Wong minrecs[0] = xfs_rtrmapbt_block_maxrecs(blocklen, true) / 2; 608fc6856c6SDarrick J. Wong minrecs[1] = xfs_rtrmapbt_block_maxrecs(blocklen, false) / 2; 609fc6856c6SDarrick J. Wong 610fc6856c6SDarrick J. Wong /* We need at most one record for every block in an rt group. */ 611fc6856c6SDarrick J. Wong return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_RGBLOCKS); 612fc6856c6SDarrick J. Wong } 613fc6856c6SDarrick J. Wong 614fc6856c6SDarrick J. Wong int __init 615fc6856c6SDarrick J. Wong xfs_rtrmapbt_init_cur_cache(void) 616fc6856c6SDarrick J. Wong { 617fc6856c6SDarrick J. Wong xfs_rtrmapbt_cur_cache = kmem_cache_create("xfs_rtrmapbt_cur", 618fc6856c6SDarrick J. Wong xfs_btree_cur_sizeof(xfs_rtrmapbt_maxlevels_ondisk()), 619fc6856c6SDarrick J. Wong 0, 0, NULL); 620fc6856c6SDarrick J. Wong 621fc6856c6SDarrick J. Wong if (!xfs_rtrmapbt_cur_cache) 622fc6856c6SDarrick J. Wong return -ENOMEM; 623fc6856c6SDarrick J. Wong return 0; 624fc6856c6SDarrick J. Wong } 625fc6856c6SDarrick J. Wong 626fc6856c6SDarrick J. Wong void 627fc6856c6SDarrick J. Wong xfs_rtrmapbt_destroy_cur_cache(void) 628fc6856c6SDarrick J. Wong { 629fc6856c6SDarrick J. Wong kmem_cache_destroy(xfs_rtrmapbt_cur_cache); 630fc6856c6SDarrick J. Wong xfs_rtrmapbt_cur_cache = NULL; 631fc6856c6SDarrick J. Wong } 632fc6856c6SDarrick J. Wong 633fc6856c6SDarrick J. Wong /* Compute the maximum height of an rt reverse mapping btree. */ 634fc6856c6SDarrick J. Wong void 635fc6856c6SDarrick J. Wong xfs_rtrmapbt_compute_maxlevels( 636fc6856c6SDarrick J. Wong struct xfs_mount *mp) 637fc6856c6SDarrick J. Wong { 638fc6856c6SDarrick J. Wong unsigned int d_maxlevels, r_maxlevels; 639fc6856c6SDarrick J. Wong 640fc6856c6SDarrick J. Wong if (!xfs_has_rtrmapbt(mp)) { 641fc6856c6SDarrick J. Wong mp->m_rtrmap_maxlevels = 0; 642fc6856c6SDarrick J. Wong return; 643fc6856c6SDarrick J. Wong } 644fc6856c6SDarrick J. Wong 645fc6856c6SDarrick J. Wong /* 646fc6856c6SDarrick J. Wong * The realtime rmapbt lives on the data device, which means that its 647fc6856c6SDarrick J. Wong * maximum height is constrained by the size of the data device and 648fc6856c6SDarrick J. Wong * the height required to store one rmap record for each block in an 649fc6856c6SDarrick J. Wong * rt group. 650fc6856c6SDarrick J. Wong */ 651fc6856c6SDarrick J. Wong d_maxlevels = xfs_btree_space_to_height(mp->m_rtrmap_mnr, 652fc6856c6SDarrick J. Wong mp->m_sb.sb_dblocks); 653fc6856c6SDarrick J. Wong r_maxlevels = xfs_btree_compute_maxlevels(mp->m_rtrmap_mnr, 654fc6856c6SDarrick J. Wong mp->m_groups[XG_TYPE_RTG].blocks); 655fc6856c6SDarrick J. Wong 656fc6856c6SDarrick J. Wong /* Add one level to handle the inode root level. */ 657fc6856c6SDarrick J. Wong mp->m_rtrmap_maxlevels = min(d_maxlevels, r_maxlevels) + 1; 658fc6856c6SDarrick J. Wong } 6598491a55cSDarrick J. Wong 6608491a55cSDarrick J. Wong /* Calculate the rtrmap btree size for some records. */ 6618491a55cSDarrick J. Wong static unsigned long long 6628491a55cSDarrick J. Wong xfs_rtrmapbt_calc_size( 6638491a55cSDarrick J. Wong struct xfs_mount *mp, 6648491a55cSDarrick J. Wong unsigned long long len) 6658491a55cSDarrick J. Wong { 6668491a55cSDarrick J. Wong return xfs_btree_calc_size(mp->m_rtrmap_mnr, len); 6678491a55cSDarrick J. Wong } 6688491a55cSDarrick J. Wong 6698491a55cSDarrick J. Wong /* 6708491a55cSDarrick J. Wong * Calculate the maximum rmap btree size. 6718491a55cSDarrick J. Wong */ 6728491a55cSDarrick J. Wong static unsigned long long 6738491a55cSDarrick J. Wong xfs_rtrmapbt_max_size( 6748491a55cSDarrick J. Wong struct xfs_mount *mp, 6758491a55cSDarrick J. Wong xfs_rtblock_t rtblocks) 6768491a55cSDarrick J. Wong { 6778491a55cSDarrick J. Wong /* Bail out if we're uninitialized, which can happen in mkfs. */ 6788491a55cSDarrick J. Wong if (mp->m_rtrmap_mxr[0] == 0) 6798491a55cSDarrick J. Wong return 0; 6808491a55cSDarrick J. Wong 6818491a55cSDarrick J. Wong return xfs_rtrmapbt_calc_size(mp, rtblocks); 6828491a55cSDarrick J. Wong } 6838491a55cSDarrick J. Wong 6848491a55cSDarrick J. Wong /* 6858491a55cSDarrick J. Wong * Figure out how many blocks to reserve and how many are used by this btree. 6868491a55cSDarrick J. Wong */ 6878491a55cSDarrick J. Wong xfs_filblks_t 6888491a55cSDarrick J. Wong xfs_rtrmapbt_calc_reserves( 6898491a55cSDarrick J. Wong struct xfs_mount *mp) 6908491a55cSDarrick J. Wong { 6918491a55cSDarrick J. Wong uint32_t blocks = mp->m_groups[XG_TYPE_RTG].blocks; 6928491a55cSDarrick J. Wong 6938491a55cSDarrick J. Wong if (!xfs_has_rtrmapbt(mp)) 6948491a55cSDarrick J. Wong return 0; 6958491a55cSDarrick J. Wong 6968491a55cSDarrick J. Wong /* Reserve 1% of the rtgroup or enough for 1 block per record. */ 6978491a55cSDarrick J. Wong return max_t(xfs_filblks_t, blocks / 100, 6988491a55cSDarrick J. Wong xfs_rtrmapbt_max_size(mp, blocks)); 6998491a55cSDarrick J. Wong } 700f33659e8SDarrick J. Wong 701f33659e8SDarrick J. Wong /* Convert on-disk form of btree root to in-memory form. */ 702f33659e8SDarrick J. Wong STATIC void 703f33659e8SDarrick J. Wong xfs_rtrmapbt_from_disk( 704f33659e8SDarrick J. Wong struct xfs_inode *ip, 705f33659e8SDarrick J. Wong struct xfs_rtrmap_root *dblock, 706f33659e8SDarrick J. Wong unsigned int dblocklen, 707f33659e8SDarrick J. Wong struct xfs_btree_block *rblock) 708f33659e8SDarrick J. Wong { 709f33659e8SDarrick J. Wong struct xfs_mount *mp = ip->i_mount; 710f33659e8SDarrick J. Wong struct xfs_rmap_key *fkp; 711f33659e8SDarrick J. Wong __be64 *fpp; 712f33659e8SDarrick J. Wong struct xfs_rmap_key *tkp; 713f33659e8SDarrick J. Wong __be64 *tpp; 714f33659e8SDarrick J. Wong struct xfs_rmap_rec *frp; 715f33659e8SDarrick J. Wong struct xfs_rmap_rec *trp; 716f33659e8SDarrick J. Wong unsigned int rblocklen = xfs_rtrmap_broot_space(mp, dblock); 717f33659e8SDarrick J. Wong unsigned int numrecs; 718f33659e8SDarrick J. Wong unsigned int maxrecs; 719f33659e8SDarrick J. Wong 720f33659e8SDarrick J. Wong xfs_btree_init_block(mp, rblock, &xfs_rtrmapbt_ops, 0, 0, ip->i_ino); 721f33659e8SDarrick J. Wong 722f33659e8SDarrick J. Wong rblock->bb_level = dblock->bb_level; 723f33659e8SDarrick J. Wong rblock->bb_numrecs = dblock->bb_numrecs; 724f33659e8SDarrick J. Wong numrecs = be16_to_cpu(dblock->bb_numrecs); 725f33659e8SDarrick J. Wong 726f33659e8SDarrick J. Wong if (be16_to_cpu(rblock->bb_level) > 0) { 727f33659e8SDarrick J. Wong maxrecs = xfs_rtrmapbt_droot_maxrecs(dblocklen, false); 728f33659e8SDarrick J. Wong fkp = xfs_rtrmap_droot_key_addr(dblock, 1); 729f33659e8SDarrick J. Wong tkp = xfs_rtrmap_key_addr(rblock, 1); 730f33659e8SDarrick J. Wong fpp = xfs_rtrmap_droot_ptr_addr(dblock, 1, maxrecs); 731f33659e8SDarrick J. Wong tpp = xfs_rtrmap_broot_ptr_addr(mp, rblock, 1, rblocklen); 732f33659e8SDarrick J. Wong memcpy(tkp, fkp, 2 * sizeof(*fkp) * numrecs); 733f33659e8SDarrick J. Wong memcpy(tpp, fpp, sizeof(*fpp) * numrecs); 734f33659e8SDarrick J. Wong } else { 735f33659e8SDarrick J. Wong frp = xfs_rtrmap_droot_rec_addr(dblock, 1); 736f33659e8SDarrick J. Wong trp = xfs_rtrmap_rec_addr(rblock, 1); 737f33659e8SDarrick J. Wong memcpy(trp, frp, sizeof(*frp) * numrecs); 738f33659e8SDarrick J. Wong } 739f33659e8SDarrick J. Wong } 740f33659e8SDarrick J. Wong 741f33659e8SDarrick J. Wong /* Load a realtime reverse mapping btree root in from disk. */ 742f33659e8SDarrick J. Wong int 743f33659e8SDarrick J. Wong xfs_iformat_rtrmap( 744f33659e8SDarrick J. Wong struct xfs_inode *ip, 745f33659e8SDarrick J. Wong struct xfs_dinode *dip) 746f33659e8SDarrick J. Wong { 747f33659e8SDarrick J. Wong struct xfs_mount *mp = ip->i_mount; 748f33659e8SDarrick J. Wong struct xfs_rtrmap_root *dfp = XFS_DFORK_PTR(dip, XFS_DATA_FORK); 749f33659e8SDarrick J. Wong struct xfs_btree_block *broot; 750f33659e8SDarrick J. Wong unsigned int numrecs; 751f33659e8SDarrick J. Wong unsigned int level; 752f33659e8SDarrick J. Wong int dsize; 753f33659e8SDarrick J. Wong 754f33659e8SDarrick J. Wong /* 755f33659e8SDarrick J. Wong * growfs must create the rtrmap inodes before adding a realtime volume 756f33659e8SDarrick J. Wong * to the filesystem, so we cannot use the rtrmapbt predicate here. 757f33659e8SDarrick J. Wong */ 758f33659e8SDarrick J. Wong if (!xfs_has_rmapbt(ip->i_mount)) 759f33659e8SDarrick J. Wong return -EFSCORRUPTED; 760f33659e8SDarrick J. Wong 761f33659e8SDarrick J. Wong dsize = XFS_DFORK_SIZE(dip, mp, XFS_DATA_FORK); 762f33659e8SDarrick J. Wong numrecs = be16_to_cpu(dfp->bb_numrecs); 763f33659e8SDarrick J. Wong level = be16_to_cpu(dfp->bb_level); 764f33659e8SDarrick J. Wong 765f33659e8SDarrick J. Wong if (level > mp->m_rtrmap_maxlevels || 766f33659e8SDarrick J. Wong xfs_rtrmap_droot_space_calc(level, numrecs) > dsize) 767f33659e8SDarrick J. Wong return -EFSCORRUPTED; 768f33659e8SDarrick J. Wong 769f33659e8SDarrick J. Wong broot = xfs_broot_alloc(xfs_ifork_ptr(ip, XFS_DATA_FORK), 770f33659e8SDarrick J. Wong xfs_rtrmap_broot_space_calc(mp, level, numrecs)); 771f33659e8SDarrick J. Wong if (broot) 772f33659e8SDarrick J. Wong xfs_rtrmapbt_from_disk(ip, dfp, dsize, broot); 773f33659e8SDarrick J. Wong return 0; 774f33659e8SDarrick J. Wong } 775f33659e8SDarrick J. Wong 776f33659e8SDarrick J. Wong /* Convert in-memory form of btree root to on-disk form. */ 777f33659e8SDarrick J. Wong void 778f33659e8SDarrick J. Wong xfs_rtrmapbt_to_disk( 779f33659e8SDarrick J. Wong struct xfs_mount *mp, 780f33659e8SDarrick J. Wong struct xfs_btree_block *rblock, 781f33659e8SDarrick J. Wong unsigned int rblocklen, 782f33659e8SDarrick J. Wong struct xfs_rtrmap_root *dblock, 783f33659e8SDarrick J. Wong unsigned int dblocklen) 784f33659e8SDarrick J. Wong { 785f33659e8SDarrick J. Wong struct xfs_rmap_key *fkp; 786f33659e8SDarrick J. Wong __be64 *fpp; 787f33659e8SDarrick J. Wong struct xfs_rmap_key *tkp; 788f33659e8SDarrick J. Wong __be64 *tpp; 789f33659e8SDarrick J. Wong struct xfs_rmap_rec *frp; 790f33659e8SDarrick J. Wong struct xfs_rmap_rec *trp; 791f33659e8SDarrick J. Wong unsigned int numrecs; 792f33659e8SDarrick J. Wong unsigned int maxrecs; 793f33659e8SDarrick J. Wong 794f33659e8SDarrick J. Wong ASSERT(rblock->bb_magic == cpu_to_be32(XFS_RTRMAP_CRC_MAGIC)); 795f33659e8SDarrick J. Wong ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid)); 796f33659e8SDarrick J. Wong ASSERT(rblock->bb_u.l.bb_blkno == cpu_to_be64(XFS_BUF_DADDR_NULL)); 797f33659e8SDarrick J. Wong ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK)); 798f33659e8SDarrick J. Wong ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK)); 799f33659e8SDarrick J. Wong 800f33659e8SDarrick J. Wong dblock->bb_level = rblock->bb_level; 801f33659e8SDarrick J. Wong dblock->bb_numrecs = rblock->bb_numrecs; 802f33659e8SDarrick J. Wong numrecs = be16_to_cpu(rblock->bb_numrecs); 803f33659e8SDarrick J. Wong 804f33659e8SDarrick J. Wong if (be16_to_cpu(rblock->bb_level) > 0) { 805f33659e8SDarrick J. Wong maxrecs = xfs_rtrmapbt_droot_maxrecs(dblocklen, false); 806f33659e8SDarrick J. Wong fkp = xfs_rtrmap_key_addr(rblock, 1); 807f33659e8SDarrick J. Wong tkp = xfs_rtrmap_droot_key_addr(dblock, 1); 808f33659e8SDarrick J. Wong fpp = xfs_rtrmap_broot_ptr_addr(mp, rblock, 1, rblocklen); 809f33659e8SDarrick J. Wong tpp = xfs_rtrmap_droot_ptr_addr(dblock, 1, maxrecs); 810f33659e8SDarrick J. Wong memcpy(tkp, fkp, 2 * sizeof(*fkp) * numrecs); 811f33659e8SDarrick J. Wong memcpy(tpp, fpp, sizeof(*fpp) * numrecs); 812f33659e8SDarrick J. Wong } else { 813f33659e8SDarrick J. Wong frp = xfs_rtrmap_rec_addr(rblock, 1); 814f33659e8SDarrick J. Wong trp = xfs_rtrmap_droot_rec_addr(dblock, 1); 815f33659e8SDarrick J. Wong memcpy(trp, frp, sizeof(*frp) * numrecs); 816f33659e8SDarrick J. Wong } 817f33659e8SDarrick J. Wong } 818f33659e8SDarrick J. Wong 819f33659e8SDarrick J. Wong /* Flush a realtime reverse mapping btree root out to disk. */ 820f33659e8SDarrick J. Wong void 821f33659e8SDarrick J. Wong xfs_iflush_rtrmap( 822f33659e8SDarrick J. Wong struct xfs_inode *ip, 823f33659e8SDarrick J. Wong struct xfs_dinode *dip) 824f33659e8SDarrick J. Wong { 825f33659e8SDarrick J. Wong struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK); 826f33659e8SDarrick J. Wong struct xfs_rtrmap_root *dfp = XFS_DFORK_PTR(dip, XFS_DATA_FORK); 827f33659e8SDarrick J. Wong 828f33659e8SDarrick J. Wong ASSERT(ifp->if_broot != NULL); 829f33659e8SDarrick J. Wong ASSERT(ifp->if_broot_bytes > 0); 830f33659e8SDarrick J. Wong ASSERT(xfs_rtrmap_droot_space(ifp->if_broot) <= 831f33659e8SDarrick J. Wong xfs_inode_fork_size(ip, XFS_DATA_FORK)); 832f33659e8SDarrick J. Wong xfs_rtrmapbt_to_disk(ip->i_mount, ifp->if_broot, ifp->if_broot_bytes, 833f33659e8SDarrick J. Wong dfp, XFS_DFORK_SIZE(dip, ip->i_mount, XFS_DATA_FORK)); 834f33659e8SDarrick J. Wong } 835*71b8acb4SDarrick J. Wong 836*71b8acb4SDarrick J. Wong /* 837*71b8acb4SDarrick J. Wong * Create a realtime rmap btree inode. 838*71b8acb4SDarrick J. Wong */ 839*71b8acb4SDarrick J. Wong int 840*71b8acb4SDarrick J. Wong xfs_rtrmapbt_create( 841*71b8acb4SDarrick J. Wong struct xfs_rtgroup *rtg, 842*71b8acb4SDarrick J. Wong struct xfs_inode *ip, 843*71b8acb4SDarrick J. Wong struct xfs_trans *tp, 844*71b8acb4SDarrick J. Wong bool init) 845*71b8acb4SDarrick J. Wong { 846*71b8acb4SDarrick J. Wong struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK); 847*71b8acb4SDarrick J. Wong struct xfs_mount *mp = ip->i_mount; 848*71b8acb4SDarrick J. Wong struct xfs_btree_block *broot; 849*71b8acb4SDarrick J. Wong 850*71b8acb4SDarrick J. Wong ifp->if_format = XFS_DINODE_FMT_META_BTREE; 851*71b8acb4SDarrick J. Wong ASSERT(ifp->if_broot_bytes == 0); 852*71b8acb4SDarrick J. Wong ASSERT(ifp->if_bytes == 0); 853*71b8acb4SDarrick J. Wong 854*71b8acb4SDarrick J. Wong /* Initialize the empty incore btree root. */ 855*71b8acb4SDarrick J. Wong broot = xfs_broot_realloc(ifp, xfs_rtrmap_broot_space_calc(mp, 0, 0)); 856*71b8acb4SDarrick J. Wong if (broot) 857*71b8acb4SDarrick J. Wong xfs_btree_init_block(mp, broot, &xfs_rtrmapbt_ops, 0, 0, 858*71b8acb4SDarrick J. Wong ip->i_ino); 859*71b8acb4SDarrick J. Wong xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE | XFS_ILOG_DBROOT); 860*71b8acb4SDarrick J. Wong 861*71b8acb4SDarrick J. Wong return 0; 862*71b8acb4SDarrick J. Wong } 863*71b8acb4SDarrick J. Wong 864*71b8acb4SDarrick J. Wong /* 865*71b8acb4SDarrick J. Wong * Initialize an rmap for a realtime superblock using the potentially updated 866*71b8acb4SDarrick J. Wong * rt geometry in the provided @mp. 867*71b8acb4SDarrick J. Wong */ 868*71b8acb4SDarrick J. Wong int 869*71b8acb4SDarrick J. Wong xfs_rtrmapbt_init_rtsb( 870*71b8acb4SDarrick J. Wong struct xfs_mount *mp, 871*71b8acb4SDarrick J. Wong struct xfs_rtgroup *rtg, 872*71b8acb4SDarrick J. Wong struct xfs_trans *tp) 873*71b8acb4SDarrick J. Wong { 874*71b8acb4SDarrick J. Wong struct xfs_rmap_irec rmap = { 875*71b8acb4SDarrick J. Wong .rm_blockcount = mp->m_sb.sb_rextsize, 876*71b8acb4SDarrick J. Wong .rm_owner = XFS_RMAP_OWN_FS, 877*71b8acb4SDarrick J. Wong }; 878*71b8acb4SDarrick J. Wong struct xfs_btree_cur *cur; 879*71b8acb4SDarrick J. Wong int error; 880*71b8acb4SDarrick J. Wong 881*71b8acb4SDarrick J. Wong ASSERT(xfs_has_rtsb(mp)); 882*71b8acb4SDarrick J. Wong ASSERT(rtg_rgno(rtg) == 0); 883*71b8acb4SDarrick J. Wong 884*71b8acb4SDarrick J. Wong cur = xfs_rtrmapbt_init_cursor(tp, rtg); 885*71b8acb4SDarrick J. Wong error = xfs_rmap_map_raw(cur, &rmap); 886*71b8acb4SDarrick J. Wong xfs_btree_del_cursor(cur, error); 887*71b8acb4SDarrick J. Wong return error; 888*71b8acb4SDarrick J. Wong } 889