19a6cc4f6SDarrick J. Wong // SPDX-License-Identifier: GPL-2.0-or-later 29a6cc4f6SDarrick J. Wong /* 39a6cc4f6SDarrick J. Wong * Copyright (c) 2018-2024 Oracle. All Rights Reserved. 49a6cc4f6SDarrick J. Wong * Author: Darrick J. Wong <djwong@kernel.org> 59a6cc4f6SDarrick J. Wong */ 69a6cc4f6SDarrick J. Wong #include "xfs.h" 79a6cc4f6SDarrick J. Wong #include "xfs_fs.h" 89a6cc4f6SDarrick J. Wong #include "xfs_shared.h" 99a6cc4f6SDarrick J. Wong #include "xfs_format.h" 109a6cc4f6SDarrick J. Wong #include "xfs_trans_resv.h" 119a6cc4f6SDarrick J. Wong #include "xfs_mount.h" 129a6cc4f6SDarrick J. Wong #include "xfs_defer.h" 139a6cc4f6SDarrick J. Wong #include "xfs_btree.h" 149a6cc4f6SDarrick J. Wong #include "xfs_bit.h" 159a6cc4f6SDarrick J. Wong #include "xfs_log_format.h" 169a6cc4f6SDarrick J. Wong #include "xfs_trans.h" 179a6cc4f6SDarrick J. Wong #include "xfs_sb.h" 189a6cc4f6SDarrick J. Wong #include "xfs_rmap.h" 199a6cc4f6SDarrick J. Wong #include "xfs_rmap_btree.h" 209a6cc4f6SDarrick J. Wong #include "xfs_rtrmap_btree.h" 219a6cc4f6SDarrick J. Wong #include "xfs_inode.h" 229a6cc4f6SDarrick J. Wong #include "xfs_rtalloc.h" 239a6cc4f6SDarrick J. Wong #include "xfs_rtgroup.h" 249a6cc4f6SDarrick J. Wong #include "xfs_metafile.h" 259a6cc4f6SDarrick J. Wong #include "scrub/xfs_scrub.h" 269a6cc4f6SDarrick J. Wong #include "scrub/scrub.h" 279a6cc4f6SDarrick J. Wong #include "scrub/common.h" 289a6cc4f6SDarrick J. Wong #include "scrub/btree.h" 299a6cc4f6SDarrick J. Wong #include "scrub/trace.h" 309a6cc4f6SDarrick J. Wong 319a6cc4f6SDarrick J. Wong /* Set us up with the realtime metadata locked. */ 329a6cc4f6SDarrick J. Wong int 339a6cc4f6SDarrick J. Wong xchk_setup_rtrmapbt( 349a6cc4f6SDarrick J. Wong struct xfs_scrub *sc) 359a6cc4f6SDarrick J. Wong { 369a6cc4f6SDarrick J. Wong int error; 379a6cc4f6SDarrick J. Wong 389a6cc4f6SDarrick J. Wong if (xchk_need_intent_drain(sc)) 399a6cc4f6SDarrick J. Wong xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN); 409a6cc4f6SDarrick J. Wong 419a6cc4f6SDarrick J. Wong error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr); 429a6cc4f6SDarrick J. Wong if (error) 439a6cc4f6SDarrick J. Wong return error; 449a6cc4f6SDarrick J. Wong 459a6cc4f6SDarrick J. Wong error = xchk_setup_rt(sc); 469a6cc4f6SDarrick J. Wong if (error) 479a6cc4f6SDarrick J. Wong return error; 489a6cc4f6SDarrick J. Wong 499a6cc4f6SDarrick J. Wong error = xchk_install_live_inode(sc, rtg_rmap(sc->sr.rtg)); 509a6cc4f6SDarrick J. Wong if (error) 519a6cc4f6SDarrick J. Wong return error; 529a6cc4f6SDarrick J. Wong 539a6cc4f6SDarrick J. Wong return xchk_rtgroup_lock(sc, &sc->sr, XCHK_RTGLOCK_ALL); 549a6cc4f6SDarrick J. Wong } 559a6cc4f6SDarrick J. Wong 569a6cc4f6SDarrick J. Wong /* Realtime reverse mapping. */ 579a6cc4f6SDarrick J. Wong 589a6cc4f6SDarrick J. Wong struct xchk_rtrmap { 599a6cc4f6SDarrick J. Wong /* 609a6cc4f6SDarrick J. Wong * The furthest-reaching of the rmapbt records that we've already 619a6cc4f6SDarrick J. Wong * processed. This enables us to detect overlapping records for space 629a6cc4f6SDarrick J. Wong * allocations that cannot be shared. 639a6cc4f6SDarrick J. Wong */ 649a6cc4f6SDarrick J. Wong struct xfs_rmap_irec overlap_rec; 659a6cc4f6SDarrick J. Wong 669a6cc4f6SDarrick J. Wong /* 679a6cc4f6SDarrick J. Wong * The previous rmapbt record, so that we can check for two records 689a6cc4f6SDarrick J. Wong * that could be one. 699a6cc4f6SDarrick J. Wong */ 709a6cc4f6SDarrick J. Wong struct xfs_rmap_irec prev_rec; 719a6cc4f6SDarrick J. Wong }; 729a6cc4f6SDarrick J. Wong 739a6cc4f6SDarrick J. Wong /* Flag failures for records that overlap but cannot. */ 749a6cc4f6SDarrick J. Wong STATIC void 759a6cc4f6SDarrick J. Wong xchk_rtrmapbt_check_overlapping( 769a6cc4f6SDarrick J. Wong struct xchk_btree *bs, 779a6cc4f6SDarrick J. Wong struct xchk_rtrmap *cr, 789a6cc4f6SDarrick J. Wong const struct xfs_rmap_irec *irec) 799a6cc4f6SDarrick J. Wong { 809a6cc4f6SDarrick J. Wong xfs_rtblock_t pnext, inext; 819a6cc4f6SDarrick J. Wong 829a6cc4f6SDarrick J. Wong if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 839a6cc4f6SDarrick J. Wong return; 849a6cc4f6SDarrick J. Wong 859a6cc4f6SDarrick J. Wong /* No previous record? */ 869a6cc4f6SDarrick J. Wong if (cr->overlap_rec.rm_blockcount == 0) 879a6cc4f6SDarrick J. Wong goto set_prev; 889a6cc4f6SDarrick J. Wong 899a6cc4f6SDarrick J. Wong /* Do overlap_rec and irec overlap? */ 909a6cc4f6SDarrick J. Wong pnext = cr->overlap_rec.rm_startblock + cr->overlap_rec.rm_blockcount; 919a6cc4f6SDarrick J. Wong if (pnext <= irec->rm_startblock) 929a6cc4f6SDarrick J. Wong goto set_prev; 939a6cc4f6SDarrick J. Wong 949a6cc4f6SDarrick J. Wong xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 959a6cc4f6SDarrick J. Wong 969a6cc4f6SDarrick J. Wong /* Save whichever rmap record extends furthest. */ 979a6cc4f6SDarrick J. Wong inext = irec->rm_startblock + irec->rm_blockcount; 989a6cc4f6SDarrick J. Wong if (pnext > inext) 999a6cc4f6SDarrick J. Wong return; 1009a6cc4f6SDarrick J. Wong 1019a6cc4f6SDarrick J. Wong set_prev: 1029a6cc4f6SDarrick J. Wong memcpy(&cr->overlap_rec, irec, sizeof(struct xfs_rmap_irec)); 1039a6cc4f6SDarrick J. Wong } 1049a6cc4f6SDarrick J. Wong 1059a6cc4f6SDarrick J. Wong /* Decide if two reverse-mapping records can be merged. */ 1069a6cc4f6SDarrick J. Wong static inline bool 1079a6cc4f6SDarrick J. Wong xchk_rtrmap_mergeable( 1089a6cc4f6SDarrick J. Wong struct xchk_rtrmap *cr, 1099a6cc4f6SDarrick J. Wong const struct xfs_rmap_irec *r2) 1109a6cc4f6SDarrick J. Wong { 1119a6cc4f6SDarrick J. Wong const struct xfs_rmap_irec *r1 = &cr->prev_rec; 1129a6cc4f6SDarrick J. Wong 1139a6cc4f6SDarrick J. Wong /* Ignore if prev_rec is not yet initialized. */ 1149a6cc4f6SDarrick J. Wong if (cr->prev_rec.rm_blockcount == 0) 1159a6cc4f6SDarrick J. Wong return false; 1169a6cc4f6SDarrick J. Wong 1179a6cc4f6SDarrick J. Wong if (r1->rm_owner != r2->rm_owner) 1189a6cc4f6SDarrick J. Wong return false; 1199a6cc4f6SDarrick J. Wong if (r1->rm_startblock + r1->rm_blockcount != r2->rm_startblock) 1209a6cc4f6SDarrick J. Wong return false; 1219a6cc4f6SDarrick J. Wong if ((unsigned long long)r1->rm_blockcount + r2->rm_blockcount > 1229a6cc4f6SDarrick J. Wong XFS_RMAP_LEN_MAX) 1239a6cc4f6SDarrick J. Wong return false; 1249a6cc4f6SDarrick J. Wong if (r1->rm_flags != r2->rm_flags) 1259a6cc4f6SDarrick J. Wong return false; 1269a6cc4f6SDarrick J. Wong return r1->rm_offset + r1->rm_blockcount == r2->rm_offset; 1279a6cc4f6SDarrick J. Wong } 1289a6cc4f6SDarrick J. Wong 1299a6cc4f6SDarrick J. Wong /* Flag failures for records that could be merged. */ 1309a6cc4f6SDarrick J. Wong STATIC void 1319a6cc4f6SDarrick J. Wong xchk_rtrmapbt_check_mergeable( 1329a6cc4f6SDarrick J. Wong struct xchk_btree *bs, 1339a6cc4f6SDarrick J. Wong struct xchk_rtrmap *cr, 1349a6cc4f6SDarrick J. Wong const struct xfs_rmap_irec *irec) 1359a6cc4f6SDarrick J. Wong { 1369a6cc4f6SDarrick J. Wong if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 1379a6cc4f6SDarrick J. Wong return; 1389a6cc4f6SDarrick J. Wong 1399a6cc4f6SDarrick J. Wong if (xchk_rtrmap_mergeable(cr, irec)) 1409a6cc4f6SDarrick J. Wong xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 1419a6cc4f6SDarrick J. Wong 1429a6cc4f6SDarrick J. Wong memcpy(&cr->prev_rec, irec, sizeof(struct xfs_rmap_irec)); 1439a6cc4f6SDarrick J. Wong } 1449a6cc4f6SDarrick J. Wong 1451ebecab5SDarrick J. Wong /* Cross-reference with other metadata. */ 1461ebecab5SDarrick J. Wong STATIC void 1471ebecab5SDarrick J. Wong xchk_rtrmapbt_xref( 1481ebecab5SDarrick J. Wong struct xfs_scrub *sc, 1491ebecab5SDarrick J. Wong struct xfs_rmap_irec *irec) 1501ebecab5SDarrick J. Wong { 1511ebecab5SDarrick J. Wong if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 1521ebecab5SDarrick J. Wong return; 1531ebecab5SDarrick J. Wong 1541ebecab5SDarrick J. Wong xchk_xref_is_used_rt_space(sc, 1551ebecab5SDarrick J. Wong xfs_rgbno_to_rtb(sc->sr.rtg, irec->rm_startblock), 1561ebecab5SDarrick J. Wong irec->rm_blockcount); 1571ebecab5SDarrick J. Wong } 1581ebecab5SDarrick J. Wong 1599a6cc4f6SDarrick J. Wong /* Scrub a realtime rmapbt record. */ 1609a6cc4f6SDarrick J. Wong STATIC int 1619a6cc4f6SDarrick J. Wong xchk_rtrmapbt_rec( 1629a6cc4f6SDarrick J. Wong struct xchk_btree *bs, 1639a6cc4f6SDarrick J. Wong const union xfs_btree_rec *rec) 1649a6cc4f6SDarrick J. Wong { 1659a6cc4f6SDarrick J. Wong struct xchk_rtrmap *cr = bs->private; 1669a6cc4f6SDarrick J. Wong struct xfs_rmap_irec irec; 1679a6cc4f6SDarrick J. Wong 1689a6cc4f6SDarrick J. Wong if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL || 1699a6cc4f6SDarrick J. Wong xfs_rtrmap_check_irec(to_rtg(bs->cur->bc_group), &irec) != NULL) { 1709a6cc4f6SDarrick J. Wong xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 1719a6cc4f6SDarrick J. Wong return 0; 1729a6cc4f6SDarrick J. Wong } 1739a6cc4f6SDarrick J. Wong 1749a6cc4f6SDarrick J. Wong if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 1759a6cc4f6SDarrick J. Wong return 0; 1769a6cc4f6SDarrick J. Wong 1779a6cc4f6SDarrick J. Wong xchk_rtrmapbt_check_mergeable(bs, cr, &irec); 1789a6cc4f6SDarrick J. Wong xchk_rtrmapbt_check_overlapping(bs, cr, &irec); 1791ebecab5SDarrick J. Wong xchk_rtrmapbt_xref(bs->sc, &irec); 1809a6cc4f6SDarrick J. Wong return 0; 1819a6cc4f6SDarrick J. Wong } 1829a6cc4f6SDarrick J. Wong 1839a6cc4f6SDarrick J. Wong /* Scrub the realtime rmap btree. */ 1849a6cc4f6SDarrick J. Wong int 1859a6cc4f6SDarrick J. Wong xchk_rtrmapbt( 1869a6cc4f6SDarrick J. Wong struct xfs_scrub *sc) 1879a6cc4f6SDarrick J. Wong { 1889a6cc4f6SDarrick J. Wong struct xfs_inode *ip = rtg_rmap(sc->sr.rtg); 1899a6cc4f6SDarrick J. Wong struct xfs_owner_info oinfo; 1909a6cc4f6SDarrick J. Wong struct xchk_rtrmap cr = { }; 1919a6cc4f6SDarrick J. Wong int error; 1929a6cc4f6SDarrick J. Wong 1939a6cc4f6SDarrick J. Wong error = xchk_metadata_inode_forks(sc); 1949a6cc4f6SDarrick J. Wong if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 1959a6cc4f6SDarrick J. Wong return error; 1969a6cc4f6SDarrick J. Wong 1979a6cc4f6SDarrick J. Wong xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, XFS_DATA_FORK); 1989a6cc4f6SDarrick J. Wong return xchk_btree(sc, sc->sr.rmap_cur, xchk_rtrmapbt_rec, &oinfo, &cr); 1999a6cc4f6SDarrick J. Wong } 200*037a44d8SDarrick J. Wong 201*037a44d8SDarrick J. Wong /* xref check that the extent has no realtime reverse mapping at all */ 202*037a44d8SDarrick J. Wong void 203*037a44d8SDarrick J. Wong xchk_xref_has_no_rt_owner( 204*037a44d8SDarrick J. Wong struct xfs_scrub *sc, 205*037a44d8SDarrick J. Wong xfs_rgblock_t bno, 206*037a44d8SDarrick J. Wong xfs_extlen_t len) 207*037a44d8SDarrick J. Wong { 208*037a44d8SDarrick J. Wong enum xbtree_recpacking outcome; 209*037a44d8SDarrick J. Wong int error; 210*037a44d8SDarrick J. Wong 211*037a44d8SDarrick J. Wong if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm)) 212*037a44d8SDarrick J. Wong return; 213*037a44d8SDarrick J. Wong 214*037a44d8SDarrick J. Wong error = xfs_rmap_has_records(sc->sr.rmap_cur, bno, len, &outcome); 215*037a44d8SDarrick J. Wong if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur)) 216*037a44d8SDarrick J. Wong return; 217*037a44d8SDarrick J. Wong if (outcome != XBTREE_RECPACKING_EMPTY) 218*037a44d8SDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0); 219*037a44d8SDarrick J. Wong } 220*037a44d8SDarrick J. Wong 221*037a44d8SDarrick J. Wong /* xref check that the extent is completely mapped */ 222*037a44d8SDarrick J. Wong void 223*037a44d8SDarrick J. Wong xchk_xref_has_rt_owner( 224*037a44d8SDarrick J. Wong struct xfs_scrub *sc, 225*037a44d8SDarrick J. Wong xfs_rgblock_t bno, 226*037a44d8SDarrick J. Wong xfs_extlen_t len) 227*037a44d8SDarrick J. Wong { 228*037a44d8SDarrick J. Wong enum xbtree_recpacking outcome; 229*037a44d8SDarrick J. Wong int error; 230*037a44d8SDarrick J. Wong 231*037a44d8SDarrick J. Wong if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm)) 232*037a44d8SDarrick J. Wong return; 233*037a44d8SDarrick J. Wong 234*037a44d8SDarrick J. Wong error = xfs_rmap_has_records(sc->sr.rmap_cur, bno, len, &outcome); 235*037a44d8SDarrick J. Wong if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur)) 236*037a44d8SDarrick J. Wong return; 237*037a44d8SDarrick J. Wong if (outcome != XBTREE_RECPACKING_FULL) 238*037a44d8SDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0); 239*037a44d8SDarrick J. Wong } 240*037a44d8SDarrick J. Wong 241*037a44d8SDarrick J. Wong /* xref check that the extent is only owned by a given owner */ 242*037a44d8SDarrick J. Wong void 243*037a44d8SDarrick J. Wong xchk_xref_is_only_rt_owned_by( 244*037a44d8SDarrick J. Wong struct xfs_scrub *sc, 245*037a44d8SDarrick J. Wong xfs_agblock_t bno, 246*037a44d8SDarrick J. Wong xfs_extlen_t len, 247*037a44d8SDarrick J. Wong const struct xfs_owner_info *oinfo) 248*037a44d8SDarrick J. Wong { 249*037a44d8SDarrick J. Wong struct xfs_rmap_matches res; 250*037a44d8SDarrick J. Wong int error; 251*037a44d8SDarrick J. Wong 252*037a44d8SDarrick J. Wong if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm)) 253*037a44d8SDarrick J. Wong return; 254*037a44d8SDarrick J. Wong 255*037a44d8SDarrick J. Wong error = xfs_rmap_count_owners(sc->sr.rmap_cur, bno, len, oinfo, &res); 256*037a44d8SDarrick J. Wong if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur)) 257*037a44d8SDarrick J. Wong return; 258*037a44d8SDarrick J. Wong if (res.matches != 1) 259*037a44d8SDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0); 260*037a44d8SDarrick J. Wong if (res.bad_non_owner_matches) 261*037a44d8SDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0); 262*037a44d8SDarrick J. Wong if (res.non_owner_matches) 263*037a44d8SDarrick J. Wong xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0); 264*037a44d8SDarrick J. Wong } 265