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 30328 : rcbag_init(
33 : struct xfs_mount *mp,
34 : struct xfs_buftarg *target,
35 : struct rcbag **bagp)
36 : {
37 30328 : struct rcbag *bag;
38 30328 : int error;
39 :
40 30328 : bag = kmalloc(sizeof(struct rcbag), XCHK_GFP_FLAGS);
41 30306 : if (!bag)
42 : return -ENOMEM;
43 :
44 30306 : bag->nr_items = 0;
45 30306 : bag->mp = mp;
46 :
47 30306 : error = rcbagbt_mem_create(mp, target, &bag->xfbtree);
48 30316 : if (error)
49 0 : goto out_bag;
50 :
51 30316 : *bagp = bag;
52 30316 : return 0;
53 :
54 : out_bag:
55 0 : kfree(bag);
56 0 : return error;
57 : }
58 :
59 : void
60 30275 : rcbag_free(
61 : struct rcbag **bagp)
62 : {
63 30275 : struct rcbag *bag = *bagp;
64 :
65 30275 : xfbtree_destroy(bag->xfbtree);
66 30302 : kfree(bag);
67 30281 : *bagp = NULL;
68 30281 : }
69 :
70 : /* Track an rmap in the refcount bag. */
71 : int
72 158840067 : rcbag_add(
73 : struct rcbag *bag,
74 : struct xfs_trans *tp,
75 : const struct xfs_rmap_irec *rmap)
76 : {
77 158840067 : struct rcbag_rec bagrec;
78 158840067 : struct xfs_mount *mp = bag->mp;
79 158840067 : struct xfs_buf *head_bp;
80 158840067 : struct xfs_btree_cur *cur;
81 158840067 : int has;
82 158840067 : int error;
83 :
84 158840067 : error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
85 158840138 : if (error)
86 : return error;
87 :
88 158840250 : cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
89 158839938 : error = rcbagbt_lookup_eq(cur, rmap, &has);
90 158840147 : if (error)
91 0 : goto out_cur;
92 :
93 158840147 : if (has) {
94 26152933 : error = rcbagbt_get_rec(cur, &bagrec, &has);
95 26152923 : if (error)
96 0 : goto out_cur;
97 26152923 : if (!has) {
98 0 : error = -EFSCORRUPTED;
99 0 : goto out_cur;
100 : }
101 :
102 26152923 : bagrec.rbg_refcount++;
103 26152923 : error = rcbagbt_update(cur, &bagrec);
104 26152937 : if (error)
105 0 : goto out_cur;
106 : } else {
107 132687214 : bagrec.rbg_startblock = rmap->rm_startblock;
108 132687214 : bagrec.rbg_blockcount = rmap->rm_blockcount;
109 132687214 : bagrec.rbg_refcount = 1;
110 :
111 132687214 : error = rcbagbt_insert(cur, &bagrec, &has);
112 132685508 : if (error)
113 0 : goto out_cur;
114 132685508 : if (!has) {
115 0 : error = -EFSCORRUPTED;
116 0 : goto out_cur;
117 : }
118 : }
119 :
120 158838445 : xfs_btree_del_cursor(cur, 0);
121 158839187 : xfs_trans_brelse(tp, head_bp);
122 :
123 158839947 : error = xfbtree_trans_commit(bag->xfbtree, tp);
124 158840468 : if (error)
125 : return error;
126 :
127 158840468 : bag->nr_items++;
128 158840468 : 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 528645733 : rcbag_count(
139 : const struct rcbag *rcbag)
140 : {
141 528645733 : 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 132154062 : 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 132154062 : struct rcbag_rec bagrec;
159 132154062 : struct xfs_mount *mp = bag->mp;
160 132154062 : struct xfs_buf *head_bp;
161 132154062 : struct xfs_btree_cur *cur;
162 132154062 : uint32_t next_bno = NULLAGBLOCK;
163 132154062 : int has;
164 132154062 : int error;
165 :
166 132154062 : if (next_valid)
167 132133229 : next_bno = next_rmap->rm_startblock;
168 :
169 132154062 : error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
170 132154628 : if (error)
171 : return error;
172 :
173 132154671 : cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
174 132153928 : error = xfs_btree_goto_left_edge(cur);
175 132154222 : if (error)
176 0 : goto out_cur;
177 :
178 427787336 : while (true) {
179 279970779 : error = xfs_btree_increment(cur, 0, &has);
180 279968973 : if (error)
181 0 : goto out_cur;
182 279968973 : if (!has)
183 : break;
184 :
185 147816415 : error = rcbagbt_get_rec(cur, &bagrec, &has);
186 147816557 : if (error)
187 0 : goto out_cur;
188 147816557 : if (!has) {
189 0 : error = -EFSCORRUPTED;
190 0 : goto out_cur;
191 : }
192 :
193 147816557 : 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 132152558 : if (next_bno == NULLAGBLOCK) {
203 0 : error = -EFSCORRUPTED;
204 0 : goto out_cur;
205 : }
206 :
207 132152558 : xfs_btree_del_cursor(cur, 0);
208 132154954 : xfs_trans_brelse(tp, head_bp);
209 :
210 132155168 : *next_bnop = next_bno;
211 132155168 : 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 132154898 : rcbag_remove_ending_at(
222 : struct rcbag *bag,
223 : struct xfs_trans *tp,
224 : uint32_t next_bno)
225 : {
226 132154898 : struct rcbag_rec bagrec;
227 132154898 : struct xfs_mount *mp = bag->mp;
228 132154898 : struct xfs_buf *head_bp;
229 132154898 : struct xfs_btree_cur *cur;
230 132154898 : int has;
231 132154898 : int error;
232 :
233 132154898 : error = xfbtree_head_read_buf(bag->xfbtree, tp, &head_bp);
234 132154525 : if (error)
235 : return error;
236 :
237 : /* go to the right edge of the tree */
238 132154583 : cur = rcbagbt_mem_cursor(mp, tp, head_bp, bag->xfbtree);
239 132154300 : memset(&cur->bc_rec, 0xFF, sizeof(cur->bc_rec));
240 132154300 : error = xfs_btree_lookup(cur, XFS_LOOKUP_GE, &has);
241 132152803 : if (error)
242 0 : goto out_cur;
243 :
244 279969171 : while (true) {
245 279969171 : error = xfs_btree_decrement(cur, 0, &has);
246 279968835 : if (error)
247 0 : goto out_cur;
248 279968835 : if (!has)
249 : break;
250 :
251 147816530 : error = rcbagbt_get_rec(cur, &bagrec, &has);
252 147816082 : if (error)
253 0 : goto out_cur;
254 147816082 : if (!has) {
255 0 : error = -EFSCORRUPTED;
256 0 : goto out_cur;
257 : }
258 :
259 147816082 : if (BAGREC_NEXT(&bagrec) != next_bno)
260 15131705 : continue;
261 :
262 132684377 : error = xfs_btree_delete(cur, &has);
263 132684663 : if (error)
264 0 : goto out_cur;
265 132684663 : if (!has) {
266 0 : error = -EFSCORRUPTED;
267 0 : goto out_cur;
268 : }
269 :
270 132684663 : bag->nr_items -= bagrec.rbg_refcount;
271 : }
272 :
273 132152305 : xfs_btree_del_cursor(cur, 0);
274 132153042 : xfs_trans_brelse(tp, head_bp);
275 132154635 : 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 : }
|