xref: /linux/fs/xfs/scrub/rtrefcount.c (revision e814f3fd16acfb7f9966773953de8f740a1e3202)
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.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 "scrub/scrub.h"
24 #include "scrub/common.h"
25 #include "scrub/btree.h"
26 #include "scrub/repair.h"
27 
28 /* Set us up with the realtime refcount metadata locked. */
29 int
30 xchk_setup_rtrefcountbt(
31 	struct xfs_scrub	*sc)
32 {
33 	int			error;
34 
35 	if (xchk_need_intent_drain(sc))
36 		xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
37 
38 	if (xchk_could_repair(sc)) {
39 		error = xrep_setup_rtrefcountbt(sc);
40 		if (error)
41 			return error;
42 	}
43 
44 	error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr);
45 	if (error)
46 		return error;
47 
48 	error = xchk_setup_rt(sc);
49 	if (error)
50 		return error;
51 
52 	error = xchk_install_live_inode(sc, rtg_refcount(sc->sr.rtg));
53 	if (error)
54 		return error;
55 
56 	return xchk_rtgroup_lock(sc, &sc->sr, XCHK_RTGLOCK_ALL);
57 }
58 
59 /* Realtime Reference count btree scrubber. */
60 
61 /*
62  * Confirming Reference Counts via Reverse Mappings
63  *
64  * We want to count the reverse mappings overlapping a refcount record
65  * (bno, len, refcount), allowing for the possibility that some of the
66  * overlap may come from smaller adjoining reverse mappings, while some
67  * comes from single extents which overlap the range entirely.  The
68  * outer loop is as follows:
69  *
70  * 1. For all reverse mappings overlapping the refcount extent,
71  *    a. If a given rmap completely overlaps, mark it as seen.
72  *    b. Otherwise, record the fragment (in agbno order) for later
73  *       processing.
74  *
75  * Once we've seen all the rmaps, we know that for all blocks in the
76  * refcount record we want to find $refcount owners and we've already
77  * visited $seen extents that overlap all the blocks.  Therefore, we
78  * need to find ($refcount - $seen) owners for every block in the
79  * extent; call that quantity $target_nr.  Proceed as follows:
80  *
81  * 2. Pull the first $target_nr fragments from the list; all of them
82  *    should start at or before the start of the extent.
83  *    Call this subset of fragments the working set.
84  * 3. Until there are no more unprocessed fragments,
85  *    a. Find the shortest fragments in the set and remove them.
86  *    b. Note the block number of the end of these fragments.
87  *    c. Pull the same number of fragments from the list.  All of these
88  *       fragments should start at the block number recorded in the
89  *       previous step.
90  *    d. Put those fragments in the set.
91  * 4. Check that there are $target_nr fragments remaining in the list,
92  *    and that they all end at or beyond the end of the refcount extent.
93  *
94  * If the refcount is correct, all the check conditions in the algorithm
95  * should always hold true.  If not, the refcount is incorrect.
96  */
97 struct xchk_rtrefcnt_frag {
98 	struct list_head	list;
99 	struct xfs_rmap_irec	rm;
100 };
101 
102 struct xchk_rtrefcnt_check {
103 	struct xfs_scrub	*sc;
104 	struct list_head	fragments;
105 
106 	/* refcount extent we're examining */
107 	xfs_rgblock_t		bno;
108 	xfs_extlen_t		len;
109 	xfs_nlink_t		refcount;
110 
111 	/* number of owners seen */
112 	xfs_nlink_t		seen;
113 };
114 
115 /*
116  * Decide if the given rmap is large enough that we can redeem it
117  * towards refcount verification now, or if it's a fragment, in
118  * which case we'll hang onto it in the hopes that we'll later
119  * discover that we've collected exactly the correct number of
120  * fragments as the rtrefcountbt says we should have.
121  */
122 STATIC int
123 xchk_rtrefcountbt_rmap_check(
124 	struct xfs_btree_cur		*cur,
125 	const struct xfs_rmap_irec	*rec,
126 	void				*priv)
127 {
128 	struct xchk_rtrefcnt_check	*refchk = priv;
129 	struct xchk_rtrefcnt_frag	*frag;
130 	xfs_rgblock_t			rm_last;
131 	xfs_rgblock_t			rc_last;
132 	int				error = 0;
133 
134 	if (xchk_should_terminate(refchk->sc, &error))
135 		return error;
136 
137 	rm_last = rec->rm_startblock + rec->rm_blockcount - 1;
138 	rc_last = refchk->bno + refchk->len - 1;
139 
140 	/* Confirm that a single-owner refc extent is a CoW stage. */
141 	if (refchk->refcount == 1 && rec->rm_owner != XFS_RMAP_OWN_COW) {
142 		xchk_btree_xref_set_corrupt(refchk->sc, cur, 0);
143 		return 0;
144 	}
145 
146 	if (rec->rm_startblock <= refchk->bno && rm_last >= rc_last) {
147 		/*
148 		 * The rmap overlaps the refcount record, so we can confirm
149 		 * one refcount owner seen.
150 		 */
151 		refchk->seen++;
152 	} else {
153 		/*
154 		 * This rmap covers only part of the refcount record, so
155 		 * save the fragment for later processing.  If the rmapbt
156 		 * is healthy each rmap_irec we see will be in agbno order
157 		 * so we don't need insertion sort here.
158 		 */
159 		frag = kmalloc(sizeof(struct xchk_rtrefcnt_frag),
160 				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
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
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
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
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
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
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
429 xchk_rtrefcountbt_xref_gaps(
430 	struct xfs_scrub	*sc,
431 	struct xchk_rtrefcbt_records *rrc,
432 	xfs_rtblock_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
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 /* Make sure we have as many refc blocks as the rmap says. */
509 STATIC void
510 xchk_refcount_xref_rmap(
511 	struct xfs_scrub	*sc,
512 	const struct xfs_owner_info *btree_oinfo,
513 	xfs_extlen_t		cow_blocks)
514 {
515 	xfs_filblks_t		refcbt_blocks = 0;
516 	xfs_filblks_t		blocks;
517 	int			error;
518 
519 	if (!sc->sr.rmap_cur || !sc->sa.rmap_cur || xchk_skip_xref(sc->sm))
520 		return;
521 
522 	/* Check that we saw as many refcbt blocks as the rmap knows about. */
523 	error = xfs_btree_count_blocks(sc->sr.refc_cur, &refcbt_blocks);
524 	if (!xchk_btree_process_error(sc, sc->sr.refc_cur, 0, &error))
525 		return;
526 	error = xchk_count_rmap_ownedby_ag(sc, sc->sa.rmap_cur, btree_oinfo,
527 			&blocks);
528 	if (!xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur))
529 		return;
530 	if (blocks != refcbt_blocks)
531 		xchk_btree_xref_set_corrupt(sc, sc->sa.rmap_cur, 0);
532 
533 	/* Check that we saw as many cow blocks as the rmap knows about. */
534 	error = xchk_count_rmap_ownedby_ag(sc, sc->sr.rmap_cur,
535 			&XFS_RMAP_OINFO_COW, &blocks);
536 	if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
537 		return;
538 	if (blocks != cow_blocks)
539 		xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
540 }
541 
542 /* Scrub the refcount btree for some AG. */
543 int
544 xchk_rtrefcountbt(
545 	struct xfs_scrub	*sc)
546 {
547 	struct xfs_owner_info	btree_oinfo;
548 	struct xchk_rtrefcbt_records rrc = {
549 		.cow_blocks		= 0,
550 		.next_unshared_rgbno	= 0,
551 		.prev_domain		= XFS_REFC_DOMAIN_SHARED,
552 	};
553 	int			error;
554 
555 	error = xchk_metadata_inode_forks(sc);
556 	if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
557 		return error;
558 
559 	xfs_rmap_ino_bmbt_owner(&btree_oinfo, rtg_refcount(sc->sr.rtg)->i_ino,
560 			XFS_DATA_FORK);
561 	error = xchk_btree(sc, sc->sr.refc_cur, xchk_rtrefcountbt_rec,
562 			&btree_oinfo, &rrc);
563 	if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
564 		return error;
565 
566 	/*
567 	 * Check that all blocks between the last refcount > 1 record and the
568 	 * end of the rt volume have at most one reverse mapping.
569 	 */
570 	xchk_rtrefcountbt_xref_gaps(sc, &rrc, sc->mp->m_sb.sb_rblocks);
571 
572 	xchk_refcount_xref_rmap(sc, &btree_oinfo, rrc.cow_blocks);
573 
574 	return 0;
575 }
576 
577 /* xref check that a cow staging extent is marked in the rtrefcountbt. */
578 void
579 xchk_xref_is_rt_cow_staging(
580 	struct xfs_scrub		*sc,
581 	xfs_rgblock_t			bno,
582 	xfs_extlen_t			len)
583 {
584 	struct xfs_refcount_irec	rc;
585 	int				has_refcount;
586 	int				error;
587 
588 	if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm))
589 		return;
590 
591 	/* Find the CoW staging extent. */
592 	error = xfs_refcount_lookup_le(sc->sr.refc_cur, XFS_REFC_DOMAIN_COW,
593 			bno, &has_refcount);
594 	if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur))
595 		return;
596 	if (!has_refcount) {
597 		xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
598 		return;
599 	}
600 
601 	error = xfs_refcount_get_rec(sc->sr.refc_cur, &rc, &has_refcount);
602 	if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur))
603 		return;
604 	if (!has_refcount) {
605 		xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
606 		return;
607 	}
608 
609 	/* CoW lookup returned a shared extent record? */
610 	if (rc.rc_domain != XFS_REFC_DOMAIN_COW)
611 		xchk_btree_xref_set_corrupt(sc, sc->sa.refc_cur, 0);
612 
613 	/* Must be at least as long as what was passed in */
614 	if (rc.rc_blockcount < len)
615 		xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
616 }
617 
618 /*
619  * xref check that the extent is not shared.  Only file data blocks
620  * can have multiple owners.
621  */
622 void
623 xchk_xref_is_not_rt_shared(
624 	struct xfs_scrub	*sc,
625 	xfs_rgblock_t		bno,
626 	xfs_extlen_t		len)
627 {
628 	enum xbtree_recpacking	outcome;
629 	int			error;
630 
631 	if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm))
632 		return;
633 
634 	error = xfs_refcount_has_records(sc->sr.refc_cur,
635 			XFS_REFC_DOMAIN_SHARED, bno, len, &outcome);
636 	if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur))
637 		return;
638 	if (outcome != XBTREE_RECPACKING_EMPTY)
639 		xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
640 }
641 
642 /* xref check that the extent is not being used for CoW staging. */
643 void
644 xchk_xref_is_not_rt_cow_staging(
645 	struct xfs_scrub	*sc,
646 	xfs_rgblock_t		bno,
647 	xfs_extlen_t		len)
648 {
649 	enum xbtree_recpacking	outcome;
650 	int			error;
651 
652 	if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm))
653 		return;
654 
655 	error = xfs_refcount_has_records(sc->sr.refc_cur, XFS_REFC_DOMAIN_COW,
656 			bno, len, &outcome);
657 	if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur))
658 		return;
659 	if (outcome != XBTREE_RECPACKING_EMPTY)
660 		xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
661 }
662