diff options
Diffstat (limited to 'fs/xfs/xfs_inode.c')
| -rw-r--r-- | fs/xfs/xfs_inode.c | 55 | 
1 files changed, 53 insertions, 2 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index e08eaea6327b..4e560e6a12c1 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -49,6 +49,7 @@  #include "xfs_trans_priv.h"  #include "xfs_log.h"  #include "xfs_bmap_btree.h" +#include "xfs_reflink.h"  kmem_zone_t *xfs_inode_zone; @@ -77,6 +78,29 @@ xfs_get_extsz_hint(  }  /* + * Helper function to extract CoW extent size hint from inode. + * Between the extent size hint and the CoW extent size hint, we + * return the greater of the two.  If the value is zero (automatic), + * use the default size. + */ +xfs_extlen_t +xfs_get_cowextsz_hint( +	struct xfs_inode	*ip) +{ +	xfs_extlen_t		a, b; + +	a = 0; +	if (ip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) +		a = ip->i_d.di_cowextsize; +	b = xfs_get_extsz_hint(ip); + +	a = max(a, b); +	if (a == 0) +		return XFS_DEFAULT_COWEXTSZ_HINT; +	return a; +} + +/*   * These two are wrapper routines around the xfs_ilock() routine used to   * centralize some grungy code.  They are used in places that wish to lock the   * inode solely for reading the extents.  The reason these places can't just @@ -651,6 +675,8 @@ _xfs_dic2xflags(  	if (di_flags2 & XFS_DIFLAG2_ANY) {  		if (di_flags2 & XFS_DIFLAG2_DAX)  			flags |= FS_XFLAG_DAX; +		if (di_flags2 & XFS_DIFLAG2_COWEXTSIZE) +			flags |= FS_XFLAG_COWEXTSIZE;  	}  	if (has_attr) @@ -821,7 +847,7 @@ xfs_ialloc(  	ip->i_d.di_nextents = 0;  	ASSERT(ip->i_d.di_nblocks == 0); -	tv = current_fs_time(mp->m_super); +	tv = current_time(inode);  	inode->i_mtime = tv;  	inode->i_atime = tv;  	inode->i_ctime = tv; @@ -834,6 +860,7 @@ xfs_ialloc(  	if (ip->i_d.di_version == 3) {  		inode->i_version = 1;  		ip->i_d.di_flags2 = 0; +		ip->i_d.di_cowextsize = 0;  		ip->i_d.di_crtime.t_sec = (__int32_t)tv.tv_sec;  		ip->i_d.di_crtime.t_nsec = (__int32_t)tv.tv_nsec;  	} @@ -896,6 +923,15 @@ xfs_ialloc(  			ip->i_d.di_flags |= di_flags;  			ip->i_d.di_flags2 |= di_flags2;  		} +		if (pip && +		    (pip->i_d.di_flags2 & XFS_DIFLAG2_ANY) && +		    pip->i_d.di_version == 3 && +		    ip->i_d.di_version == 3) { +			if (pip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) { +				ip->i_d.di_flags2 |= XFS_DIFLAG2_COWEXTSIZE; +				ip->i_d.di_cowextsize = pip->i_d.di_cowextsize; +			} +		}  		/* FALLTHROUGH */  	case S_IFLNK:  		ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; @@ -1586,6 +1622,20 @@ xfs_itruncate_extents(  			goto out;  	} +	/* Remove all pending CoW reservations. */ +	error = xfs_reflink_cancel_cow_blocks(ip, &tp, first_unmap_block, +			last_block); +	if (error) +		goto out; + +	/* +	 * Clear the reflink flag if we truncated everything. +	 */ +	if (ip->i_d.di_nblocks == 0 && xfs_is_reflink_inode(ip)) { +		ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; +		xfs_inode_clear_cowblocks_tag(ip); +	} +  	/*  	 * Always re-log the inode so that our permanent transaction can keep  	 * on rolling it forward in the log. @@ -1710,7 +1760,7 @@ xfs_inactive_truncate(  	/*  	 * Log the inode size first to prevent stale data exposure in the event  	 * of a system crash before the truncate completes. See the related -	 * comment in xfs_setattr_size() for details. +	 * comment in xfs_vn_setattr_size() for details.  	 */  	ip->i_d.di_size = 0;  	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); @@ -1850,6 +1900,7 @@ xfs_inactive(  	}  	mp = ip->i_mount; +	ASSERT(!xfs_iflags_test(ip, XFS_IRECOVERY));  	/* If this is a read-only mount, don't do this (would generate I/O) */  	if (mp->m_flags & XFS_MOUNT_RDONLY)  |