diff options
| -rw-r--r-- | fs/xfs/xfs_alloc_btree.c | 61 | ||||
| -rw-r--r-- | fs/xfs/xfs_bmap.c | 60 | ||||
| -rw-r--r-- | fs/xfs/xfs_bmap_btree.c | 47 | ||||
| -rw-r--r-- | fs/xfs/xfs_bmap_btree.h | 1 | ||||
| -rw-r--r-- | fs/xfs/xfs_btree.c | 66 | ||||
| -rw-r--r-- | fs/xfs/xfs_btree.h | 10 | ||||
| -rw-r--r-- | fs/xfs/xfs_ialloc_btree.c | 40 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.h | 1 | ||||
| -rw-r--r-- | fs/xfs/xfs_itable.c | 3 |
10 files changed, 230 insertions, 61 deletions
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index f7876c6d6165..46961e52e9b8 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c | |||
| @@ -272,6 +272,66 @@ xfs_allocbt_key_diff( | |||
| 272 | return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; | 272 | return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | void | ||
| 276 | xfs_allocbt_read_verify( | ||
| 277 | struct xfs_buf *bp) | ||
| 278 | { | ||
| 279 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
| 280 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); | ||
| 281 | struct xfs_perag *pag = bp->b_pag; | ||
| 282 | unsigned int level; | ||
| 283 | int sblock_ok; /* block passes checks */ | ||
| 284 | |||
| 285 | /* | ||
| 286 | * magic number and level verification | ||
| 287 | * | ||
| 288 | * During growfs operations, we can't verify the exact level as the | ||
| 289 | * perag is not fully initialised and hence not attached to the buffer. | ||
| 290 | * In this case, check against the maximum tree depth. | ||
| 291 | */ | ||
| 292 | level = be16_to_cpu(block->bb_level); | ||
| 293 | switch (block->bb_magic) { | ||
| 294 | case cpu_to_be32(XFS_ABTB_MAGIC): | ||
| 295 | if (pag) | ||
| 296 | sblock_ok = level < pag->pagf_levels[XFS_BTNUM_BNOi]; | ||
| 297 | else | ||
| 298 | sblock_ok = level < mp->m_ag_maxlevels; | ||
| 299 | break; | ||
| 300 | case cpu_to_be32(XFS_ABTC_MAGIC): | ||
| 301 | if (pag) | ||
| 302 | sblock_ok = level < pag->pagf_levels[XFS_BTNUM_CNTi]; | ||
| 303 | else | ||
| 304 | sblock_ok = level < mp->m_ag_maxlevels; | ||
| 305 | break; | ||
| 306 | default: | ||
| 307 | sblock_ok = 0; | ||
| 308 | break; | ||
| 309 | } | ||
| 310 | |||
| 311 | /* numrecs verification */ | ||
| 312 | sblock_ok = sblock_ok && | ||
| 313 | be16_to_cpu(block->bb_numrecs) <= mp->m_alloc_mxr[level != 0]; | ||
| 314 | |||
| 315 | /* sibling pointer verification */ | ||
| 316 | sblock_ok = sblock_ok && | ||
| 317 | (block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) || | ||
| 318 | be32_to_cpu(block->bb_u.s.bb_leftsib) < mp->m_sb.sb_agblocks) && | ||
| 319 | block->bb_u.s.bb_leftsib && | ||
| 320 | (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) || | ||
| 321 | be32_to_cpu(block->bb_u.s.bb_rightsib) < mp->m_sb.sb_agblocks) && | ||
| 322 | block->bb_u.s.bb_rightsib; | ||
| 323 | |||
| 324 | if (!sblock_ok) { | ||
| 325 | trace_xfs_btree_corrupt(bp, _RET_IP_); | ||
| 326 | XFS_CORRUPTION_ERROR("xfs_allocbt_read_verify", | ||
| 327 | XFS_ERRLEVEL_LOW, mp, block); | ||
| 328 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
| 329 | } | ||
| 330 | |||
| 331 | bp->b_iodone = NULL; | ||
| 332 | xfs_buf_ioend(bp, 0); | ||
| 333 | } | ||
| 334 | |||
| 275 | #ifdef DEBUG | 335 | #ifdef DEBUG |
| 276 | STATIC int | 336 | STATIC int |
| 277 | xfs_allocbt_keys_inorder( | 337 | xfs_allocbt_keys_inorder( |
| @@ -327,6 +387,7 @@ static const struct xfs_btree_ops xfs_allocbt_ops = { | |||
| 327 | .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, | 387 | .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, |
| 328 | .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, | 388 | .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, |
| 329 | .key_diff = xfs_allocbt_key_diff, | 389 | .key_diff = xfs_allocbt_key_diff, |
| 390 | .read_verify = xfs_allocbt_read_verify, | ||
| 330 | #ifdef DEBUG | 391 | #ifdef DEBUG |
| 331 | .keys_inorder = xfs_allocbt_keys_inorder, | 392 | .keys_inorder = xfs_allocbt_keys_inorder, |
| 332 | .recs_inorder = xfs_allocbt_recs_inorder, | 393 | .recs_inorder = xfs_allocbt_recs_inorder, |
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index a60f3d1f151c..9ae7aba52e0f 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
| @@ -2662,8 +2662,9 @@ xfs_bmap_btree_to_extents( | |||
| 2662 | if ((error = xfs_btree_check_lptr(cur, cbno, 1))) | 2662 | if ((error = xfs_btree_check_lptr(cur, cbno, 1))) |
| 2663 | return error; | 2663 | return error; |
| 2664 | #endif | 2664 | #endif |
| 2665 | if ((error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp, | 2665 | error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp, XFS_BMAP_BTREE_REF, |
| 2666 | XFS_BMAP_BTREE_REF))) | 2666 | xfs_bmbt_read_verify); |
| 2667 | if (error) | ||
| 2667 | return error; | 2668 | return error; |
| 2668 | cblock = XFS_BUF_TO_BLOCK(cbp); | 2669 | cblock = XFS_BUF_TO_BLOCK(cbp); |
| 2669 | if ((error = xfs_btree_check_block(cur, cblock, 0, cbp))) | 2670 | if ((error = xfs_btree_check_block(cur, cblock, 0, cbp))) |
| @@ -4078,8 +4079,9 @@ xfs_bmap_read_extents( | |||
| 4078 | * pointer (leftmost) at each level. | 4079 | * pointer (leftmost) at each level. |
| 4079 | */ | 4080 | */ |
| 4080 | while (level-- > 0) { | 4081 | while (level-- > 0) { |
| 4081 | if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, | 4082 | error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, |
| 4082 | XFS_BMAP_BTREE_REF))) | 4083 | XFS_BMAP_BTREE_REF, xfs_bmbt_read_verify); |
| 4084 | if (error) | ||
| 4083 | return error; | 4085 | return error; |
| 4084 | block = XFS_BUF_TO_BLOCK(bp); | 4086 | block = XFS_BUF_TO_BLOCK(bp); |
| 4085 | XFS_WANT_CORRUPTED_GOTO( | 4087 | XFS_WANT_CORRUPTED_GOTO( |
| @@ -4124,7 +4126,8 @@ xfs_bmap_read_extents( | |||
| 4124 | */ | 4126 | */ |
| 4125 | nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); | 4127 | nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); |
| 4126 | if (nextbno != NULLFSBLOCK) | 4128 | if (nextbno != NULLFSBLOCK) |
| 4127 | xfs_btree_reada_bufl(mp, nextbno, 1); | 4129 | xfs_btree_reada_bufl(mp, nextbno, 1, |
| 4130 | xfs_bmbt_read_verify); | ||
| 4128 | /* | 4131 | /* |
| 4129 | * Copy records into the extent records. | 4132 | * Copy records into the extent records. |
| 4130 | */ | 4133 | */ |
| @@ -4156,8 +4159,9 @@ xfs_bmap_read_extents( | |||
| 4156 | */ | 4159 | */ |
| 4157 | if (bno == NULLFSBLOCK) | 4160 | if (bno == NULLFSBLOCK) |
| 4158 | break; | 4161 | break; |
| 4159 | if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, | 4162 | error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, |
| 4160 | XFS_BMAP_BTREE_REF))) | 4163 | XFS_BMAP_BTREE_REF, xfs_bmbt_read_verify); |
| 4164 | if (error) | ||
| 4161 | return error; | 4165 | return error; |
| 4162 | block = XFS_BUF_TO_BLOCK(bp); | 4166 | block = XFS_BUF_TO_BLOCK(bp); |
| 4163 | } | 4167 | } |
| @@ -5868,15 +5872,16 @@ xfs_bmap_check_leaf_extents( | |||
| 5868 | */ | 5872 | */ |
| 5869 | while (level-- > 0) { | 5873 | while (level-- > 0) { |
| 5870 | /* See if buf is in cur first */ | 5874 | /* See if buf is in cur first */ |
| 5875 | bp_release = 0; | ||
| 5871 | bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); | 5876 | bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); |
| 5872 | if (bp) { | 5877 | if (!bp) { |
| 5873 | bp_release = 0; | ||
| 5874 | } else { | ||
| 5875 | bp_release = 1; | 5878 | bp_release = 1; |
| 5879 | error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, | ||
| 5880 | XFS_BMAP_BTREE_REF, | ||
| 5881 | xfs_bmbt_read_verify); | ||
| 5882 | if (error) | ||
| 5883 | goto error_norelse; | ||
| 5876 | } | 5884 | } |
| 5877 | if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, | ||
| 5878 | XFS_BMAP_BTREE_REF))) | ||
| 5879 | goto error_norelse; | ||
| 5880 | block = XFS_BUF_TO_BLOCK(bp); | 5885 | block = XFS_BUF_TO_BLOCK(bp); |
| 5881 | XFS_WANT_CORRUPTED_GOTO( | 5886 | XFS_WANT_CORRUPTED_GOTO( |
| 5882 | xfs_bmap_sanity_check(mp, bp, level), | 5887 | xfs_bmap_sanity_check(mp, bp, level), |
| @@ -5953,15 +5958,16 @@ xfs_bmap_check_leaf_extents( | |||
| 5953 | if (bno == NULLFSBLOCK) | 5958 | if (bno == NULLFSBLOCK) |
| 5954 | break; | 5959 | break; |
| 5955 | 5960 | ||
| 5961 | bp_release = 0; | ||
| 5956 | bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); | 5962 | bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); |
| 5957 | if (bp) { | 5963 | if (!bp) { |
| 5958 | bp_release = 0; | ||
| 5959 | } else { | ||
| 5960 | bp_release = 1; | 5964 | bp_release = 1; |
| 5965 | error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, | ||
| 5966 | XFS_BMAP_BTREE_REF, | ||
| 5967 | xfs_bmbt_read_verify); | ||
| 5968 | if (error) | ||
| 5969 | goto error_norelse; | ||
| 5961 | } | 5970 | } |
| 5962 | if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, | ||
| 5963 | XFS_BMAP_BTREE_REF))) | ||
| 5964 | goto error_norelse; | ||
| 5965 | block = XFS_BUF_TO_BLOCK(bp); | 5971 | block = XFS_BUF_TO_BLOCK(bp); |
| 5966 | } | 5972 | } |
| 5967 | if (bp_release) { | 5973 | if (bp_release) { |
| @@ -6052,7 +6058,9 @@ xfs_bmap_count_tree( | |||
| 6052 | struct xfs_btree_block *block, *nextblock; | 6058 | struct xfs_btree_block *block, *nextblock; |
| 6053 | int numrecs; | 6059 | int numrecs; |
| 6054 | 6060 | ||
| 6055 | if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF))) | 6061 | error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF, |
| 6062 | xfs_bmbt_read_verify); | ||
| 6063 | if (error) | ||
| 6056 | return error; | 6064 | return error; |
| 6057 | *count += 1; | 6065 | *count += 1; |
| 6058 | block = XFS_BUF_TO_BLOCK(bp); | 6066 | block = XFS_BUF_TO_BLOCK(bp); |
| @@ -6061,8 +6069,10 @@ xfs_bmap_count_tree( | |||
| 6061 | /* Not at node above leaves, count this level of nodes */ | 6069 | /* Not at node above leaves, count this level of nodes */ |
| 6062 | nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); | 6070 | nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); |
| 6063 | while (nextbno != NULLFSBLOCK) { | 6071 | while (nextbno != NULLFSBLOCK) { |
| 6064 | if ((error = xfs_btree_read_bufl(mp, tp, nextbno, | 6072 | error = xfs_btree_read_bufl(mp, tp, nextbno, 0, &nbp, |
| 6065 | 0, &nbp, XFS_BMAP_BTREE_REF))) | 6073 | XFS_BMAP_BTREE_REF, |
| 6074 | xfs_bmbt_read_verify); | ||
| 6075 | if (error) | ||
| 6066 | return error; | 6076 | return error; |
| 6067 | *count += 1; | 6077 | *count += 1; |
| 6068 | nextblock = XFS_BUF_TO_BLOCK(nbp); | 6078 | nextblock = XFS_BUF_TO_BLOCK(nbp); |
| @@ -6091,8 +6101,10 @@ xfs_bmap_count_tree( | |||
| 6091 | if (nextbno == NULLFSBLOCK) | 6101 | if (nextbno == NULLFSBLOCK) |
| 6092 | break; | 6102 | break; |
| 6093 | bno = nextbno; | 6103 | bno = nextbno; |
| 6094 | if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, | 6104 | error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, |
| 6095 | XFS_BMAP_BTREE_REF))) | 6105 | XFS_BMAP_BTREE_REF, |
| 6106 | xfs_bmbt_read_verify); | ||
| 6107 | if (error) | ||
| 6096 | return error; | 6108 | return error; |
| 6097 | *count += 1; | 6109 | *count += 1; |
| 6098 | block = XFS_BUF_TO_BLOCK(bp); | 6110 | block = XFS_BUF_TO_BLOCK(bp); |
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 862084a47a7e..bddca9b92869 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include "xfs_bmap.h" | 36 | #include "xfs_bmap.h" |
| 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 | 40 | ||
| 40 | /* | 41 | /* |
| 41 | * Determine the extent state. | 42 | * Determine the extent state. |
| @@ -707,6 +708,51 @@ xfs_bmbt_key_diff( | |||
| 707 | cur->bc_rec.b.br_startoff; | 708 | cur->bc_rec.b.br_startoff; |
| 708 | } | 709 | } |
| 709 | 710 | ||
| 711 | void | ||
| 712 | xfs_bmbt_read_verify( | ||
| 713 | struct xfs_buf *bp) | ||
| 714 | { | ||
| 715 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
| 716 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); | ||
| 717 | unsigned int level; | ||
| 718 | int lblock_ok; /* block passes checks */ | ||
| 719 | |||
| 720 | /* magic number and level verification. | ||
| 721 | * | ||
| 722 | * We don't know waht fork we belong to, so just verify that the level | ||
| 723 | * is less than the maximum of the two. Later checks will be more | ||
| 724 | * precise. | ||
| 725 | */ | ||
| 726 | level = be16_to_cpu(block->bb_level); | ||
| 727 | lblock_ok = block->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC) && | ||
| 728 | level < max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1]); | ||
| 729 | |||
| 730 | /* numrecs verification */ | ||
| 731 | lblock_ok = lblock_ok && | ||
| 732 | be16_to_cpu(block->bb_numrecs) <= mp->m_bmap_dmxr[level != 0]; | ||
| 733 | |||
| 734 | /* sibling pointer verification */ | ||
| 735 | lblock_ok = lblock_ok && | ||
| 736 | block->bb_u.l.bb_leftsib && | ||
| 737 | (block->bb_u.l.bb_leftsib == cpu_to_be64(NULLDFSBNO) || | ||
| 738 | XFS_FSB_SANITY_CHECK(mp, | ||
| 739 | be64_to_cpu(block->bb_u.l.bb_leftsib))) && | ||
| 740 | block->bb_u.l.bb_rightsib && | ||
| 741 | (block->bb_u.l.bb_rightsib == cpu_to_be64(NULLDFSBNO) || | ||
| 742 | XFS_FSB_SANITY_CHECK(mp, | ||
| 743 | be64_to_cpu(block->bb_u.l.bb_rightsib))); | ||
| 744 | |||
| 745 | if (!lblock_ok) { | ||
| 746 | trace_xfs_btree_corrupt(bp, _RET_IP_); | ||
| 747 | XFS_CORRUPTION_ERROR("xfs_bmbt_read_verify", | ||
| 748 | XFS_ERRLEVEL_LOW, mp, block); | ||
| 749 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
| 750 | } | ||
| 751 | |||
| 752 | bp->b_iodone = NULL; | ||
| 753 | xfs_buf_ioend(bp, 0); | ||
| 754 | } | ||
| 755 | |||
| 710 | #ifdef DEBUG | 756 | #ifdef DEBUG |
| 711 | STATIC int | 757 | STATIC int |
| 712 | xfs_bmbt_keys_inorder( | 758 | xfs_bmbt_keys_inorder( |
| @@ -746,6 +792,7 @@ static const struct xfs_btree_ops xfs_bmbt_ops = { | |||
| 746 | .init_rec_from_cur = xfs_bmbt_init_rec_from_cur, | 792 | .init_rec_from_cur = xfs_bmbt_init_rec_from_cur, |
| 747 | .init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur, | 793 | .init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur, |
| 748 | .key_diff = xfs_bmbt_key_diff, | 794 | .key_diff = xfs_bmbt_key_diff, |
| 795 | .read_verify = xfs_bmbt_read_verify, | ||
| 749 | #ifdef DEBUG | 796 | #ifdef DEBUG |
| 750 | .keys_inorder = xfs_bmbt_keys_inorder, | 797 | .keys_inorder = xfs_bmbt_keys_inorder, |
| 751 | .recs_inorder = xfs_bmbt_recs_inorder, | 798 | .recs_inorder = xfs_bmbt_recs_inorder, |
diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index 0e66c4ea0f85..1d00fbe9dd79 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h | |||
| @@ -232,6 +232,7 @@ extern void xfs_bmbt_to_bmdr(struct xfs_mount *, struct xfs_btree_block *, int, | |||
| 232 | extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level); | 232 | extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level); |
| 233 | extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf); | 233 | extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf); |
| 234 | extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf); | 234 | extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf); |
| 235 | extern void xfs_bmbt_read_verify(struct xfs_buf *bp); | ||
| 235 | 236 | ||
| 236 | extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *, | 237 | extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *, |
| 237 | struct xfs_trans *, struct xfs_inode *, int); | 238 | struct xfs_trans *, struct xfs_inode *, int); |
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 7e791160092d..ef1066078c33 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
| @@ -270,7 +270,8 @@ xfs_btree_dup_cursor( | |||
| 270 | if (bp) { | 270 | if (bp) { |
| 271 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, | 271 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, |
| 272 | XFS_BUF_ADDR(bp), mp->m_bsize, | 272 | XFS_BUF_ADDR(bp), mp->m_bsize, |
| 273 | 0, &bp, NULL); | 273 | 0, &bp, |
| 274 | cur->bc_ops->read_verify); | ||
| 274 | if (error) { | 275 | if (error) { |
| 275 | xfs_btree_del_cursor(new, error); | 276 | xfs_btree_del_cursor(new, error); |
| 276 | *ncur = NULL; | 277 | *ncur = NULL; |
| @@ -612,23 +613,24 @@ xfs_btree_offsets( | |||
| 612 | * Get a buffer for the block, return it read in. | 613 | * Get a buffer for the block, return it read in. |
| 613 | * Long-form addressing. | 614 | * Long-form addressing. |
| 614 | */ | 615 | */ |
| 615 | int /* error */ | 616 | int |
| 616 | xfs_btree_read_bufl( | 617 | xfs_btree_read_bufl( |
| 617 | xfs_mount_t *mp, /* file system mount point */ | 618 | struct xfs_mount *mp, /* file system mount point */ |
| 618 | xfs_trans_t *tp, /* transaction pointer */ | 619 | struct xfs_trans *tp, /* transaction pointer */ |
| 619 | xfs_fsblock_t fsbno, /* file system block number */ | 620 | xfs_fsblock_t fsbno, /* file system block number */ |
| 620 | uint lock, /* lock flags for read_buf */ | 621 | uint lock, /* lock flags for read_buf */ |
| 621 | xfs_buf_t **bpp, /* buffer for fsbno */ | 622 | struct xfs_buf **bpp, /* buffer for fsbno */ |
| 622 | int refval) /* ref count value for buffer */ | 623 | int refval, /* ref count value for buffer */ |
| 623 | { | 624 | xfs_buf_iodone_t verify) |
| 624 | xfs_buf_t *bp; /* return value */ | 625 | { |
| 626 | struct xfs_buf *bp; /* return value */ | ||
| 625 | xfs_daddr_t d; /* real disk block address */ | 627 | xfs_daddr_t d; /* real disk block address */ |
| 626 | int error; | 628 | int error; |
| 627 | 629 | ||
| 628 | ASSERT(fsbno != NULLFSBLOCK); | 630 | ASSERT(fsbno != NULLFSBLOCK); |
| 629 | d = XFS_FSB_TO_DADDR(mp, fsbno); | 631 | d = XFS_FSB_TO_DADDR(mp, fsbno); |
| 630 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, | 632 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, |
| 631 | mp->m_bsize, lock, &bp, NULL); | 633 | mp->m_bsize, lock, &bp, verify); |
| 632 | if (error) | 634 | if (error) |
| 633 | return error; | 635 | return error; |
| 634 | ASSERT(!xfs_buf_geterror(bp)); | 636 | ASSERT(!xfs_buf_geterror(bp)); |
| @@ -645,15 +647,16 @@ xfs_btree_read_bufl( | |||
| 645 | /* ARGSUSED */ | 647 | /* ARGSUSED */ |
| 646 | void | 648 | void |
| 647 | xfs_btree_reada_bufl( | 649 | xfs_btree_reada_bufl( |
| 648 | xfs_mount_t *mp, /* file system mount point */ | 650 | struct xfs_mount *mp, /* file system mount point */ |
| 649 | xfs_fsblock_t fsbno, /* file system block number */ | 651 | xfs_fsblock_t fsbno, /* file system block number */ |
| 650 | xfs_extlen_t count) /* count of filesystem blocks */ | 652 | xfs_extlen_t count, /* count of filesystem blocks */ |
| 653 | xfs_buf_iodone_t verify) | ||
| 651 | { | 654 | { |
| 652 | xfs_daddr_t d; | 655 | xfs_daddr_t d; |
| 653 | 656 | ||
| 654 | ASSERT(fsbno != NULLFSBLOCK); | 657 | ASSERT(fsbno != NULLFSBLOCK); |
| 655 | d = XFS_FSB_TO_DADDR(mp, fsbno); | 658 | d = XFS_FSB_TO_DADDR(mp, fsbno); |
| 656 | xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, NULL); | 659 | xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, verify); |
| 657 | } | 660 | } |
| 658 | 661 | ||
| 659 | /* | 662 | /* |
| @@ -663,17 +666,18 @@ xfs_btree_reada_bufl( | |||
| 663 | /* ARGSUSED */ | 666 | /* ARGSUSED */ |
| 664 | void | 667 | void |
| 665 | xfs_btree_reada_bufs( | 668 | xfs_btree_reada_bufs( |
| 666 | xfs_mount_t *mp, /* file system mount point */ | 669 | struct xfs_mount *mp, /* file system mount point */ |
| 667 | xfs_agnumber_t agno, /* allocation group number */ | 670 | xfs_agnumber_t agno, /* allocation group number */ |
| 668 | xfs_agblock_t agbno, /* allocation group block number */ | 671 | xfs_agblock_t agbno, /* allocation group block number */ |
| 669 | xfs_extlen_t count) /* count of filesystem blocks */ | 672 | xfs_extlen_t count, /* count of filesystem blocks */ |
| 673 | xfs_buf_iodone_t verify) | ||
| 670 | { | 674 | { |
| 671 | xfs_daddr_t d; | 675 | xfs_daddr_t d; |
| 672 | 676 | ||
| 673 | ASSERT(agno != NULLAGNUMBER); | 677 | ASSERT(agno != NULLAGNUMBER); |
| 674 | ASSERT(agbno != NULLAGBLOCK); | 678 | ASSERT(agbno != NULLAGBLOCK); |
| 675 | d = XFS_AGB_TO_DADDR(mp, agno, agbno); | 679 | d = XFS_AGB_TO_DADDR(mp, agno, agbno); |
| 676 | xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, NULL); | 680 | xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, verify); |
| 677 | } | 681 | } |
| 678 | 682 | ||
| 679 | STATIC int | 683 | STATIC int |
| @@ -687,12 +691,14 @@ xfs_btree_readahead_lblock( | |||
| 687 | xfs_dfsbno_t right = be64_to_cpu(block->bb_u.l.bb_rightsib); | 691 | xfs_dfsbno_t right = be64_to_cpu(block->bb_u.l.bb_rightsib); |
| 688 | 692 | ||
| 689 | if ((lr & XFS_BTCUR_LEFTRA) && left != NULLDFSBNO) { | 693 | if ((lr & XFS_BTCUR_LEFTRA) && left != NULLDFSBNO) { |
| 690 | xfs_btree_reada_bufl(cur->bc_mp, left, 1); | 694 | xfs_btree_reada_bufl(cur->bc_mp, left, 1, |
| 695 | cur->bc_ops->read_verify); | ||
| 691 | rval++; | 696 | rval++; |
| 692 | } | 697 | } |
| 693 | 698 | ||
| 694 | if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLDFSBNO) { | 699 | if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLDFSBNO) { |
| 695 | xfs_btree_reada_bufl(cur->bc_mp, right, 1); | 700 | xfs_btree_reada_bufl(cur->bc_mp, right, 1, |
| 701 | cur->bc_ops->read_verify); | ||
| 696 | rval++; | 702 | rval++; |
| 697 | } | 703 | } |
| 698 | 704 | ||
| @@ -712,13 +718,13 @@ xfs_btree_readahead_sblock( | |||
| 712 | 718 | ||
| 713 | if ((lr & XFS_BTCUR_LEFTRA) && left != NULLAGBLOCK) { | 719 | if ((lr & XFS_BTCUR_LEFTRA) && left != NULLAGBLOCK) { |
| 714 | xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, | 720 | xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, |
| 715 | left, 1); | 721 | left, 1, cur->bc_ops->read_verify); |
| 716 | rval++; | 722 | rval++; |
| 717 | } | 723 | } |
| 718 | 724 | ||
| 719 | if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLAGBLOCK) { | 725 | if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLAGBLOCK) { |
| 720 | xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, | 726 | xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, |
| 721 | right, 1); | 727 | right, 1, cur->bc_ops->read_verify); |
| 722 | rval++; | 728 | rval++; |
| 723 | } | 729 | } |
| 724 | 730 | ||
| @@ -1016,19 +1022,15 @@ xfs_btree_read_buf_block( | |||
| 1016 | 1022 | ||
| 1017 | d = xfs_btree_ptr_to_daddr(cur, ptr); | 1023 | d = xfs_btree_ptr_to_daddr(cur, ptr); |
| 1018 | error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d, | 1024 | error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d, |
| 1019 | mp->m_bsize, flags, bpp, NULL); | 1025 | mp->m_bsize, flags, bpp, |
| 1026 | cur->bc_ops->read_verify); | ||
| 1020 | if (error) | 1027 | if (error) |
| 1021 | return error; | 1028 | return error; |
| 1022 | 1029 | ||
| 1023 | ASSERT(!xfs_buf_geterror(*bpp)); | 1030 | ASSERT(!xfs_buf_geterror(*bpp)); |
| 1024 | |||
| 1025 | xfs_btree_set_refs(cur, *bpp); | 1031 | xfs_btree_set_refs(cur, *bpp); |
| 1026 | *block = XFS_BUF_TO_BLOCK(*bpp); | 1032 | *block = XFS_BUF_TO_BLOCK(*bpp); |
| 1027 | 1033 | return 0; | |
| 1028 | error = xfs_btree_check_block(cur, *block, level, *bpp); | ||
| 1029 | if (error) | ||
| 1030 | xfs_trans_brelse(cur->bc_tp, *bpp); | ||
| 1031 | return error; | ||
| 1032 | } | 1034 | } |
| 1033 | 1035 | ||
| 1034 | /* | 1036 | /* |
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index c9cf2d00e236..3a4c314047a0 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h | |||
| @@ -188,6 +188,7 @@ struct xfs_btree_ops { | |||
| 188 | __int64_t (*key_diff)(struct xfs_btree_cur *cur, | 188 | __int64_t (*key_diff)(struct xfs_btree_cur *cur, |
| 189 | union xfs_btree_key *key); | 189 | union xfs_btree_key *key); |
| 190 | 190 | ||
| 191 | void (*read_verify)(struct xfs_buf *bp); | ||
| 191 | #ifdef DEBUG | 192 | #ifdef DEBUG |
| 192 | /* check that k1 is lower than k2 */ | 193 | /* check that k1 is lower than k2 */ |
| 193 | int (*keys_inorder)(struct xfs_btree_cur *cur, | 194 | int (*keys_inorder)(struct xfs_btree_cur *cur, |
| @@ -355,7 +356,8 @@ xfs_btree_read_bufl( | |||
| 355 | xfs_fsblock_t fsbno, /* file system block number */ | 356 | xfs_fsblock_t fsbno, /* file system block number */ |
| 356 | uint lock, /* lock flags for read_buf */ | 357 | uint lock, /* lock flags for read_buf */ |
| 357 | struct xfs_buf **bpp, /* buffer for fsbno */ | 358 | struct xfs_buf **bpp, /* buffer for fsbno */ |
| 358 | int refval);/* ref count value for buffer */ | 359 | int refval, /* ref count value for buffer */ |
| 360 | xfs_buf_iodone_t verify); | ||
| 359 | 361 | ||
| 360 | /* | 362 | /* |
| 361 | * Read-ahead the block, don't wait for it, don't return a buffer. | 363 | * Read-ahead the block, don't wait for it, don't return a buffer. |
| @@ -365,7 +367,8 @@ void /* error */ | |||
| 365 | xfs_btree_reada_bufl( | 367 | xfs_btree_reada_bufl( |
| 366 | struct xfs_mount *mp, /* file system mount point */ | 368 | struct xfs_mount *mp, /* file system mount point */ |
| 367 | xfs_fsblock_t fsbno, /* file system block number */ | 369 | xfs_fsblock_t fsbno, /* file system block number */ |
| 368 | xfs_extlen_t count); /* count of filesystem blocks */ | 370 | xfs_extlen_t count, /* count of filesystem blocks */ |
| 371 | xfs_buf_iodone_t verify); | ||
| 369 | 372 | ||
| 370 | /* | 373 | /* |
| 371 | * Read-ahead the block, don't wait for it, don't return a buffer. | 374 | * Read-ahead the block, don't wait for it, don't return a buffer. |
| @@ -376,7 +379,8 @@ xfs_btree_reada_bufs( | |||
| 376 | struct xfs_mount *mp, /* file system mount point */ | 379 | struct xfs_mount *mp, /* file system mount point */ |
| 377 | xfs_agnumber_t agno, /* allocation group number */ | 380 | xfs_agnumber_t agno, /* allocation group number */ |
| 378 | xfs_agblock_t agbno, /* allocation group block number */ | 381 | xfs_agblock_t agbno, /* allocation group block number */ |
| 379 | xfs_extlen_t count); /* count of filesystem blocks */ | 382 | xfs_extlen_t count, /* count of filesystem blocks */ |
| 383 | xfs_buf_iodone_t verify); | ||
| 380 | 384 | ||
| 381 | /* | 385 | /* |
| 382 | * Initialise a new btree block header | 386 | * Initialise a new btree block header |
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c index 2b8b7a37aa18..11306c6d61c7 100644 --- a/fs/xfs/xfs_ialloc_btree.c +++ b/fs/xfs/xfs_ialloc_btree.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include "xfs_ialloc.h" | 33 | #include "xfs_ialloc.h" |
| 34 | #include "xfs_alloc.h" | 34 | #include "xfs_alloc.h" |
| 35 | #include "xfs_error.h" | 35 | #include "xfs_error.h" |
| 36 | #include "xfs_trace.h" | ||
| 36 | 37 | ||
| 37 | 38 | ||
| 38 | STATIC int | 39 | STATIC int |
| @@ -181,6 +182,44 @@ xfs_inobt_key_diff( | |||
| 181 | cur->bc_rec.i.ir_startino; | 182 | cur->bc_rec.i.ir_startino; |
| 182 | } | 183 | } |
| 183 | 184 | ||
| 185 | void | ||
| 186 | xfs_inobt_read_verify( | ||
| 187 | struct xfs_buf *bp) | ||
| 188 | { | ||
| 189 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
| 190 | struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); | ||
| 191 | unsigned int level; | ||
| 192 | int sblock_ok; /* block passes checks */ | ||
| 193 | |||
| 194 | /* magic number and level verification */ | ||
| 195 | level = be16_to_cpu(block->bb_level); | ||
| 196 | sblock_ok = block->bb_magic == cpu_to_be32(XFS_IBT_MAGIC) && | ||
| 197 | level < mp->m_in_maxlevels; | ||
| 198 | |||
| 199 | /* numrecs verification */ | ||
| 200 | sblock_ok = sblock_ok && | ||
| 201 | be16_to_cpu(block->bb_numrecs) <= mp->m_inobt_mxr[level != 0]; | ||
| 202 | |||
| 203 | /* sibling pointer verification */ | ||
| 204 | sblock_ok = sblock_ok && | ||
| 205 | (block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) || | ||
| 206 | be32_to_cpu(block->bb_u.s.bb_leftsib) < mp->m_sb.sb_agblocks) && | ||
| 207 | block->bb_u.s.bb_leftsib && | ||
| 208 | (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) || | ||
| 209 | be32_to_cpu(block->bb_u.s.bb_rightsib) < mp->m_sb.sb_agblocks) && | ||
| 210 | block->bb_u.s.bb_rightsib; | ||
| 211 | |||
| 212 | if (!sblock_ok) { | ||
| 213 | trace_xfs_btree_corrupt(bp, _RET_IP_); | ||
| 214 | XFS_CORRUPTION_ERROR("xfs_inobt_read_verify", | ||
| 215 | XFS_ERRLEVEL_LOW, mp, block); | ||
| 216 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
| 217 | } | ||
| 218 | |||
| 219 | bp->b_iodone = NULL; | ||
| 220 | xfs_buf_ioend(bp, 0); | ||
| 221 | } | ||
| 222 | |||
| 184 | #ifdef DEBUG | 223 | #ifdef DEBUG |
| 185 | STATIC int | 224 | STATIC int |
| 186 | xfs_inobt_keys_inorder( | 225 | xfs_inobt_keys_inorder( |
| @@ -218,6 +257,7 @@ static const struct xfs_btree_ops xfs_inobt_ops = { | |||
| 218 | .init_rec_from_cur = xfs_inobt_init_rec_from_cur, | 257 | .init_rec_from_cur = xfs_inobt_init_rec_from_cur, |
| 219 | .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, | 258 | .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, |
| 220 | .key_diff = xfs_inobt_key_diff, | 259 | .key_diff = xfs_inobt_key_diff, |
| 260 | .read_verify = xfs_inobt_read_verify, | ||
| 221 | #ifdef DEBUG | 261 | #ifdef DEBUG |
| 222 | .keys_inorder = xfs_inobt_keys_inorder, | 262 | .keys_inorder = xfs_inobt_keys_inorder, |
| 223 | .recs_inorder = xfs_inobt_recs_inorder, | 263 | .recs_inorder = xfs_inobt_recs_inorder, |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 514eac913f1c..3a243d076950 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -382,7 +382,7 @@ xfs_inobp_check( | |||
| 382 | } | 382 | } |
| 383 | #endif | 383 | #endif |
| 384 | 384 | ||
| 385 | static void | 385 | void |
| 386 | xfs_inode_buf_verify( | 386 | xfs_inode_buf_verify( |
| 387 | struct xfs_buf *bp) | 387 | struct xfs_buf *bp) |
| 388 | { | 388 | { |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 21b4de3df716..1a892114792f 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
| @@ -554,6 +554,7 @@ int xfs_imap_to_bp(struct xfs_mount *, struct xfs_trans *, | |||
| 554 | struct xfs_buf **, uint, uint); | 554 | struct xfs_buf **, uint, uint); |
| 555 | int xfs_iread(struct xfs_mount *, struct xfs_trans *, | 555 | int xfs_iread(struct xfs_mount *, struct xfs_trans *, |
| 556 | struct xfs_inode *, uint); | 556 | struct xfs_inode *, uint); |
| 557 | void xfs_inode_buf_verify(struct xfs_buf *); | ||
| 557 | void xfs_dinode_to_disk(struct xfs_dinode *, | 558 | void xfs_dinode_to_disk(struct xfs_dinode *, |
| 558 | struct xfs_icdinode *); | 559 | struct xfs_icdinode *); |
| 559 | void xfs_idestroy_fork(struct xfs_inode *, int); | 560 | void xfs_idestroy_fork(struct xfs_inode *, int); |
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 3998fd2a7949..0f18d412e3e8 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
| @@ -396,7 +396,8 @@ xfs_bulkstat( | |||
| 396 | if (xfs_inobt_maskn(chunkidx, nicluster) | 396 | if (xfs_inobt_maskn(chunkidx, nicluster) |
| 397 | & ~r.ir_free) | 397 | & ~r.ir_free) |
| 398 | xfs_btree_reada_bufs(mp, agno, | 398 | xfs_btree_reada_bufs(mp, agno, |
| 399 | agbno, nbcluster); | 399 | agbno, nbcluster, |
| 400 | xfs_inode_buf_verify); | ||
| 400 | } | 401 | } |
| 401 | irbp->ir_startino = r.ir_startino; | 402 | irbp->ir_startino = r.ir_startino; |
| 402 | irbp->ir_freecount = r.ir_freecount; | 403 | irbp->ir_freecount = r.ir_freecount; |
