diff options
author | Tao Ma <tao.ma@oracle.com> | 2009-08-24 20:02:48 -0400 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2009-09-22 23:09:37 -0400 |
commit | 293b2f70b4a16a1ca91efd28ef3d6634262c6887 (patch) | |
tree | 4a85078faae7c529fa313d4964e0d6ad0905a612 /fs | |
parent | 6ae23c5555176c5b23480c9c578ff27437085ba5 (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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/aops.c | 19 | ||||
-rw-r--r-- | fs/ocfs2/file.c | 84 | ||||
-rw-r--r-- | fs/ocfs2/file.h | 2 |
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 | ||
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; |
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, | |||
69 | int ocfs2_change_file_space(struct file *file, unsigned int cmd, | 69 | int ocfs2_change_file_space(struct file *file, unsigned int cmd, |
70 | struct ocfs2_space_resv *sr); | 70 | struct ocfs2_space_resv *sr); |
71 | 71 | ||
72 | int 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 */ |