aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs')
-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;