]>
Commit | Line | Data |
---|---|---|
0b61f8a4 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
efa7a99c DW |
2 | /* |
3 | * Copyright (C) 2017 Oracle. All Rights Reserved. | |
efa7a99c | 4 | * Author: Darrick J. Wong <[email protected]> |
efa7a99c DW |
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 | |
c517b3aa | 30 | xchk_setup_ag_allocbt( |
1d8a748a | 31 | struct xfs_scrub *sc, |
032d91f9 | 32 | struct xfs_inode *ip) |
efa7a99c | 33 | { |
c517b3aa | 34 | return xchk_setup_ag_btree(sc, ip, false); |
efa7a99c DW |
35 | } |
36 | ||
37 | /* Free space btree scrubber. */ | |
e1134b12 DW |
38 | /* |
39 | * Ensure there's a corresponding cntbt/bnobt record matching this | |
40 | * bnobt/cntbt record, respectively. | |
41 | */ | |
42 | STATIC void | |
c517b3aa | 43 | xchk_allocbt_xref_other( |
1d8a748a | 44 | struct xfs_scrub *sc, |
032d91f9 DW |
45 | xfs_agblock_t agbno, |
46 | xfs_extlen_t len) | |
e1134b12 | 47 | { |
032d91f9 DW |
48 | struct xfs_btree_cur **pcur; |
49 | xfs_agblock_t fbno; | |
50 | xfs_extlen_t flen; | |
51 | int has_otherrec; | |
52 | int error; | |
e1134b12 DW |
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; | |
c517b3aa | 58 | if (!*pcur || xchk_skip_xref(sc->sm)) |
e1134b12 DW |
59 | return; |
60 | ||
61 | error = xfs_alloc_lookup_le(*pcur, agbno, len, &has_otherrec); | |
c517b3aa | 62 | if (!xchk_should_check_xref(sc, &error, pcur)) |
e1134b12 DW |
63 | return; |
64 | if (!has_otherrec) { | |
c517b3aa | 65 | xchk_btree_xref_set_corrupt(sc, *pcur, 0); |
e1134b12 DW |
66 | return; |
67 | } | |
68 | ||
69 | error = xfs_alloc_get_rec(*pcur, &fbno, &flen, &has_otherrec); | |
c517b3aa | 70 | if (!xchk_should_check_xref(sc, &error, pcur)) |
e1134b12 DW |
71 | return; |
72 | if (!has_otherrec) { | |
c517b3aa | 73 | xchk_btree_xref_set_corrupt(sc, *pcur, 0); |
e1134b12 DW |
74 | return; |
75 | } | |
76 | ||
77 | if (fbno != agbno || flen != len) | |
c517b3aa | 78 | xchk_btree_xref_set_corrupt(sc, *pcur, 0); |
e1134b12 | 79 | } |
efa7a99c | 80 | |
166d7641 DW |
81 | /* Cross-reference with the other btrees. */ |
82 | STATIC void | |
c517b3aa | 83 | xchk_allocbt_xref( |
1d8a748a | 84 | struct xfs_scrub *sc, |
032d91f9 DW |
85 | xfs_agblock_t agbno, |
86 | xfs_extlen_t len) | |
166d7641 DW |
87 | { |
88 | if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) | |
89 | return; | |
e1134b12 | 90 | |
c517b3aa DW |
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); | |
166d7641 DW |
95 | } |
96 | ||
efa7a99c DW |
97 | /* Scrub a bnobt/cntbt record. */ |
98 | STATIC int | |
c517b3aa | 99 | xchk_allocbt_rec( |
032d91f9 DW |
100 | struct xchk_btree *bs, |
101 | union xfs_btree_rec *rec) | |
efa7a99c | 102 | { |
032d91f9 DW |
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; | |
efa7a99c DW |
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)) | |
c517b3aa | 115 | xchk_btree_set_corrupt(bs->sc, bs->cur, 0); |
efa7a99c | 116 | |
c517b3aa | 117 | xchk_allocbt_xref(bs->sc, bno, len); |
166d7641 | 118 | |
efa7a99c DW |
119 | return error; |
120 | } | |
121 | ||
122 | /* Scrub the freespace btrees for some AG. */ | |
123 | STATIC int | |
c517b3aa | 124 | xchk_allocbt( |
1d8a748a | 125 | struct xfs_scrub *sc, |
032d91f9 | 126 | xfs_btnum_t which) |
efa7a99c | 127 | { |
032d91f9 | 128 | struct xfs_btree_cur *cur; |
efa7a99c | 129 | |
efa7a99c | 130 | cur = which == XFS_BTNUM_BNO ? sc->sa.bno_cur : sc->sa.cnt_cur; |
7280feda | 131 | return xchk_btree(sc, cur, xchk_allocbt_rec, &XFS_RMAP_OINFO_AG, NULL); |
efa7a99c DW |
132 | } |
133 | ||
134 | int | |
c517b3aa | 135 | xchk_bnobt( |
1d8a748a | 136 | struct xfs_scrub *sc) |
efa7a99c | 137 | { |
c517b3aa | 138 | return xchk_allocbt(sc, XFS_BTNUM_BNO); |
efa7a99c DW |
139 | } |
140 | ||
141 | int | |
c517b3aa | 142 | xchk_cntbt( |
1d8a748a | 143 | struct xfs_scrub *sc) |
efa7a99c | 144 | { |
c517b3aa | 145 | return xchk_allocbt(sc, XFS_BTNUM_CNT); |
efa7a99c | 146 | } |
52dc4b44 DW |
147 | |
148 | /* xref check that the extent is not free */ | |
149 | void | |
c517b3aa | 150 | xchk_xref_is_used_space( |
1d8a748a | 151 | struct xfs_scrub *sc, |
032d91f9 DW |
152 | xfs_agblock_t agbno, |
153 | xfs_extlen_t len) | |
52dc4b44 | 154 | { |
032d91f9 DW |
155 | bool is_freesp; |
156 | int error; | |
52dc4b44 | 157 | |
c517b3aa | 158 | if (!sc->sa.bno_cur || xchk_skip_xref(sc->sm)) |
52dc4b44 DW |
159 | return; |
160 | ||
161 | error = xfs_alloc_has_record(sc->sa.bno_cur, agbno, len, &is_freesp); | |
c517b3aa | 162 | if (!xchk_should_check_xref(sc, &error, &sc->sa.bno_cur)) |
52dc4b44 DW |
163 | return; |
164 | if (is_freesp) | |
c517b3aa | 165 | xchk_btree_xref_set_corrupt(sc, sc->sa.bno_cur, 0); |
52dc4b44 | 166 | } |