diff options
Diffstat (limited to 'fs/ocfs2/file.c')
-rw-r--r-- | fs/ocfs2/file.c | 84 |
1 files changed, 83 insertions, 1 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 4921b4ee9431..6ee20e82bcc5 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -59,6 +59,7 @@ | |||
59 | #include "xattr.h" | 59 | #include "xattr.h" |
60 | #include "acl.h" | 60 | #include "acl.h" |
61 | #include "quota.h" | 61 | #include "quota.h" |
62 | #include "refcounttree.h" | ||
62 | 63 | ||
63 | #include "buffer_head_io.h" | 64 | #include "buffer_head_io.h" |
64 | 65 | ||
@@ -1656,6 +1657,70 @@ static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset, | |||
1656 | OCFS2_IOC_RESVSP64, &sr, change_size); | 1657 | OCFS2_IOC_RESVSP64, &sr, change_size); |
1657 | } | 1658 | } |
1658 | 1659 | ||
1660 | int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos, | ||
1661 | size_t count) | ||
1662 | { | ||
1663 | int ret = 0; | ||
1664 | unsigned int extent_flags; | ||
1665 | u32 cpos, clusters, extent_len, phys_cpos; | ||
1666 | struct super_block *sb = inode->i_sb; | ||
1667 | |||
1668 | if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)) || | ||
1669 | !(OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)) | ||
1670 | return 0; | ||
1671 | |||
1672 | cpos = pos >> OCFS2_SB(sb)->s_clustersize_bits; | ||
1673 | clusters = ocfs2_clusters_for_bytes(sb, pos + count) - cpos; | ||
1674 | |||
1675 | while (clusters) { | ||
1676 | ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, &extent_len, | ||
1677 | &extent_flags); | ||
1678 | if (ret < 0) { | ||
1679 | mlog_errno(ret); | ||
1680 | goto out; | ||
1681 | } | ||
1682 | |||
1683 | if (phys_cpos && (extent_flags & OCFS2_EXT_REFCOUNTED)) { | ||
1684 | ret = 1; | ||
1685 | break; | ||
1686 | } | ||
1687 | |||
1688 | if (extent_len > clusters) | ||
1689 | extent_len = clusters; | ||
1690 | |||
1691 | clusters -= extent_len; | ||
1692 | cpos += extent_len; | ||
1693 | } | ||
1694 | out: | ||
1695 | return ret; | ||
1696 | } | ||
1697 | |||
1698 | static int ocfs2_prepare_inode_for_refcount(struct inode *inode, | ||
1699 | loff_t pos, size_t count, | ||
1700 | int *meta_level) | ||
1701 | { | ||
1702 | int ret; | ||
1703 | struct buffer_head *di_bh = NULL; | ||
1704 | u32 cpos = pos >> OCFS2_SB(inode->i_sb)->s_clustersize_bits; | ||
1705 | u32 clusters = | ||
1706 | ocfs2_clusters_for_bytes(inode->i_sb, pos + count) - cpos; | ||
1707 | |||
1708 | ret = ocfs2_inode_lock(inode, &di_bh, 1); | ||
1709 | if (ret) { | ||
1710 | mlog_errno(ret); | ||
1711 | goto out; | ||
1712 | } | ||
1713 | |||
1714 | *meta_level = 1; | ||
1715 | |||
1716 | ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters); | ||
1717 | if (ret) | ||
1718 | mlog_errno(ret); | ||
1719 | out: | ||
1720 | brelse(di_bh); | ||
1721 | return ret; | ||
1722 | } | ||
1723 | |||
1659 | static int ocfs2_prepare_inode_for_write(struct dentry *dentry, | 1724 | static int ocfs2_prepare_inode_for_write(struct dentry *dentry, |
1660 | loff_t *ppos, | 1725 | loff_t *ppos, |
1661 | size_t count, | 1726 | size_t count, |
@@ -1712,6 +1777,22 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, | |||
1712 | 1777 | ||
1713 | end = saved_pos + count; | 1778 | end = saved_pos + count; |
1714 | 1779 | ||
1780 | ret = ocfs2_check_range_for_refcount(inode, saved_pos, count); | ||
1781 | if (ret == 1) { | ||
1782 | ocfs2_inode_unlock(inode, meta_level); | ||
1783 | meta_level = -1; | ||
1784 | |||
1785 | ret = ocfs2_prepare_inode_for_refcount(inode, | ||
1786 | saved_pos, | ||
1787 | count, | ||
1788 | &meta_level); | ||
1789 | } | ||
1790 | |||
1791 | if (ret < 0) { | ||
1792 | mlog_errno(ret); | ||
1793 | goto out_unlock; | ||
1794 | } | ||
1795 | |||
1715 | /* | 1796 | /* |
1716 | * Skip the O_DIRECT checks if we don't need | 1797 | * Skip the O_DIRECT checks if we don't need |
1717 | * them. | 1798 | * them. |
@@ -1758,7 +1839,8 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, | |||
1758 | *ppos = saved_pos; | 1839 | *ppos = saved_pos; |
1759 | 1840 | ||
1760 | out_unlock: | 1841 | out_unlock: |
1761 | ocfs2_inode_unlock(inode, meta_level); | 1842 | if (meta_level >= 0) |
1843 | ocfs2_inode_unlock(inode, meta_level); | ||
1762 | 1844 | ||
1763 | out: | 1845 | out: |
1764 | return ret; | 1846 | return ret; |