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 120457 : rcbag_init(
33 : struct xfs_mount *mp,
34 : struct xfs_buftarg *target,
35 : struct rcbag **bagp)
36 : {
37 120457 : struct rcbag *bag;
38 120457 : int error;
39 :
40 120457 : bag = kmalloc(sizeof(struct rcbag), XCHK_GFP_FLAGS);
41 120446 : if (!bag)
42 : return -ENOMEM;
43 :
44 120446 : bag->nr_items = 0;
45 120446 : bag->mp = mp;
46 :
47 120446 : error = rcbagbt_mem_create(mp, target, &bag->xfbtree);
48 120325 : if (error)
49 0 : goto out_bag;
50 :
51 120325 : *bagp = bag;
52 120325 : return 0;
53 :
54 : out_bag:
55 0 : kfree(bag);
56 0 : return error;
57 : }
58 :
59 : void
60 120103 : rcbag_free(
61 : struct rcbag **bagp)
62 : {
63 120103 : struct rcbag *bag = *bagp;
64 :
65 120103 : xfbtree_destroy(bag->xfbtree);
66 120361 : kfree(bag);
67 120275 : *bagp = NULL;
68 120275 : }
69 :
70 : /* Track an rmap in the refcount bag. */
71 : int
72 352817417 : rcbag_add(
73 : struct rcbag *bag,
74 : struct xfs_trans *tp,
75 : const struct xfs_rmap_irec *rmap)
76 : {
77 352817417 : struct rcbag_rec bagrec;
78 352817417 : struct xfs_mount *mp = bag->mp;
79 352817417 : struct xfs_buf *head_bp;
80 352817417 : struct xfs_btree_cur *cur;
81 352817417 : int has;
82 352817417 : int error;
83 :
84 352817417 : error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
85 352814759 : if (error)
86 : return error;
87 :
88 352815169 : cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
89 352820544 : error = rcbagbt_lookup_eq(cur, rmap, &has);
90 352816939 : if (error)
91 0 : goto out_cur;
92 :
93 352816939 : if (has) {
94 67704813 : error = rcbagbt_get_rec(cur, &bagrec, &has);
95 67703737 : if (error)
96 0 : goto out_cur;
97 67703737 : if (!has) {
98 0 : error = -EFSCORRUPTED;
99 0 : goto out_cur;
100 : }
101 :
102 67703737 : bagrec.rbg_refcount++;
103 67703737 : error = rcbagbt_update(cur, &bagrec);
104 67704445 : if (error)
105 0 : goto out_cur;
106 : } else {
107 285112126 : bagrec.rbg_startblock = rmap->rm_startblock;
108 285112126 : bagrec.rbg_blockcount = rmap->rm_blockcount;
109 285112126 : bagrec.rbg_refcount = 1;
110 :
111 285112126 : error = rcbagbt_insert(cur, &bagrec, &has);
112 285107336 : if (error)
113 0 : goto out_cur;
114 285107336 : if (!has) {
115 0 : error = -EFSCORRUPTED;
116 0 : goto out_cur;
117 : }
118 : }
119 :
120 352811781 : xfs_btree_del_cursor(cur, 0);
121 352812939 : xfs_trans_brelse(tp, head_bp);
122 :
123 352817098 : error = xfbtree_trans_commit(bag->xfbtree, tp);
124 352815338 : if (error)
125 : return error;
126 :
127 352815338 : bag->nr_items++;
128 352815338 : 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 1133846718 : rcbag_count(
139 : const struct rcbag *rcbag)
140 : {
141 1133846718 : 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 283432207 : 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 283432207 : struct rcbag_rec bagrec;
159 283432207 : struct xfs_mount *mp = bag->mp;
160 283432207 : struct xfs_buf *head_bp;
161 283432207 : struct xfs_btree_cur *cur;
162 283432207 : uint32_t next_bno = NULLAGBLOCK;
163 283432207 : int has;
164 283432207 : int error;
165 :
166 283432207 : if (next_valid)
167 283339461 : next_bno = next_rmap->rm_startblock;
168 :
169 283432207 : error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
170 283431857 : if (error)
171 : return error;
172 :
173 283432214 : cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
174 283438330 : error = xfs_btree_goto_left_edge(cur);
175 283430817 : if (error)
176 0 : goto out_cur;
177 :
178 909926433 : while (true) {
179 596678625 : error = xfs_btree_increment(cur, 0, &has);
180 596673450 : if (error)
181 0 : goto out_cur;
182 596673450 : if (!has)
183 : break;
184 :
185 313249697 : error = rcbagbt_get_rec(cur, &bagrec, &has);
186 313247808 : if (error)
187 0 : goto out_cur;
188 313247808 : if (!has) {
189 0 : error = -EFSCORRUPTED;
190 0 : goto out_cur;
191 : }
192 :
193 313247808 : 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 283423753 : if (next_bno == NULLAGBLOCK) {
203 0 : error = -EFSCORRUPTED;
204 0 : goto out_cur;
205 : }
206 :
207 283423753 : xfs_btree_del_cursor(cur, 0);
208 283433449 : xfs_trans_brelse(tp, head_bp);
209 :
210 283435977 : *next_bnop = next_bno;
211 283435977 : 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 283435630 : rcbag_remove_ending_at(
222 : struct rcbag *bag,
223 : struct xfs_trans *tp,
224 : uint32_t next_bno)
225 : {
226 283435630 : struct rcbag_rec bagrec;
227 283435630 : struct xfs_mount *mp = bag->mp;
228 283435630 : struct xfs_buf *head_bp;
229 283435630 : struct xfs_btree_cur *cur;
230 283435630 : int has;
231 283435630 : int error;
232 :
233 283435630 : error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
234 283431540 : if (error)
235 : return error;
236 :
237 : /* go to the right edge of the tree */
238 283431794 : cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
239 283438219 : memset(&cur->bc_rec, 0xFF, sizeof(cur->bc_rec));
240 283438219 : error = xfs_btree_lookup(cur, XFS_LOOKUP_GE, &has);
241 283427686 : if (error)
242 0 : goto out_cur;
243 :
244 596682092 : while (true) {
245 596682092 : error = xfs_btree_decrement(cur, 0, &has);
246 596682948 : if (error)
247 0 : goto out_cur;
248 596682948 : if (!has)
249 : break;
250 :
251 313251676 : error = rcbagbt_get_rec(cur, &bagrec, &has);
252 313251547 : if (error)
253 0 : goto out_cur;
254 313251547 : if (!has) {
255 0 : error = -EFSCORRUPTED;
256 0 : goto out_cur;
257 : }
258 :
259 313251547 : if (BAGREC_NEXT(&bagrec) != next_bno)
260 28143707 : continue;
261 :
262 285107840 : error = xfs_btree_delete(cur, &has);
263 285110699 : if (error)
264 0 : goto out_cur;
265 285110699 : if (!has) {
266 0 : error = -EFSCORRUPTED;
267 0 : goto out_cur;
268 : }
269 :
270 285110699 : bag->nr_items -= bagrec.rbg_refcount;
271 : }
272 :
273 283431272 : xfs_btree_del_cursor(cur, 0);
274 283432417 : xfs_trans_brelse(tp, head_bp);
275 283435585 : 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 : }
|