diff options
Diffstat (limited to 'fs/xfs/xfs_alloc_btree.c')
| -rw-r--r-- | fs/xfs/xfs_alloc_btree.c | 77 | 
1 files changed, 77 insertions, 0 deletions
| diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index f7876c6d6165..b1ddef6b2689 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c @@ -272,6 +272,82 @@ xfs_allocbt_key_diff(  	return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock;  } +static void +xfs_allocbt_verify( +	struct xfs_buf		*bp) +{ +	struct xfs_mount	*mp = bp->b_target->bt_mount; +	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp); +	struct xfs_perag	*pag = bp->b_pag; +	unsigned int		level; +	int			sblock_ok; /* block passes checks */ + +	/* +	 * magic number and level verification +	 * +	 * During growfs operations, we can't verify the exact level as the +	 * perag is not fully initialised and hence not attached to the buffer. +	 * In this case, check against the maximum tree depth. +	 */ +	level = be16_to_cpu(block->bb_level); +	switch (block->bb_magic) { +	case cpu_to_be32(XFS_ABTB_MAGIC): +		if (pag) +			sblock_ok = level < pag->pagf_levels[XFS_BTNUM_BNOi]; +		else +			sblock_ok = level < mp->m_ag_maxlevels; +		break; +	case cpu_to_be32(XFS_ABTC_MAGIC): +		if (pag) +			sblock_ok = level < pag->pagf_levels[XFS_BTNUM_CNTi]; +		else +			sblock_ok = level < mp->m_ag_maxlevels; +		break; +	default: +		sblock_ok = 0; +		break; +	} + +	/* numrecs verification */ +	sblock_ok = sblock_ok && +		be16_to_cpu(block->bb_numrecs) <= mp->m_alloc_mxr[level != 0]; + +	/* sibling pointer verification */ +	sblock_ok = sblock_ok && +		(block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) || +		 be32_to_cpu(block->bb_u.s.bb_leftsib) < mp->m_sb.sb_agblocks) && +		block->bb_u.s.bb_leftsib && +		(block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) || +		 be32_to_cpu(block->bb_u.s.bb_rightsib) < mp->m_sb.sb_agblocks) && +		block->bb_u.s.bb_rightsib; + +	if (!sblock_ok) { +		trace_xfs_btree_corrupt(bp, _RET_IP_); +		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, block); +		xfs_buf_ioerror(bp, EFSCORRUPTED); +	} +} + +static void +xfs_allocbt_read_verify( +	struct xfs_buf	*bp) +{ +	xfs_allocbt_verify(bp); +} + +static void +xfs_allocbt_write_verify( +	struct xfs_buf	*bp) +{ +	xfs_allocbt_verify(bp); +} + +const struct xfs_buf_ops xfs_allocbt_buf_ops = { +	.verify_read = xfs_allocbt_read_verify, +	.verify_write = xfs_allocbt_write_verify, +}; + +  #ifdef DEBUG  STATIC int  xfs_allocbt_keys_inorder( @@ -327,6 +403,7 @@ static const struct xfs_btree_ops xfs_allocbt_ops = {  	.init_rec_from_cur	= xfs_allocbt_init_rec_from_cur,  	.init_ptr_from_cur	= xfs_allocbt_init_ptr_from_cur,  	.key_diff		= xfs_allocbt_key_diff, +	.buf_ops		= &xfs_allocbt_buf_ops,  #ifdef DEBUG  	.keys_inorder		= xfs_allocbt_keys_inorder,  	.recs_inorder		= xfs_allocbt_recs_inorder, |