diff options
| -rw-r--r-- | fs/xfs/xfs_bmap_util.c | 81 | 
1 files changed, 37 insertions, 44 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 5d29aa17475e..8f7da5877fa3 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c @@ -1672,6 +1672,30 @@ xfs_swap_extents_check_format(  }  int +xfs_swap_extent_flush( +	struct xfs_inode	*ip) +{ +	int	error; + +	error = filemap_write_and_wait(VFS_I(ip)->i_mapping); +	if (error) +		return error; +	truncate_pagecache_range(VFS_I(ip), 0, -1); + +	/* Verify O_DIRECT for ftmp */ +	if (VFS_I(ip)->i_mapping->nrpages) +		return -EINVAL; + +	/* +	 * Don't try to swap extents on mmap()d files because we can't lock +	 * out races against page faults safely. +	 */ +	if (mapping_mapped(VFS_I(ip)->i_mapping)) +		return -EBUSY; +	return 0; +} + +int  xfs_swap_extents(  	xfs_inode_t	*ip,	/* target inode */  	xfs_inode_t	*tip,	/* tmp inode */ @@ -1715,26 +1739,28 @@ xfs_swap_extents(  		goto out_unlock;  	} -	error = filemap_write_and_wait(VFS_I(tip)->i_mapping); +	error = xfs_swap_extent_flush(ip); +	if (error) +		goto out_unlock; +	error = xfs_swap_extent_flush(tip);  	if (error)  		goto out_unlock; -	truncate_pagecache_range(VFS_I(tip), 0, -1); - -	xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); -	lock_flags |= XFS_ILOCK_EXCL; -	/* Verify O_DIRECT for ftmp */ -	if (VFS_I(tip)->i_mapping->nrpages) { -		error = -EINVAL; +	tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); +	error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); +	if (error) { +		xfs_trans_cancel(tp, 0);  		goto out_unlock;  	} +	xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); +	lock_flags |= XFS_ILOCK_EXCL;  	/* Verify all data are being swapped */  	if (sxp->sx_offset != 0 ||  	    sxp->sx_length != ip->i_d.di_size ||  	    sxp->sx_length != tip->i_d.di_size) {  		error = -EFAULT; -		goto out_unlock; +		goto out_trans_cancel;  	}  	trace_xfs_swap_extent_before(ip, 0); @@ -1746,7 +1772,7 @@ xfs_swap_extents(  		xfs_notice(mp,  		    "%s: inode 0x%llx format is incompatible for exchanging.",  				__func__, ip->i_ino); -		goto out_unlock; +		goto out_trans_cancel;  	}  	/* @@ -1761,41 +1787,8 @@ xfs_swap_extents(  	    (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) ||  	    (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) {  		error = -EBUSY; -		goto out_unlock; -	} - -	/* We need to fail if the file is memory mapped.  Once we have tossed -	 * all existing pages, the page fault will have no option -	 * but to go to the filesystem for pages. By making the page fault call -	 * vop_read (or write in the case of autogrow) they block on the iolock -	 * until we have switched the extents. -	 */ -	if (mapping_mapped(VFS_I(ip)->i_mapping)) { -		error = -EBUSY; -		goto out_unlock; -	} - -	xfs_iunlock(ip, XFS_ILOCK_EXCL); -	xfs_iunlock(tip, XFS_ILOCK_EXCL); -	lock_flags &= ~XFS_ILOCK_EXCL; - -	/* -	 * There is a race condition here since we gave up the -	 * ilock.  However, the data fork will not change since -	 * we have the iolock (locked for truncation too) so we -	 * are safe.  We don't really care if non-io related -	 * fields change. -	 */ -	truncate_pagecache_range(VFS_I(ip), 0, -1); - -	tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); -	error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); -	if (error)  		goto out_trans_cancel; - -	xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); -	lock_flags |= XFS_ILOCK_EXCL; - +	}  	/*  	 * Count the number of extended attribute blocks  	 */  | 
