1 /* 2 * Copyright (C) 2017 Oracle. All Rights Reserved. 3 * 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it would be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 19 */ 20 #include "xfs.h" 21 #include "xfs_fs.h" 22 #include "xfs_shared.h" 23 #include "xfs_format.h" 24 #include "xfs_trans_resv.h" 25 #include "xfs_mount.h" 26 #include "xfs_defer.h" 27 #include "xfs_btree.h" 28 #include "xfs_bit.h" 29 #include "xfs_log_format.h" 30 #include "xfs_trans.h" 31 #include "xfs_sb.h" 32 #include "xfs_alloc.h" 33 #include "xfs_rmap.h" 34 #include "xfs_alloc.h" 35 #include "scrub/xfs_scrub.h" 36 #include "scrub/scrub.h" 37 #include "scrub/common.h" 38 #include "scrub/btree.h" 39 #include "scrub/trace.h" 40 41 /* 42 * Set us up to scrub free space btrees. 43 */ 44 int 45 xfs_scrub_setup_ag_allocbt( 46 struct xfs_scrub_context *sc, 47 struct xfs_inode *ip) 48 { 49 return xfs_scrub_setup_ag_btree(sc, ip, false); 50 } 51 52 /* Free space btree scrubber. */ 53 /* 54 * Ensure there's a corresponding cntbt/bnobt record matching this 55 * bnobt/cntbt record, respectively. 56 */ 57 STATIC void 58 xfs_scrub_allocbt_xref_other( 59 struct xfs_scrub_context *sc, 60 xfs_agblock_t agbno, 61 xfs_extlen_t len) 62 { 63 struct xfs_btree_cur **pcur; 64 xfs_agblock_t fbno; 65 xfs_extlen_t flen; 66 int has_otherrec; 67 int error; 68 69 if (sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT) 70 pcur = &sc->sa.cnt_cur; 71 else 72 pcur = &sc->sa.bno_cur; 73 if (!*pcur) 74 return; 75 76 error = xfs_alloc_lookup_le(*pcur, agbno, len, &has_otherrec); 77 if (!xfs_scrub_should_check_xref(sc, &error, pcur)) 78 return; 79 if (!has_otherrec) { 80 xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0); 81 return; 82 } 83 84 error = xfs_alloc_get_rec(*pcur, &fbno, &flen, &has_otherrec); 85 if (!xfs_scrub_should_check_xref(sc, &error, pcur)) 86 return; 87 if (!has_otherrec) { 88 xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0); 89 return; 90 } 91 92 if (fbno != agbno || flen != len) 93 xfs_scrub_btree_xref_set_corrupt(sc, *pcur, 0); 94 } 95 96 /* Cross-reference with the other btrees. */ 97 STATIC void 98 xfs_scrub_allocbt_xref( 99 struct xfs_scrub_context *sc, 100 xfs_agblock_t agbno, 101 xfs_extlen_t len) 102 { 103 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 104 return; 105 106 xfs_scrub_allocbt_xref_other(sc, agbno, len); 107 xfs_scrub_xref_is_not_inode_chunk(sc, agbno, len); 108 xfs_scrub_xref_has_no_owner(sc, agbno, len); 109 xfs_scrub_xref_is_not_shared(sc, agbno, len); 110 } 111 112 /* Scrub a bnobt/cntbt record. */ 113 STATIC int 114 xfs_scrub_allocbt_rec( 115 struct xfs_scrub_btree *bs, 116 union xfs_btree_rec *rec) 117 { 118 struct xfs_mount *mp = bs->cur->bc_mp; 119 xfs_agnumber_t agno = bs->cur->bc_private.a.agno; 120 xfs_agblock_t bno; 121 xfs_extlen_t len; 122 int error = 0; 123 124 bno = be32_to_cpu(rec->alloc.ar_startblock); 125 len = be32_to_cpu(rec->alloc.ar_blockcount); 126 127 if (bno + len <= bno || 128 !xfs_verify_agbno(mp, agno, bno) || 129 !xfs_verify_agbno(mp, agno, bno + len - 1)) 130 xfs_scrub_btree_set_corrupt(bs->sc, bs->cur, 0); 131 132 xfs_scrub_allocbt_xref(bs->sc, bno, len); 133 134 return error; 135 } 136 137 /* Scrub the freespace btrees for some AG. */ 138 STATIC int 139 xfs_scrub_allocbt( 140 struct xfs_scrub_context *sc, 141 xfs_btnum_t which) 142 { 143 struct xfs_owner_info oinfo; 144 struct xfs_btree_cur *cur; 145 146 xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_AG); 147 cur = which == XFS_BTNUM_BNO ? sc->sa.bno_cur : sc->sa.cnt_cur; 148 return xfs_scrub_btree(sc, cur, xfs_scrub_allocbt_rec, &oinfo, NULL); 149 } 150 151 int 152 xfs_scrub_bnobt( 153 struct xfs_scrub_context *sc) 154 { 155 return xfs_scrub_allocbt(sc, XFS_BTNUM_BNO); 156 } 157 158 int 159 xfs_scrub_cntbt( 160 struct xfs_scrub_context *sc) 161 { 162 return xfs_scrub_allocbt(sc, XFS_BTNUM_CNT); 163 } 164 165 /* xref check that the extent is not free */ 166 void 167 xfs_scrub_xref_is_used_space( 168 struct xfs_scrub_context *sc, 169 xfs_agblock_t agbno, 170 xfs_extlen_t len) 171 { 172 bool is_freesp; 173 int error; 174 175 if (!sc->sa.bno_cur) 176 return; 177 178 error = xfs_alloc_has_record(sc->sa.bno_cur, agbno, len, &is_freesp); 179 if (!xfs_scrub_should_check_xref(sc, &error, &sc->sa.bno_cur)) 180 return; 181 if (is_freesp) 182 xfs_scrub_btree_xref_set_corrupt(sc, sc->sa.bno_cur, 0); 183 } 184