aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2009-08-24 20:02:48 -0400
committerJoel Becker <joel.becker@oracle.com>2009-09-22 23:09:37 -0400
commit293b2f70b4a16a1ca91efd28ef3d6634262c6887 (patch)
tree4a85078faae7c529fa313d4964e0d6ad0905a612
parent6ae23c5555176c5b23480c9c578ff27437085ba5 (diff)
ocfs2: Integrate CoW in file write.
When we use mmap, we CoW the refcountd clusters in ocfs2_write_begin_nolock. While for normal file io(including directio), we do CoW in ocfs2_prepare_inode_for_write. Signed-off-by: Tao Ma <tao.ma@oracle.com>
-rw-r--r--fs/ocfs2/aops.c19
-rw-r--r--fs/ocfs2/file.c84
-rw-r--r--fs/ocfs2/file.h2
3 files changed, 104 insertions, 1 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index fdad075fed61..9db9d64ca475 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -44,6 +44,7 @@
44#include "suballoc.h" 44#include "suballoc.h"
45#include "super.h" 45#include "super.h"
46#include "symlink.h" 46#include "symlink.h"
47#include "refcounttree.h"
47 48
48#include "buffer_head_io.h" 49#include "buffer_head_io.h"
49 50
@@ -590,6 +591,8 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
590 goto bail; 591 goto bail;
591 } 592 }
592 593
594 /* We should already CoW the refcounted extent. */
595 BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED);
593 /* 596 /*
594 * get_more_blocks() expects us to describe a hole by clearing 597 * get_more_blocks() expects us to describe a hole by clearing
595 * the mapped bit on bh_result(). 598 * the mapped bit on bh_result().
@@ -1449,6 +1452,9 @@ static int ocfs2_populate_write_desc(struct inode *inode,
1449 goto out; 1452 goto out;
1450 } 1453 }
1451 1454
1455 /* We should already CoW the refcountd extent. */
1456 BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED);
1457
1452 /* 1458 /*
1453 * Assume worst case - that we're writing in 1459 * Assume worst case - that we're writing in
1454 * the middle of the extent. 1460 * the middle of the extent.
@@ -1700,6 +1706,19 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
1700 goto out; 1706 goto out;
1701 } 1707 }
1702 1708
1709 ret = ocfs2_check_range_for_refcount(inode, pos, len);
1710 if (ret < 0) {
1711 mlog_errno(ret);
1712 goto out;
1713 } else if (ret == 1) {
1714 ret = ocfs2_refcount_cow(inode, di_bh,
1715 wc->w_cpos, wc->w_clen);
1716 if (ret) {
1717 mlog_errno(ret);
1718 goto out;
1719 }
1720 }
1721
1703 ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc, 1722 ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc,
1704 &extents_to_split); 1723 &extents_to_split);
1705 if (ret) { 1724 if (ret) {
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;
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index 172f9fbc9fc7..d66cf4f7c70e 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -69,4 +69,6 @@ int ocfs2_update_inode_atime(struct inode *inode,
69int ocfs2_change_file_space(struct file *file, unsigned int cmd, 69int ocfs2_change_file_space(struct file *file, unsigned int cmd,
70 struct ocfs2_space_resv *sr); 70 struct ocfs2_space_resv *sr);
71 71
72int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
73 size_t count);
72#endif /* OCFS2_FILE_H */ 74#endif /* OCFS2_FILE_H */