aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2014-08-03 23:44:08 -0400
committerDave Chinner <david@fromorbit.com>2014-08-03 23:44:08 -0400
commit4ef897a27543b513351262881660147366c042a1 (patch)
tree8b1bf48a105a81a61a3a1299b0cf49fd5508ef41 /fs
parent812176832169c77b4bacddd01edc3e55340263fd (diff)
xfs: flush both inodes in xfs_swap_extents
We need to treat both inodes identically from a page cache point of view when prepareing them for extent swapping. We don't do this right now - we assume that one of the inodes empty, because that's what xfs_fsr currently does. Remove this assumption from the code. While factoring out the flushing and related checks, move the transactions reservation to immeidately after the flushes so that we don't need to pick up and then drop the ilock to do the transaction reservation. There are no issues with aborting the transaction it if the checks fail before we join the inodes to the transaction and dirty them, so this is a safe change to make. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_bmap_util.c81
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(
1672} 1672}
1673 1673
1674int 1674int
1675xfs_swap_extent_flush(
1676 struct xfs_inode *ip)
1677{
1678 int error;
1679
1680 error = filemap_write_and_wait(VFS_I(ip)->i_mapping);
1681 if (error)
1682 return error;
1683 truncate_pagecache_range(VFS_I(ip), 0, -1);
1684
1685 /* Verify O_DIRECT for ftmp */
1686 if (VFS_I(ip)->i_mapping->nrpages)
1687 return -EINVAL;
1688
1689 /*
1690 * Don't try to swap extents on mmap()d files because we can't lock
1691 * out races against page faults safely.
1692 */
1693 if (mapping_mapped(VFS_I(ip)->i_mapping))
1694 return -EBUSY;
1695 return 0;
1696}
1697
1698int
1675xfs_swap_extents( 1699xfs_swap_extents(
1676 xfs_inode_t *ip, /* target inode */ 1700 xfs_inode_t *ip, /* target inode */
1677 xfs_inode_t *tip, /* tmp inode */ 1701 xfs_inode_t *tip, /* tmp inode */
@@ -1715,26 +1739,28 @@ xfs_swap_extents(
1715 goto out_unlock; 1739 goto out_unlock;
1716 } 1740 }
1717 1741
1718 error = filemap_write_and_wait(VFS_I(tip)->i_mapping); 1742 error = xfs_swap_extent_flush(ip);
1743 if (error)
1744 goto out_unlock;
1745 error = xfs_swap_extent_flush(tip);
1719 if (error) 1746 if (error)
1720 goto out_unlock; 1747 goto out_unlock;
1721 truncate_pagecache_range(VFS_I(tip), 0, -1);
1722
1723 xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
1724 lock_flags |= XFS_ILOCK_EXCL;
1725 1748
1726 /* Verify O_DIRECT for ftmp */ 1749 tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
1727 if (VFS_I(tip)->i_mapping->nrpages) { 1750 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
1728 error = -EINVAL; 1751 if (error) {
1752 xfs_trans_cancel(tp, 0);
1729 goto out_unlock; 1753 goto out_unlock;
1730 } 1754 }
1755 xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
1756 lock_flags |= XFS_ILOCK_EXCL;
1731 1757
1732 /* Verify all data are being swapped */ 1758 /* Verify all data are being swapped */
1733 if (sxp->sx_offset != 0 || 1759 if (sxp->sx_offset != 0 ||
1734 sxp->sx_length != ip->i_d.di_size || 1760 sxp->sx_length != ip->i_d.di_size ||
1735 sxp->sx_length != tip->i_d.di_size) { 1761 sxp->sx_length != tip->i_d.di_size) {
1736 error = -EFAULT; 1762 error = -EFAULT;
1737 goto out_unlock; 1763 goto out_trans_cancel;
1738 } 1764 }
1739 1765
1740 trace_xfs_swap_extent_before(ip, 0); 1766 trace_xfs_swap_extent_before(ip, 0);
@@ -1746,7 +1772,7 @@ xfs_swap_extents(
1746 xfs_notice(mp, 1772 xfs_notice(mp,
1747 "%s: inode 0x%llx format is incompatible for exchanging.", 1773 "%s: inode 0x%llx format is incompatible for exchanging.",
1748 __func__, ip->i_ino); 1774 __func__, ip->i_ino);
1749 goto out_unlock; 1775 goto out_trans_cancel;
1750 } 1776 }
1751 1777
1752 /* 1778 /*
@@ -1761,41 +1787,8 @@ xfs_swap_extents(
1761 (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) || 1787 (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) ||
1762 (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) { 1788 (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) {
1763 error = -EBUSY; 1789 error = -EBUSY;
1764 goto out_unlock;
1765 }
1766
1767 /* We need to fail if the file is memory mapped. Once we have tossed
1768 * all existing pages, the page fault will have no option
1769 * but to go to the filesystem for pages. By making the page fault call
1770 * vop_read (or write in the case of autogrow) they block on the iolock
1771 * until we have switched the extents.
1772 */
1773 if (mapping_mapped(VFS_I(ip)->i_mapping)) {
1774 error = -EBUSY;
1775 goto out_unlock;
1776 }
1777
1778 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1779 xfs_iunlock(tip, XFS_ILOCK_EXCL);
1780 lock_flags &= ~XFS_ILOCK_EXCL;
1781
1782 /*
1783 * There is a race condition here since we gave up the
1784 * ilock. However, the data fork will not change since
1785 * we have the iolock (locked for truncation too) so we
1786 * are safe. We don't really care if non-io related
1787 * fields change.
1788 */
1789 truncate_pagecache_range(VFS_I(ip), 0, -1);
1790
1791 tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
1792 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
1793 if (error)
1794 goto out_trans_cancel; 1790 goto out_trans_cancel;
1795 1791 }
1796 xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
1797 lock_flags |= XFS_ILOCK_EXCL;
1798
1799 /* 1792 /*
1800 * Count the number of extended attribute blocks 1793 * Count the number of extended attribute blocks
1801 */ 1794 */