Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Copyright (C) 2017-2023 Oracle. All Rights Reserved.
4 : * Author: Darrick J. Wong <djwong@kernel.org>
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_btree.h"
13 : #include "xfs_alloc.h"
14 : #include "xfs_rmap.h"
15 : #include "scrub/scrub.h"
16 : #include "scrub/common.h"
17 : #include "scrub/btree.h"
18 : #include "xfs_ag.h"
19 :
20 : /*
21 : * Set us up to scrub free space btrees.
22 : */
23 : int
24 1820280 : xchk_setup_ag_allocbt(
25 : struct xfs_scrub *sc)
26 : {
27 1820280 : if (xchk_need_intent_drain(sc))
28 9967 : xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
29 :
30 1820280 : return xchk_setup_ag_btree(sc, false);
31 : }
32 :
33 : /* Free space btree scrubber. */
34 :
35 : struct xchk_alloc {
36 : /* Previous free space extent. */
37 : struct xfs_alloc_rec_incore prev;
38 : };
39 :
40 : /*
41 : * Ensure there's a corresponding cntbt/bnobt record matching this
42 : * bnobt/cntbt record, respectively.
43 : */
44 : STATIC void
45 327558495 : xchk_allocbt_xref_other(
46 : struct xfs_scrub *sc,
47 : xfs_agblock_t agbno,
48 : xfs_extlen_t len)
49 : {
50 327558495 : struct xfs_btree_cur **pcur;
51 327558495 : xfs_agblock_t fbno;
52 327558495 : xfs_extlen_t flen;
53 327558495 : int has_otherrec;
54 327558495 : int error;
55 :
56 327558495 : if (sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT)
57 162576543 : pcur = &sc->sa.cnt_cur;
58 : else
59 164981952 : pcur = &sc->sa.bno_cur;
60 327558495 : if (!*pcur || xchk_skip_xref(sc->sm))
61 26592 : return;
62 :
63 327531903 : error = xfs_alloc_lookup_le(*pcur, agbno, len, &has_otherrec);
64 327552006 : if (!xchk_should_check_xref(sc, &error, pcur))
65 : return;
66 327533770 : if (!has_otherrec) {
67 0 : xchk_btree_xref_set_corrupt(sc, *pcur, 0);
68 0 : return;
69 : }
70 :
71 327533770 : error = xfs_alloc_get_rec(*pcur, &fbno, &flen, &has_otherrec);
72 327481052 : if (!xchk_should_check_xref(sc, &error, pcur))
73 : return;
74 327508741 : if (!has_otherrec) {
75 0 : xchk_btree_xref_set_corrupt(sc, *pcur, 0);
76 0 : return;
77 : }
78 :
79 327508741 : if (fbno != agbno || flen != len)
80 2459 : xchk_btree_xref_set_corrupt(sc, *pcur, 0);
81 : }
82 :
83 : /* Cross-reference with the other btrees. */
84 : STATIC void
85 327471428 : xchk_allocbt_xref(
86 : struct xfs_scrub *sc,
87 : const struct xfs_alloc_rec_incore *irec)
88 : {
89 327471428 : xfs_agblock_t agbno = irec->ar_startblock;
90 327471428 : xfs_extlen_t len = irec->ar_blockcount;
91 :
92 327471428 : if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
93 : return;
94 :
95 327474445 : xchk_allocbt_xref_other(sc, agbno, len);
96 327551234 : xchk_xref_is_not_inode_chunk(sc, agbno, len);
97 327594659 : xchk_xref_has_no_owner(sc, agbno, len);
98 327562823 : xchk_xref_is_not_shared(sc, agbno, len);
99 327550796 : xchk_xref_is_not_cow_staging(sc, agbno, len);
100 : }
101 :
102 : /* Flag failures for records that could be merged. */
103 : STATIC void
104 327470022 : xchk_allocbt_mergeable(
105 : struct xchk_btree *bs,
106 : struct xchk_alloc *ca,
107 : const struct xfs_alloc_rec_incore *irec)
108 : {
109 327470022 : if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
110 : return;
111 :
112 327470022 : if (ca->prev.ar_blockcount > 0 &&
113 325630184 : ca->prev.ar_startblock + ca->prev.ar_blockcount == irec->ar_startblock &&
114 0 : ca->prev.ar_blockcount + irec->ar_blockcount < (uint32_t)~0U)
115 0 : xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
116 :
117 654940044 : memcpy(&ca->prev, irec, sizeof(*irec));
118 : }
119 :
120 : /* Scrub a bnobt/cntbt record. */
121 : STATIC int
122 327491792 : xchk_allocbt_rec(
123 : struct xchk_btree *bs,
124 : const union xfs_btree_rec *rec)
125 : {
126 327491792 : struct xfs_alloc_rec_incore irec;
127 327491792 : struct xchk_alloc *ca = bs->private;
128 :
129 327491792 : xfs_alloc_btrec_to_irec(rec, &irec);
130 327398486 : if (xfs_alloc_check_irec(bs->cur, &irec) != NULL) {
131 0 : xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
132 0 : return 0;
133 : }
134 :
135 327443329 : xchk_allocbt_mergeable(bs, ca, &irec);
136 327469557 : xchk_allocbt_xref(bs->sc, &irec);
137 :
138 327469557 : return 0;
139 : }
140 :
141 : /* Scrub the freespace btrees for some AG. */
142 : STATIC int
143 1804641 : xchk_allocbt(
144 : struct xfs_scrub *sc,
145 : xfs_btnum_t which)
146 : {
147 1804641 : struct xchk_alloc ca = { };
148 1804641 : struct xfs_btree_cur *cur;
149 :
150 1804641 : cur = which == XFS_BTNUM_BNO ? sc->sa.bno_cur : sc->sa.cnt_cur;
151 1804641 : return xchk_btree(sc, cur, xchk_allocbt_rec, &XFS_RMAP_OINFO_AG, &ca);
152 : }
153 :
154 : int
155 901451 : xchk_bnobt(
156 : struct xfs_scrub *sc)
157 : {
158 901451 : return xchk_allocbt(sc, XFS_BTNUM_BNO);
159 : }
160 :
161 : int
162 906231 : xchk_cntbt(
163 : struct xfs_scrub *sc)
164 : {
165 906231 : return xchk_allocbt(sc, XFS_BTNUM_CNT);
166 : }
167 :
168 : /* xref check that the extent is not free */
169 : void
170 1480641913 : xchk_xref_is_used_space(
171 : struct xfs_scrub *sc,
172 : xfs_agblock_t agbno,
173 : xfs_extlen_t len)
174 : {
175 1480641913 : enum xbtree_recpacking outcome;
176 1480641913 : int error;
177 :
178 1480641913 : if (!sc->sa.bno_cur || xchk_skip_xref(sc->sm))
179 0 : return;
180 :
181 1480641913 : error = xfs_alloc_has_records(sc->sa.bno_cur, agbno, len, &outcome);
182 1481472040 : if (!xchk_should_check_xref(sc, &error, &sc->sa.bno_cur))
183 : return;
184 1478945062 : if (outcome != XBTREE_RECPACKING_EMPTY)
185 0 : xchk_btree_xref_set_corrupt(sc, sc->sa.bno_cur, 0);
186 : }
|