1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2018-2024 Oracle. All Rights Reserved. 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 */ 6 #include "xfs.h" 7 #include "xfs_fs.h" 8 #include "xfs_shared.h" 9 #include "xfs_format.h" 10 #include "xfs_trans_resv.h" 11 #include "xfs_mount.h" 12 #include "xfs_defer.h" 13 #include "xfs_btree.h" 14 #include "xfs_bit.h" 15 #include "xfs_log_format.h" 16 #include "xfs_trans.h" 17 #include "xfs_sb.h" 18 #include "xfs_rmap.h" 19 #include "xfs_rmap_btree.h" 20 #include "xfs_rtrmap_btree.h" 21 #include "xfs_inode.h" 22 #include "xfs_rtalloc.h" 23 #include "xfs_rtgroup.h" 24 #include "xfs_metafile.h" 25 #include "scrub/xfs_scrub.h" 26 #include "scrub/scrub.h" 27 #include "scrub/common.h" 28 #include "scrub/btree.h" 29 #include "scrub/trace.h" 30 31 /* Set us up with the realtime metadata locked. */ 32 int 33 xchk_setup_rtrmapbt( 34 struct xfs_scrub *sc) 35 { 36 int error; 37 38 if (xchk_need_intent_drain(sc)) 39 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN); 40 41 error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr); 42 if (error) 43 return error; 44 45 error = xchk_setup_rt(sc); 46 if (error) 47 return error; 48 49 error = xchk_install_live_inode(sc, rtg_rmap(sc->sr.rtg)); 50 if (error) 51 return error; 52 53 return xchk_rtgroup_lock(sc, &sc->sr, XCHK_RTGLOCK_ALL); 54 } 55 56 /* Realtime reverse mapping. */ 57 58 struct xchk_rtrmap { 59 /* 60 * The furthest-reaching of the rmapbt records that we've already 61 * processed. This enables us to detect overlapping records for space 62 * allocations that cannot be shared. 63 */ 64 struct xfs_rmap_irec overlap_rec; 65 66 /* 67 * The previous rmapbt record, so that we can check for two records 68 * that could be one. 69 */ 70 struct xfs_rmap_irec prev_rec; 71 }; 72 73 /* Flag failures for records that overlap but cannot. */ 74 STATIC void 75 xchk_rtrmapbt_check_overlapping( 76 struct xchk_btree *bs, 77 struct xchk_rtrmap *cr, 78 const struct xfs_rmap_irec *irec) 79 { 80 xfs_rtblock_t pnext, inext; 81 82 if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 83 return; 84 85 /* No previous record? */ 86 if (cr->overlap_rec.rm_blockcount == 0) 87 goto set_prev; 88 89 /* Do overlap_rec and irec overlap? */ 90 pnext = cr->overlap_rec.rm_startblock + cr->overlap_rec.rm_blockcount; 91 if (pnext <= irec->rm_startblock) 92 goto set_prev; 93 94 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 95 96 /* Save whichever rmap record extends furthest. */ 97 inext = irec->rm_startblock + irec->rm_blockcount; 98 if (pnext > inext) 99 return; 100 101 set_prev: 102 memcpy(&cr->overlap_rec, irec, sizeof(struct xfs_rmap_irec)); 103 } 104 105 /* Decide if two reverse-mapping records can be merged. */ 106 static inline bool 107 xchk_rtrmap_mergeable( 108 struct xchk_rtrmap *cr, 109 const struct xfs_rmap_irec *r2) 110 { 111 const struct xfs_rmap_irec *r1 = &cr->prev_rec; 112 113 /* Ignore if prev_rec is not yet initialized. */ 114 if (cr->prev_rec.rm_blockcount == 0) 115 return false; 116 117 if (r1->rm_owner != r2->rm_owner) 118 return false; 119 if (r1->rm_startblock + r1->rm_blockcount != r2->rm_startblock) 120 return false; 121 if ((unsigned long long)r1->rm_blockcount + r2->rm_blockcount > 122 XFS_RMAP_LEN_MAX) 123 return false; 124 if (r1->rm_flags != r2->rm_flags) 125 return false; 126 return r1->rm_offset + r1->rm_blockcount == r2->rm_offset; 127 } 128 129 /* Flag failures for records that could be merged. */ 130 STATIC void 131 xchk_rtrmapbt_check_mergeable( 132 struct xchk_btree *bs, 133 struct xchk_rtrmap *cr, 134 const struct xfs_rmap_irec *irec) 135 { 136 if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 137 return; 138 139 if (xchk_rtrmap_mergeable(cr, irec)) 140 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 141 142 memcpy(&cr->prev_rec, irec, sizeof(struct xfs_rmap_irec)); 143 } 144 145 /* Cross-reference with other metadata. */ 146 STATIC void 147 xchk_rtrmapbt_xref( 148 struct xfs_scrub *sc, 149 struct xfs_rmap_irec *irec) 150 { 151 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 152 return; 153 154 xchk_xref_is_used_rt_space(sc, 155 xfs_rgbno_to_rtb(sc->sr.rtg, irec->rm_startblock), 156 irec->rm_blockcount); 157 } 158 159 /* Scrub a realtime rmapbt record. */ 160 STATIC int 161 xchk_rtrmapbt_rec( 162 struct xchk_btree *bs, 163 const union xfs_btree_rec *rec) 164 { 165 struct xchk_rtrmap *cr = bs->private; 166 struct xfs_rmap_irec irec; 167 168 if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL || 169 xfs_rtrmap_check_irec(to_rtg(bs->cur->bc_group), &irec) != NULL) { 170 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 171 return 0; 172 } 173 174 if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 175 return 0; 176 177 xchk_rtrmapbt_check_mergeable(bs, cr, &irec); 178 xchk_rtrmapbt_check_overlapping(bs, cr, &irec); 179 xchk_rtrmapbt_xref(bs->sc, &irec); 180 return 0; 181 } 182 183 /* Scrub the realtime rmap btree. */ 184 int 185 xchk_rtrmapbt( 186 struct xfs_scrub *sc) 187 { 188 struct xfs_inode *ip = rtg_rmap(sc->sr.rtg); 189 struct xfs_owner_info oinfo; 190 struct xchk_rtrmap cr = { }; 191 int error; 192 193 error = xchk_metadata_inode_forks(sc); 194 if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 195 return error; 196 197 xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, XFS_DATA_FORK); 198 return xchk_btree(sc, sc->sr.rmap_cur, xchk_rtrmapbt_rec, &oinfo, &cr); 199 } 200