30
30
#include "xfs_trans.h"
31
31
#include "xfs_sb.h"
32
32
#include "xfs_inode.h"
33
+ #include "xfs_alloc.h"
33
34
#include "scrub/xfs_scrub.h"
34
35
#include "scrub/scrub.h"
35
36
#include "scrub/common.h"
@@ -52,6 +53,65 @@ xfs_scrub_setup_ag_header(
52
53
return xfs_scrub_setup_fs (sc , ip );
53
54
}
54
55
56
+ /* Walk all the blocks in the AGFL. */
57
+ int
58
+ xfs_scrub_walk_agfl (
59
+ struct xfs_scrub_context * sc ,
60
+ int (* fn )(struct xfs_scrub_context * ,
61
+ xfs_agblock_t bno , void * ),
62
+ void * priv )
63
+ {
64
+ struct xfs_agf * agf ;
65
+ __be32 * agfl_bno ;
66
+ struct xfs_mount * mp = sc -> mp ;
67
+ unsigned int flfirst ;
68
+ unsigned int fllast ;
69
+ int i ;
70
+ int error ;
71
+
72
+ agf = XFS_BUF_TO_AGF (sc -> sa .agf_bp );
73
+ agfl_bno = XFS_BUF_TO_AGFL_BNO (mp , sc -> sa .agfl_bp );
74
+ flfirst = be32_to_cpu (agf -> agf_flfirst );
75
+ fllast = be32_to_cpu (agf -> agf_fllast );
76
+
77
+ /* Nothing to walk in an empty AGFL. */
78
+ if (agf -> agf_flcount == cpu_to_be32 (0 ))
79
+ return 0 ;
80
+
81
+ /* first to last is a consecutive list. */
82
+ if (fllast >= flfirst ) {
83
+ for (i = flfirst ; i <= fllast ; i ++ ) {
84
+ error = fn (sc , be32_to_cpu (agfl_bno [i ]), priv );
85
+ if (error )
86
+ return error ;
87
+ if (sc -> sm -> sm_flags & XFS_SCRUB_OFLAG_CORRUPT )
88
+ return error ;
89
+ }
90
+
91
+ return 0 ;
92
+ }
93
+
94
+ /* first to the end */
95
+ for (i = flfirst ; i < XFS_AGFL_SIZE (mp ); i ++ ) {
96
+ error = fn (sc , be32_to_cpu (agfl_bno [i ]), priv );
97
+ if (error )
98
+ return error ;
99
+ if (sc -> sm -> sm_flags & XFS_SCRUB_OFLAG_CORRUPT )
100
+ return error ;
101
+ }
102
+
103
+ /* the start to last. */
104
+ for (i = 0 ; i <= fllast ; i ++ ) {
105
+ error = fn (sc , be32_to_cpu (agfl_bno [i ]), priv );
106
+ if (error )
107
+ return error ;
108
+ if (sc -> sm -> sm_flags & XFS_SCRUB_OFLAG_CORRUPT )
109
+ return error ;
110
+ }
111
+
112
+ return 0 ;
113
+ }
114
+
55
115
/* Superblock */
56
116
57
117
/*
@@ -328,3 +388,127 @@ xfs_scrub_superblock(
328
388
329
389
return error ;
330
390
}
391
+
392
+ /* AGF */
393
+
394
+ /* Scrub the AGF. */
395
+ int
396
+ xfs_scrub_agf (
397
+ struct xfs_scrub_context * sc )
398
+ {
399
+ struct xfs_mount * mp = sc -> mp ;
400
+ struct xfs_agf * agf ;
401
+ xfs_agnumber_t agno ;
402
+ xfs_agblock_t agbno ;
403
+ xfs_agblock_t eoag ;
404
+ xfs_agblock_t agfl_first ;
405
+ xfs_agblock_t agfl_last ;
406
+ xfs_agblock_t agfl_count ;
407
+ xfs_agblock_t fl_count ;
408
+ int level ;
409
+ int error = 0 ;
410
+
411
+ agno = sc -> sa .agno = sc -> sm -> sm_agno ;
412
+ error = xfs_scrub_ag_read_headers (sc , agno , & sc -> sa .agi_bp ,
413
+ & sc -> sa .agf_bp , & sc -> sa .agfl_bp );
414
+ if (!xfs_scrub_process_error (sc , agno , XFS_AGF_BLOCK (sc -> mp ), & error ))
415
+ goto out ;
416
+
417
+ agf = XFS_BUF_TO_AGF (sc -> sa .agf_bp );
418
+
419
+ /* Check the AG length */
420
+ eoag = be32_to_cpu (agf -> agf_length );
421
+ if (eoag != xfs_ag_block_count (mp , agno ))
422
+ xfs_scrub_block_set_corrupt (sc , sc -> sa .agf_bp );
423
+
424
+ /* Check the AGF btree roots and levels */
425
+ agbno = be32_to_cpu (agf -> agf_roots [XFS_BTNUM_BNO ]);
426
+ if (!xfs_verify_agbno (mp , agno , agbno ))
427
+ xfs_scrub_block_set_corrupt (sc , sc -> sa .agf_bp );
428
+
429
+ agbno = be32_to_cpu (agf -> agf_roots [XFS_BTNUM_CNT ]);
430
+ if (!xfs_verify_agbno (mp , agno , agbno ))
431
+ xfs_scrub_block_set_corrupt (sc , sc -> sa .agf_bp );
432
+
433
+ level = be32_to_cpu (agf -> agf_levels [XFS_BTNUM_BNO ]);
434
+ if (level <= 0 || level > XFS_BTREE_MAXLEVELS )
435
+ xfs_scrub_block_set_corrupt (sc , sc -> sa .agf_bp );
436
+
437
+ level = be32_to_cpu (agf -> agf_levels [XFS_BTNUM_CNT ]);
438
+ if (level <= 0 || level > XFS_BTREE_MAXLEVELS )
439
+ xfs_scrub_block_set_corrupt (sc , sc -> sa .agf_bp );
440
+
441
+ if (xfs_sb_version_hasrmapbt (& mp -> m_sb )) {
442
+ agbno = be32_to_cpu (agf -> agf_roots [XFS_BTNUM_RMAP ]);
443
+ if (!xfs_verify_agbno (mp , agno , agbno ))
444
+ xfs_scrub_block_set_corrupt (sc , sc -> sa .agf_bp );
445
+
446
+ level = be32_to_cpu (agf -> agf_levels [XFS_BTNUM_RMAP ]);
447
+ if (level <= 0 || level > XFS_BTREE_MAXLEVELS )
448
+ xfs_scrub_block_set_corrupt (sc , sc -> sa .agf_bp );
449
+ }
450
+
451
+ if (xfs_sb_version_hasreflink (& mp -> m_sb )) {
452
+ agbno = be32_to_cpu (agf -> agf_refcount_root );
453
+ if (!xfs_verify_agbno (mp , agno , agbno ))
454
+ xfs_scrub_block_set_corrupt (sc , sc -> sa .agf_bp );
455
+
456
+ level = be32_to_cpu (agf -> agf_refcount_level );
457
+ if (level <= 0 || level > XFS_BTREE_MAXLEVELS )
458
+ xfs_scrub_block_set_corrupt (sc , sc -> sa .agf_bp );
459
+ }
460
+
461
+ /* Check the AGFL counters */
462
+ agfl_first = be32_to_cpu (agf -> agf_flfirst );
463
+ agfl_last = be32_to_cpu (agf -> agf_fllast );
464
+ agfl_count = be32_to_cpu (agf -> agf_flcount );
465
+ if (agfl_last > agfl_first )
466
+ fl_count = agfl_last - agfl_first + 1 ;
467
+ else
468
+ fl_count = XFS_AGFL_SIZE (mp ) - agfl_first + agfl_last + 1 ;
469
+ if (agfl_count != 0 && fl_count != agfl_count )
470
+ xfs_scrub_block_set_corrupt (sc , sc -> sa .agf_bp );
471
+
472
+ out :
473
+ return error ;
474
+ }
475
+
476
+ /* AGFL */
477
+
478
+ /* Scrub an AGFL block. */
479
+ STATIC int
480
+ xfs_scrub_agfl_block (
481
+ struct xfs_scrub_context * sc ,
482
+ xfs_agblock_t agbno ,
483
+ void * priv )
484
+ {
485
+ struct xfs_mount * mp = sc -> mp ;
486
+ xfs_agnumber_t agno = sc -> sa .agno ;
487
+
488
+ if (!xfs_verify_agbno (mp , agno , agbno ))
489
+ xfs_scrub_block_set_corrupt (sc , sc -> sa .agfl_bp );
490
+
491
+ return 0 ;
492
+ }
493
+
494
+ /* Scrub the AGFL. */
495
+ int
496
+ xfs_scrub_agfl (
497
+ struct xfs_scrub_context * sc )
498
+ {
499
+ xfs_agnumber_t agno ;
500
+ int error ;
501
+
502
+ agno = sc -> sa .agno = sc -> sm -> sm_agno ;
503
+ error = xfs_scrub_ag_read_headers (sc , agno , & sc -> sa .agi_bp ,
504
+ & sc -> sa .agf_bp , & sc -> sa .agfl_bp );
505
+ if (!xfs_scrub_process_error (sc , agno , XFS_AGFL_BLOCK (sc -> mp ), & error ))
506
+ goto out ;
507
+ if (!sc -> sa .agf_bp )
508
+ return - EFSCORRUPTED ;
509
+
510
+ /* Check the blocks in the AGFL. */
511
+ return xfs_scrub_walk_agfl (sc , xfs_scrub_agfl_block , NULL );
512
+ out :
513
+ return error ;
514
+ }
0 commit comments