summaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
authorTristan Ye <tristan.ye@oracle.com>2010-05-11 11:54:43 +0200
committerJoel Becker <joel.becker@oracle.com>2010-05-18 21:27:46 +0200
commite8aec068ecb1957630816cfa2c150c6b3ddd1790 (patch)
treeb6140b82846cd2f5ab264d01be2a4473e56faf97 /fs/ocfs2
parentOcfs2: Optimize ocfs2 truncate to use ocfs2_remove_btree_range() instead. (diff)
downloadlinux-e8aec068ecb1957630816cfa2c150c6b3ddd1790.tar.xz
linux-e8aec068ecb1957630816cfa2c150c6b3ddd1790.zip
Ocfs2: Fix hole punching to correctly do CoW during cluster zeroing.
Based on the previous patch of optimizing truncate, the bugfix for refcount trees when punching holes can be fairly easy and straightforward since most of work we should take into account for refcounting have been completed already in ocfs2_remove_btree_range(). This patch performs CoW for refcounted extents when a hole being punched whose start or end offset were in the middle of a cluster, which means partial zeroing of the cluster will be performed soon. The patch has been tested fixing the following bug: http://oss.oracle.com/bugzilla/show_bug.cgi?id=1216 Signed-off-by: Tristan Ye <tristan.ye@oracle.com> Acked-by: Mark Fasheh <mfasheh@suse.com> Signed-off-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/file.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 4c7a4d8ed32c..3346e5b199d5 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1422,12 +1422,14 @@ static int ocfs2_remove_inode_range(struct inode *inode,
struct buffer_head *di_bh, u64 byte_start,
u64 byte_len)
{
- int ret = 0;
+ int ret = 0, flags = 0;
u32 trunc_start, trunc_len, cpos, phys_cpos, alloc_size;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct ocfs2_cached_dealloc_ctxt dealloc;
struct address_space *mapping = inode->i_mapping;
struct ocfs2_extent_tree et;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ u64 refcount_loc = le64_to_cpu(di->i_refcount_loc);
ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh);
ocfs2_init_dealloc_ctxt(&dealloc);
@@ -1453,6 +1455,27 @@ static int ocfs2_remove_inode_range(struct inode *inode,
goto out;
}
+ /*
+ * For reflinks, we may need to CoW 2 clusters which might be
+ * partially zero'd later, if hole's start and end offset were
+ * within one cluster(means is not exactly aligned to clustersize).
+ */
+
+ if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) {
+
+ ret = ocfs2_cow_file_pos(inode, di_bh, byte_start);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_cow_file_pos(inode, di_bh, byte_start + byte_len);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start);
trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits;
if (trunc_len >= trunc_start)
@@ -1474,7 +1497,7 @@ static int ocfs2_remove_inode_range(struct inode *inode,
cpos = trunc_start;
while (trunc_len) {
ret = ocfs2_get_clusters(inode, cpos, &phys_cpos,
- &alloc_size, NULL);
+ &alloc_size, &flags);
if (ret) {
mlog_errno(ret);
goto out;
@@ -1487,7 +1510,8 @@ static int ocfs2_remove_inode_range(struct inode *inode,
if (phys_cpos != 0) {
ret = ocfs2_remove_btree_range(inode, &et, cpos,
phys_cpos, alloc_size,
- 0, &dealloc, 0);
+ flags, &dealloc,
+ refcount_loc);
if (ret) {
mlog_errno(ret);
goto out;