diff options
Diffstat (limited to 'fs/xfs/xfs_bmap_btree.c')
-rw-r--r-- | fs/xfs/xfs_bmap_btree.c | 110 |
1 files changed, 78 insertions, 32 deletions
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 061b45cbe614..3a86c3fa6de1 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include "xfs_error.h" | 37 | #include "xfs_error.h" |
38 | #include "xfs_quota.h" | 38 | #include "xfs_quota.h" |
39 | #include "xfs_trace.h" | 39 | #include "xfs_trace.h" |
40 | #include "xfs_cksum.h" | ||
40 | 41 | ||
41 | /* | 42 | /* |
42 | * Determine the extent state. | 43 | * Determine the extent state. |
@@ -59,24 +60,31 @@ xfs_extent_state( | |||
59 | */ | 60 | */ |
60 | void | 61 | void |
61 | xfs_bmdr_to_bmbt( | 62 | xfs_bmdr_to_bmbt( |
62 | struct xfs_mount *mp, | 63 | struct xfs_inode *ip, |
63 | xfs_bmdr_block_t *dblock, | 64 | xfs_bmdr_block_t *dblock, |
64 | int dblocklen, | 65 | int dblocklen, |
65 | struct xfs_btree_block *rblock, | 66 | struct xfs_btree_block *rblock, |
66 | int rblocklen) | 67 | int rblocklen) |
67 | { | 68 | { |
69 | struct xfs_mount *mp = ip->i_mount; | ||
68 | int dmxr; | 70 | int dmxr; |
69 | xfs_bmbt_key_t *fkp; | 71 | xfs_bmbt_key_t *fkp; |
70 | __be64 *fpp; | 72 | __be64 *fpp; |
71 | xfs_bmbt_key_t *tkp; | 73 | xfs_bmbt_key_t *tkp; |
72 | __be64 *tpp; | 74 | __be64 *tpp; |
73 | 75 | ||
74 | rblock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC); | 76 | if (xfs_sb_version_hascrc(&mp->m_sb)) |
77 | xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL, | ||
78 | XFS_BMAP_CRC_MAGIC, 0, 0, ip->i_ino, | ||
79 | XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS); | ||
80 | else | ||
81 | xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL, | ||
82 | XFS_BMAP_MAGIC, 0, 0, ip->i_ino, | ||
83 | XFS_BTREE_LONG_PTRS); | ||
84 | |||
75 | rblock->bb_level = dblock->bb_level; | 85 | rblock->bb_level = dblock->bb_level; |
76 | ASSERT(be16_to_cpu(rblock->bb_level) > 0); | 86 | ASSERT(be16_to_cpu(rblock->bb_level) > 0); |
77 | rblock->bb_numrecs = dblock->bb_numrecs; | 87 | rblock->bb_numrecs = dblock->bb_numrecs; |
78 | rblock->bb_u.l.bb_leftsib = cpu_to_be64(NULLDFSBNO); | ||
79 | rblock->bb_u.l.bb_rightsib = cpu_to_be64(NULLDFSBNO); | ||
80 | dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0); | 88 | dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0); |
81 | fkp = XFS_BMDR_KEY_ADDR(dblock, 1); | 89 | fkp = XFS_BMDR_KEY_ADDR(dblock, 1); |
82 | tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); | 90 | tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); |
@@ -424,7 +432,13 @@ xfs_bmbt_to_bmdr( | |||
424 | xfs_bmbt_key_t *tkp; | 432 | xfs_bmbt_key_t *tkp; |
425 | __be64 *tpp; | 433 | __be64 *tpp; |
426 | 434 | ||
427 | ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC)); | 435 | if (xfs_sb_version_hascrc(&mp->m_sb)) { |
436 | ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC)); | ||
437 | ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid)); | ||
438 | ASSERT(rblock->bb_u.l.bb_blkno == | ||
439 | cpu_to_be64(XFS_BUF_DADDR_NULL)); | ||
440 | } else | ||
441 | ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC)); | ||
428 | ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO)); | 442 | ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO)); |
429 | ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO)); | 443 | ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO)); |
430 | ASSERT(rblock->bb_level != 0); | 444 | ASSERT(rblock->bb_level != 0); |
@@ -708,59 +722,89 @@ xfs_bmbt_key_diff( | |||
708 | cur->bc_rec.b.br_startoff; | 722 | cur->bc_rec.b.br_startoff; |
709 | } | 723 | } |
710 | 724 | ||
711 | static void | 725 | static int |
712 | xfs_bmbt_verify( | 726 | xfs_bmbt_verify( |
713 | struct xfs_buf *bp) | 727 | struct xfs_buf *bp) |
714 | { | 728 | { |
715 | struct xfs_mount *mp = bp->b_target->bt_mount; | 729 | struct xfs_mount *mp = bp->b_target->bt_mount; |
716 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); | 730 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); |
717 | unsigned int level; | 731 | unsigned int level; |
718 | int lblock_ok; /* block passes checks */ | ||
719 | 732 | ||
720 | /* magic number and level verification. | 733 | switch (block->bb_magic) { |
734 | case cpu_to_be32(XFS_BMAP_CRC_MAGIC): | ||
735 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
736 | return false; | ||
737 | if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid)) | ||
738 | return false; | ||
739 | if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn) | ||
740 | return false; | ||
741 | /* | ||
742 | * XXX: need a better way of verifying the owner here. Right now | ||
743 | * just make sure there has been one set. | ||
744 | */ | ||
745 | if (be64_to_cpu(block->bb_u.l.bb_owner) == 0) | ||
746 | return false; | ||
747 | /* fall through */ | ||
748 | case cpu_to_be32(XFS_BMAP_MAGIC): | ||
749 | break; | ||
750 | default: | ||
751 | return false; | ||
752 | } | ||
753 | |||
754 | /* | ||
755 | * numrecs and level verification. | ||
721 | * | 756 | * |
722 | * We don't know waht fork we belong to, so just verify that the level | 757 | * We don't know what fork we belong to, so just verify that the level |
723 | * is less than the maximum of the two. Later checks will be more | 758 | * is less than the maximum of the two. Later checks will be more |
724 | * precise. | 759 | * precise. |
725 | */ | 760 | */ |
726 | level = be16_to_cpu(block->bb_level); | 761 | level = be16_to_cpu(block->bb_level); |
727 | lblock_ok = block->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC) && | 762 | if (level > max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1])) |
728 | level < max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1]); | 763 | return false; |
729 | 764 | if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[level != 0]) | |
730 | /* numrecs verification */ | 765 | return false; |
731 | lblock_ok = lblock_ok && | ||
732 | be16_to_cpu(block->bb_numrecs) <= mp->m_bmap_dmxr[level != 0]; | ||
733 | 766 | ||
734 | /* sibling pointer verification */ | 767 | /* sibling pointer verification */ |
735 | lblock_ok = lblock_ok && | 768 | if (!block->bb_u.l.bb_leftsib || |
736 | block->bb_u.l.bb_leftsib && | 769 | (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLDFSBNO) && |
737 | (block->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO) || | 770 | !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_leftsib)))) |
738 | XFS_FSB_SANITY_CHECK(mp, | 771 | return false; |
739 | be64_to_cpu(block->bb_u.l.bb_leftsib))) && | 772 | if (!block->bb_u.l.bb_rightsib || |
740 | block->bb_u.l.bb_rightsib && | 773 | (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLDFSBNO) && |
741 | (block->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO) || | 774 | !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_rightsib)))) |
742 | XFS_FSB_SANITY_CHECK(mp, | 775 | return false; |
743 | be64_to_cpu(block->bb_u.l.bb_rightsib))); | 776 | |
744 | 777 | return true; | |
745 | if (!lblock_ok) { | 778 | |
746 | trace_xfs_btree_corrupt(bp, _RET_IP_); | ||
747 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, block); | ||
748 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
749 | } | ||
750 | } | 779 | } |
751 | 780 | ||
752 | static void | 781 | static void |
753 | xfs_bmbt_read_verify( | 782 | xfs_bmbt_read_verify( |
754 | struct xfs_buf *bp) | 783 | struct xfs_buf *bp) |
755 | { | 784 | { |
756 | xfs_bmbt_verify(bp); | 785 | if (!(xfs_btree_lblock_verify_crc(bp) && |
786 | xfs_bmbt_verify(bp))) { | ||
787 | trace_xfs_btree_corrupt(bp, _RET_IP_); | ||
788 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, | ||
789 | bp->b_target->bt_mount, bp->b_addr); | ||
790 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
791 | } | ||
792 | |||
757 | } | 793 | } |
758 | 794 | ||
759 | static void | 795 | static void |
760 | xfs_bmbt_write_verify( | 796 | xfs_bmbt_write_verify( |
761 | struct xfs_buf *bp) | 797 | struct xfs_buf *bp) |
762 | { | 798 | { |
763 | xfs_bmbt_verify(bp); | 799 | if (!xfs_bmbt_verify(bp)) { |
800 | xfs_warn(bp->b_target->bt_mount, "bmbt daddr 0x%llx failed", bp->b_bn); | ||
801 | trace_xfs_btree_corrupt(bp, _RET_IP_); | ||
802 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, | ||
803 | bp->b_target->bt_mount, bp->b_addr); | ||
804 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
805 | return; | ||
806 | } | ||
807 | xfs_btree_lblock_calc_crc(bp); | ||
764 | } | 808 | } |
765 | 809 | ||
766 | const struct xfs_buf_ops xfs_bmbt_buf_ops = { | 810 | const struct xfs_buf_ops xfs_bmbt_buf_ops = { |
@@ -838,6 +882,8 @@ xfs_bmbt_init_cursor( | |||
838 | 882 | ||
839 | cur->bc_ops = &xfs_bmbt_ops; | 883 | cur->bc_ops = &xfs_bmbt_ops; |
840 | cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE; | 884 | cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE; |
885 | if (xfs_sb_version_hascrc(&mp->m_sb)) | ||
886 | cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; | ||
841 | 887 | ||
842 | cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); | 888 | cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); |
843 | cur->bc_private.b.ip = ip; | 889 | cur->bc_private.b.ip = ip; |