1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 */ 6 #include "xfs_platform.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_btree.h" 13 #include "xfs_inode.h" 14 #include "xfs_log_format.h" 15 #include "xfs_trans.h" 16 #include "xfs_rtbitmap.h" 17 #include "xfs_bit.h" 18 #include "xfs_bmap.h" 19 #include "xfs_sb.h" 20 #include "xfs_exchmaps.h" 21 #include "xfs_rtgroup.h" 22 #include "scrub/scrub.h" 23 #include "scrub/common.h" 24 #include "scrub/trace.h" 25 #include "scrub/xfile.h" 26 #include "scrub/repair.h" 27 #include "scrub/tempexch.h" 28 #include "scrub/rtsummary.h" 29 30 /* 31 * Realtime Summary 32 * ================ 33 * 34 * We check the realtime summary by scanning the realtime bitmap file to create 35 * a new summary file incore, and then we compare the computed version against 36 * the ondisk version. We use the 'xfile' functionality to store this 37 * (potentially large) amount of data in pageable memory. 38 */ 39 40 /* Set us up to check the rtsummary file. */ 41 int 42 xchk_setup_rtsummary( 43 struct xfs_scrub *sc) 44 { 45 struct xfs_mount *mp = sc->mp; 46 struct xchk_rtsummary *rts; 47 int error; 48 49 if (xchk_need_intent_drain(sc)) 50 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN); 51 52 rts = kvzalloc(struct_size(rts, words, mp->m_blockwsize), 53 XCHK_GFP_FLAGS); 54 if (!rts) 55 return -ENOMEM; 56 sc->buf = rts; 57 58 error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr); 59 if (error) 60 return error; 61 62 if (xchk_could_repair(sc)) { 63 error = xrep_setup_rtsummary(sc, rts); 64 if (error) 65 return error; 66 } 67 68 /* 69 * Create an xfile to construct a new rtsummary file. The xfile allows 70 * us to avoid pinning kernel memory for this purpose. 71 */ 72 error = xfile_create("realtime summary file", 73 XFS_FSB_TO_B(mp, mp->m_rsumblocks), &sc->xfile); 74 if (error) 75 return error; 76 77 error = xchk_trans_alloc(sc, rts->resblks); 78 if (error) 79 return error; 80 81 error = xchk_install_live_inode(sc, rtg_summary(sc->sr.rtg)); 82 if (error) 83 return error; 84 85 error = xchk_ino_dqattach(sc); 86 if (error) 87 return error; 88 89 error = xchk_rtgroup_lock(sc, &sc->sr, XFS_RTGLOCK_BITMAP); 90 if (error) 91 return error; 92 93 /* 94 * Now that we've locked the rtbitmap and rtsummary, we can't race with 95 * growfsrt trying to expand the summary or change the size of the rt 96 * volume. Hence it is safe to compute and check the geometry values. 97 * 98 * Note that there is no strict requirement for an exclusive lock on the 99 * summary here, but to keep the locking APIs simple we lock both inodes 100 * exclusively here. If we ever start caring about running concurrent 101 * fsmap with scrub this could be changed. 102 */ 103 if (mp->m_sb.sb_rblocks) { 104 rts->rextents = xfs_blen_to_rtbxlen(mp, mp->m_sb.sb_rblocks); 105 rts->rbmblocks = xfs_rtbitmap_blockcount(mp); 106 rts->rsumblocks = 107 xfs_rtsummary_blockcount(mp, &rts->rsumlevels); 108 } 109 110 return 0; 111 } 112 113 /* Helper functions to record suminfo words in an xfile. */ 114 115 static inline int 116 xfsum_load( 117 struct xfs_scrub *sc, 118 xfs_rtsumoff_t sumoff, 119 union xfs_suminfo_raw *rawinfo) 120 { 121 return xfile_load(sc->xfile, rawinfo, 122 sizeof(union xfs_suminfo_raw), 123 sumoff << XFS_WORDLOG); 124 } 125 126 static inline int 127 xfsum_store( 128 struct xfs_scrub *sc, 129 xfs_rtsumoff_t sumoff, 130 const union xfs_suminfo_raw rawinfo) 131 { 132 return xfile_store(sc->xfile, &rawinfo, 133 sizeof(union xfs_suminfo_raw), 134 sumoff << XFS_WORDLOG); 135 } 136 137 inline int 138 xfsum_copyout( 139 struct xfs_scrub *sc, 140 xfs_rtsumoff_t sumoff, 141 union xfs_suminfo_raw *rawinfo, 142 unsigned int nr_words) 143 { 144 return xfile_load(sc->xfile, rawinfo, nr_words << XFS_WORDLOG, 145 sumoff << XFS_WORDLOG); 146 } 147 148 static inline xfs_suminfo_t 149 xchk_rtsum_inc( 150 struct xfs_mount *mp, 151 union xfs_suminfo_raw *v) 152 { 153 if (xfs_has_rtgroups(mp)) { 154 be32_add_cpu(&v->rtg, 1); 155 return be32_to_cpu(v->rtg); 156 } 157 158 v->old += 1; 159 return v->old; 160 } 161 162 /* Update the summary file to reflect the free extent that we've accumulated. */ 163 STATIC int 164 xchk_rtsum_record_free( 165 struct xfs_rtgroup *rtg, 166 struct xfs_trans *tp, 167 const struct xfs_rtalloc_rec *rec, 168 void *priv) 169 { 170 struct xfs_mount *mp = rtg_mount(rtg); 171 struct xfs_scrub *sc = priv; 172 xfs_fileoff_t rbmoff; 173 xfs_rtblock_t rtbno; 174 xfs_filblks_t rtlen; 175 xfs_rtsumoff_t offs; 176 unsigned int lenlog; 177 union xfs_suminfo_raw v; 178 xfs_suminfo_t value; 179 int error = 0; 180 181 if (xchk_should_terminate(sc, &error)) 182 return error; 183 184 /* Compute the relevant location in the rtsum file. */ 185 rbmoff = xfs_rtx_to_rbmblock(mp, rec->ar_startext); 186 lenlog = xfs_highbit64(rec->ar_extcount); 187 offs = xfs_rtsumoffs(mp, lenlog, rbmoff); 188 189 rtbno = xfs_rtx_to_rtb(rtg, rec->ar_startext); 190 rtlen = xfs_rtxlen_to_extlen(mp, rec->ar_extcount); 191 192 if (!xfs_verify_rtbext(mp, rtbno, rtlen)) { 193 xchk_ino_xref_set_corrupt(sc, rtg_bitmap(rtg)->i_ino); 194 return -EFSCORRUPTED; 195 } 196 197 /* Bump the summary count. */ 198 error = xfsum_load(sc, offs, &v); 199 if (error) 200 return error; 201 202 value = xchk_rtsum_inc(sc->mp, &v); 203 trace_xchk_rtsum_record_free(mp, rec->ar_startext, rec->ar_extcount, 204 lenlog, offs, value); 205 206 return xfsum_store(sc, offs, v); 207 } 208 209 /* Compute the realtime summary from the realtime bitmap. */ 210 STATIC int 211 xchk_rtsum_compute( 212 struct xfs_scrub *sc) 213 { 214 struct xfs_mount *mp = sc->mp; 215 struct xfs_rtgroup *rtg = sc->sr.rtg; 216 217 /* If the bitmap size doesn't match the computed size, bail. */ 218 if (XFS_FSB_TO_B(mp, xfs_rtbitmap_blockcount(mp)) != 219 rtg_bitmap(rtg)->i_disk_size) 220 return -EFSCORRUPTED; 221 222 return xfs_rtalloc_query_all(rtg, sc->tp, xchk_rtsum_record_free, sc); 223 } 224 225 /* Compare the rtsummary file against the one we computed. */ 226 STATIC int 227 xchk_rtsum_compare( 228 struct xfs_scrub *sc) 229 { 230 struct xfs_bmbt_irec map; 231 struct xfs_iext_cursor icur; 232 233 struct xfs_mount *mp = sc->mp; 234 struct xfs_inode *ip = sc->ip; 235 struct xchk_rtsummary *rts = sc->buf; 236 xfs_fileoff_t off = 0; 237 xfs_fileoff_t endoff; 238 xfs_rtsumoff_t sumoff = 0; 239 int error = 0; 240 241 rts->args.mp = mp; 242 rts->args.tp = sc->tp; 243 rts->args.rtg = sc->sr.rtg; 244 245 /* Mappings may not cross or lie beyond EOF. */ 246 endoff = XFS_B_TO_FSB(mp, ip->i_disk_size); 247 if (xfs_iext_lookup_extent(ip, &ip->i_df, endoff, &icur, &map)) { 248 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, endoff); 249 return 0; 250 } 251 252 while (off < endoff) { 253 int nmap = 1; 254 255 if (xchk_should_terminate(sc, &error)) 256 return error; 257 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 258 return 0; 259 260 /* Make sure we have a written extent. */ 261 error = xfs_bmapi_read(ip, off, endoff - off, &map, &nmap, 262 XFS_DATA_FORK); 263 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error)) 264 return error; 265 266 if (nmap != 1 || !xfs_bmap_is_written_extent(&map)) { 267 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off); 268 return 0; 269 } 270 271 off += map.br_blockcount; 272 } 273 274 for (off = 0; off < endoff; off++) { 275 union xfs_suminfo_raw *ondisk_info; 276 277 /* Read a block's worth of ondisk rtsummary file. */ 278 error = xfs_rtsummary_read_buf(&rts->args, off); 279 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error)) 280 return error; 281 282 /* Read a block's worth of computed rtsummary file. */ 283 error = xfsum_copyout(sc, sumoff, rts->words, mp->m_blockwsize); 284 if (error) { 285 xfs_rtbuf_cache_relse(&rts->args); 286 return error; 287 } 288 289 ondisk_info = xfs_rsumblock_infoptr(&rts->args, 0); 290 if (memcmp(ondisk_info, rts->words, 291 mp->m_blockwsize << XFS_WORDLOG) != 0) { 292 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off); 293 xfs_rtbuf_cache_relse(&rts->args); 294 return error; 295 } 296 297 xfs_rtbuf_cache_relse(&rts->args); 298 sumoff += mp->m_blockwsize; 299 } 300 301 return 0; 302 } 303 304 /* Scrub the realtime summary. */ 305 int 306 xchk_rtsummary( 307 struct xfs_scrub *sc) 308 { 309 struct xfs_mount *mp = sc->mp; 310 struct xfs_rtgroup *rtg = sc->sr.rtg; 311 struct xfs_inode *rbmip = rtg_bitmap(rtg); 312 struct xfs_inode *rsumip = rtg_summary(rtg); 313 struct xchk_rtsummary *rts = sc->buf; 314 int error; 315 316 /* Is sb_rextents correct? */ 317 if (mp->m_sb.sb_rextents != rts->rextents) { 318 xchk_ino_set_corrupt(sc, rbmip->i_ino); 319 return 0; 320 } 321 322 /* Is m_rsumlevels correct? */ 323 if (mp->m_rsumlevels != rts->rsumlevels) { 324 xchk_ino_set_corrupt(sc, rsumip->i_ino); 325 return 0; 326 } 327 328 /* Is m_rsumsize correct? */ 329 if (mp->m_rsumblocks != rts->rsumblocks) { 330 xchk_ino_set_corrupt(sc, rsumip->i_ino); 331 return 0; 332 } 333 334 /* The summary file length must be aligned to an fsblock. */ 335 if (rsumip->i_disk_size & mp->m_blockmask) { 336 xchk_ino_set_corrupt(sc, rsumip->i_ino); 337 return 0; 338 } 339 340 /* 341 * Is the summary file itself large enough to handle the rt volume? 342 * growfsrt expands the summary file before updating sb_rextents, so 343 * the file can be larger than rsumsize. 344 */ 345 if (rsumip->i_disk_size < XFS_FSB_TO_B(mp, rts->rsumblocks)) { 346 xchk_ino_set_corrupt(sc, rsumip->i_ino); 347 return 0; 348 } 349 350 /* Invoke the fork scrubber. */ 351 error = xchk_metadata_inode_forks(sc); 352 if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 353 return error; 354 355 /* Construct the new summary file from the rtbitmap. */ 356 error = xchk_rtsum_compute(sc); 357 if (error == -EFSCORRUPTED) { 358 /* 359 * EFSCORRUPTED means the rtbitmap is corrupt, which is an xref 360 * error since we're checking the summary file. 361 */ 362 xchk_ino_set_corrupt(sc, rbmip->i_ino); 363 return 0; 364 } 365 if (error) 366 return error; 367 368 /* Does the computed summary file match the actual rtsummary file? */ 369 return xchk_rtsum_compare(sc); 370 } 371