diff options
Diffstat (limited to 'fs/xfs')
-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; |