]> Git Repo - linux.git/blob - fs/xfs/scrub/alloc.c
x86/alternative: Make custom return thunk unconditional
[linux.git] / fs / xfs / scrub / alloc.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2017-2023 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <[email protected]>
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 xchk_setup_ag_allocbt(
25         struct xfs_scrub        *sc)
26 {
27         if (xchk_need_intent_drain(sc))
28                 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
29
30         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 xchk_allocbt_xref_other(
46         struct xfs_scrub        *sc,
47         xfs_agblock_t           agbno,
48         xfs_extlen_t            len)
49 {
50         struct xfs_btree_cur    **pcur;
51         xfs_agblock_t           fbno;
52         xfs_extlen_t            flen;
53         int                     has_otherrec;
54         int                     error;
55
56         if (sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT)
57                 pcur = &sc->sa.cnt_cur;
58         else
59                 pcur = &sc->sa.bno_cur;
60         if (!*pcur || xchk_skip_xref(sc->sm))
61                 return;
62
63         error = xfs_alloc_lookup_le(*pcur, agbno, len, &has_otherrec);
64         if (!xchk_should_check_xref(sc, &error, pcur))
65                 return;
66         if (!has_otherrec) {
67                 xchk_btree_xref_set_corrupt(sc, *pcur, 0);
68                 return;
69         }
70
71         error = xfs_alloc_get_rec(*pcur, &fbno, &flen, &has_otherrec);
72         if (!xchk_should_check_xref(sc, &error, pcur))
73                 return;
74         if (!has_otherrec) {
75                 xchk_btree_xref_set_corrupt(sc, *pcur, 0);
76                 return;
77         }
78
79         if (fbno != agbno || flen != len)
80                 xchk_btree_xref_set_corrupt(sc, *pcur, 0);
81 }
82
83 /* Cross-reference with the other btrees. */
84 STATIC void
85 xchk_allocbt_xref(
86         struct xfs_scrub        *sc,
87         const struct xfs_alloc_rec_incore *irec)
88 {
89         xfs_agblock_t           agbno = irec->ar_startblock;
90         xfs_extlen_t            len = irec->ar_blockcount;
91
92         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
93                 return;
94
95         xchk_allocbt_xref_other(sc, agbno, len);
96         xchk_xref_is_not_inode_chunk(sc, agbno, len);
97         xchk_xref_has_no_owner(sc, agbno, len);
98         xchk_xref_is_not_shared(sc, agbno, len);
99         xchk_xref_is_not_cow_staging(sc, agbno, len);
100 }
101
102 /* Flag failures for records that could be merged. */
103 STATIC void
104 xchk_allocbt_mergeable(
105         struct xchk_btree       *bs,
106         struct xchk_alloc       *ca,
107         const struct xfs_alloc_rec_incore *irec)
108 {
109         if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
110                 return;
111
112         if (ca->prev.ar_blockcount > 0 &&
113             ca->prev.ar_startblock + ca->prev.ar_blockcount == irec->ar_startblock &&
114             ca->prev.ar_blockcount + irec->ar_blockcount < (uint32_t)~0U)
115                 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
116
117         memcpy(&ca->prev, irec, sizeof(*irec));
118 }
119
120 /* Scrub a bnobt/cntbt record. */
121 STATIC int
122 xchk_allocbt_rec(
123         struct xchk_btree               *bs,
124         const union xfs_btree_rec       *rec)
125 {
126         struct xfs_alloc_rec_incore     irec;
127         struct xchk_alloc       *ca = bs->private;
128
129         xfs_alloc_btrec_to_irec(rec, &irec);
130         if (xfs_alloc_check_irec(bs->cur, &irec) != NULL) {
131                 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
132                 return 0;
133         }
134
135         xchk_allocbt_mergeable(bs, ca, &irec);
136         xchk_allocbt_xref(bs->sc, &irec);
137
138         return 0;
139 }
140
141 /* Scrub the freespace btrees for some AG. */
142 STATIC int
143 xchk_allocbt(
144         struct xfs_scrub        *sc,
145         xfs_btnum_t             which)
146 {
147         struct xchk_alloc       ca = { };
148         struct xfs_btree_cur    *cur;
149
150         cur = which == XFS_BTNUM_BNO ? sc->sa.bno_cur : sc->sa.cnt_cur;
151         return xchk_btree(sc, cur, xchk_allocbt_rec, &XFS_RMAP_OINFO_AG, &ca);
152 }
153
154 int
155 xchk_bnobt(
156         struct xfs_scrub        *sc)
157 {
158         return xchk_allocbt(sc, XFS_BTNUM_BNO);
159 }
160
161 int
162 xchk_cntbt(
163         struct xfs_scrub        *sc)
164 {
165         return xchk_allocbt(sc, XFS_BTNUM_CNT);
166 }
167
168 /* xref check that the extent is not free */
169 void
170 xchk_xref_is_used_space(
171         struct xfs_scrub        *sc,
172         xfs_agblock_t           agbno,
173         xfs_extlen_t            len)
174 {
175         enum xbtree_recpacking  outcome;
176         int                     error;
177
178         if (!sc->sa.bno_cur || xchk_skip_xref(sc->sm))
179                 return;
180
181         error = xfs_alloc_has_records(sc->sa.bno_cur, agbno, len, &outcome);
182         if (!xchk_should_check_xref(sc, &error, &sc->sa.bno_cur))
183                 return;
184         if (outcome != XBTREE_RECPACKING_EMPTY)
185                 xchk_btree_xref_set_corrupt(sc, sc->sa.bno_cur, 0);
186 }
This page took 0.043037 seconds and 4 git commands to generate.