diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_alloc.c')
| -rw-r--r-- | fs/xfs/libxfs/xfs_alloc.c | 124 | 
1 files changed, 79 insertions, 45 deletions
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index 83ed7715f856..c02781a4c091 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -167,7 +167,7 @@ xfs_alloc_lookup_ge(   * Lookup the first record less than or equal to [bno, len]   * in the btree given by cur.   */ -static int				/* error */ +int					/* error */  xfs_alloc_lookup_le(  	struct xfs_btree_cur	*cur,	/* btree cursor */  	xfs_agblock_t		bno,	/* starting block of extent */ @@ -520,7 +520,7 @@ xfs_alloc_fixup_trees(  	return 0;  } -static bool +static xfs_failaddr_t  xfs_agfl_verify(  	struct xfs_buf	*bp)  { @@ -528,10 +528,19 @@ xfs_agfl_verify(  	struct xfs_agfl	*agfl = XFS_BUF_TO_AGFL(bp);  	int		i; +	/* +	 * There is no verification of non-crc AGFLs because mkfs does not +	 * initialise the AGFL to zero or NULL. Hence the only valid part of the +	 * AGFL is what the AGF says is active. We can't get to the AGF, so we +	 * can't verify just those entries are valid. +	 */ +	if (!xfs_sb_version_hascrc(&mp->m_sb)) +		return NULL; +  	if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid)) -		return false; +		return __this_address;  	if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC) -		return false; +		return __this_address;  	/*  	 * during growfs operations, the perag is not fully initialised,  	 * so we can't use it for any useful checking. growfs ensures we can't @@ -539,16 +548,17 @@ xfs_agfl_verify(  	 * so we can detect and avoid this problem.  	 */  	if (bp->b_pag && be32_to_cpu(agfl->agfl_seqno) != bp->b_pag->pag_agno) -		return false; +		return __this_address;  	for (i = 0; i < XFS_AGFL_SIZE(mp); i++) {  		if (be32_to_cpu(agfl->agfl_bno[i]) != NULLAGBLOCK &&  		    be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks) -			return false; +			return __this_address;  	} -	return xfs_log_check_lsn(mp, -				 be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn)); +	if (!xfs_log_check_lsn(mp, be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn))) +		return __this_address; +	return NULL;  }  static void @@ -556,6 +566,7 @@ xfs_agfl_read_verify(  	struct xfs_buf	*bp)  {  	struct xfs_mount *mp = bp->b_target->bt_mount; +	xfs_failaddr_t	fa;  	/*  	 * There is no verification of non-crc AGFLs because mkfs does not @@ -567,28 +578,29 @@ xfs_agfl_read_verify(  		return;  	if (!xfs_buf_verify_cksum(bp, XFS_AGFL_CRC_OFF)) -		xfs_buf_ioerror(bp, -EFSBADCRC); -	else if (!xfs_agfl_verify(bp)) -		xfs_buf_ioerror(bp, -EFSCORRUPTED); - -	if (bp->b_error) -		xfs_verifier_error(bp); +		xfs_verifier_error(bp, -EFSBADCRC, __this_address); +	else { +		fa = xfs_agfl_verify(bp); +		if (fa) +			xfs_verifier_error(bp, -EFSCORRUPTED, fa); +	}  }  static void  xfs_agfl_write_verify(  	struct xfs_buf	*bp)  { -	struct xfs_mount *mp = bp->b_target->bt_mount; -	struct xfs_buf_log_item	*bip = bp->b_fspriv; +	struct xfs_mount	*mp = bp->b_target->bt_mount; +	struct xfs_buf_log_item	*bip = bp->b_log_item; +	xfs_failaddr_t		fa;  	/* no verification of non-crc AGFLs */  	if (!xfs_sb_version_hascrc(&mp->m_sb))  		return; -	if (!xfs_agfl_verify(bp)) { -		xfs_buf_ioerror(bp, -EFSCORRUPTED); -		xfs_verifier_error(bp); +	fa = xfs_agfl_verify(bp); +	if (fa) { +		xfs_verifier_error(bp, -EFSCORRUPTED, fa);  		return;  	} @@ -602,6 +614,7 @@ const struct xfs_buf_ops xfs_agfl_buf_ops = {  	.name = "xfs_agfl",  	.verify_read = xfs_agfl_read_verify,  	.verify_write = xfs_agfl_write_verify, +	.verify_struct = xfs_agfl_verify,  };  /* @@ -2397,19 +2410,19 @@ xfs_alloc_put_freelist(  	return 0;  } -static bool +static xfs_failaddr_t  xfs_agf_verify( -	struct xfs_mount *mp, -	struct xfs_buf	*bp) - { -	struct xfs_agf	*agf = XFS_BUF_TO_AGF(bp); +	struct xfs_buf		*bp) +{ +	struct xfs_mount	*mp = bp->b_target->bt_mount; +	struct xfs_agf		*agf = XFS_BUF_TO_AGF(bp);  	if (xfs_sb_version_hascrc(&mp->m_sb)) {  		if (!uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) -			return false; +			return __this_address;  		if (!xfs_log_check_lsn(mp,  				be64_to_cpu(XFS_BUF_TO_AGF(bp)->agf_lsn))) -			return false; +			return __this_address;  	}  	if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) && @@ -2418,18 +2431,18 @@ xfs_agf_verify(  	      be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) &&  	      be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) &&  	      be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp))) -		return false; +		return __this_address;  	if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) < 1 ||  	    be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) < 1 ||  	    be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS ||  	    be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS) -		return false; +		return __this_address;  	if (xfs_sb_version_hasrmapbt(&mp->m_sb) &&  	    (be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) < 1 ||  	     be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) > XFS_BTREE_MAXLEVELS)) -		return false; +		return __this_address;  	/*  	 * during growfs operations, the perag is not fully initialised, @@ -2438,18 +2451,18 @@ xfs_agf_verify(  	 * so we can detect and avoid this problem.  	 */  	if (bp->b_pag && be32_to_cpu(agf->agf_seqno) != bp->b_pag->pag_agno) -		return false; +		return __this_address;  	if (xfs_sb_version_haslazysbcount(&mp->m_sb) &&  	    be32_to_cpu(agf->agf_btreeblks) > be32_to_cpu(agf->agf_length)) -		return false; +		return __this_address;  	if (xfs_sb_version_hasreflink(&mp->m_sb) &&  	    (be32_to_cpu(agf->agf_refcount_level) < 1 ||  	     be32_to_cpu(agf->agf_refcount_level) > XFS_BTREE_MAXLEVELS)) -		return false; +		return __this_address; -	return true;; +	return NULL;  } @@ -2458,28 +2471,29 @@ xfs_agf_read_verify(  	struct xfs_buf	*bp)  {  	struct xfs_mount *mp = bp->b_target->bt_mount; +	xfs_failaddr_t	fa;  	if (xfs_sb_version_hascrc(&mp->m_sb) &&  	    !xfs_buf_verify_cksum(bp, XFS_AGF_CRC_OFF)) -		xfs_buf_ioerror(bp, -EFSBADCRC); -	else if (XFS_TEST_ERROR(!xfs_agf_verify(mp, bp), mp, -				XFS_ERRTAG_ALLOC_READ_AGF)) -		xfs_buf_ioerror(bp, -EFSCORRUPTED); - -	if (bp->b_error) -		xfs_verifier_error(bp); +		xfs_verifier_error(bp, -EFSBADCRC, __this_address); +	else { +		fa = xfs_agf_verify(bp); +		if (XFS_TEST_ERROR(fa, mp, XFS_ERRTAG_ALLOC_READ_AGF)) +			xfs_verifier_error(bp, -EFSCORRUPTED, fa); +	}  }  static void  xfs_agf_write_verify(  	struct xfs_buf	*bp)  { -	struct xfs_mount *mp = bp->b_target->bt_mount; -	struct xfs_buf_log_item	*bip = bp->b_fspriv; +	struct xfs_mount	*mp = bp->b_target->bt_mount; +	struct xfs_buf_log_item	*bip = bp->b_log_item; +	xfs_failaddr_t		fa; -	if (!xfs_agf_verify(mp, bp)) { -		xfs_buf_ioerror(bp, -EFSCORRUPTED); -		xfs_verifier_error(bp); +	fa = xfs_agf_verify(bp); +	if (fa) { +		xfs_verifier_error(bp, -EFSCORRUPTED, fa);  		return;  	} @@ -2496,6 +2510,7 @@ const struct xfs_buf_ops xfs_agf_buf_ops = {  	.name = "xfs_agf",  	.verify_read = xfs_agf_read_verify,  	.verify_write = xfs_agf_write_verify, +	.verify_struct = xfs_agf_verify,  };  /* @@ -2981,3 +2996,22 @@ xfs_verify_fsbno(  		return false;  	return xfs_verify_agbno(mp, agno, XFS_FSB_TO_AGBNO(mp, fsbno));  } + +/* Is there a record covering a given extent? */ +int +xfs_alloc_has_record( +	struct xfs_btree_cur	*cur, +	xfs_agblock_t		bno, +	xfs_extlen_t		len, +	bool			*exists) +{ +	union xfs_btree_irec	low; +	union xfs_btree_irec	high; + +	memset(&low, 0, sizeof(low)); +	low.a.ar_startblock = bno; +	memset(&high, 0xFF, sizeof(high)); +	high.a.ar_startblock = bno + len - 1; + +	return xfs_btree_has_record(cur, &low, &high, exists); +}  |