diff mbox

[RFC,5/8] xfs: consider the local format inode in misc operations

Message ID 1530846750-6686-6-git-send-email-shan.hai@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shan Hai July 6, 2018, 3:12 a.m. UTC
The local format inode is a legal citizen from now on and consider
it in misc operations.

Signed-off-by: Shan Hai <shan.hai@oracle.com>
---
 fs/xfs/libxfs/xfs_bmap.c      | 18 ++++++++++--------
 fs/xfs/libxfs/xfs_inode_buf.c |  6 ------
 fs/xfs/scrub/inode.c          |  2 +-
 fs/xfs/xfs_bmap_util.c        | 11 +++++++++--
 fs/xfs/xfs_inode.c            | 20 ++++++++++++++------
 fs/xfs/xfs_inode_item.c       |  5 ++++-
 fs/xfs/xfs_iomap.c            |  5 +++--
 fs/xfs/xfs_log_recover.c      |  3 ++-
 8 files changed, 43 insertions(+), 27 deletions(-)

Comments

Darrick J. Wong July 6, 2018, 3:40 a.m. UTC | #1
On Fri, Jul 06, 2018 at 11:12:26AM +0800, Shan Hai wrote:
> The local format inode is a legal citizen from now on and consider
> it in misc operations.
> 
> Signed-off-by: Shan Hai <shan.hai@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_bmap.c      | 18 ++++++++++--------
>  fs/xfs/libxfs/xfs_inode_buf.c |  6 ------
>  fs/xfs/scrub/inode.c          |  2 +-
>  fs/xfs/xfs_bmap_util.c        | 11 +++++++++--
>  fs/xfs/xfs_inode.c            | 20 ++++++++++++++------
>  fs/xfs/xfs_inode_item.c       |  5 ++++-
>  fs/xfs/xfs_iomap.c            |  5 +++--
>  fs/xfs/xfs_log_recover.c      |  3 ++-
>  8 files changed, 43 insertions(+), 27 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index bea6dc254a7d..6b151bd15da7 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -830,11 +830,6 @@ xfs_bmap_local_to_extents(
>  	struct xfs_bmbt_irec rec;
>  	struct xfs_iext_cursor icur;
>  
> -	/*
> -	 * We don't want to deal with the case of keeping inode data inline yet.
> -	 * So sending the data fork of a regular inode is invalid.
> -	 */
> -	ASSERT(!(S_ISREG(VFS_I(ip)->i_mode) && whichfork == XFS_DATA_FORK));
>  	ifp = XFS_IFORK_PTR(ip, whichfork);
>  	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
>  
> @@ -3840,7 +3835,8 @@ xfs_bmapi_read(
>  
>  	if (unlikely(XFS_TEST_ERROR(
>  	    (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
> -	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
> +	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
> +	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL),
>  	     mp, XFS_ERRTAG_BMAPIFORMAT))) {
>  		XFS_ERROR_REPORT("xfs_bmapi_read", XFS_ERRLEVEL_LOW, mp);
>  		return -EFSCORRUPTED;
> @@ -3863,7 +3859,7 @@ xfs_bmapi_read(
>  		return 0;
>  	}
>  
> -	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
> +	if (!(ifp->if_flags & (XFS_IFINLINE | XFS_IFEXTENTS))) {
>  		error = xfs_iread_extents(NULL, ip, whichfork);
>  		if (error)
>  			return error;
> @@ -4285,7 +4281,6 @@ xfs_bmapi_write(
>  	       (flags & (XFS_BMAPI_CONVERT | XFS_BMAPI_COWFORK)) ==
>  			(XFS_BMAPI_CONVERT | XFS_BMAPI_COWFORK));
>  	ASSERT(len > 0);
> -	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL);
>  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
>  	ASSERT(!(flags & XFS_BMAPI_REMAP));
>  
> @@ -5244,11 +5239,18 @@ __xfs_bunmapi(
>  	ifp = XFS_IFORK_PTR(ip, whichfork);
>  	if (unlikely(
>  	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
> +	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL &&
>  	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
>  		XFS_ERROR_REPORT("xfs_bunmapi", XFS_ERRLEVEL_LOW,
>  				 ip->i_mount);
>  		return -EFSCORRUPTED;
>  	}
> +
> +	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
> +		*rlen = 0;
> +		return 0;
> +	}
> +
>  	mp = ip->i_mount;
>  	if (XFS_FORCED_SHUTDOWN(mp))
>  		return -EIO;
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> index 33dc34655ac3..cb3c4b308137 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> @@ -157,7 +157,6 @@ const struct xfs_buf_ops xfs_inode_buf_ra_ops = {
>  	.verify_write = xfs_inode_buf_write_verify,
>  };
>  
> -
>  /*
>   * 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
> @@ -384,12 +383,7 @@ xfs_dinode_verify_fork(
>  
>  	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;
> diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
> index 7a6208505980..1501983dd7aa 100644
> --- a/fs/xfs/scrub/inode.c
> +++ b/fs/xfs/scrub/inode.c
> @@ -283,7 +283,7 @@ xfs_scrub_dinode(
>  			xfs_scrub_ino_set_corrupt(sc, ino);
>  		break;
>  	case XFS_DINODE_FMT_LOCAL:
> -		if (!S_ISDIR(mode) && !S_ISLNK(mode))
> +		if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
>  			xfs_scrub_ino_set_corrupt(sc, ino);
>  		break;
>  	case XFS_DINODE_FMT_EXTENTS:
> diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
> index 83b1e8c6c18f..46f718177fd7 100644
> --- a/fs/xfs/xfs_bmap_util.c
> +++ b/fs/xfs/xfs_bmap_util.c
> @@ -760,7 +760,8 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
>  		return false;
>  
>  	/* If we haven't read in the extent list, then don't do it now. */
> -	if (!(ip->i_df.if_flags & XFS_IFEXTENTS))
> +	if (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL &&
> +		!(ip->i_df.if_flags & XFS_IFEXTENTS))
>  		return false;
>  
>  	/*
> @@ -768,7 +769,8 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
>  	 * has delalloc blocks and we are forced to remove them.
>  	 */
>  	if (ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND))
> -		if (!force || ip->i_delayed_blks == 0)
> +		if ((ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) &&
> +			(!force || ip->i_delayed_blks == 0))
>  			return false;
>  
>  	return true;
> @@ -792,6 +794,11 @@ xfs_free_eofblocks(
>  	struct xfs_bmbt_irec	imap;
>  	struct xfs_mount	*mp = ip->i_mount;
>  
> +	if (xfs_sb_version_hasinlinedata(&mp->m_sb) &&
> +		ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) {

Bleh, this indentation is confusing me.

if (foobarblahblabhlbahlabhlabh... &&
    bazcow...)
	dostuff();

or:

if (foobarblahblabhlabhalbhba.. &&
		bazcow...)
	dostuff();

> +		ip->i_delayed_blks = 0;
> +		return 0;
> +	}
>  	/*
>  	 * Figure out if there are any blocks beyond the end
>  	 * of the file.  If not, then there is nothing to do.
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 5df4de666cc1..78b9790a7cd4 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -1563,7 +1563,6 @@ xfs_itruncate_extents_flags(
>  	ASSERT(!XFS_NOT_DQATTACHED(mp, ip));
>  
>  	trace_xfs_itruncate_extents_start(ip, new_size);
> -
>  	flags |= xfs_bmapi_aflag(whichfork);
>  
>  	/*
> @@ -1745,9 +1744,15 @@ xfs_inactive_truncate(
>  	ip->i_d.di_size = 0;
>  	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
>  
> -	error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
> -	if (error)
> -		goto error_trans_cancel;
> +	if (xfs_sb_version_hasinlinedata(&mp->m_sb) &&
> +		ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
> +		ASSERT(ip->i_d.di_nextents == 0);
> +		ip->i_delayed_blks = 0;
> +	} else {
> +		error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
> +		if (error)
> +			goto error_trans_cancel;
> +	}
>  
>  	ASSERT(ip->i_d.di_nextents == 0);
>  
> @@ -1879,6 +1884,7 @@ xfs_inactive(
>  	if (VFS_I(ip)->i_mode == 0) {
>  		ASSERT(ip->i_df.if_real_bytes == 0);
>  		ASSERT(ip->i_df.if_broot_bytes == 0);
> +		ASSERT(ip->i_delayed_blks == 0);

Why?

>  		return;
>  	}
>  
> @@ -1911,8 +1917,9 @@ xfs_inactive(
>  
>  	if (S_ISREG(VFS_I(ip)->i_mode) &&
>  	    (ip->i_d.di_size != 0 || XFS_ISIZE(ip) != 0 ||
> -	     ip->i_d.di_nextents > 0 || ip->i_delayed_blks > 0))
> +	     ip->i_d.di_nextents >= 0 || ip->i_delayed_blks >= 0)) {

Why does the test change from > to >= ?

>  		truncate = 1;
> +	}
>  
>  	error = xfs_qm_dqattach(ip);
>  	if (error)
> @@ -3554,7 +3561,8 @@ xfs_iflush_int(
>  	if (S_ISREG(VFS_I(ip)->i_mode)) {
>  		if (XFS_TEST_ERROR(
>  		    (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
> -		    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE),
> +		    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
> +		    (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL),
>  		    mp, XFS_ERRTAG_IFLUSH_3)) {
>  			xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
>  				"%s: Bad regular inode %Lu, ptr "PTR_FMT,
> diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
> index 2389c34c172d..52b297987a75 100644
> --- a/fs/xfs/xfs_inode_item.c
> +++ b/fs/xfs/xfs_inode_item.c
> @@ -139,6 +139,7 @@ xfs_inode_item_format_data_fork(
>  	struct xfs_log_iovec	**vecp)
>  {
>  	struct xfs_inode	*ip = iip->ili_inode;
> +	struct xfs_mount	*mp = ip->i_mount;
>  	size_t			data_bytes;
>  
>  	switch (ip->i_d.di_format) {
> @@ -197,7 +198,9 @@ xfs_inode_item_format_data_fork(
>  			ASSERT(ip->i_df.if_real_bytes == 0 ||
>  			       ip->i_df.if_real_bytes >= data_bytes);
>  			ASSERT(ip->i_df.if_u1.if_data != NULL);
> -			ASSERT(ip->i_d.di_size > 0);
> +			if (!xfs_sb_version_hasinlinedata(&mp->m_sb)) {
> +				ASSERT(ip->i_d.di_size > 0);

ASSERT(di_size > 0 || hasinlinedata); ??

> +			}
>  			xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL,
>  					ip->i_df.if_u1.if_data, data_bytes);
>  			ilf->ilf_dsize = (unsigned)data_bytes;
> diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
> index 55876dd02f0c..aa72966081c5 100644
> --- a/fs/xfs/xfs_iomap.c
> +++ b/fs/xfs/xfs_iomap.c
> @@ -532,7 +532,8 @@ xfs_file_iomap_begin_delay(
>  
>  	if (unlikely(XFS_TEST_ERROR(
>  	    (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS &&
> -	     XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE),
> +	     XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE &&
> +	     XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_LOCAL),
>  	     mp, XFS_ERRTAG_BMAPIFORMAT))) {
>  		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
>  		error = -EFSCORRUPTED;
> @@ -541,7 +542,7 @@ xfs_file_iomap_begin_delay(
>  
>  	XFS_STATS_INC(mp, xs_blk_mapw);
>  
> -	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
> +	if (!(ifp->if_flags & (XFS_IFINLINE |XFS_IFEXTENTS))) {
>  		error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
>  		if (error)
>  			goto out_unlock;
> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
> index b181b5f57a19..d8828f275d9a 100644
> --- a/fs/xfs/xfs_log_recover.c
> +++ b/fs/xfs/xfs_log_recover.c
> @@ -3121,7 +3121,8 @@ xlog_recover_inode_pass2(
>  
>  	if (unlikely(S_ISREG(ldip->di_mode))) {
>  		if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) &&
> -		    (ldip->di_format != XFS_DINODE_FMT_BTREE)) {
> +		    (ldip->di_format != XFS_DINODE_FMT_BTREE) &&
> +		    (ldip->di_format != XFS_DINODE_FMT_LOCAL)) {
>  			XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(3)",
>  					 XFS_ERRLEVEL_LOW, mp, ldip,
>  					 sizeof(*ldip));
> -- 
> 2.11.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Shan Hai July 6, 2018, 4:40 a.m. UTC | #2
On 2018年07月06日 11:40, Darrick J. Wong wrote:
> On Fri, Jul 06, 2018 at 11:12:26AM +0800, Shan Hai wrote:
>> The local format inode is a legal citizen from now on and consider
>> it in misc operations.
>>
>> Signed-off-by: Shan Hai <shan.hai@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_bmap.c      | 18 ++++++++++--------
>>   fs/xfs/libxfs/xfs_inode_buf.c |  6 ------
>>   fs/xfs/scrub/inode.c          |  2 +-
>>   fs/xfs/xfs_bmap_util.c        | 11 +++++++++--
>>   fs/xfs/xfs_inode.c            | 20 ++++++++++++++------
>>   fs/xfs/xfs_inode_item.c       |  5 ++++-
>>   fs/xfs/xfs_iomap.c            |  5 +++--
>>   fs/xfs/xfs_log_recover.c      |  3 ++-
>>   8 files changed, 43 insertions(+), 27 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
>> index bea6dc254a7d..6b151bd15da7 100644
>> --- a/fs/xfs/libxfs/xfs_bmap.c
>> +++ b/fs/xfs/libxfs/xfs_bmap.c
>> @@ -830,11 +830,6 @@ xfs_bmap_local_to_extents(
>>   	struct xfs_bmbt_irec rec;
>>   	struct xfs_iext_cursor icur;
>>   
>> -	/*
>> -	 * We don't want to deal with the case of keeping inode data inline yet.
>> -	 * So sending the data fork of a regular inode is invalid.
>> -	 */
>> -	ASSERT(!(S_ISREG(VFS_I(ip)->i_mode) && whichfork == XFS_DATA_FORK));
>>   	ifp = XFS_IFORK_PTR(ip, whichfork);
>>   	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
>>   
>> @@ -3840,7 +3835,8 @@ xfs_bmapi_read(
>>   
>>   	if (unlikely(XFS_TEST_ERROR(
>>   	    (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
>> -	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
>> +	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
>> +	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL),
>>   	     mp, XFS_ERRTAG_BMAPIFORMAT))) {
>>   		XFS_ERROR_REPORT("xfs_bmapi_read", XFS_ERRLEVEL_LOW, mp);
>>   		return -EFSCORRUPTED;
>> @@ -3863,7 +3859,7 @@ xfs_bmapi_read(
>>   		return 0;
>>   	}
>>   
>> -	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
>> +	if (!(ifp->if_flags & (XFS_IFINLINE | XFS_IFEXTENTS))) {
>>   		error = xfs_iread_extents(NULL, ip, whichfork);
>>   		if (error)
>>   			return error;
>> @@ -4285,7 +4281,6 @@ xfs_bmapi_write(
>>   	       (flags & (XFS_BMAPI_CONVERT | XFS_BMAPI_COWFORK)) ==
>>   			(XFS_BMAPI_CONVERT | XFS_BMAPI_COWFORK));
>>   	ASSERT(len > 0);
>> -	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL);
>>   	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
>>   	ASSERT(!(flags & XFS_BMAPI_REMAP));
>>   
>> @@ -5244,11 +5239,18 @@ __xfs_bunmapi(
>>   	ifp = XFS_IFORK_PTR(ip, whichfork);
>>   	if (unlikely(
>>   	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
>> +	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL &&
>>   	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
>>   		XFS_ERROR_REPORT("xfs_bunmapi", XFS_ERRLEVEL_LOW,
>>   				 ip->i_mount);
>>   		return -EFSCORRUPTED;
>>   	}
>> +
>> +	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
>> +		*rlen = 0;
>> +		return 0;
>> +	}
>> +
>>   	mp = ip->i_mount;
>>   	if (XFS_FORCED_SHUTDOWN(mp))
>>   		return -EIO;
>> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
>> index 33dc34655ac3..cb3c4b308137 100644
>> --- a/fs/xfs/libxfs/xfs_inode_buf.c
>> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
>> @@ -157,7 +157,6 @@ const struct xfs_buf_ops xfs_inode_buf_ra_ops = {
>>   	.verify_write = xfs_inode_buf_write_verify,
>>   };
>>   
>> -
>>   /*
>>    * 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
>> @@ -384,12 +383,7 @@ xfs_dinode_verify_fork(
>>   
>>   	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;
>> diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
>> index 7a6208505980..1501983dd7aa 100644
>> --- a/fs/xfs/scrub/inode.c
>> +++ b/fs/xfs/scrub/inode.c
>> @@ -283,7 +283,7 @@ xfs_scrub_dinode(
>>   			xfs_scrub_ino_set_corrupt(sc, ino);
>>   		break;
>>   	case XFS_DINODE_FMT_LOCAL:
>> -		if (!S_ISDIR(mode) && !S_ISLNK(mode))
>> +		if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
>>   			xfs_scrub_ino_set_corrupt(sc, ino);
>>   		break;
>>   	case XFS_DINODE_FMT_EXTENTS:
>> diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
>> index 83b1e8c6c18f..46f718177fd7 100644
>> --- a/fs/xfs/xfs_bmap_util.c
>> +++ b/fs/xfs/xfs_bmap_util.c
>> @@ -760,7 +760,8 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
>>   		return false;
>>   
>>   	/* If we haven't read in the extent list, then don't do it now. */
>> -	if (!(ip->i_df.if_flags & XFS_IFEXTENTS))
>> +	if (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL &&
>> +		!(ip->i_df.if_flags & XFS_IFEXTENTS))
>>   		return false;
>>   
>>   	/*
>> @@ -768,7 +769,8 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
>>   	 * has delalloc blocks and we are forced to remove them.
>>   	 */
>>   	if (ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND))
>> -		if (!force || ip->i_delayed_blks == 0)
>> +		if ((ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) &&
>> +			(!force || ip->i_delayed_blks == 0))
>>   			return false;
>>   
>>   	return true;
>> @@ -792,6 +794,11 @@ xfs_free_eofblocks(
>>   	struct xfs_bmbt_irec	imap;
>>   	struct xfs_mount	*mp = ip->i_mount;
>>   
>> +	if (xfs_sb_version_hasinlinedata(&mp->m_sb) &&
>> +		ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
> Bleh, this indentation is confusing me.
>
> if (foobarblahblabhlbahlabhlabh... &&
>      bazcow...)
> 	dostuff();
>
> or:
>
> if (foobarblahblabhlabhalbhba.. &&
> 		bazcow...)
> 	dostuff();
>
>> +		ip->i_delayed_blks = 0;
>> +		return 0;
>> +	}
>>   	/*
>>   	 * Figure out if there are any blocks beyond the end
>>   	 * of the file.  If not, then there is nothing to do.
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index 5df4de666cc1..78b9790a7cd4 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -1563,7 +1563,6 @@ xfs_itruncate_extents_flags(
>>   	ASSERT(!XFS_NOT_DQATTACHED(mp, ip));
>>   
>>   	trace_xfs_itruncate_extents_start(ip, new_size);
>> -
>>   	flags |= xfs_bmapi_aflag(whichfork);
>>   
>>   	/*
>> @@ -1745,9 +1744,15 @@ xfs_inactive_truncate(
>>   	ip->i_d.di_size = 0;
>>   	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
>>   
>> -	error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
>> -	if (error)
>> -		goto error_trans_cancel;
>> +	if (xfs_sb_version_hasinlinedata(&mp->m_sb) &&
>> +		ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
>> +		ASSERT(ip->i_d.di_nextents == 0);
>> +		ip->i_delayed_blks = 0;
>> +	} else {
>> +		error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
>> +		if (error)
>> +			goto error_trans_cancel;
>> +	}
>>   
>>   	ASSERT(ip->i_d.di_nextents == 0);
>>   
>> @@ -1879,6 +1884,7 @@ xfs_inactive(
>>   	if (VFS_I(ip)->i_mode == 0) {
>>   		ASSERT(ip->i_df.if_real_bytes == 0);
>>   		ASSERT(ip->i_df.if_broot_bytes == 0);
>> +		ASSERT(ip->i_delayed_blks == 0);
> Why?

There is no delayed allocation for the existing local format inode so no 
delayed blocks at all,
like below:

1, a local format inode resides on disk
2, open and write data to it, the write_iter copies the data to the data 
fork and returns if
     the data can be inlined, the block allocation is not necessary, so 
there is no delayed
     allocation and the ip->i_delayed_blks == 0
3, unlink the inode after the inline data write, the ip->i_delayed_blks 
should equals 0

>>   		return;
>>   	}
>>   
>> @@ -1911,8 +1917,9 @@ xfs_inactive(
>>   
>>   	if (S_ISREG(VFS_I(ip)->i_mode) &&
>>   	    (ip->i_d.di_size != 0 || XFS_ISIZE(ip) != 0 ||
>> -	     ip->i_d.di_nextents > 0 || ip->i_delayed_blks > 0))
>> +	     ip->i_d.di_nextents >= 0 || ip->i_delayed_blks >= 0)) {
> Why does the test change from > to >= ?

The same reasons as described above, unlinking a local format inode 
would encounter
ip->i_delayed_blks == 0.

But it should be put in the xfs_sb_version_hasinlinedata scope, that's 
totally my fault,
will fix it.

>>   		truncate = 1;
>> +	}
>>   
>>   	error = xfs_qm_dqattach(ip);
>>   	if (error)
>> @@ -3554,7 +3561,8 @@ xfs_iflush_int(
>>   	if (S_ISREG(VFS_I(ip)->i_mode)) {
>>   		if (XFS_TEST_ERROR(
>>   		    (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
>> -		    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE),
>> +		    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
>> +		    (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL),
>>   		    mp, XFS_ERRTAG_IFLUSH_3)) {
>>   			xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
>>   				"%s: Bad regular inode %Lu, ptr "PTR_FMT,
>> diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
>> index 2389c34c172d..52b297987a75 100644
>> --- a/fs/xfs/xfs_inode_item.c
>> +++ b/fs/xfs/xfs_inode_item.c
>> @@ -139,6 +139,7 @@ xfs_inode_item_format_data_fork(
>>   	struct xfs_log_iovec	**vecp)
>>   {
>>   	struct xfs_inode	*ip = iip->ili_inode;
>> +	struct xfs_mount	*mp = ip->i_mount;
>>   	size_t			data_bytes;
>>   
>>   	switch (ip->i_d.di_format) {
>> @@ -197,7 +198,9 @@ xfs_inode_item_format_data_fork(
>>   			ASSERT(ip->i_df.if_real_bytes == 0 ||
>>   			       ip->i_df.if_real_bytes >= data_bytes);
>>   			ASSERT(ip->i_df.if_u1.if_data != NULL);
>> -			ASSERT(ip->i_d.di_size > 0);
>> +			if (!xfs_sb_version_hasinlinedata(&mp->m_sb)) {
>> +				ASSERT(ip->i_d.di_size > 0);
> ASSERT(di_size > 0 || hasinlinedata); ??

Yes, agreed, it's much better.

Thanks
Shan Hai
>> +			}
>>   			xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL,
>>   					ip->i_df.if_u1.if_data, data_bytes);
>>   			ilf->ilf_dsize = (unsigned)data_bytes;
>> diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
>> index 55876dd02f0c..aa72966081c5 100644
>> --- a/fs/xfs/xfs_iomap.c
>> +++ b/fs/xfs/xfs_iomap.c
>> @@ -532,7 +532,8 @@ xfs_file_iomap_begin_delay(
>>   
>>   	if (unlikely(XFS_TEST_ERROR(
>>   	    (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS &&
>> -	     XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE),
>> +	     XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE &&
>> +	     XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_LOCAL),
>>   	     mp, XFS_ERRTAG_BMAPIFORMAT))) {
>>   		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
>>   		error = -EFSCORRUPTED;
>> @@ -541,7 +542,7 @@ xfs_file_iomap_begin_delay(
>>   
>>   	XFS_STATS_INC(mp, xs_blk_mapw);
>>   
>> -	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
>> +	if (!(ifp->if_flags & (XFS_IFINLINE |XFS_IFEXTENTS))) {
>>   		error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
>>   		if (error)
>>   			goto out_unlock;
>> diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
>> index b181b5f57a19..d8828f275d9a 100644
>> --- a/fs/xfs/xfs_log_recover.c
>> +++ b/fs/xfs/xfs_log_recover.c
>> @@ -3121,7 +3121,8 @@ xlog_recover_inode_pass2(
>>   
>>   	if (unlikely(S_ISREG(ldip->di_mode))) {
>>   		if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) &&
>> -		    (ldip->di_format != XFS_DINODE_FMT_BTREE)) {
>> +		    (ldip->di_format != XFS_DINODE_FMT_BTREE) &&
>> +		    (ldip->di_format != XFS_DINODE_FMT_LOCAL)) {
>>   			XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(3)",
>>   					 XFS_ERRLEVEL_LOW, mp, ldip,
>>   					 sizeof(*ldip));
>> -- 
>> 2.11.0
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Christoph Hellwig July 8, 2018, 3:51 p.m. UTC | #3
On Fri, Jul 06, 2018 at 11:12:26AM +0800, Shan Hai wrote:
> The local format inode is a legal citizen from now on and consider
> it in misc operations.

This probably wants to go towards the front of the series, and split
into multiple patches with better changelogs for each.

>  
>  	if (unlikely(XFS_TEST_ERROR(
>  	    (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
> -	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
> +	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
> +	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL),

This are all the three possible values.  It is kinda confusing to read
the checks this way as we alreayd checked for a valid fork type in
the inode read verifies.

Also this seems to be in xfs_bmapi_read, for which reading allowing
inline format forks seems wrong to me.

> -	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
> +	if (!(ifp->if_flags & (XFS_IFINLINE | XFS_IFEXTENTS))) {
>  		error = xfs_iread_extents(NULL, ip, whichfork);
>  		if (error)
>  			return error;

I think we need to clean this up better.  We probably want an
xfs_inode_has_extents helper, or even hide the check inside
xfs_iread_extents itself.  Also I wonder if the above is read, the
XFS_IFEXTENTS flag has always meant that we have the current extent list
in memory, which should always be the case for a fork in inline format.

> @@ -5244,11 +5239,18 @@ __xfs_bunmapi(
>  	ifp = XFS_IFORK_PTR(ip, whichfork);
>  	if (unlikely(
>  	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
> +	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL &&
>  	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
>  		XFS_ERROR_REPORT("xfs_bunmapi", XFS_ERRLEVEL_LOW,
>  				 ip->i_mount);
>  		return -EFSCORRUPTED;
>  	}
> +
> +	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
> +		*rlen = 0;
> +		return 0;
> +	}

I don't think we should ever call bunmapi for an inline format fork.

>  };
>  
> -
>  /*

Spurious whitespace change.

>   * 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
> @@ -384,12 +383,7 @@ xfs_dinode_verify_fork(
>  
>  	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;

I think you need to check the new feature bit here and only allow the
inline regular case if the feature bit it set.

> @@ -283,7 +283,7 @@ xfs_scrub_dinode(
>  			xfs_scrub_ino_set_corrupt(sc, ino);
>  		break;
>  	case XFS_DINODE_FMT_LOCAL:
> -		if (!S_ISDIR(mode) && !S_ISLNK(mode))
> +		if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
>  			xfs_scrub_ino_set_corrupt(sc, ino);
>  		break;

Same here.
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Shan Hai July 9, 2018, 3:06 a.m. UTC | #4
On 2018年07月08日 23:51, Christoph Hellwig wrote:
> On Fri, Jul 06, 2018 at 11:12:26AM +0800, Shan Hai wrote:
>> The local format inode is a legal citizen from now on and consider
>> it in misc operations.
> This probably wants to go towards the front of the series, and split
> into multiple patches with better changelogs for each.
>
>>   
>>   	if (unlikely(XFS_TEST_ERROR(
>>   	    (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
>> -	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
>> +	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
>> +	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL),
> This are all the three possible values.  It is kinda confusing to read
> the checks this way as we alreayd checked for a valid fork type in
> the inode read verifies.
>
> Also this seems to be in xfs_bmapi_read, for which reading allowing
> inline format forks seems wrong to me.

Agreed.

>> -	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
>> +	if (!(ifp->if_flags & (XFS_IFINLINE | XFS_IFEXTENTS))) {
>>   		error = xfs_iread_extents(NULL, ip, whichfork);
>>   		if (error)
>>   			return error;
> I think we need to clean this up better.  We probably want an
> xfs_inode_has_extents helper, or even hide the check inside
> xfs_iread_extents itself.  Also I wonder if the above is read, the
> XFS_IFEXTENTS flag has always meant that we have the current extent list
> in memory, which should always be the case for a fork in inline format.
>

Yes, you are right, seems the above 2 checks are left over from my code 
cleanup before
sending it out, my apology for wasting your time like this,  really sorry.

>> @@ -5244,11 +5239,18 @@ __xfs_bunmapi(
>>   	ifp = XFS_IFORK_PTR(ip, whichfork);
>>   	if (unlikely(
>>   	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
>> +	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL &&
>>   	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
>>   		XFS_ERROR_REPORT("xfs_bunmapi", XFS_ERRLEVEL_LOW,
>>   				 ip->i_mount);
>>   		return -EFSCORRUPTED;
>>   	}
>> +
>> +	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
>> +		*rlen = 0;
>> +		return 0;
>> +	}
> I don't think we should ever call bunmapi for an inline format fork.
>
>>   };
>>   
>> -
>>   /*
> Spurious whitespace change.
>
>>    * 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
>> @@ -384,12 +383,7 @@ xfs_dinode_verify_fork(
>>   
>>   	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;
> I think you need to check the new feature bit here and only allow the
> inline regular case if the feature bit it set.

OK, I will do that.

>> @@ -283,7 +283,7 @@ xfs_scrub_dinode(
>>   			xfs_scrub_ino_set_corrupt(sc, ino);
>>   		break;
>>   	case XFS_DINODE_FMT_LOCAL:
>> -		if (!S_ISDIR(mode) && !S_ISLNK(mode))
>> +		if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
>>   			xfs_scrub_ino_set_corrupt(sc, ino);
>>   		break;
> Same here.

Ditto.

Thanks
Shan Hai
--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index bea6dc254a7d..6b151bd15da7 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -830,11 +830,6 @@  xfs_bmap_local_to_extents(
 	struct xfs_bmbt_irec rec;
 	struct xfs_iext_cursor icur;
 
-	/*
-	 * We don't want to deal with the case of keeping inode data inline yet.
-	 * So sending the data fork of a regular inode is invalid.
-	 */
-	ASSERT(!(S_ISREG(VFS_I(ip)->i_mode) && whichfork == XFS_DATA_FORK));
 	ifp = XFS_IFORK_PTR(ip, whichfork);
 	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
 
@@ -3840,7 +3835,8 @@  xfs_bmapi_read(
 
 	if (unlikely(XFS_TEST_ERROR(
 	    (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
-	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
+	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
+	     XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL),
 	     mp, XFS_ERRTAG_BMAPIFORMAT))) {
 		XFS_ERROR_REPORT("xfs_bmapi_read", XFS_ERRLEVEL_LOW, mp);
 		return -EFSCORRUPTED;
@@ -3863,7 +3859,7 @@  xfs_bmapi_read(
 		return 0;
 	}
 
-	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+	if (!(ifp->if_flags & (XFS_IFINLINE | XFS_IFEXTENTS))) {
 		error = xfs_iread_extents(NULL, ip, whichfork);
 		if (error)
 			return error;
@@ -4285,7 +4281,6 @@  xfs_bmapi_write(
 	       (flags & (XFS_BMAPI_CONVERT | XFS_BMAPI_COWFORK)) ==
 			(XFS_BMAPI_CONVERT | XFS_BMAPI_COWFORK));
 	ASSERT(len > 0);
-	ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL);
 	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 	ASSERT(!(flags & XFS_BMAPI_REMAP));
 
@@ -5244,11 +5239,18 @@  __xfs_bunmapi(
 	ifp = XFS_IFORK_PTR(ip, whichfork);
 	if (unlikely(
 	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
+	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL &&
 	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
 		XFS_ERROR_REPORT("xfs_bunmapi", XFS_ERRLEVEL_LOW,
 				 ip->i_mount);
 		return -EFSCORRUPTED;
 	}
+
+	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
+		*rlen = 0;
+		return 0;
+	}
+
 	mp = ip->i_mount;
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return -EIO;
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 33dc34655ac3..cb3c4b308137 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -157,7 +157,6 @@  const struct xfs_buf_ops xfs_inode_buf_ra_ops = {
 	.verify_write = xfs_inode_buf_write_verify,
 };
 
-
 /*
  * 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
@@ -384,12 +383,7 @@  xfs_dinode_verify_fork(
 
 	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;
diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
index 7a6208505980..1501983dd7aa 100644
--- a/fs/xfs/scrub/inode.c
+++ b/fs/xfs/scrub/inode.c
@@ -283,7 +283,7 @@  xfs_scrub_dinode(
 			xfs_scrub_ino_set_corrupt(sc, ino);
 		break;
 	case XFS_DINODE_FMT_LOCAL:
-		if (!S_ISDIR(mode) && !S_ISLNK(mode))
+		if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
 			xfs_scrub_ino_set_corrupt(sc, ino);
 		break;
 	case XFS_DINODE_FMT_EXTENTS:
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 83b1e8c6c18f..46f718177fd7 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -760,7 +760,8 @@  xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
 		return false;
 
 	/* If we haven't read in the extent list, then don't do it now. */
-	if (!(ip->i_df.if_flags & XFS_IFEXTENTS))
+	if (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL &&
+		!(ip->i_df.if_flags & XFS_IFEXTENTS))
 		return false;
 
 	/*
@@ -768,7 +769,8 @@  xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
 	 * has delalloc blocks and we are forced to remove them.
 	 */
 	if (ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND))
-		if (!force || ip->i_delayed_blks == 0)
+		if ((ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) &&
+			(!force || ip->i_delayed_blks == 0))
 			return false;
 
 	return true;
@@ -792,6 +794,11 @@  xfs_free_eofblocks(
 	struct xfs_bmbt_irec	imap;
 	struct xfs_mount	*mp = ip->i_mount;
 
+	if (xfs_sb_version_hasinlinedata(&mp->m_sb) &&
+		ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
+		ip->i_delayed_blks = 0;
+		return 0;
+	}
 	/*
 	 * Figure out if there are any blocks beyond the end
 	 * of the file.  If not, then there is nothing to do.
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 5df4de666cc1..78b9790a7cd4 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1563,7 +1563,6 @@  xfs_itruncate_extents_flags(
 	ASSERT(!XFS_NOT_DQATTACHED(mp, ip));
 
 	trace_xfs_itruncate_extents_start(ip, new_size);
-
 	flags |= xfs_bmapi_aflag(whichfork);
 
 	/*
@@ -1745,9 +1744,15 @@  xfs_inactive_truncate(
 	ip->i_d.di_size = 0;
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 
-	error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
-	if (error)
-		goto error_trans_cancel;
+	if (xfs_sb_version_hasinlinedata(&mp->m_sb) &&
+		ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
+		ASSERT(ip->i_d.di_nextents == 0);
+		ip->i_delayed_blks = 0;
+	} else {
+		error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
+		if (error)
+			goto error_trans_cancel;
+	}
 
 	ASSERT(ip->i_d.di_nextents == 0);
 
@@ -1879,6 +1884,7 @@  xfs_inactive(
 	if (VFS_I(ip)->i_mode == 0) {
 		ASSERT(ip->i_df.if_real_bytes == 0);
 		ASSERT(ip->i_df.if_broot_bytes == 0);
+		ASSERT(ip->i_delayed_blks == 0);
 		return;
 	}
 
@@ -1911,8 +1917,9 @@  xfs_inactive(
 
 	if (S_ISREG(VFS_I(ip)->i_mode) &&
 	    (ip->i_d.di_size != 0 || XFS_ISIZE(ip) != 0 ||
-	     ip->i_d.di_nextents > 0 || ip->i_delayed_blks > 0))
+	     ip->i_d.di_nextents >= 0 || ip->i_delayed_blks >= 0)) {
 		truncate = 1;
+	}
 
 	error = xfs_qm_dqattach(ip);
 	if (error)
@@ -3554,7 +3561,8 @@  xfs_iflush_int(
 	if (S_ISREG(VFS_I(ip)->i_mode)) {
 		if (XFS_TEST_ERROR(
 		    (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) &&
-		    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE),
+		    (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
+		    (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL),
 		    mp, XFS_ERRTAG_IFLUSH_3)) {
 			xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
 				"%s: Bad regular inode %Lu, ptr "PTR_FMT,
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 2389c34c172d..52b297987a75 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -139,6 +139,7 @@  xfs_inode_item_format_data_fork(
 	struct xfs_log_iovec	**vecp)
 {
 	struct xfs_inode	*ip = iip->ili_inode;
+	struct xfs_mount	*mp = ip->i_mount;
 	size_t			data_bytes;
 
 	switch (ip->i_d.di_format) {
@@ -197,7 +198,9 @@  xfs_inode_item_format_data_fork(
 			ASSERT(ip->i_df.if_real_bytes == 0 ||
 			       ip->i_df.if_real_bytes >= data_bytes);
 			ASSERT(ip->i_df.if_u1.if_data != NULL);
-			ASSERT(ip->i_d.di_size > 0);
+			if (!xfs_sb_version_hasinlinedata(&mp->m_sb)) {
+				ASSERT(ip->i_d.di_size > 0);
+			}
 			xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL,
 					ip->i_df.if_u1.if_data, data_bytes);
 			ilf->ilf_dsize = (unsigned)data_bytes;
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 55876dd02f0c..aa72966081c5 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -532,7 +532,8 @@  xfs_file_iomap_begin_delay(
 
 	if (unlikely(XFS_TEST_ERROR(
 	    (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS &&
-	     XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE),
+	     XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE &&
+	     XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_LOCAL),
 	     mp, XFS_ERRTAG_BMAPIFORMAT))) {
 		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
 		error = -EFSCORRUPTED;
@@ -541,7 +542,7 @@  xfs_file_iomap_begin_delay(
 
 	XFS_STATS_INC(mp, xs_blk_mapw);
 
-	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+	if (!(ifp->if_flags & (XFS_IFINLINE |XFS_IFEXTENTS))) {
 		error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
 		if (error)
 			goto out_unlock;
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index b181b5f57a19..d8828f275d9a 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3121,7 +3121,8 @@  xlog_recover_inode_pass2(
 
 	if (unlikely(S_ISREG(ldip->di_mode))) {
 		if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) &&
-		    (ldip->di_format != XFS_DINODE_FMT_BTREE)) {
+		    (ldip->di_format != XFS_DINODE_FMT_BTREE) &&
+		    (ldip->di_format != XFS_DINODE_FMT_LOCAL)) {
 			XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(3)",
 					 XFS_ERRLEVEL_LOW, mp, ldip,
 					 sizeof(*ldip));