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.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 char *descr; 47 struct xchk_rtsummary *rts; 48 int error; 49 50 if (xchk_need_intent_drain(sc)) 51 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN); 52 53 rts = kvzalloc(struct_size(rts, words, mp->m_blockwsize), 54 XCHK_GFP_FLAGS); 55 if (!rts) 56 return -ENOMEM; 57 sc->buf = rts; 58 59 error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr); 60 if (error) 61 return error; 62 63 if (xchk_could_repair(sc)) { 64 error = xrep_setup_rtsummary(sc, rts); 65 if (error) 66 return error; 67 } 68 69 /* 70 * Create an xfile to construct a new rtsummary file. The xfile allows 71 * us to avoid pinning kernel memory for this purpose. 72 */ 73 descr = xchk_xfile_descr(sc, "realtime summary file"); 74 error = xfile_create(descr, XFS_FSB_TO_B(mp, mp->m_rsumblocks), 75 &sc->xfile); 76 kfree(descr); 77 if (error) 78 return error; 79 80 error = xchk_trans_alloc(sc, rts->resblks); 81 if (error) 82 return error; 83 84 error = xchk_install_live_inode(sc, 85 sc->sr.rtg->rtg_inodes[XFS_RTGI_SUMMARY]); 86 if (error) 87 return error; 88 89 error = xchk_ino_dqattach(sc); 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 xchk_rtgroup_lock(&sc->sr, XFS_RTGLOCK_BITMAP); 104 if (mp->m_sb.sb_rblocks) { 105 rts->rextents = xfs_blen_to_rtbxlen(mp, mp->m_sb.sb_rblocks); 106 rts->rbmblocks = xfs_rtbitmap_blockcount(mp); 107 rts->rsumblocks = 108 xfs_rtsummary_blockcount(mp, &rts->rsumlevels); 109 } 110 111 return 0; 112 } 113 114 /* Helper functions to record suminfo words in an xfile. */ 115 116 static inline int 117 xfsum_load( 118 struct xfs_scrub *sc, 119 xfs_rtsumoff_t sumoff, 120 union xfs_suminfo_raw *rawinfo) 121 { 122 return xfile_load(sc->xfile, rawinfo, 123 sizeof(union xfs_suminfo_raw), 124 sumoff << XFS_WORDLOG); 125 } 126 127 static inline int 128 xfsum_store( 129 struct xfs_scrub *sc, 130 xfs_rtsumoff_t sumoff, 131 const union xfs_suminfo_raw rawinfo) 132 { 133 return xfile_store(sc->xfile, &rawinfo, 134 sizeof(union xfs_suminfo_raw), 135 sumoff << XFS_WORDLOG); 136 } 137 138 inline int 139 xfsum_copyout( 140 struct xfs_scrub *sc, 141 xfs_rtsumoff_t sumoff, 142 union xfs_suminfo_raw *rawinfo, 143 unsigned int nr_words) 144 { 145 return xfile_load(sc->xfile, rawinfo, nr_words << XFS_WORDLOG, 146 sumoff << XFS_WORDLOG); 147 } 148 149 static inline xfs_suminfo_t 150 xchk_rtsum_inc( 151 struct xfs_mount *mp, 152 union xfs_suminfo_raw *v) 153 { 154 if (xfs_has_rtgroups(mp)) { 155 be32_add_cpu(&v->rtg, 1); 156 return be32_to_cpu(v->rtg); 157 } 158 159 v->old += 1; 160 return v->old; 161 } 162 163 /* Update the summary file to reflect the free extent that we've accumulated. */ 164 STATIC int 165 xchk_rtsum_record_free( 166 struct xfs_rtgroup *rtg, 167 struct xfs_trans *tp, 168 const struct xfs_rtalloc_rec *rec, 169 void *priv) 170 { 171 struct xfs_mount *mp = rtg_mount(rtg); 172 struct xfs_scrub *sc = priv; 173 xfs_fileoff_t rbmoff; 174 xfs_rtblock_t rtbno; 175 xfs_filblks_t rtlen; 176 xfs_rtsumoff_t offs; 177 unsigned int lenlog; 178 union xfs_suminfo_raw v; 179 xfs_suminfo_t value; 180 int error = 0; 181 182 if (xchk_should_terminate(sc, &error)) 183 return error; 184 185 /* Compute the relevant location in the rtsum file. */ 186 rbmoff = xfs_rtx_to_rbmblock(mp, rec->ar_startext); 187 lenlog = xfs_highbit64(rec->ar_extcount); 188 offs = xfs_rtsumoffs(mp, lenlog, rbmoff); 189 190 rtbno = xfs_rtx_to_rtb(rtg, rec->ar_startext); 191 rtlen = xfs_rtxlen_to_extlen(mp, rec->ar_extcount); 192 193 if (!xfs_verify_rtbext(mp, rtbno, rtlen)) { 194 xchk_ino_xref_set_corrupt(sc, 195 rtg->rtg_inodes[XFS_RTGI_BITMAP]->i_ino); 196 return -EFSCORRUPTED; 197 } 198 199 /* Bump the summary count. */ 200 error = xfsum_load(sc, offs, &v); 201 if (error) 202 return error; 203 204 value = xchk_rtsum_inc(sc->mp, &v); 205 trace_xchk_rtsum_record_free(mp, rec->ar_startext, rec->ar_extcount, 206 lenlog, offs, value); 207 208 return xfsum_store(sc, offs, v); 209 } 210 211 /* Compute the realtime summary from the realtime bitmap. */ 212 STATIC int 213 xchk_rtsum_compute( 214 struct xfs_scrub *sc) 215 { 216 struct xfs_mount *mp = sc->mp; 217 struct xfs_rtgroup *rtg = sc->sr.rtg; 218 219 /* If the bitmap size doesn't match the computed size, bail. */ 220 if (XFS_FSB_TO_B(mp, xfs_rtbitmap_blockcount(mp)) != 221 rtg->rtg_inodes[XFS_RTGI_BITMAP]->i_disk_size) 222 return -EFSCORRUPTED; 223 224 return xfs_rtalloc_query_all(rtg, sc->tp, xchk_rtsum_record_free, sc); 225 } 226 227 /* Compare the rtsummary file against the one we computed. */ 228 STATIC int 229 xchk_rtsum_compare( 230 struct xfs_scrub *sc) 231 { 232 struct xfs_bmbt_irec map; 233 struct xfs_iext_cursor icur; 234 235 struct xfs_mount *mp = sc->mp; 236 struct xfs_inode *ip = sc->ip; 237 struct xchk_rtsummary *rts = sc->buf; 238 xfs_fileoff_t off = 0; 239 xfs_fileoff_t endoff; 240 xfs_rtsumoff_t sumoff = 0; 241 int error = 0; 242 243 rts->args.mp = mp; 244 rts->args.tp = sc->tp; 245 rts->args.rtg = sc->sr.rtg; 246 247 /* Mappings may not cross or lie beyond EOF. */ 248 endoff = XFS_B_TO_FSB(mp, ip->i_disk_size); 249 if (xfs_iext_lookup_extent(ip, &ip->i_df, endoff, &icur, &map)) { 250 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, endoff); 251 return 0; 252 } 253 254 while (off < endoff) { 255 int nmap = 1; 256 257 if (xchk_should_terminate(sc, &error)) 258 return error; 259 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 260 return 0; 261 262 /* Make sure we have a written extent. */ 263 error = xfs_bmapi_read(ip, off, endoff - off, &map, &nmap, 264 XFS_DATA_FORK); 265 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error)) 266 return error; 267 268 if (nmap != 1 || !xfs_bmap_is_written_extent(&map)) { 269 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off); 270 return 0; 271 } 272 273 off += map.br_blockcount; 274 } 275 276 for (off = 0; off < endoff; off++) { 277 union xfs_suminfo_raw *ondisk_info; 278 279 /* Read a block's worth of ondisk rtsummary file. */ 280 error = xfs_rtsummary_read_buf(&rts->args, off); 281 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error)) 282 return error; 283 284 /* Read a block's worth of computed rtsummary file. */ 285 error = xfsum_copyout(sc, sumoff, rts->words, mp->m_blockwsize); 286 if (error) { 287 xfs_rtbuf_cache_relse(&rts->args); 288 return error; 289 } 290 291 ondisk_info = xfs_rsumblock_infoptr(&rts->args, 0); 292 if (memcmp(ondisk_info, rts->words, 293 mp->m_blockwsize << XFS_WORDLOG) != 0) { 294 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off); 295 xfs_rtbuf_cache_relse(&rts->args); 296 return error; 297 } 298 299 xfs_rtbuf_cache_relse(&rts->args); 300 sumoff += mp->m_blockwsize; 301 } 302 303 return 0; 304 } 305 306 /* Scrub the realtime summary. */ 307 int 308 xchk_rtsummary( 309 struct xfs_scrub *sc) 310 { 311 struct xfs_mount *mp = sc->mp; 312 struct xfs_rtgroup *rtg = sc->sr.rtg; 313 struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTGI_BITMAP]; 314 struct xfs_inode *rsumip = rtg->rtg_inodes[XFS_RTGI_SUMMARY]; 315 struct xchk_rtsummary *rts = sc->buf; 316 int error; 317 318 /* Is sb_rextents correct? */ 319 if (mp->m_sb.sb_rextents != rts->rextents) { 320 xchk_ino_set_corrupt(sc, rbmip->i_ino); 321 return 0; 322 } 323 324 /* Is m_rsumlevels correct? */ 325 if (mp->m_rsumlevels != rts->rsumlevels) { 326 xchk_ino_set_corrupt(sc, rsumip->i_ino); 327 return 0; 328 } 329 330 /* Is m_rsumsize correct? */ 331 if (mp->m_rsumblocks != rts->rsumblocks) { 332 xchk_ino_set_corrupt(sc, rsumip->i_ino); 333 return 0; 334 } 335 336 /* The summary file length must be aligned to an fsblock. */ 337 if (rsumip->i_disk_size & mp->m_blockmask) { 338 xchk_ino_set_corrupt(sc, rsumip->i_ino); 339 return 0; 340 } 341 342 /* 343 * Is the summary file itself large enough to handle the rt volume? 344 * growfsrt expands the summary file before updating sb_rextents, so 345 * the file can be larger than rsumsize. 346 */ 347 if (rsumip->i_disk_size < XFS_FSB_TO_B(mp, rts->rsumblocks)) { 348 xchk_ino_set_corrupt(sc, rsumip->i_ino); 349 return 0; 350 } 351 352 /* Invoke the fork scrubber. */ 353 error = xchk_metadata_inode_forks(sc); 354 if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 355 return error; 356 357 /* Construct the new summary file from the rtbitmap. */ 358 error = xchk_rtsum_compute(sc); 359 if (error == -EFSCORRUPTED) { 360 /* 361 * EFSCORRUPTED means the rtbitmap is corrupt, which is an xref 362 * error since we're checking the summary file. 363 */ 364 xchk_ino_set_corrupt(sc, rbmip->i_ino); 365 return 0; 366 } 367 if (error) 368 return error; 369 370 /* Does the computed summary file match the actual rtsummary file? */ 371 return xchk_rtsum_compare(sc); 372 } 373