Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Copyright (C) 2022-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_log_format.h"
11 : #include "xfs_trans.h"
12 : #include "xfs_trans_resv.h"
13 : #include "xfs_mount.h"
14 : #include "xfs_defer.h"
15 : #include "xfs_btree.h"
16 : #include "xfs_btree_mem.h"
17 : #include "xfs_error.h"
18 : #include "scrub/scrub.h"
19 : #include "scrub/xfile.h"
20 : #include "scrub/xfbtree.h"
21 : #include "scrub/rcbag_btree.h"
22 : #include "scrub/rcbag.h"
23 : #include "scrub/trace.h"
24 :
25 : struct rcbag {
26 : struct xfs_mount *mp;
27 : struct xfbtree *xfbtree;
28 : uint64_t nr_items;
29 : };
30 :
31 : int
32 65969 : rcbag_init(
33 : struct xfs_mount *mp,
34 : struct xfs_buftarg *target,
35 : struct rcbag **bagp)
36 : {
37 65969 : struct rcbag *bag;
38 65969 : int error;
39 :
40 65969 : bag = kmalloc(sizeof(struct rcbag), XCHK_GFP_FLAGS);
41 65969 : if (!bag)
42 : return -ENOMEM;
43 :
44 65969 : bag->nr_items = 0;
45 65969 : bag->mp = mp;
46 :
47 65969 : error = rcbagbt_mem_create(mp, target, &bag->xfbtree);
48 65968 : if (error)
49 0 : goto out_bag;
50 :
51 65968 : *bagp = bag;
52 65968 : return 0;
53 :
54 : out_bag:
55 0 : kfree(bag);
56 0 : return error;
57 : }
58 :
59 : void
60 65962 : rcbag_free(
61 : struct rcbag **bagp)
62 : {
63 65962 : struct rcbag *bag = *bagp;
64 :
65 65962 : xfbtree_destroy(bag->xfbtree);
66 65969 : kfree(bag);
67 65969 : *bagp = NULL;
68 65969 : }
69 :
70 : /* Track an rmap in the refcount bag. */
71 : int
72 361612107 : rcbag_add(
73 : struct rcbag *bag,
74 : struct xfs_trans *tp,
75 : const struct xfs_rmap_irec *rmap)
76 : {
77 361612107 : struct rcbag_rec bagrec;
78 361612107 : struct xfs_mount *mp = bag->mp;
79 361612107 : struct xfs_buf *head_bp;
80 361612107 : struct xfs_btree_cur *cur;
81 361612107 : int has;
82 361612107 : int error;
83 :
84 361612107 : error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
85 361612107 : if (error)
86 : return error;
87 :
88 361612107 : cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
89 361612106 : error = rcbagbt_lookup_eq(cur, rmap, &has);
90 361612107 : if (error)
91 0 : goto out_cur;
92 :
93 361612107 : if (has) {
94 29363159 : error = rcbagbt_get_rec(cur, &bagrec, &has);
95 29363159 : if (error)
96 0 : goto out_cur;
97 29363159 : if (!has) {
98 0 : error = -EFSCORRUPTED;
99 0 : goto out_cur;
100 : }
101 :
102 29363159 : bagrec.rbg_refcount++;
103 29363159 : error = rcbagbt_update(cur, &bagrec);
104 29363159 : if (error)
105 0 : goto out_cur;
106 : } else {
107 332248948 : bagrec.rbg_startblock = rmap->rm_startblock;
108 332248948 : bagrec.rbg_blockcount = rmap->rm_blockcount;
109 332248948 : bagrec.rbg_refcount = 1;
110 :
111 332248948 : error = rcbagbt_insert(cur, &bagrec, &has);
112 332248948 : if (error)
113 0 : goto out_cur;
114 332248948 : if (!has) {
115 0 : error = -EFSCORRUPTED;
116 0 : goto out_cur;
117 : }
118 : }
119 :
120 361612107 : xfs_btree_del_cursor(cur, 0);
121 361612105 : xfs_trans_brelse(tp, head_bp);
122 :
123 361612107 : error = xfbtree_trans_commit(bag->xfbtree, tp);
124 361612106 : if (error)
125 : return error;
126 :
127 361612106 : bag->nr_items++;
128 361612106 : return 0;
129 :
130 0 : out_cur:
131 0 : xfs_btree_del_cursor(cur, error);
132 0 : xfs_trans_brelse(tp, head_bp);
133 0 : xfbtree_trans_cancel(bag->xfbtree, tp);
134 0 : return error;
135 : }
136 :
137 : uint64_t
138 1327413299 : rcbag_count(
139 : const struct rcbag *rcbag)
140 : {
141 1327413299 : return rcbag->nr_items;
142 : }
143 :
144 : #define BAGREC_NEXT(r) ((r)->rbg_startblock + (r)->rbg_blockcount)
145 :
146 : /*
147 : * Find the next block where the refcount changes, given the next rmap we
148 : * looked at and the ones we're already tracking.
149 : */
150 : int
151 331836919 : rcbag_next_edge(
152 : struct rcbag *bag,
153 : struct xfs_trans *tp,
154 : const struct xfs_rmap_irec *next_rmap,
155 : bool next_valid,
156 : uint32_t *next_bnop)
157 : {
158 331836919 : struct rcbag_rec bagrec;
159 331836919 : struct xfs_mount *mp = bag->mp;
160 331836919 : struct xfs_buf *head_bp;
161 331836919 : struct xfs_btree_cur *cur;
162 331836919 : uint32_t next_bno = NULLAGBLOCK;
163 331836919 : int has;
164 331836919 : int error;
165 :
166 331836919 : if (next_valid)
167 331780441 : next_bno = next_rmap->rm_startblock;
168 :
169 331836919 : error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
170 331836922 : if (error)
171 : return error;
172 :
173 331836668 : cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
174 331836921 : error = xfs_btree_goto_left_edge(cur);
175 331836922 : if (error)
176 0 : goto out_cur;
177 :
178 1020395780 : while (true) {
179 676116351 : error = xfs_btree_increment(cur, 0, &has);
180 676116351 : if (error)
181 0 : goto out_cur;
182 676116351 : if (!has)
183 : break;
184 :
185 344279430 : error = rcbagbt_get_rec(cur, &bagrec, &has);
186 344279429 : if (error)
187 0 : goto out_cur;
188 344279429 : if (!has) {
189 0 : error = -EFSCORRUPTED;
190 0 : goto out_cur;
191 : }
192 :
193 344279429 : next_bno = min(next_bno, BAGREC_NEXT(&bagrec));
194 : }
195 :
196 : /*
197 : * We should have found /something/ because either next_rrm is the next
198 : * interesting rmap to look at after emitting this refcount extent, or
199 : * there are other rmaps in rmap_bag contributing to the current
200 : * sharing count. But if something is seriously wrong, bail out.
201 : */
202 331836921 : if (next_bno == NULLAGBLOCK) {
203 0 : error = -EFSCORRUPTED;
204 0 : goto out_cur;
205 : }
206 :
207 331836921 : xfs_btree_del_cursor(cur, 0);
208 331836921 : xfs_trans_brelse(tp, head_bp);
209 :
210 331836921 : *next_bnop = next_bno;
211 331836921 : return 0;
212 :
213 0 : out_cur:
214 0 : xfs_btree_del_cursor(cur, error);
215 0 : xfs_trans_brelse(tp, head_bp);
216 0 : return error;
217 : }
218 :
219 : /* Pop all refcount bag records that end at next_bno */
220 : int
221 331836920 : rcbag_remove_ending_at(
222 : struct rcbag *bag,
223 : struct xfs_trans *tp,
224 : uint32_t next_bno)
225 : {
226 331836920 : struct rcbag_rec bagrec;
227 331836920 : struct xfs_mount *mp = bag->mp;
228 331836920 : struct xfs_buf *head_bp;
229 331836920 : struct xfs_btree_cur *cur;
230 331836920 : int has;
231 331836920 : int error;
232 :
233 331836920 : error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
234 331836922 : if (error)
235 : return error;
236 :
237 : /* go to the right edge of the tree */
238 331836922 : cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
239 331836922 : memset(&cur->bc_rec, 0xFF, sizeof(cur->bc_rec));
240 331836922 : error = xfs_btree_lookup(cur, XFS_LOOKUP_GE, &has);
241 331836922 : if (error)
242 0 : goto out_cur;
243 :
244 676116352 : while (true) {
245 676116352 : error = xfs_btree_decrement(cur, 0, &has);
246 676116352 : if (error)
247 0 : goto out_cur;
248 676116352 : if (!has)
249 : break;
250 :
251 344279430 : error = rcbagbt_get_rec(cur, &bagrec, &has);
252 344279429 : if (error)
253 0 : goto out_cur;
254 344279429 : if (!has) {
255 0 : error = -EFSCORRUPTED;
256 0 : goto out_cur;
257 : }
258 :
259 344279429 : if (BAGREC_NEXT(&bagrec) != next_bno)
260 12030482 : continue;
261 :
262 332248947 : error = xfs_btree_delete(cur, &has);
263 332248948 : if (error)
264 0 : goto out_cur;
265 332248948 : if (!has) {
266 0 : error = -EFSCORRUPTED;
267 0 : goto out_cur;
268 : }
269 :
270 332248948 : bag->nr_items -= bagrec.rbg_refcount;
271 : }
272 :
273 331836922 : xfs_btree_del_cursor(cur, 0);
274 331836921 : xfs_trans_brelse(tp, head_bp);
275 331836922 : return xfbtree_trans_commit(bag->xfbtree, tp);
276 0 : out_cur:
277 0 : xfs_btree_del_cursor(cur, error);
278 0 : xfs_trans_brelse(tp, head_bp);
279 0 : xfbtree_trans_cancel(bag->xfbtree, tp);
280 0 : return error;
281 : }
282 :
283 : /* Dump the rcbag. */
284 : void
285 0 : rcbag_dump(
286 : struct rcbag *bag,
287 : struct xfs_trans *tp)
288 : {
289 0 : struct rcbag_rec bagrec;
290 0 : struct xfs_mount *mp = bag->mp;
291 0 : struct xfs_buf *head_bp;
292 0 : struct xfs_btree_cur *cur;
293 0 : unsigned long long nr = 0;
294 0 : int has;
295 0 : int error;
296 :
297 0 : error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
298 0 : if (error)
299 0 : return;
300 :
301 0 : cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
302 0 : error = xfs_btree_goto_left_edge(cur);
303 0 : if (error)
304 0 : goto out_cur;
305 :
306 0 : while (true) {
307 0 : error = xfs_btree_increment(cur, 0, &has);
308 0 : if (error)
309 0 : goto out_cur;
310 0 : if (!has)
311 : break;
312 :
313 0 : error = rcbagbt_get_rec(cur, &bagrec, &has);
314 0 : if (error)
315 0 : goto out_cur;
316 0 : if (!has) {
317 0 : error = -EFSCORRUPTED;
318 0 : goto out_cur;
319 : }
320 :
321 0 : xfs_err(bag->mp, "[%llu]: bno 0x%x fsbcount 0x%x refcount 0x%llx\n",
322 : nr++,
323 : (unsigned int)bagrec.rbg_startblock,
324 : (unsigned int)bagrec.rbg_blockcount,
325 : (unsigned long long)bagrec.rbg_refcount);
326 : }
327 :
328 0 : out_cur:
329 0 : xfs_btree_del_cursor(cur, error);
330 0 : xfs_trans_brelse(tp, head_bp);
331 : }
|