aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_bmap_btree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_bmap_btree.c')
-rw-r--r--fs/xfs/xfs_bmap_btree.c110
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 */
60void 61void
61xfs_bmdr_to_bmbt( 62xfs_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
711static void 725static int
712xfs_bmbt_verify( 726xfs_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
752static void 781static void
753xfs_bmbt_read_verify( 782xfs_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
759static void 795static void
760xfs_bmbt_write_verify( 796xfs_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
766const struct xfs_buf_ops xfs_bmbt_buf_ops = { 810const 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;