diff options
author | Tao Ma <tao.ma@oracle.com> | 2009-08-25 21:47:28 -0400 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2009-09-22 23:09:38 -0400 |
commit | 37f8a2bfaa8364dd3644cccee8824bb8f5e409a5 (patch) | |
tree | ab3083179c621c3e8d0be3980aaed96528f90599 /fs/ocfs2/file.c | |
parent | 293b2f70b4a16a1ca91efd28ef3d6634262c6887 (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.c | 46 |
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 | ||
338 | static 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 | |||
367 | out: | ||
368 | return status; | ||
369 | } | ||
370 | |||
338 | static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb, | 371 | static 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); |
1719 | out: | 1763 | out: |