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 145*1ebecab5SDarrick J. Wong /* Cross-reference with other metadata. */ 146*1ebecab5SDarrick J. Wong STATIC void 147*1ebecab5SDarrick J. Wong xchk_rtrmapbt_xref( 148*1ebecab5SDarrick J. Wong struct xfs_scrub *sc, 149*1ebecab5SDarrick J. Wong struct xfs_rmap_irec *irec) 150*1ebecab5SDarrick J. Wong { 151*1ebecab5SDarrick J. Wong if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 152*1ebecab5SDarrick J. Wong return; 153*1ebecab5SDarrick J. Wong 154*1ebecab5SDarrick J. Wong xchk_xref_is_used_rt_space(sc, 155*1ebecab5SDarrick J. Wong xfs_rgbno_to_rtb(sc->sr.rtg, irec->rm_startblock), 156*1ebecab5SDarrick J. Wong irec->rm_blockcount); 157*1ebecab5SDarrick J. Wong } 158*1ebecab5SDarrick 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); 179*1ebecab5SDarrick 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