|
31 | 31 | #include "xfs_sb.h"
|
32 | 32 | #include "xfs_inode.h"
|
33 | 33 | #include "xfs_alloc.h"
|
| 34 | +#include "xfs_ialloc.h" |
34 | 35 | #include "scrub/xfs_scrub.h"
|
35 | 36 | #include "scrub/scrub.h"
|
36 | 37 | #include "scrub/common.h"
|
@@ -512,3 +513,87 @@ xfs_scrub_agfl(
|
512 | 513 | out:
|
513 | 514 | return error;
|
514 | 515 | }
|
| 516 | + |
| 517 | +/* AGI */ |
| 518 | + |
| 519 | +/* Scrub the AGI. */ |
| 520 | +int |
| 521 | +xfs_scrub_agi( |
| 522 | + struct xfs_scrub_context *sc) |
| 523 | +{ |
| 524 | + struct xfs_mount *mp = sc->mp; |
| 525 | + struct xfs_agi *agi; |
| 526 | + xfs_agnumber_t agno; |
| 527 | + xfs_agblock_t agbno; |
| 528 | + xfs_agblock_t eoag; |
| 529 | + xfs_agino_t agino; |
| 530 | + xfs_agino_t first_agino; |
| 531 | + xfs_agino_t last_agino; |
| 532 | + xfs_agino_t icount; |
| 533 | + int i; |
| 534 | + int level; |
| 535 | + int error = 0; |
| 536 | + |
| 537 | + agno = sc->sa.agno = sc->sm->sm_agno; |
| 538 | + error = xfs_scrub_ag_read_headers(sc, agno, &sc->sa.agi_bp, |
| 539 | + &sc->sa.agf_bp, &sc->sa.agfl_bp); |
| 540 | + if (!xfs_scrub_process_error(sc, agno, XFS_AGI_BLOCK(sc->mp), &error)) |
| 541 | + goto out; |
| 542 | + |
| 543 | + agi = XFS_BUF_TO_AGI(sc->sa.agi_bp); |
| 544 | + |
| 545 | + /* Check the AG length */ |
| 546 | + eoag = be32_to_cpu(agi->agi_length); |
| 547 | + if (eoag != xfs_ag_block_count(mp, agno)) |
| 548 | + xfs_scrub_block_set_corrupt(sc, sc->sa.agi_bp); |
| 549 | + |
| 550 | + /* Check btree roots and levels */ |
| 551 | + agbno = be32_to_cpu(agi->agi_root); |
| 552 | + if (!xfs_verify_agbno(mp, agno, agbno)) |
| 553 | + xfs_scrub_block_set_corrupt(sc, sc->sa.agi_bp); |
| 554 | + |
| 555 | + level = be32_to_cpu(agi->agi_level); |
| 556 | + if (level <= 0 || level > XFS_BTREE_MAXLEVELS) |
| 557 | + xfs_scrub_block_set_corrupt(sc, sc->sa.agi_bp); |
| 558 | + |
| 559 | + if (xfs_sb_version_hasfinobt(&mp->m_sb)) { |
| 560 | + agbno = be32_to_cpu(agi->agi_free_root); |
| 561 | + if (!xfs_verify_agbno(mp, agno, agbno)) |
| 562 | + xfs_scrub_block_set_corrupt(sc, sc->sa.agi_bp); |
| 563 | + |
| 564 | + level = be32_to_cpu(agi->agi_free_level); |
| 565 | + if (level <= 0 || level > XFS_BTREE_MAXLEVELS) |
| 566 | + xfs_scrub_block_set_corrupt(sc, sc->sa.agi_bp); |
| 567 | + } |
| 568 | + |
| 569 | + /* Check inode counters */ |
| 570 | + xfs_ialloc_agino_range(mp, agno, &first_agino, &last_agino); |
| 571 | + icount = be32_to_cpu(agi->agi_count); |
| 572 | + if (icount > last_agino - first_agino + 1 || |
| 573 | + icount < be32_to_cpu(agi->agi_freecount)) |
| 574 | + xfs_scrub_block_set_corrupt(sc, sc->sa.agi_bp); |
| 575 | + |
| 576 | + /* Check inode pointers */ |
| 577 | + agino = be32_to_cpu(agi->agi_newino); |
| 578 | + if (agino != NULLAGINO && !xfs_verify_agino(mp, agno, agino)) |
| 579 | + xfs_scrub_block_set_corrupt(sc, sc->sa.agi_bp); |
| 580 | + |
| 581 | + agino = be32_to_cpu(agi->agi_dirino); |
| 582 | + if (agino != NULLAGINO && !xfs_verify_agino(mp, agno, agino)) |
| 583 | + xfs_scrub_block_set_corrupt(sc, sc->sa.agi_bp); |
| 584 | + |
| 585 | + /* Check unlinked inode buckets */ |
| 586 | + for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { |
| 587 | + agino = be32_to_cpu(agi->agi_unlinked[i]); |
| 588 | + if (agino == NULLAGINO) |
| 589 | + continue; |
| 590 | + if (!xfs_verify_agino(mp, agno, agino)) |
| 591 | + xfs_scrub_block_set_corrupt(sc, sc->sa.agi_bp); |
| 592 | + } |
| 593 | + |
| 594 | + if (agi->agi_pad32 != cpu_to_be32(0)) |
| 595 | + xfs_scrub_block_set_corrupt(sc, sc->sa.agi_bp); |
| 596 | + |
| 597 | +out: |
| 598 | + return error; |
| 599 | +} |
0 commit comments