diff options
Diffstat (limited to 'fs/xfs')
| -rw-r--r-- | fs/xfs/xfs_inode.c | 100 | 
1 files changed, 51 insertions, 49 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 8d696301048..514eac913f1 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -382,6 +382,46 @@ xfs_inobp_check(  }  #endif +static void +xfs_inode_buf_verify( +	struct xfs_buf	*bp) +{ +	struct xfs_mount *mp = bp->b_target->bt_mount; +	int		i; +	int		ni; + +	/* +	 * Validate the magic number and version of every inode in the buffer +	 */ +	ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock; +	for (i = 0; i < ni; i++) { +		int		di_ok; +		xfs_dinode_t	*dip; + +		dip = (struct xfs_dinode *)xfs_buf_offset(bp, +					(i << mp->m_sb.sb_inodelog)); +		di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) && +			    XFS_DINODE_GOOD_VERSION(dip->di_version); +		if (unlikely(XFS_TEST_ERROR(!di_ok, mp, +						XFS_ERRTAG_ITOBP_INOTOBP, +						XFS_RANDOM_ITOBP_INOTOBP))) { +			xfs_buf_ioerror(bp, EFSCORRUPTED); +			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH, +					     mp, dip); +#ifdef DEBUG +			xfs_emerg(mp, +				"bad inode magic/vsn daddr %lld #%d (magic=%x)", +				(unsigned long long)bp->b_bn, i, +				be16_to_cpu(dip->di_magic)); +			ASSERT(0); +#endif +		} +	} +	xfs_inobp_check(mp, bp); +	bp->b_iodone = NULL; +	xfs_buf_ioend(bp, 0); +} +  /*   * This routine is called to map an inode to the buffer containing the on-disk   * version of the inode.  It returns a pointer to the buffer containing the @@ -396,71 +436,33 @@ xfs_imap_to_bp(  	struct xfs_mount	*mp,  	struct xfs_trans	*tp,  	struct xfs_imap		*imap, -	struct xfs_dinode	**dipp, +	struct xfs_dinode       **dipp,  	struct xfs_buf		**bpp,  	uint			buf_flags,  	uint			iget_flags)  {  	struct xfs_buf		*bp;  	int			error; -	int			i; -	int			ni;  	buf_flags |= XBF_UNMAPPED;  	error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno, -				   (int)imap->im_len, buf_flags, &bp, NULL); +				   (int)imap->im_len, buf_flags, &bp, +				   xfs_inode_buf_verify);  	if (error) { -		if (error != EAGAIN) { -			xfs_warn(mp, -				"%s: xfs_trans_read_buf() returned error %d.", -				__func__, error); -		} else { +		if (error == EAGAIN) {  			ASSERT(buf_flags & XBF_TRYLOCK); +			return error;  		} -		return error; -	} -	/* -	 * Validate the magic number and version of every inode in the buffer -	 * (if DEBUG kernel) or the first inode in the buffer, otherwise. -	 */ -#ifdef DEBUG -	ni = BBTOB(imap->im_len) >> mp->m_sb.sb_inodelog; -#else	/* usual case */ -	ni = 1; -#endif +		if (error == EFSCORRUPTED && +		    (iget_flags & XFS_IGET_UNTRUSTED)) +			return XFS_ERROR(EINVAL); -	for (i = 0; i < ni; i++) { -		int		di_ok; -		xfs_dinode_t	*dip; - -		dip = (xfs_dinode_t *)xfs_buf_offset(bp, -					(i << mp->m_sb.sb_inodelog)); -		di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) && -			    XFS_DINODE_GOOD_VERSION(dip->di_version); -		if (unlikely(XFS_TEST_ERROR(!di_ok, mp, -						XFS_ERRTAG_ITOBP_INOTOBP, -						XFS_RANDOM_ITOBP_INOTOBP))) { -			if (iget_flags & XFS_IGET_UNTRUSTED) { -				xfs_trans_brelse(tp, bp); -				return XFS_ERROR(EINVAL); -			} -			XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH, -					     mp, dip); -#ifdef DEBUG -			xfs_emerg(mp, -				"bad inode magic/vsn daddr %lld #%d (magic=%x)", -				(unsigned long long)imap->im_blkno, i, -				be16_to_cpu(dip->di_magic)); -			ASSERT(0); -#endif -			xfs_trans_brelse(tp, bp); -			return XFS_ERROR(EFSCORRUPTED); -		} +		xfs_warn(mp, "%s: xfs_trans_read_buf() returned error %d.", +			__func__, error); +		return error;  	} -	xfs_inobp_check(mp, bp); -  	*bpp = bp;  	*dipp = (struct xfs_dinode *)xfs_buf_offset(bp, imap->im_boffset);  	return 0;  |