1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2017 Oracle. All Rights Reserved. 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 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_alloc.h" 19 #include "xfs_rmap.h" 20 #include "scrub/xfs_scrub.h" 21 #include "scrub/scrub.h" 22 #include "scrub/common.h" 23 #include "scrub/btree.h" 24 #include "scrub/trace.h" 25 26 /* 27 * Set us up to scrub free space btrees. 28 */ 29 int 30 xchk_setup_ag_allocbt( 31 struct xfs_scrub *sc, 32 struct xfs_inode *ip) 33 { 34 return xchk_setup_ag_btree(sc, ip, false); 35 } 36 37 /* Free space btree scrubber. */ 38 /* 39 * Ensure there's a corresponding cntbt/bnobt record matching this 40 * bnobt/cntbt record, respectively. 41 */ 42 STATIC void 43 xchk_allocbt_xref_other( 44 struct xfs_scrub *sc, 45 xfs_agblock_t agbno, 46 xfs_extlen_t len) 47 { 48 struct xfs_btree_cur **pcur; 49 xfs_agblock_t fbno; 50 xfs_extlen_t flen; 51 int has_otherrec; 52 int error; 53 54 if (sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT) 55 pcur = &sc->sa.cnt_cur; 56 else 57 pcur = &sc->sa.bno_cur; 58 if (!*pcur || xchk_skip_xref(sc->sm)) 59 return; 60 61 error = xfs_alloc_lookup_le(*pcur, agbno, len, &has_otherrec); 62 if (!xchk_should_check_xref(sc, &error, pcur)) 63 return; 64 if (!has_otherrec) { 65 xchk_btree_xref_set_corrupt(sc, *pcur, 0); 66 return; 67 } 68 69 error = xfs_alloc_get_rec(*pcur, &fbno, &flen, &has_otherrec); 70 if (!xchk_should_check_xref(sc, &error, pcur)) 71 return; 72 if (!has_otherrec) { 73 xchk_btree_xref_set_corrupt(sc, *pcur, 0); 74 return; 75 } 76 77 if (fbno != agbno || flen != len) 78 xchk_btree_xref_set_corrupt(sc, *pcur, 0); 79 } 80 81 /* Cross-reference with the other btrees. */ 82 STATIC void 83 xchk_allocbt_xref( 84 struct xfs_scrub *sc, 85 xfs_agblock_t agbno, 86 xfs_extlen_t len) 87 { 88 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 89 return; 90 91 xchk_allocbt_xref_other(sc, agbno, len); 92 xchk_xref_is_not_inode_chunk(sc, agbno, len); 93 xchk_xref_has_no_owner(sc, agbno, len); 94 xchk_xref_is_not_shared(sc, agbno, len); 95 } 96 97 /* Scrub a bnobt/cntbt record. */ 98 STATIC int 99 xchk_allocbt_rec( 100 struct xchk_btree *bs, 101 union xfs_btree_rec *rec) 102 { 103 struct xfs_mount *mp = bs->cur->bc_mp; 104 xfs_agnumber_t agno = bs->cur->bc_private.a.agno; 105 xfs_agblock_t bno; 106 xfs_extlen_t len; 107 int error = 0; 108 109 bno = be32_to_cpu(rec->alloc.ar_startblock); 110 len = be32_to_cpu(rec->alloc.ar_blockcount); 111 112 if (bno + len <= bno || 113 !xfs_verify_agbno(mp, agno, bno) || 114 !xfs_verify_agbno(mp, agno, bno + len - 1)) 115 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 116 117 xchk_allocbt_xref(bs->sc, bno, len); 118 119 return error; 120 } 121 122 /* Scrub the freespace btrees for some AG. */ 123 STATIC int 124 xchk_allocbt( 125 struct xfs_scrub *sc, 126 xfs_btnum_t which) 127 { 128 struct xfs_btree_cur *cur; 129 130 cur = which == XFS_BTNUM_BNO ? sc->sa.bno_cur : sc->sa.cnt_cur; 131 return xchk_btree(sc, cur, xchk_allocbt_rec, &XFS_RMAP_OINFO_AG, NULL); 132 } 133 134 int 135 xchk_bnobt( 136 struct xfs_scrub *sc) 137 { 138 return xchk_allocbt(sc, XFS_BTNUM_BNO); 139 } 140 141 int 142 xchk_cntbt( 143 struct xfs_scrub *sc) 144 { 145 return xchk_allocbt(sc, XFS_BTNUM_CNT); 146 } 147 148 /* xref check that the extent is not free */ 149 void 150 xchk_xref_is_used_space( 151 struct xfs_scrub *sc, 152 xfs_agblock_t agbno, 153 xfs_extlen_t len) 154 { 155 bool is_freesp; 156 int error; 157 158 if (!sc->sa.bno_cur || xchk_skip_xref(sc->sm)) 159 return; 160 161 error = xfs_alloc_has_record(sc->sa.bno_cur, agbno, len, &is_freesp); 162 if (!xchk_should_check_xref(sc, &error, &sc->sa.bno_cur)) 163 return; 164 if (is_freesp) 165 xchk_btree_xref_set_corrupt(sc, sc->sa.bno_cur, 0); 166 } 167