diff options
| -rw-r--r-- | fs/xfs/xfs_inode.c | 37 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.h | 1 | ||||
| -rw-r--r-- | fs/xfs/xfs_vnodeops.c | 19 | 
3 files changed, 45 insertions, 12 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 965598eb308..7449cb943ef 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -3912,3 +3912,40 @@ xfs_iext_irec_update_extoffs(  		ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff;  	}  } + +/* + * Test whether it is appropriate to check an inode for and free post EOF + * blocks. The 'force' parameter determines whether we should also consider + * regular files that are marked preallocated or append-only. + */ +bool +xfs_can_free_eofblocks(struct xfs_inode *ip, bool force) +{ +	/* prealloc/delalloc exists only on regular files */ +	if (!S_ISREG(ip->i_d.di_mode)) +		return false; + +	/* +	 * Zero sized files with no cached pages and delalloc blocks will not +	 * have speculative prealloc/delalloc blocks to remove. +	 */ +	if (VFS_I(ip)->i_size == 0 && +	    VN_CACHED(VFS_I(ip)) == 0 && +	    ip->i_delayed_blks == 0) +		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)) +		return false; + +	/* +	 * Do not free real preallocated or append-only files unless the file +	 * 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) +			return false; + +	return true; +} + diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 1fc2065e010..21b4de3df71 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -585,6 +585,7 @@ void		xfs_iext_irec_compact(xfs_ifork_t *);  void		xfs_iext_irec_compact_pages(xfs_ifork_t *);  void		xfs_iext_irec_compact_full(xfs_ifork_t *);  void		xfs_iext_irec_update_extoffs(xfs_ifork_t *, int, int); +bool		xfs_can_free_eofblocks(struct xfs_inode *, bool);  #define xfs_ipincount(ip)	((unsigned int) atomic_read(&ip->i_pincount)) diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index e6e1d11dfdf..c4c15390020 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -436,11 +436,7 @@ xfs_release(  	if (ip->i_d.di_nlink == 0)  		return 0; -	if ((S_ISREG(ip->i_d.di_mode) && -	     (VFS_I(ip)->i_size > 0 || -	      (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) && -	     (ip->i_df.if_flags & XFS_IFEXTENTS))  && -	    (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) { +	if (xfs_can_free_eofblocks(ip, false)) {  		/*  		 * If we can't get the iolock just skip truncating the blocks @@ -516,13 +512,12 @@ xfs_inactive(  		goto out;  	if (ip->i_d.di_nlink != 0) { -		if ((S_ISREG(ip->i_d.di_mode) && -		    (VFS_I(ip)->i_size > 0 || -		     (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) && -		    (ip->i_df.if_flags & XFS_IFEXTENTS) && -		    (!(ip->i_d.di_flags & -				(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) || -		     ip->i_delayed_blks != 0))) { +		/* +		 * force is true because we are evicting an inode from the +		 * cache. Post-eof blocks must be freed, lest we end up with +		 * broken free space accounting. +		 */ +		if (xfs_can_free_eofblocks(ip, true)) {  			error = xfs_free_eofblocks(mp, ip, false);  			if (error)  				return VN_INACTIVE_CACHE;  |