diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_dir2_block.c')
| -rw-r--r-- | fs/xfs/libxfs/xfs_dir2_block.c | 33 | 
1 files changed, 31 insertions, 2 deletions
| diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c index d6ced59b9567..1dbf2f980a26 100644 --- a/fs/xfs/libxfs/xfs_dir2_block.c +++ b/fs/xfs/libxfs/xfs_dir2_block.c @@ -114,6 +114,23 @@ const struct xfs_buf_ops xfs_dir3_block_buf_ops = {  	.verify_struct = xfs_dir3_block_verify,  }; +static xfs_failaddr_t +xfs_dir3_block_header_check( +	struct xfs_inode	*dp, +	struct xfs_buf		*bp) +{ +	struct xfs_mount	*mp = dp->i_mount; + +	if (xfs_sb_version_hascrc(&mp->m_sb)) { +		struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; + +		if (be64_to_cpu(hdr3->owner) != dp->i_ino) +			return __this_address; +	} + +	return NULL; +} +  int  xfs_dir3_block_read(  	struct xfs_trans	*tp, @@ -121,12 +138,24 @@ xfs_dir3_block_read(  	struct xfs_buf		**bpp)  {  	struct xfs_mount	*mp = dp->i_mount; +	xfs_failaddr_t		fa;  	int			err;  	err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, 0, bpp,  				XFS_DATA_FORK, &xfs_dir3_block_buf_ops); -	if (!err && tp && *bpp) -		xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF); +	if (err || !*bpp) +		return err; + +	/* Check things that we can't do in the verifier. */ +	fa = xfs_dir3_block_header_check(dp, *bpp); +	if (fa) { +		__xfs_buf_mark_corrupt(*bpp, fa); +		xfs_trans_brelse(tp, *bpp); +		*bpp = NULL; +		return -EFSCORRUPTED; +	} + +	xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);  	return err;  } |