aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/file.c
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2009-08-25 21:47:28 -0400
committerJoel Becker <joel.becker@oracle.com>2009-09-22 23:09:38 -0400
commit37f8a2bfaa8364dd3644cccee8824bb8f5e409a5 (patch)
treeab3083179c621c3e8d0be3980aaed96528f90599 /fs/ocfs2/file.c
parent293b2f70b4a16a1ca91efd28ef3d6634262c6887 (diff)
ocfs2: CoW a reflinked cluster when it is truncated.
When we truncate a file to a specific size which resides in a reflinked cluster, we need to CoW it since ocfs2_zero_range_for_truncate will zero the space after the size(just another type of write). So we add a "max_cpos" in ocfs2_refcount_cow so that it will stop when it hit the max cluster offset. Signed-off-by: Tao Ma <tao.ma@oracle.com>
Diffstat (limited to 'fs/ocfs2/file.c')
-rw-r--r--fs/ocfs2/file.c46
1 files changed, 45 insertions, 1 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 6ee20e82bcc5..75f5b81805b5 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -335,6 +335,39 @@ out:
335 return ret; 335 return ret;
336} 336}
337 337
338static int ocfs2_cow_file_pos(struct inode *inode,
339 struct buffer_head *fe_bh,
340 u64 offset)
341{
342 int status;
343 u32 phys, cpos = offset >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
344 unsigned int num_clusters = 0;
345 unsigned int ext_flags = 0;
346
347 /*
348 * If the new offset is aligned to the range of the cluster, there is
349 * no space for ocfs2_zero_range_for_truncate to fill, so no need to
350 * CoW either.
351 */
352 if ((offset & (OCFS2_SB(inode->i_sb)->s_clustersize - 1)) == 0)
353 return 0;
354
355 status = ocfs2_get_clusters(inode, cpos, &phys,
356 &num_clusters, &ext_flags);
357 if (status) {
358 mlog_errno(status);
359 goto out;
360 }
361
362 if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
363 goto out;
364
365 return ocfs2_refcount_cow(inode, fe_bh, cpos, 1, cpos+1);
366
367out:
368 return status;
369}
370
338static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb, 371static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
339 struct inode *inode, 372 struct inode *inode,
340 struct buffer_head *fe_bh, 373 struct buffer_head *fe_bh,
@@ -347,6 +380,17 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
347 380
348 mlog_entry_void(); 381 mlog_entry_void();
349 382
383 /*
384 * We need to CoW the cluster contains the offset if it is reflinked
385 * since we will call ocfs2_zero_range_for_truncate later which will
386 * write "0" from offset to the end of the cluster.
387 */
388 status = ocfs2_cow_file_pos(inode, fe_bh, new_i_size);
389 if (status) {
390 mlog_errno(status);
391 return status;
392 }
393
350 /* TODO: This needs to actually orphan the inode in this 394 /* TODO: This needs to actually orphan the inode in this
351 * transaction. */ 395 * transaction. */
352 396
@@ -1713,7 +1757,7 @@ static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
1713 1757
1714 *meta_level = 1; 1758 *meta_level = 1;
1715 1759
1716 ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters); 1760 ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX);
1717 if (ret) 1761 if (ret)
1718 mlog_errno(ret); 1762 mlog_errno(ret);
1719out: 1763out: