]>
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 <darrick.wong@oracle.com> |
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" | |
efa7a99c | 12 | #include "xfs_btree.h" |
efa7a99c DW |
13 | #include "xfs_alloc.h" |
14 | #include "xfs_rmap.h" | |
efa7a99c DW |
15 | #include "scrub/scrub.h" |
16 | #include "scrub/common.h" | |
17 | #include "scrub/btree.h" | |
50f02fe3 | 18 | #include "xfs_ag.h" |
efa7a99c DW |
19 | |
20 | /* | |
21 | * Set us up to scrub free space btrees. | |
22 | */ | |
23 | int | |
c517b3aa | 24 | xchk_setup_ag_allocbt( |
026f57eb | 25 | struct xfs_scrub *sc) |
efa7a99c | 26 | { |
026f57eb | 27 | return xchk_setup_ag_btree(sc, false); |
efa7a99c DW |
28 | } |
29 | ||
30 | /* Free space btree scrubber. */ | |
e1134b12 DW |
31 | /* |
32 | * Ensure there's a corresponding cntbt/bnobt record matching this | |
33 | * bnobt/cntbt record, respectively. | |
34 | */ | |
35 | STATIC void | |
c517b3aa | 36 | xchk_allocbt_xref_other( |
1d8a748a | 37 | struct xfs_scrub *sc, |
032d91f9 DW |
38 | xfs_agblock_t agbno, |
39 | xfs_extlen_t len) | |
e1134b12 | 40 | { |
032d91f9 DW |
41 | struct xfs_btree_cur **pcur; |
42 | xfs_agblock_t fbno; | |
43 | xfs_extlen_t flen; | |
44 | int has_otherrec; | |
45 | int error; | |
e1134b12 DW |
46 | |
47 | if (sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT) | |
48 | pcur = &sc->sa.cnt_cur; | |
49 | else | |
50 | pcur = &sc->sa.bno_cur; | |
c517b3aa | 51 | if (!*pcur || xchk_skip_xref(sc->sm)) |
e1134b12 DW |
52 | return; |
53 | ||
54 | error = xfs_alloc_lookup_le(*pcur, agbno, len, &has_otherrec); | |
c517b3aa | 55 | if (!xchk_should_check_xref(sc, &error, pcur)) |
e1134b12 DW |
56 | return; |
57 | if (!has_otherrec) { | |
c517b3aa | 58 | xchk_btree_xref_set_corrupt(sc, *pcur, 0); |
e1134b12 DW |
59 | return; |
60 | } | |
61 | ||
62 | error = xfs_alloc_get_rec(*pcur, &fbno, &flen, &has_otherrec); | |
c517b3aa | 63 | if (!xchk_should_check_xref(sc, &error, pcur)) |
e1134b12 DW |
64 | return; |
65 | if (!has_otherrec) { | |
c517b3aa | 66 | xchk_btree_xref_set_corrupt(sc, *pcur, 0); |
e1134b12 DW |
67 | return; |
68 | } | |
69 | ||
70 | if (fbno != agbno || flen != len) | |
c517b3aa | 71 | xchk_btree_xref_set_corrupt(sc, *pcur, 0); |
e1134b12 | 72 | } |
efa7a99c | 73 | |
166d7641 DW |
74 | /* Cross-reference with the other btrees. */ |
75 | STATIC void | |
c517b3aa | 76 | xchk_allocbt_xref( |
1d8a748a | 77 | struct xfs_scrub *sc, |
032d91f9 DW |
78 | xfs_agblock_t agbno, |
79 | xfs_extlen_t len) | |
166d7641 DW |
80 | { |
81 | if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) | |
82 | return; | |
e1134b12 | 83 | |
c517b3aa DW |
84 | xchk_allocbt_xref_other(sc, agbno, len); |
85 | xchk_xref_is_not_inode_chunk(sc, agbno, len); | |
86 | xchk_xref_has_no_owner(sc, agbno, len); | |
87 | xchk_xref_is_not_shared(sc, agbno, len); | |
166d7641 DW |
88 | } |
89 | ||
efa7a99c DW |
90 | /* Scrub a bnobt/cntbt record. */ |
91 | STATIC int | |
c517b3aa | 92 | xchk_allocbt_rec( |
032d91f9 | 93 | struct xchk_btree *bs, |
22ece4e8 | 94 | const union xfs_btree_rec *rec) |
efa7a99c | 95 | { |
0800169e | 96 | struct xfs_perag *pag = bs->cur->bc_ag.pag; |
032d91f9 DW |
97 | xfs_agblock_t bno; |
98 | xfs_extlen_t len; | |
efa7a99c DW |
99 | |
100 | bno = be32_to_cpu(rec->alloc.ar_startblock); | |
101 | len = be32_to_cpu(rec->alloc.ar_blockcount); | |
102 | ||
103 | if (bno + len <= bno || | |
0800169e DC |
104 | !xfs_verify_agbno(pag, bno) || |
105 | !xfs_verify_agbno(pag, bno + len - 1)) | |
c517b3aa | 106 | xchk_btree_set_corrupt(bs->sc, bs->cur, 0); |
efa7a99c | 107 | |
c517b3aa | 108 | xchk_allocbt_xref(bs->sc, bno, len); |
166d7641 | 109 | |
583e4eff | 110 | return 0; |
efa7a99c DW |
111 | } |
112 | ||
113 | /* Scrub the freespace btrees for some AG. */ | |
114 | STATIC int | |
c517b3aa | 115 | xchk_allocbt( |
1d8a748a | 116 | struct xfs_scrub *sc, |
032d91f9 | 117 | xfs_btnum_t which) |
efa7a99c | 118 | { |
032d91f9 | 119 | struct xfs_btree_cur *cur; |
efa7a99c | 120 | |
efa7a99c | 121 | cur = which == XFS_BTNUM_BNO ? sc->sa.bno_cur : sc->sa.cnt_cur; |
7280feda | 122 | return xchk_btree(sc, cur, xchk_allocbt_rec, &XFS_RMAP_OINFO_AG, NULL); |
efa7a99c DW |
123 | } |
124 | ||
125 | int | |
c517b3aa | 126 | xchk_bnobt( |
1d8a748a | 127 | struct xfs_scrub *sc) |
efa7a99c | 128 | { |
c517b3aa | 129 | return xchk_allocbt(sc, XFS_BTNUM_BNO); |
efa7a99c DW |
130 | } |
131 | ||
132 | int | |
c517b3aa | 133 | xchk_cntbt( |
1d8a748a | 134 | struct xfs_scrub *sc) |
efa7a99c | 135 | { |
c517b3aa | 136 | return xchk_allocbt(sc, XFS_BTNUM_CNT); |
efa7a99c | 137 | } |
52dc4b44 DW |
138 | |
139 | /* xref check that the extent is not free */ | |
140 | void | |
c517b3aa | 141 | xchk_xref_is_used_space( |
1d8a748a | 142 | struct xfs_scrub *sc, |
032d91f9 DW |
143 | xfs_agblock_t agbno, |
144 | xfs_extlen_t len) | |
52dc4b44 | 145 | { |
032d91f9 DW |
146 | bool is_freesp; |
147 | int error; | |
52dc4b44 | 148 | |
c517b3aa | 149 | if (!sc->sa.bno_cur || xchk_skip_xref(sc->sm)) |
52dc4b44 DW |
150 | return; |
151 | ||
152 | error = xfs_alloc_has_record(sc->sa.bno_cur, agbno, len, &is_freesp); | |
c517b3aa | 153 | if (!xchk_should_check_xref(sc, &error, &sc->sa.bno_cur)) |
52dc4b44 DW |
154 | return; |
155 | if (is_freesp) | |
c517b3aa | 156 | xchk_btree_xref_set_corrupt(sc, sc->sa.bno_cur, 0); |
52dc4b44 | 157 | } |