aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2012-11-12 06:54:08 -0500
committerBen Myers <bpm@sgi.com>2012-11-15 22:34:31 -0500
commit3d3e6f64e22c94115d47de670611bcd3ecda3796 (patch)
treeec97be647a06d5aef171333624b370cf482285b4
parentaf133e8606d32c2aed43870491ebbdc56feec8a8 (diff)
xfs: verify btree blocks as they are read from disk
Add an btree block verify callback function and pass it into the buffer read functions. Because each different btree block type requires different verification, add a function to the ops structure that is called from the generic code. Also, propagate the verification callback functions through the readahead functions, and into the external bmap and bulkstat inode readahead code that uses the generic btree buffer read functions. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Phil White <pwhite@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
-rw-r--r--fs/xfs/xfs_alloc_btree.c61
-rw-r--r--fs/xfs/xfs_bmap.c60
-rw-r--r--fs/xfs/xfs_bmap_btree.c47
-rw-r--r--fs/xfs/xfs_bmap_btree.h1
-rw-r--r--fs/xfs/xfs_btree.c66
-rw-r--r--fs/xfs/xfs_btree.h10
-rw-r--r--fs/xfs/xfs_ialloc_btree.c40
-rw-r--r--fs/xfs/xfs_inode.c2
-rw-r--r--fs/xfs/xfs_inode.h1
-rw-r--r--fs/xfs/xfs_itable.c3
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
275void
276xfs_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
276STATIC int 336STATIC int
277xfs_allocbt_keys_inorder( 337xfs_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
711void
712xfs_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
711STATIC int 757STATIC int
712xfs_bmbt_keys_inorder( 758xfs_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,
232extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level); 232extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level);
233extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf); 233extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf);
234extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf); 234extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf);
235extern void xfs_bmbt_read_verify(struct xfs_buf *bp);
235 236
236extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *, 237extern 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 */
615int /* error */ 616int
616xfs_btree_read_bufl( 617xfs_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 */
646void 648void
647xfs_btree_reada_bufl( 649xfs_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 */
664void 667void
665xfs_btree_reada_bufs( 668xfs_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
679STATIC int 683STATIC 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 */
365xfs_btree_reada_bufl( 367xfs_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
38STATIC int 39STATIC 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
185void
186xfs_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
185STATIC int 224STATIC int
186xfs_inobt_keys_inorder( 225xfs_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
385static void 385void
386xfs_inode_buf_verify( 386xfs_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);
555int xfs_iread(struct xfs_mount *, struct xfs_trans *, 555int xfs_iread(struct xfs_mount *, struct xfs_trans *,
556 struct xfs_inode *, uint); 556 struct xfs_inode *, uint);
557void xfs_inode_buf_verify(struct xfs_buf *);
557void xfs_dinode_to_disk(struct xfs_dinode *, 558void xfs_dinode_to_disk(struct xfs_dinode *,
558 struct xfs_icdinode *); 559 struct xfs_icdinode *);
559void xfs_idestroy_fork(struct xfs_inode *, int); 560void 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;