diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_inode_buf.c')
| -rw-r--r-- | fs/xfs/libxfs/xfs_inode_buf.c | 82 | 
1 files changed, 51 insertions, 31 deletions
| diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c index d38d724534c4..30d1d60f1d46 100644 --- a/fs/xfs/libxfs/xfs_inode_buf.c +++ b/fs/xfs/libxfs/xfs_inode_buf.c @@ -374,6 +374,47 @@ xfs_log_dinode_to_disk(  	}  } +static xfs_failaddr_t +xfs_dinode_verify_fork( +	struct xfs_dinode	*dip, +	struct xfs_mount	*mp, +	int			whichfork) +{ +	uint32_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork); + +	switch (XFS_DFORK_FORMAT(dip, whichfork)) { +	case XFS_DINODE_FMT_LOCAL: +		/* +		 * no local regular files yet +		 */ +		if (whichfork == XFS_DATA_FORK) { +			if (S_ISREG(be16_to_cpu(dip->di_mode))) +				return __this_address; +			if (be64_to_cpu(dip->di_size) > +					XFS_DFORK_SIZE(dip, mp, whichfork)) +				return __this_address; +		} +		if (di_nextents) +			return __this_address; +		break; +	case XFS_DINODE_FMT_EXTENTS: +		if (di_nextents > XFS_DFORK_MAXEXT(dip, mp, whichfork)) +			return __this_address; +		break; +	case XFS_DINODE_FMT_BTREE: +		if (whichfork == XFS_ATTR_FORK) { +			if (di_nextents > MAXAEXTNUM) +				return __this_address; +		} else if (di_nextents > MAXEXTNUM) { +			return __this_address; +		} +		break; +	default: +		return __this_address; +	} +	return NULL; +} +  xfs_failaddr_t  xfs_dinode_verify(  	struct xfs_mount	*mp, @@ -441,24 +482,9 @@ xfs_dinode_verify(  	case S_IFREG:  	case S_IFLNK:  	case S_IFDIR: -		switch (dip->di_format) { -		case XFS_DINODE_FMT_LOCAL: -			/* -			 * no local regular files yet -			 */ -			if (S_ISREG(mode)) -				return __this_address; -			if (di_size > XFS_DFORK_DSIZE(dip, mp)) -				return __this_address; -			if (dip->di_nextents) -				return __this_address; -			/* fall through */ -		case XFS_DINODE_FMT_EXTENTS: -		case XFS_DINODE_FMT_BTREE: -			break; -		default: -			return __this_address; -		} +		fa = xfs_dinode_verify_fork(dip, mp, XFS_DATA_FORK); +		if (fa) +			return fa;  		break;  	case 0:  		/* Uninitialized inode ok. */ @@ -468,17 +494,9 @@ xfs_dinode_verify(  	}  	if (XFS_DFORK_Q(dip)) { -		switch (dip->di_aformat) { -		case XFS_DINODE_FMT_LOCAL: -			if (dip->di_anextents) -				return __this_address; -		/* fall through */ -		case XFS_DINODE_FMT_EXTENTS: -		case XFS_DINODE_FMT_BTREE: -			break; -		default: -			return __this_address; -		} +		fa = xfs_dinode_verify_fork(dip, mp, XFS_ATTR_FORK); +		if (fa) +			return fa;  	} else {  		/*  		 * If there is no fork offset, this may be a freshly-made inode @@ -713,7 +731,8 @@ xfs_inode_validate_extsize(  	if ((hint_flag || inherit_flag) && extsize == 0)  		return __this_address; -	if (!(hint_flag || inherit_flag) && extsize != 0) +	/* free inodes get flags set to zero but extsize remains */ +	if (mode && !(hint_flag || inherit_flag) && extsize != 0)  		return __this_address;  	if (extsize_bytes % blocksize_bytes) @@ -759,7 +778,8 @@ xfs_inode_validate_cowextsize(  	if (hint_flag && cowextsize == 0)  		return __this_address; -	if (!hint_flag && cowextsize != 0) +	/* free inodes get flags set to zero but cowextsize remains */ +	if (mode && !hint_flag && cowextsize != 0)  		return __this_address;  	if (hint_flag && rt_flag) |