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