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 "xfs_alloc.h" 21 #include "scrub/xfs_scrub.h" 22 #include "scrub/scrub.h" 23 #include "scrub/common.h" 24 #include "scrub/btree.h" 25 #include "scrub/trace.h" 26 27 /* 28 * Set us up to scrub free space btrees. 29 */ 30 int 31 xfs_scrub_setup_ag_allocbt( 32 struct xfs_scrub_context *sc, 33 struct xfs_inode *ip) 34 { 35 return xfs_scrub_setup_ag_btree(sc, ip, false); 36 } 37 38 /* Free space btree scrubber. */ 39 /* 40 * Ensure there's a corresponding cntbt/bnobt record matching this 41 * bnobt/cntbt record, respectively. 42 */ 43 STATIC void 44 xfs_scrub_allocbt_xref_other( 45 struct xfs_scrub_context *sc, 46 xfs_agblock_t agbno, 47 xfs_extlen_t len) 48 { 49 struct xfs_btree_cur **pcur; 50 xfs_agblock_t fbno; 51 xfs_extlen_t flen; 52 int has_otherrec; 53 int error; 54 55 if (sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT) 56 pcur = &sc->sa.cnt_cur; 57 else 58 pcur = &sc->sa.bno_cur; 59 if (!*pcur || xfs_scrub_skip_xref(sc->sm)) 60 return; 61 62 error = xfs_alloc_lookup_le(*pcur, agbno, len, &has_otherrec); 63 if (!xfs_scrub_should_check_xref(sc, &error, pcur)) 64 return; 65 if (!has_otherrec) { 66 xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0); 67 return; 68 } 69 70 error = xfs_alloc_get_rec(*pcur, &fbno, &flen, &has_otherrec); 71 if (!xfs_scrub_should_check_xref(sc, &error, pcur)) 72 return; 73 if (!has_otherrec) { 74 xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0); 75 return; 76 } 77 78 if (fbno != agbno || flen != len) 79 xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0); 80 } 81 82 /* Cross-reference with the other btrees. */ 83 STATIC void 84 xfs_scrub_allocbt_xref( 85 struct xfs_scrub_context *sc, 86 xfs_agblock_t agbno, 87 xfs_extlen_t len) 88 { 89 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 90 return; 91 92 xfs_scrub_allocbt_xref_other(sc, agbno, len); 93 xfs_scrub_xref_is_not_inode_chunk(sc, agbno, len); 94 xfs_scrub_xref_has_no_owner(sc, agbno, len); 95 xfs_scrub_xref_is_not_shared(sc, agbno, len); 96 } 97 98 /* Scrub a bnobt/cntbt record. */ 99 STATIC int 100 xfs_scrub_allocbt_rec( 101 struct xfs_scrub_btree *bs, 102 union xfs_btree_rec *rec) 103 { 104 struct xfs_mount *mp = bs->cur->bc_mp; 105 xfs_agnumber_t agno = bs->cur->bc_private.a.agno; 106 xfs_agblock_t bno; 107 xfs_extlen_t len; 108 int error = 0; 109 110 bno = be32_to_cpu(rec->alloc.ar_startblock); 111 len = be32_to_cpu(rec->alloc.ar_blockcount); 112 113 if (bno + len <= bno || 114 !xfs_verify_agbno(mp, agno, bno) || 115 !xfs_verify_agbno(mp, agno, bno + len - 1)) 116 xfs_scrub_btree_set_corrupt(bs->sc, bs->cur, 0); 117 118 xfs_scrub_allocbt_xref(bs->sc, bno, len); 119 120 return error; 121 } 122 123 /* Scrub the freespace btrees for some AG. */ 124 STATIC int 125 xfs_scrub_allocbt( 126 struct xfs_scrub_context *sc, 127 xfs_btnum_t which) 128 { 129 struct xfs_owner_info oinfo; 130 struct xfs_btree_cur *cur; 131 132 xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_AG); 133 cur = which == XFS_BTNUM_BNO ? sc->sa.bno_cur : sc->sa.cnt_cur; 134 return xfs_scrub_btree(sc, cur, xfs_scrub_allocbt_rec, &oinfo, NULL); 135 } 136 137 int 138 xfs_scrub_bnobt( 139 struct xfs_scrub_context *sc) 140 { 141 return xfs_scrub_allocbt(sc, XFS_BTNUM_BNO); 142 } 143 144 int 145 xfs_scrub_cntbt( 146 struct xfs_scrub_context *sc) 147 { 148 return xfs_scrub_allocbt(sc, XFS_BTNUM_CNT); 149 } 150 151 /* xref check that the extent is not free */ 152 void 153 xfs_scrub_xref_is_used_space( 154 struct xfs_scrub_context *sc, 155 xfs_agblock_t agbno, 156 xfs_extlen_t len) 157 { 158 bool is_freesp; 159 int error; 160 161 if (!sc->sa.bno_cur || xfs_scrub_skip_xref(sc->sm)) 162 return; 163 164 error = xfs_alloc_has_record(sc->sa.bno_cur, agbno, len, &is_freesp); 165 if (!xfs_scrub_should_check_xref(sc, &error, &sc->sa.bno_cur)) 166 return; 167 if (is_freesp) 168 xfs_scrub_btree_xref_set_corrupt(sc, sc->sa.bno_cur, 0); 169 } 170