diff options
Diffstat (limited to 'fs/xfs/xfs_bmap_util.c')
-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( | |||
1672 | } | 1672 | } |
1673 | 1673 | ||
1674 | int | 1674 | int |
1675 | xfs_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 | |||
1698 | int | ||
1675 | xfs_swap_extents( | 1699 | xfs_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 | */ |