1
2
3
4
5
6#include "xfs.h"
7#include "xfs_fs.h"
8#include "xfs_shared.h"
9#include "xfs_format.h"
10#include "xfs_trans_resv.h"
11#include "xfs_mount.h"
12#include "xfs_inode.h"
13#include "xfs_btree.h"
14#include "scrub/scrub.h"
15#include "scrub/common.h"
16#include "scrub/btree.h"
17#include "scrub/trace.h"
18
19
20
21
22
23
24
25static bool
26__xchk_btree_process_error(
27 struct xfs_scrub *sc,
28 struct xfs_btree_cur *cur,
29 int level,
30 int *error,
31 __u32 errflag,
32 void *ret_ip)
33{
34 if (*error == 0)
35 return true;
36
37 switch (*error) {
38 case -EDEADLOCK:
39
40 trace_xchk_deadlock_retry(sc->ip, sc->sm, *error);
41 break;
42 case -EFSBADCRC:
43 case -EFSCORRUPTED:
44
45 sc->sm->sm_flags |= errflag;
46 *error = 0;
47
48 default:
49 if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
50 trace_xchk_ifork_btree_op_error(sc, cur, level,
51 *error, ret_ip);
52 else
53 trace_xchk_btree_op_error(sc, cur, level,
54 *error, ret_ip);
55 break;
56 }
57 return false;
58}
59
60bool
61xchk_btree_process_error(
62 struct xfs_scrub *sc,
63 struct xfs_btree_cur *cur,
64 int level,
65 int *error)
66{
67 return __xchk_btree_process_error(sc, cur, level, error,
68 XFS_SCRUB_OFLAG_CORRUPT, __return_address);
69}
70
71bool
72xchk_btree_xref_process_error(
73 struct xfs_scrub *sc,
74 struct xfs_btree_cur *cur,
75 int level,
76 int *error)
77{
78 return __xchk_btree_process_error(sc, cur, level, error,
79 XFS_SCRUB_OFLAG_XFAIL, __return_address);
80}
81
82
83static void
84__xchk_btree_set_corrupt(
85 struct xfs_scrub *sc,
86 struct xfs_btree_cur *cur,
87 int level,
88 __u32 errflag,
89 void *ret_ip)
90{
91 sc->sm->sm_flags |= errflag;
92
93 if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
94 trace_xchk_ifork_btree_error(sc, cur, level,
95 ret_ip);
96 else
97 trace_xchk_btree_error(sc, cur, level,
98 ret_ip);
99}
100
101void
102xchk_btree_set_corrupt(
103 struct xfs_scrub *sc,
104 struct xfs_btree_cur *cur,
105 int level)
106{
107 __xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_CORRUPT,
108 __return_address);
109}
110
111void
112xchk_btree_xref_set_corrupt(
113 struct xfs_scrub *sc,
114 struct xfs_btree_cur *cur,
115 int level)
116{
117 __xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_XCORRUPT,
118 __return_address);
119}
120
121
122
123
124
125STATIC void
126xchk_btree_rec(
127 struct xchk_btree *bs)
128{
129 struct xfs_btree_cur *cur = bs->cur;
130 union xfs_btree_rec *rec;
131 union xfs_btree_key key;
132 union xfs_btree_key hkey;
133 union xfs_btree_key *keyp;
134 struct xfs_btree_block *block;
135 struct xfs_btree_block *keyblock;
136 struct xfs_buf *bp;
137
138 block = xfs_btree_get_block(cur, 0, &bp);
139 rec = xfs_btree_rec_addr(cur, cur->bc_ptrs[0], block);
140
141 trace_xchk_btree_rec(bs->sc, cur, 0);
142
143
144 if (!bs->firstrec && !cur->bc_ops->recs_inorder(cur, &bs->lastrec, rec))
145 xchk_btree_set_corrupt(bs->sc, cur, 0);
146 bs->firstrec = false;
147 memcpy(&bs->lastrec, rec, cur->bc_ops->rec_len);
148
149 if (cur->bc_nlevels == 1)
150 return;
151
152
153 cur->bc_ops->init_key_from_rec(&key, rec);
154 keyblock = xfs_btree_get_block(cur, 1, &bp);
155 keyp = xfs_btree_key_addr(cur, cur->bc_ptrs[1], keyblock);
156 if (cur->bc_ops->diff_two_keys(cur, &key, keyp) < 0)
157 xchk_btree_set_corrupt(bs->sc, cur, 1);
158
159 if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
160 return;
161
162
163 cur->bc_ops->init_high_key_from_rec(&hkey, rec);
164 keyp = xfs_btree_high_key_addr(cur, cur->bc_ptrs[1], keyblock);
165 if (cur->bc_ops->diff_two_keys(cur, keyp, &hkey) < 0)
166 xchk_btree_set_corrupt(bs->sc, cur, 1);
167}
168
169
170
171
172
173STATIC void
174xchk_btree_key(
175 struct xchk_btree *bs,
176 int level)
177{
178 struct xfs_btree_cur *cur = bs->cur;
179 union xfs_btree_key *key;
180 union xfs_btree_key *keyp;
181 struct xfs_btree_block *block;
182 struct xfs_btree_block *keyblock;
183 struct xfs_buf *bp;
184
185 block = xfs_btree_get_block(cur, level, &bp);
186 key = xfs_btree_key_addr(cur, cur->bc_ptrs[level], block);
187
188 trace_xchk_btree_key(bs->sc, cur, level);
189
190
191 if (!bs->firstkey[level] &&
192 !cur->bc_ops->keys_inorder(cur, &bs->lastkey[level], key))
193 xchk_btree_set_corrupt(bs->sc, cur, level);
194 bs->firstkey[level] = false;
195 memcpy(&bs->lastkey[level], key, cur->bc_ops->key_len);
196
197 if (level + 1 >= cur->bc_nlevels)
198 return;
199
200
201 keyblock = xfs_btree_get_block(cur, level + 1, &bp);
202 keyp = xfs_btree_key_addr(cur, cur->bc_ptrs[level + 1], keyblock);
203 if (cur->bc_ops->diff_two_keys(cur, key, keyp) < 0)
204 xchk_btree_set_corrupt(bs->sc, cur, level);
205
206 if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
207 return;
208
209
210 key = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level], block);
211 keyp = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level + 1], keyblock);
212 if (cur->bc_ops->diff_two_keys(cur, keyp, key) < 0)
213 xchk_btree_set_corrupt(bs->sc, cur, level);
214}
215
216
217
218
219
220static bool
221xchk_btree_ptr_ok(
222 struct xchk_btree *bs,
223 int level,
224 union xfs_btree_ptr *ptr)
225{
226 bool res;
227
228
229 if ((bs->cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
230 level == bs->cur->bc_nlevels)
231 return true;
232
233
234 if (bs->cur->bc_flags & XFS_BTREE_LONG_PTRS)
235 res = xfs_btree_check_lptr(bs->cur, be64_to_cpu(ptr->l), level);
236 else
237 res = xfs_btree_check_sptr(bs->cur, be32_to_cpu(ptr->s), level);
238 if (!res)
239 xchk_btree_set_corrupt(bs->sc, bs->cur, level);
240
241 return res;
242}
243
244
245STATIC int
246xchk_btree_block_check_sibling(
247 struct xchk_btree *bs,
248 int level,
249 int direction,
250 union xfs_btree_ptr *sibling)
251{
252 struct xfs_btree_cur *cur = bs->cur;
253 struct xfs_btree_block *pblock;
254 struct xfs_buf *pbp;
255 struct xfs_btree_cur *ncur = NULL;
256 union xfs_btree_ptr *pp;
257 int success;
258 int error;
259
260 error = xfs_btree_dup_cursor(cur, &ncur);
261 if (!xchk_btree_process_error(bs->sc, cur, level + 1, &error) ||
262 !ncur)
263 return error;
264
265
266
267
268
269 if (xfs_btree_ptr_is_null(cur, sibling)) {
270 if (direction > 0)
271 error = xfs_btree_increment(ncur, level + 1, &success);
272 else
273 error = xfs_btree_decrement(ncur, level + 1, &success);
274 if (error == 0 && success)
275 xchk_btree_set_corrupt(bs->sc, cur, level);
276 error = 0;
277 goto out;
278 }
279
280
281 if (direction > 0)
282 error = xfs_btree_increment(ncur, level + 1, &success);
283 else
284 error = xfs_btree_decrement(ncur, level + 1, &success);
285 if (!xchk_btree_process_error(bs->sc, cur, level + 1, &error))
286 goto out;
287 if (!success) {
288 xchk_btree_set_corrupt(bs->sc, cur, level + 1);
289 goto out;
290 }
291
292
293 pblock = xfs_btree_get_block(ncur, level + 1, &pbp);
294 pp = xfs_btree_ptr_addr(ncur, ncur->bc_ptrs[level + 1], pblock);
295 if (!xchk_btree_ptr_ok(bs, level + 1, pp))
296 goto out;
297 if (pbp)
298 xchk_buffer_recheck(bs->sc, pbp);
299
300 if (xfs_btree_diff_two_ptrs(cur, pp, sibling))
301 xchk_btree_set_corrupt(bs->sc, cur, level);
302out:
303 xfs_btree_del_cursor(ncur, XFS_BTREE_ERROR);
304 return error;
305}
306
307
308STATIC int
309xchk_btree_block_check_siblings(
310 struct xchk_btree *bs,
311 struct xfs_btree_block *block)
312{
313 struct xfs_btree_cur *cur = bs->cur;
314 union xfs_btree_ptr leftsib;
315 union xfs_btree_ptr rightsib;
316 int level;
317 int error = 0;
318
319 xfs_btree_get_sibling(cur, block, &leftsib, XFS_BB_LEFTSIB);
320 xfs_btree_get_sibling(cur, block, &rightsib, XFS_BB_RIGHTSIB);
321 level = xfs_btree_get_level(block);
322
323
324 if (level == cur->bc_nlevels - 1) {
325 if (!xfs_btree_ptr_is_null(cur, &leftsib) ||
326 !xfs_btree_ptr_is_null(cur, &rightsib))
327 xchk_btree_set_corrupt(bs->sc, cur, level);
328 goto out;
329 }
330
331
332
333
334
335
336 error = xchk_btree_block_check_sibling(bs, level, -1, &leftsib);
337 if (error)
338 return error;
339 error = xchk_btree_block_check_sibling(bs, level, 1, &rightsib);
340 if (error)
341 return error;
342out:
343 return error;
344}
345
346struct check_owner {
347 struct list_head list;
348 xfs_daddr_t daddr;
349 int level;
350};
351
352
353
354
355
356STATIC int
357xchk_btree_check_block_owner(
358 struct xchk_btree *bs,
359 int level,
360 xfs_daddr_t daddr)
361{
362 xfs_agnumber_t agno;
363 xfs_agblock_t agbno;
364 xfs_btnum_t btnum;
365 bool init_sa;
366 int error = 0;
367
368 if (!bs->cur)
369 return 0;
370
371 btnum = bs->cur->bc_btnum;
372 agno = xfs_daddr_to_agno(bs->cur->bc_mp, daddr);
373 agbno = xfs_daddr_to_agbno(bs->cur->bc_mp, daddr);
374
375 init_sa = bs->cur->bc_flags & XFS_BTREE_LONG_PTRS;
376 if (init_sa) {
377 error = xchk_ag_init(bs->sc, agno, &bs->sc->sa);
378 if (!xchk_btree_xref_process_error(bs->sc, bs->cur,
379 level, &error))
380 return error;
381 }
382
383 xchk_xref_is_used_space(bs->sc, agbno, 1);
384
385
386
387
388
389 if (!bs->sc->sa.bno_cur && btnum == XFS_BTNUM_BNO)
390 bs->cur = NULL;
391
392 xchk_xref_is_owned_by(bs->sc, agbno, 1, bs->oinfo);
393 if (!bs->sc->sa.rmap_cur && btnum == XFS_BTNUM_RMAP)
394 bs->cur = NULL;
395
396 if (init_sa)
397 xchk_ag_free(bs->sc, &bs->sc->sa);
398
399 return error;
400}
401
402
403STATIC int
404xchk_btree_check_owner(
405 struct xchk_btree *bs,
406 int level,
407 struct xfs_buf *bp)
408{
409 struct xfs_btree_cur *cur = bs->cur;
410 struct check_owner *co;
411
412
413
414
415
416
417
418 if (bp == NULL) {
419 if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE))
420 xchk_btree_set_corrupt(bs->sc, bs->cur, level);
421 return 0;
422 }
423
424
425
426
427
428
429
430
431
432 if (cur->bc_btnum == XFS_BTNUM_BNO || cur->bc_btnum == XFS_BTNUM_RMAP) {
433 co = kmem_alloc(sizeof(struct check_owner),
434 KM_MAYFAIL);
435 if (!co)
436 return -ENOMEM;
437 co->level = level;
438 co->daddr = XFS_BUF_ADDR(bp);
439 list_add_tail(&co->list, &bs->to_check);
440 return 0;
441 }
442
443 return xchk_btree_check_block_owner(bs, level, XFS_BUF_ADDR(bp));
444}
445
446
447static inline bool
448xchk_btree_check_iroot_minrecs(
449 struct xchk_btree *bs)
450{
451
452
453
454
455
456
457
458
459
460
461
462 if (bs->cur->bc_btnum == XFS_BTNUM_BMAP &&
463 bs->cur->bc_ino.whichfork == XFS_DATA_FORK &&
464 XFS_IFORK_Q(bs->sc->ip))
465 return false;
466
467 return true;
468}
469
470
471
472
473
474STATIC void
475xchk_btree_check_minrecs(
476 struct xchk_btree *bs,
477 int level,
478 struct xfs_btree_block *block)
479{
480 struct xfs_btree_cur *cur = bs->cur;
481 unsigned int root_level = cur->bc_nlevels - 1;
482 unsigned int numrecs = be16_to_cpu(block->bb_numrecs);
483
484
485 if (numrecs >= cur->bc_ops->get_minrecs(cur, level))
486 return;
487
488
489
490
491
492
493
494
495 if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
496 level == cur->bc_nlevels - 2) {
497 struct xfs_btree_block *root_block;
498 struct xfs_buf *root_bp;
499 int root_maxrecs;
500
501 root_block = xfs_btree_get_block(cur, root_level, &root_bp);
502 root_maxrecs = cur->bc_ops->get_dmaxrecs(cur, root_level);
503 if (xchk_btree_check_iroot_minrecs(bs) &&
504 (be16_to_cpu(root_block->bb_numrecs) != 1 ||
505 numrecs <= root_maxrecs))
506 xchk_btree_set_corrupt(bs->sc, cur, level);
507 return;
508 }
509
510
511
512
513
514 if (level < root_level)
515 xchk_btree_set_corrupt(bs->sc, cur, level);
516}
517
518
519
520
521
522STATIC int
523xchk_btree_get_block(
524 struct xchk_btree *bs,
525 int level,
526 union xfs_btree_ptr *pp,
527 struct xfs_btree_block **pblock,
528 struct xfs_buf **pbp)
529{
530 xfs_failaddr_t failed_at;
531 int error;
532
533 *pblock = NULL;
534 *pbp = NULL;
535
536 error = xfs_btree_lookup_get_block(bs->cur, level, pp, pblock);
537 if (!xchk_btree_process_error(bs->sc, bs->cur, level, &error) ||
538 !*pblock)
539 return error;
540
541 xfs_btree_get_block(bs->cur, level, pbp);
542 if (bs->cur->bc_flags & XFS_BTREE_LONG_PTRS)
543 failed_at = __xfs_btree_check_lblock(bs->cur, *pblock,
544 level, *pbp);
545 else
546 failed_at = __xfs_btree_check_sblock(bs->cur, *pblock,
547 level, *pbp);
548 if (failed_at) {
549 xchk_btree_set_corrupt(bs->sc, bs->cur, level);
550 return 0;
551 }
552 if (*pbp)
553 xchk_buffer_recheck(bs->sc, *pbp);
554
555 xchk_btree_check_minrecs(bs, level, *pblock);
556
557
558
559
560
561 error = xchk_btree_check_owner(bs, level, *pbp);
562 if (error)
563 return error;
564
565
566
567
568
569 return xchk_btree_block_check_siblings(bs, *pblock);
570}
571
572
573
574
575
576STATIC void
577xchk_btree_block_keys(
578 struct xchk_btree *bs,
579 int level,
580 struct xfs_btree_block *block)
581{
582 union xfs_btree_key block_keys;
583 struct xfs_btree_cur *cur = bs->cur;
584 union xfs_btree_key *high_bk;
585 union xfs_btree_key *parent_keys;
586 union xfs_btree_key *high_pk;
587 struct xfs_btree_block *parent_block;
588 struct xfs_buf *bp;
589
590 if (level >= cur->bc_nlevels - 1)
591 return;
592
593
594 xfs_btree_get_keys(cur, block, &block_keys);
595
596
597 parent_block = xfs_btree_get_block(cur, level + 1, &bp);
598 parent_keys = xfs_btree_key_addr(cur, cur->bc_ptrs[level + 1],
599 parent_block);
600
601 if (cur->bc_ops->diff_two_keys(cur, &block_keys, parent_keys) != 0)
602 xchk_btree_set_corrupt(bs->sc, cur, 1);
603
604 if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
605 return;
606
607
608 high_bk = xfs_btree_high_key_from_key(cur, &block_keys);
609 high_pk = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level + 1],
610 parent_block);
611
612 if (cur->bc_ops->diff_two_keys(cur, high_bk, high_pk) != 0)
613 xchk_btree_set_corrupt(bs->sc, cur, 1);
614}
615
616
617
618
619
620
621int
622xchk_btree(
623 struct xfs_scrub *sc,
624 struct xfs_btree_cur *cur,
625 xchk_btree_rec_fn scrub_fn,
626 const struct xfs_owner_info *oinfo,
627 void *private)
628{
629 struct xchk_btree bs = {
630 .cur = cur,
631 .scrub_rec = scrub_fn,
632 .oinfo = oinfo,
633 .firstrec = true,
634 .private = private,
635 .sc = sc,
636 };
637 union xfs_btree_ptr ptr;
638 union xfs_btree_ptr *pp;
639 union xfs_btree_rec *recp;
640 struct xfs_btree_block *block;
641 int level;
642 struct xfs_buf *bp;
643 struct check_owner *co;
644 struct check_owner *n;
645 int i;
646 int error = 0;
647
648
649 for (i = 0; i < XFS_BTREE_MAXLEVELS; i++)
650 bs.firstkey[i] = true;
651 INIT_LIST_HEAD(&bs.to_check);
652
653
654 if (cur->bc_nlevels > XFS_BTREE_MAXLEVELS) {
655 xchk_btree_set_corrupt(sc, cur, 0);
656 goto out;
657 }
658
659
660
661
662
663 level = cur->bc_nlevels - 1;
664 cur->bc_ops->init_ptr_from_cur(cur, &ptr);
665 if (!xchk_btree_ptr_ok(&bs, cur->bc_nlevels, &ptr))
666 goto out;
667 error = xchk_btree_get_block(&bs, level, &ptr, &block, &bp);
668 if (error || !block)
669 goto out;
670
671 cur->bc_ptrs[level] = 1;
672
673 while (level < cur->bc_nlevels) {
674 block = xfs_btree_get_block(cur, level, &bp);
675
676 if (level == 0) {
677
678 if (cur->bc_ptrs[level] >
679 be16_to_cpu(block->bb_numrecs)) {
680 xchk_btree_block_keys(&bs, level, block);
681 if (level < cur->bc_nlevels - 1)
682 cur->bc_ptrs[level + 1]++;
683 level++;
684 continue;
685 }
686
687
688 xchk_btree_rec(&bs);
689
690
691 recp = xfs_btree_rec_addr(cur, cur->bc_ptrs[0], block);
692 error = bs.scrub_rec(&bs, recp);
693 if (error)
694 break;
695 if (xchk_should_terminate(sc, &error) ||
696 (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
697 break;
698
699 cur->bc_ptrs[level]++;
700 continue;
701 }
702
703
704 if (cur->bc_ptrs[level] > be16_to_cpu(block->bb_numrecs)) {
705 xchk_btree_block_keys(&bs, level, block);
706 if (level < cur->bc_nlevels - 1)
707 cur->bc_ptrs[level + 1]++;
708 level++;
709 continue;
710 }
711
712
713 xchk_btree_key(&bs, level);
714
715
716 pp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[level], block);
717 if (!xchk_btree_ptr_ok(&bs, level, pp)) {
718 cur->bc_ptrs[level]++;
719 continue;
720 }
721 level--;
722 error = xchk_btree_get_block(&bs, level, pp, &block, &bp);
723 if (error || !block)
724 goto out;
725
726 cur->bc_ptrs[level] = 1;
727 }
728
729out:
730
731 list_for_each_entry_safe(co, n, &bs.to_check, list) {
732 if (!error && bs.cur)
733 error = xchk_btree_check_block_owner(&bs,
734 co->level, co->daddr);
735 list_del(&co->list);
736 kmem_free(co);
737 }
738
739 return error;
740}
741