aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ocfs2/file.c')
-rw-r--r--fs/ocfs2/file.c84
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
1660int 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 }
1694out:
1695 return ret;
1696}
1697
1698static 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);
1719out:
1720 brelse(di_bh);
1721 return ret;
1722}
1723
1659static int ocfs2_prepare_inode_for_write(struct dentry *dentry, 1724static 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
1760out_unlock: 1841out_unlock:
1761 ocfs2_inode_unlock(inode, meta_level); 1842 if (meta_level >= 0)
1843 ocfs2_inode_unlock(inode, meta_level);
1762 1844
1763out: 1845out:
1764 return ret; 1846 return ret;