1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <djwong@kernel.org>
5 */
6 #include "xfs_platform.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_resv.h"
12 #include "xfs_mount.h"
13 #include "xfs_trans.h"
14 #include "xfs_btree.h"
15 #include "xfs_rmap.h"
16 #include "xfs_refcount.h"
17 #include "xfs_inode.h"
18 #include "xfs_rtbitmap.h"
19 #include "xfs_rtgroup.h"
20 #include "xfs_metafile.h"
21 #include "xfs_rtrefcount_btree.h"
22 #include "xfs_rtalloc.h"
23 #include "xfs_ag.h"
24 #include "scrub/scrub.h"
25 #include "scrub/common.h"
26 #include "scrub/btree.h"
27 #include "scrub/repair.h"
28
29 /* Set us up with the realtime refcount metadata locked. */
30 int
xchk_setup_rtrefcountbt(struct xfs_scrub * sc)31 xchk_setup_rtrefcountbt(
32 struct xfs_scrub *sc)
33 {
34 int error;
35
36 if (xchk_need_intent_drain(sc))
37 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
38
39 if (xchk_could_repair(sc)) {
40 error = xrep_setup_rtrefcountbt(sc);
41 if (error)
42 return error;
43 }
44
45 error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr);
46 if (error)
47 return error;
48
49 error = xchk_setup_rt(sc);
50 if (error)
51 return error;
52
53 error = xchk_install_live_inode(sc, rtg_refcount(sc->sr.rtg));
54 if (error)
55 return error;
56
57 return xchk_rtgroup_lock(sc, &sc->sr, XCHK_RTGLOCK_ALL);
58 }
59
60 /* Realtime Reference count btree scrubber. */
61
62 /*
63 * Confirming Reference Counts via Reverse Mappings
64 *
65 * We want to count the reverse mappings overlapping a refcount record
66 * (bno, len, refcount), allowing for the possibility that some of the
67 * overlap may come from smaller adjoining reverse mappings, while some
68 * comes from single extents which overlap the range entirely. The
69 * outer loop is as follows:
70 *
71 * 1. For all reverse mappings overlapping the refcount extent,
72 * a. If a given rmap completely overlaps, mark it as seen.
73 * b. Otherwise, record the fragment (in agbno order) for later
74 * processing.
75 *
76 * Once we've seen all the rmaps, we know that for all blocks in the
77 * refcount record we want to find $refcount owners and we've already
78 * visited $seen extents that overlap all the blocks. Therefore, we
79 * need to find ($refcount - $seen) owners for every block in the
80 * extent; call that quantity $target_nr. Proceed as follows:
81 *
82 * 2. Pull the first $target_nr fragments from the list; all of them
83 * should start at or before the start of the extent.
84 * Call this subset of fragments the working set.
85 * 3. Until there are no more unprocessed fragments,
86 * a. Find the shortest fragments in the set and remove them.
87 * b. Note the block number of the end of these fragments.
88 * c. Pull the same number of fragments from the list. All of these
89 * fragments should start at the block number recorded in the
90 * previous step.
91 * d. Put those fragments in the set.
92 * 4. Check that there are $target_nr fragments remaining in the list,
93 * and that they all end at or beyond the end of the refcount extent.
94 *
95 * If the refcount is correct, all the check conditions in the algorithm
96 * should always hold true. If not, the refcount is incorrect.
97 */
98 struct xchk_rtrefcnt_frag {
99 struct list_head list;
100 struct xfs_rmap_irec rm;
101 };
102
103 struct xchk_rtrefcnt_check {
104 struct xfs_scrub *sc;
105 struct list_head fragments;
106
107 /* refcount extent we're examining */
108 xfs_rgblock_t bno;
109 xfs_extlen_t len;
110 xfs_nlink_t refcount;
111
112 /* number of owners seen */
113 xfs_nlink_t seen;
114 };
115
116 /*
117 * Decide if the given rmap is large enough that we can redeem it
118 * towards refcount verification now, or if it's a fragment, in
119 * which case we'll hang onto it in the hopes that we'll later
120 * discover that we've collected exactly the correct number of
121 * fragments as the rtrefcountbt says we should have.
122 */
123 STATIC int
xchk_rtrefcountbt_rmap_check(struct xfs_btree_cur * cur,const struct xfs_rmap_irec * rec,void * priv)124 xchk_rtrefcountbt_rmap_check(
125 struct xfs_btree_cur *cur,
126 const struct xfs_rmap_irec *rec,
127 void *priv)
128 {
129 struct xchk_rtrefcnt_check *refchk = priv;
130 struct xchk_rtrefcnt_frag *frag;
131 xfs_rgblock_t rm_last;
132 xfs_rgblock_t rc_last;
133 int error = 0;
134
135 if (xchk_should_terminate(refchk->sc, &error))
136 return error;
137
138 rm_last = rec->rm_startblock + rec->rm_blockcount - 1;
139 rc_last = refchk->bno + refchk->len - 1;
140
141 /* Confirm that a single-owner refc extent is a CoW stage. */
142 if (refchk->refcount == 1 && rec->rm_owner != XFS_RMAP_OWN_COW) {
143 xchk_btree_xref_set_corrupt(refchk->sc, cur, 0);
144 return 0;
145 }
146
147 if (rec->rm_startblock <= refchk->bno && rm_last >= rc_last) {
148 /*
149 * The rmap overlaps the refcount record, so we can confirm
150 * one refcount owner seen.
151 */
152 refchk->seen++;
153 } else {
154 /*
155 * This rmap covers only part of the refcount record, so
156 * save the fragment for later processing. If the rmapbt
157 * is healthy each rmap_irec we see will be in agbno order
158 * so we don't need insertion sort here.
159 */
160 frag = kmalloc_obj(struct xchk_rtrefcnt_frag, XCHK_GFP_FLAGS);
161 if (!frag)
162 return -ENOMEM;
163 memcpy(&frag->rm, rec, sizeof(frag->rm));
164 list_add_tail(&frag->list, &refchk->fragments);
165 }
166
167 return 0;
168 }
169
170 /*
171 * Given a bunch of rmap fragments, iterate through them, keeping
172 * a running tally of the refcount. If this ever deviates from
173 * what we expect (which is the rtrefcountbt's refcount minus the
174 * number of extents that totally covered the rtrefcountbt extent),
175 * we have a rtrefcountbt error.
176 */
177 STATIC void
xchk_rtrefcountbt_process_rmap_fragments(struct xchk_rtrefcnt_check * refchk)178 xchk_rtrefcountbt_process_rmap_fragments(
179 struct xchk_rtrefcnt_check *refchk)
180 {
181 struct list_head worklist;
182 struct xchk_rtrefcnt_frag *frag;
183 struct xchk_rtrefcnt_frag *n;
184 xfs_rgblock_t bno;
185 xfs_rgblock_t rbno;
186 xfs_rgblock_t next_rbno;
187 xfs_nlink_t nr;
188 xfs_nlink_t target_nr;
189
190 target_nr = refchk->refcount - refchk->seen;
191 if (target_nr == 0)
192 return;
193
194 /*
195 * There are (refchk->rc.rc_refcount - refchk->nr refcount)
196 * references we haven't found yet. Pull that many off the
197 * fragment list and figure out where the smallest rmap ends
198 * (and therefore the next rmap should start). All the rmaps
199 * we pull off should start at or before the beginning of the
200 * refcount record's range.
201 */
202 INIT_LIST_HEAD(&worklist);
203 rbno = NULLRGBLOCK;
204
205 /* Make sure the fragments actually /are/ in bno order. */
206 bno = 0;
207 list_for_each_entry(frag, &refchk->fragments, list) {
208 if (frag->rm.rm_startblock < bno)
209 goto done;
210 bno = frag->rm.rm_startblock;
211 }
212
213 /*
214 * Find all the rmaps that start at or before the refc extent,
215 * and put them on the worklist.
216 */
217 nr = 0;
218 list_for_each_entry_safe(frag, n, &refchk->fragments, list) {
219 if (frag->rm.rm_startblock > refchk->bno || nr > target_nr)
220 break;
221 bno = frag->rm.rm_startblock + frag->rm.rm_blockcount;
222 if (bno < rbno)
223 rbno = bno;
224 list_move_tail(&frag->list, &worklist);
225 nr++;
226 }
227
228 /*
229 * We should have found exactly $target_nr rmap fragments starting
230 * at or before the refcount extent.
231 */
232 if (nr != target_nr)
233 goto done;
234
235 while (!list_empty(&refchk->fragments)) {
236 /* Discard any fragments ending at rbno from the worklist. */
237 nr = 0;
238 next_rbno = NULLRGBLOCK;
239 list_for_each_entry_safe(frag, n, &worklist, list) {
240 bno = frag->rm.rm_startblock + frag->rm.rm_blockcount;
241 if (bno != rbno) {
242 if (bno < next_rbno)
243 next_rbno = bno;
244 continue;
245 }
246 list_del(&frag->list);
247 kfree(frag);
248 nr++;
249 }
250
251 /* Try to add nr rmaps starting at rbno to the worklist. */
252 list_for_each_entry_safe(frag, n, &refchk->fragments, list) {
253 bno = frag->rm.rm_startblock + frag->rm.rm_blockcount;
254 if (frag->rm.rm_startblock != rbno)
255 goto done;
256 list_move_tail(&frag->list, &worklist);
257 if (next_rbno > bno)
258 next_rbno = bno;
259 nr--;
260 if (nr == 0)
261 break;
262 }
263
264 /*
265 * If we get here and nr > 0, this means that we added fewer
266 * items to the worklist than we discarded because the fragment
267 * list ran out of items. Therefore, we cannot maintain the
268 * required refcount. Something is wrong, so we're done.
269 */
270 if (nr)
271 goto done;
272
273 rbno = next_rbno;
274 }
275
276 /*
277 * Make sure the last extent we processed ends at or beyond
278 * the end of the refcount extent.
279 */
280 if (rbno < refchk->bno + refchk->len)
281 goto done;
282
283 /* Actually record us having seen the remaining refcount. */
284 refchk->seen = refchk->refcount;
285 done:
286 /* Delete fragments and work list. */
287 list_for_each_entry_safe(frag, n, &worklist, list) {
288 list_del(&frag->list);
289 kfree(frag);
290 }
291 list_for_each_entry_safe(frag, n, &refchk->fragments, list) {
292 list_del(&frag->list);
293 kfree(frag);
294 }
295 }
296
297 /* Use the rmap entries covering this extent to verify the refcount. */
298 STATIC void
xchk_rtrefcountbt_xref_rmap(struct xfs_scrub * sc,const struct xfs_refcount_irec * irec)299 xchk_rtrefcountbt_xref_rmap(
300 struct xfs_scrub *sc,
301 const struct xfs_refcount_irec *irec)
302 {
303 struct xchk_rtrefcnt_check refchk = {
304 .sc = sc,
305 .bno = irec->rc_startblock,
306 .len = irec->rc_blockcount,
307 .refcount = irec->rc_refcount,
308 .seen = 0,
309 };
310 struct xfs_rmap_irec low;
311 struct xfs_rmap_irec high;
312 struct xchk_rtrefcnt_frag *frag;
313 struct xchk_rtrefcnt_frag *n;
314 int error;
315
316 if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm))
317 return;
318
319 /* Cross-reference with the rmapbt to confirm the refcount. */
320 memset(&low, 0, sizeof(low));
321 low.rm_startblock = irec->rc_startblock;
322 memset(&high, 0xFF, sizeof(high));
323 high.rm_startblock = irec->rc_startblock + irec->rc_blockcount - 1;
324
325 INIT_LIST_HEAD(&refchk.fragments);
326 error = xfs_rmap_query_range(sc->sr.rmap_cur, &low, &high,
327 xchk_rtrefcountbt_rmap_check, &refchk);
328 if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
329 goto out_free;
330
331 xchk_rtrefcountbt_process_rmap_fragments(&refchk);
332 if (irec->rc_refcount != refchk.seen)
333 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
334
335 out_free:
336 list_for_each_entry_safe(frag, n, &refchk.fragments, list) {
337 list_del(&frag->list);
338 kfree(frag);
339 }
340 }
341
342 /* Cross-reference with the other btrees. */
343 STATIC void
xchk_rtrefcountbt_xref(struct xfs_scrub * sc,const struct xfs_refcount_irec * irec)344 xchk_rtrefcountbt_xref(
345 struct xfs_scrub *sc,
346 const struct xfs_refcount_irec *irec)
347 {
348 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
349 return;
350
351 xchk_xref_is_used_rt_space(sc,
352 xfs_rgbno_to_rtb(sc->sr.rtg, irec->rc_startblock),
353 irec->rc_blockcount);
354 xchk_rtrefcountbt_xref_rmap(sc, irec);
355 }
356
357 struct xchk_rtrefcbt_records {
358 /* Previous refcount record. */
359 struct xfs_refcount_irec prev_rec;
360
361 /* The next rtgroup block where we aren't expecting shared extents. */
362 xfs_rgblock_t next_unshared_rgbno;
363
364 /* Number of CoW blocks we expect. */
365 xfs_extlen_t cow_blocks;
366
367 /* Was the last record a shared or CoW staging extent? */
368 enum xfs_refc_domain prev_domain;
369 };
370
371 static inline bool
xchk_rtrefcount_mergeable(struct xchk_rtrefcbt_records * rrc,const struct xfs_refcount_irec * r2)372 xchk_rtrefcount_mergeable(
373 struct xchk_rtrefcbt_records *rrc,
374 const struct xfs_refcount_irec *r2)
375 {
376 const struct xfs_refcount_irec *r1 = &rrc->prev_rec;
377
378 /* Ignore if prev_rec is not yet initialized. */
379 if (r1->rc_blockcount == 0)
380 return false;
381
382 if (r1->rc_startblock + r1->rc_blockcount != r2->rc_startblock)
383 return false;
384 if (r1->rc_refcount != r2->rc_refcount)
385 return false;
386 if ((unsigned long long)r1->rc_blockcount + r2->rc_blockcount >
387 XFS_REFC_LEN_MAX)
388 return false;
389
390 return true;
391 }
392
393 /* Flag failures for records that could be merged. */
394 STATIC void
xchk_rtrefcountbt_check_mergeable(struct xchk_btree * bs,struct xchk_rtrefcbt_records * rrc,const struct xfs_refcount_irec * irec)395 xchk_rtrefcountbt_check_mergeable(
396 struct xchk_btree *bs,
397 struct xchk_rtrefcbt_records *rrc,
398 const struct xfs_refcount_irec *irec)
399 {
400 if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
401 return;
402
403 if (xchk_rtrefcount_mergeable(rrc, irec))
404 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
405
406 memcpy(&rrc->prev_rec, irec, sizeof(struct xfs_refcount_irec));
407 }
408
409 STATIC int
xchk_rtrefcountbt_rmap_check_gap(struct xfs_btree_cur * cur,const struct xfs_rmap_irec * rec,void * priv)410 xchk_rtrefcountbt_rmap_check_gap(
411 struct xfs_btree_cur *cur,
412 const struct xfs_rmap_irec *rec,
413 void *priv)
414 {
415 xfs_rgblock_t *next_bno = priv;
416
417 if (*next_bno != NULLRGBLOCK && rec->rm_startblock < *next_bno)
418 return -ECANCELED;
419
420 *next_bno = rec->rm_startblock + rec->rm_blockcount;
421 return 0;
422 }
423
424 /*
425 * Make sure that a gap in the reference count records does not correspond to
426 * overlapping records (i.e. shared extents) in the reverse mappings.
427 */
428 static inline void
xchk_rtrefcountbt_xref_gaps(struct xfs_scrub * sc,struct xchk_rtrefcbt_records * rrc,xfs_rgblock_t bno)429 xchk_rtrefcountbt_xref_gaps(
430 struct xfs_scrub *sc,
431 struct xchk_rtrefcbt_records *rrc,
432 xfs_rgblock_t bno)
433 {
434 struct xfs_rmap_irec low;
435 struct xfs_rmap_irec high;
436 xfs_rgblock_t next_bno = NULLRGBLOCK;
437 int error;
438
439 if (bno <= rrc->next_unshared_rgbno || !sc->sr.rmap_cur ||
440 xchk_skip_xref(sc->sm))
441 return;
442
443 memset(&low, 0, sizeof(low));
444 low.rm_startblock = rrc->next_unshared_rgbno;
445 memset(&high, 0xFF, sizeof(high));
446 high.rm_startblock = bno - 1;
447
448 error = xfs_rmap_query_range(sc->sr.rmap_cur, &low, &high,
449 xchk_rtrefcountbt_rmap_check_gap, &next_bno);
450 if (error == -ECANCELED)
451 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
452 else
453 xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur);
454 }
455
456 /* Scrub a rtrefcountbt record. */
457 STATIC int
xchk_rtrefcountbt_rec(struct xchk_btree * bs,const union xfs_btree_rec * rec)458 xchk_rtrefcountbt_rec(
459 struct xchk_btree *bs,
460 const union xfs_btree_rec *rec)
461 {
462 struct xfs_mount *mp = bs->cur->bc_mp;
463 struct xchk_rtrefcbt_records *rrc = bs->private;
464 struct xfs_refcount_irec irec;
465 u32 mod;
466
467 xfs_refcount_btrec_to_irec(rec, &irec);
468 if (xfs_rtrefcount_check_irec(to_rtg(bs->cur->bc_group), &irec) !=
469 NULL) {
470 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
471 return 0;
472 }
473
474 /* We can only share full rt extents. */
475 mod = xfs_rgbno_to_rtxoff(mp, irec.rc_startblock);
476 if (mod)
477 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
478 mod = xfs_extlen_to_rtxmod(mp, irec.rc_blockcount);
479 if (mod)
480 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
481
482 if (irec.rc_domain == XFS_REFC_DOMAIN_COW)
483 rrc->cow_blocks += irec.rc_blockcount;
484
485 /* Shared records always come before CoW records. */
486 if (irec.rc_domain == XFS_REFC_DOMAIN_SHARED &&
487 rrc->prev_domain == XFS_REFC_DOMAIN_COW)
488 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
489 rrc->prev_domain = irec.rc_domain;
490
491 xchk_rtrefcountbt_check_mergeable(bs, rrc, &irec);
492 xchk_rtrefcountbt_xref(bs->sc, &irec);
493
494 /*
495 * If this is a record for a shared extent, check that all blocks
496 * between the previous record and this one have at most one reverse
497 * mapping.
498 */
499 if (irec.rc_domain == XFS_REFC_DOMAIN_SHARED) {
500 xchk_rtrefcountbt_xref_gaps(bs->sc, rrc, irec.rc_startblock);
501 rrc->next_unshared_rgbno = irec.rc_startblock +
502 irec.rc_blockcount;
503 }
504
505 return 0;
506 }
507
508 /* Count the number of blocks used by the rtrefcount btree file in this AG. */
509 static int
xchk_rtrefcount_count_agblocks(struct xfs_scrub * sc,xfs_agnumber_t agno,const struct xfs_owner_info * btree_oinfo,xfs_filblks_t * blocks)510 xchk_rtrefcount_count_agblocks(
511 struct xfs_scrub *sc,
512 xfs_agnumber_t agno,
513 const struct xfs_owner_info *btree_oinfo,
514 xfs_filblks_t *blocks)
515 {
516 xfs_filblks_t agblocks = 0;
517 int error;
518
519 error = xchk_ag_init_existing(sc, agno, &sc->sa);
520 if (error)
521 goto out_free;
522
523 /*
524 * If we don't have an rmap cursor, we can't complete the cross
525 * referencing, so return EFSCORRUPTED to end the loop and trigger the
526 * XFAIL flag.
527 */
528 if (!sc->sa.rmap_cur) {
529 error = -EFSCORRUPTED;
530 goto out_free;
531 }
532
533 error = xchk_count_rmap_ownedby_ag(sc, sc->sa.rmap_cur, btree_oinfo,
534 &agblocks);
535 if (error)
536 goto out_free;
537
538 *blocks += agblocks;
539 out_free:
540 xchk_ag_free(sc, &sc->sa);
541 return error;
542 }
543
544 /* Make sure we have as many refc blocks as the rmap says. */
545 STATIC void
xchk_rtrefcount_xref_rmap(struct xfs_scrub * sc,const struct xfs_owner_info * btree_oinfo,xfs_extlen_t cow_blocks)546 xchk_rtrefcount_xref_rmap(
547 struct xfs_scrub *sc,
548 const struct xfs_owner_info *btree_oinfo,
549 xfs_extlen_t cow_blocks)
550 {
551 xfs_filblks_t refcbt_blocks = 0;
552 xfs_filblks_t blocks = 1; /* one for the iroot */
553 xfs_agnumber_t agno;
554 int error = 0;
555
556 if (!xfs_has_rmapbt(sc->mp) || xchk_skip_xref(sc->sm))
557 return;
558
559 /* Check that we saw as many refcbt blocks as the rmap knows about. */
560 error = xfs_btree_count_blocks(sc->sr.refc_cur, &refcbt_blocks);
561 if (!xchk_btree_process_error(sc, sc->sr.refc_cur, 0, &error))
562 return;
563
564 for (agno = 0; agno < sc->mp->m_sb.sb_agcount; agno++) {
565 error = xchk_rtrefcount_count_agblocks(sc, agno, btree_oinfo,
566 &blocks);
567 if (error)
568 break;
569 }
570 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
571 return;
572 if (blocks != refcbt_blocks)
573 xchk_fblock_xref_set_corrupt(sc, XFS_DATA_FORK, 0);
574
575 if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm))
576 return;
577
578 /* Check that we saw as many cow blocks as the rmap knows about. */
579 error = xchk_count_rmap_ownedby_ag(sc, sc->sr.rmap_cur,
580 &XFS_RMAP_OINFO_COW, &blocks);
581 if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
582 return;
583 if (blocks != cow_blocks)
584 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
585 }
586
587 /* Scrub the refcount btree for some rtgroup. */
588 int
xchk_rtrefcountbt(struct xfs_scrub * sc)589 xchk_rtrefcountbt(
590 struct xfs_scrub *sc)
591 {
592 struct xfs_owner_info btree_oinfo;
593 struct xchk_rtrefcbt_records rrc = {
594 .cow_blocks = 0,
595 .next_unshared_rgbno = 0,
596 .prev_domain = XFS_REFC_DOMAIN_SHARED,
597 };
598 int error;
599
600 error = xchk_metadata_inode_forks(sc);
601 if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
602 return error;
603
604 xfs_rmap_inode_bmbt_owner(&btree_oinfo, rtg_refcount(sc->sr.rtg),
605 XFS_DATA_FORK);
606 error = xchk_btree(sc, sc->sr.refc_cur, xchk_rtrefcountbt_rec,
607 &btree_oinfo, &rrc);
608 if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
609 return error;
610
611 /*
612 * Check that all blocks between the last refcount > 1 record and the
613 * end of the rtgroup have at most one reverse mapping.
614 */
615 xchk_rtrefcountbt_xref_gaps(sc, &rrc,
616 xfs_rtx_to_rgbno(sc->sr.rtg, sc->mp->m_sb.sb_rgextents));
617 xchk_rtrefcount_xref_rmap(sc, &btree_oinfo, rrc.cow_blocks);
618
619 return 0;
620 }
621
622 /* xref check that a cow staging extent is marked in the rtrefcountbt. */
623 void
xchk_xref_is_rt_cow_staging(struct xfs_scrub * sc,xfs_rgblock_t bno,xfs_extlen_t len)624 xchk_xref_is_rt_cow_staging(
625 struct xfs_scrub *sc,
626 xfs_rgblock_t bno,
627 xfs_extlen_t len)
628 {
629 struct xfs_refcount_irec rc;
630 int has_refcount;
631 int error;
632
633 if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm))
634 return;
635
636 /* Find the CoW staging extent. */
637 error = xfs_refcount_lookup_le(sc->sr.refc_cur, XFS_REFC_DOMAIN_COW,
638 bno, &has_refcount);
639 if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur))
640 return;
641 if (!has_refcount) {
642 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
643 return;
644 }
645
646 error = xfs_refcount_get_rec(sc->sr.refc_cur, &rc, &has_refcount);
647 if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur))
648 return;
649 if (!has_refcount) {
650 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
651 return;
652 }
653
654 /* CoW lookup returned a shared extent record? */
655 if (rc.rc_domain != XFS_REFC_DOMAIN_COW)
656 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
657
658 /* Can't start after bno */
659 if (rc.rc_startblock > bno)
660 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
661
662 /* Must be at least as long as what was passed in */
663 if (rc.rc_startblock + rc.rc_blockcount < bno + len)
664 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
665 }
666
667 /*
668 * xref check that the extent is not shared. Only file data blocks
669 * can have multiple owners.
670 */
671 void
xchk_xref_is_not_rt_shared(struct xfs_scrub * sc,xfs_rgblock_t bno,xfs_extlen_t len)672 xchk_xref_is_not_rt_shared(
673 struct xfs_scrub *sc,
674 xfs_rgblock_t bno,
675 xfs_extlen_t len)
676 {
677 enum xbtree_recpacking outcome;
678 int error;
679
680 if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm))
681 return;
682
683 error = xfs_refcount_has_records(sc->sr.refc_cur,
684 XFS_REFC_DOMAIN_SHARED, bno, len, &outcome);
685 if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur))
686 return;
687 if (outcome != XBTREE_RECPACKING_EMPTY)
688 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
689 }
690
691 /* xref check that the extent is not being used for CoW staging. */
692 void
xchk_xref_is_not_rt_cow_staging(struct xfs_scrub * sc,xfs_rgblock_t bno,xfs_extlen_t len)693 xchk_xref_is_not_rt_cow_staging(
694 struct xfs_scrub *sc,
695 xfs_rgblock_t bno,
696 xfs_extlen_t len)
697 {
698 enum xbtree_recpacking outcome;
699 int error;
700
701 if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm))
702 return;
703
704 error = xfs_refcount_has_records(sc->sr.refc_cur, XFS_REFC_DOMAIN_COW,
705 bno, len, &outcome);
706 if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur))
707 return;
708 if (outcome != XBTREE_RECPACKING_EMPTY)
709 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
710 }
711