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 | |
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>
-rw-r--r-- | fs/ocfs2/aops.c | 2 | ||||
-rw-r--r-- | fs/ocfs2/file.c | 46 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.c | 34 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.h | 2 |
4 files changed, 70 insertions, 14 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 9db9d64ca475..33e03c551127 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -1712,7 +1712,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, | |||
1712 | goto out; | 1712 | goto out; |
1713 | } else if (ret == 1) { | 1713 | } else if (ret == 1) { |
1714 | ret = ocfs2_refcount_cow(inode, di_bh, | 1714 | ret = ocfs2_refcount_cow(inode, di_bh, |
1715 | wc->w_cpos, wc->w_clen); | 1715 | wc->w_cpos, wc->w_clen, UINT_MAX); |
1716 | if (ret) { | 1716 | if (ret) { |
1717 | mlog_errno(ret); | 1717 | mlog_errno(ret); |
1718 | goto out; | 1718 | goto out; |
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: |
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 0a92436557e3..37aa0c8696d6 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
@@ -2482,6 +2482,7 @@ static inline unsigned int ocfs2_cow_align_length(struct super_block *sb, | |||
2482 | * | 2482 | * |
2483 | * cpos is vitual start cluster position we want to do CoW in a | 2483 | * cpos is vitual start cluster position we want to do CoW in a |
2484 | * file and write_len is the cluster length. | 2484 | * file and write_len is the cluster length. |
2485 | * max_cpos is the place where we want to stop CoW intentionally. | ||
2485 | * | 2486 | * |
2486 | * Normal we will start CoW from the beginning of extent record cotaining cpos. | 2487 | * Normal we will start CoW from the beginning of extent record cotaining cpos. |
2487 | * We try to break up extents on boundaries of MAX_CONTIG_BYTES so that we | 2488 | * We try to break up extents on boundaries of MAX_CONTIG_BYTES so that we |
@@ -2491,6 +2492,7 @@ static int ocfs2_refcount_cal_cow_clusters(struct inode *inode, | |||
2491 | struct buffer_head *di_bh, | 2492 | struct buffer_head *di_bh, |
2492 | u32 cpos, | 2493 | u32 cpos, |
2493 | u32 write_len, | 2494 | u32 write_len, |
2495 | u32 max_cpos, | ||
2494 | u32 *cow_start, | 2496 | u32 *cow_start, |
2495 | u32 *cow_len) | 2497 | u32 *cow_len) |
2496 | { | 2498 | { |
@@ -2505,6 +2507,8 @@ static int ocfs2_refcount_cal_cow_clusters(struct inode *inode, | |||
2505 | int contig_clusters = ocfs2_cow_contig_clusters(inode->i_sb); | 2507 | int contig_clusters = ocfs2_cow_contig_clusters(inode->i_sb); |
2506 | int leaf_clusters; | 2508 | int leaf_clusters; |
2507 | 2509 | ||
2510 | BUG_ON(cpos + write_len > max_cpos); | ||
2511 | |||
2508 | if (tree_height > 0) { | 2512 | if (tree_height > 0) { |
2509 | ret = ocfs2_find_leaf(INODE_CACHE(inode), el, cpos, &eb_bh); | 2513 | ret = ocfs2_find_leaf(INODE_CACHE(inode), el, cpos, &eb_bh); |
2510 | if (ret) { | 2514 | if (ret) { |
@@ -2549,15 +2553,20 @@ static int ocfs2_refcount_cal_cow_clusters(struct inode *inode, | |||
2549 | } | 2553 | } |
2550 | 2554 | ||
2551 | /* | 2555 | /* |
2552 | * If we encounter a hole or a non-refcounted record, | 2556 | * If we encounter a hole, a non-refcounted record or |
2553 | * stop the search. | 2557 | * pass the max_cpos, stop the search. |
2554 | */ | 2558 | */ |
2555 | if ((!(rec->e_flags & OCFS2_EXT_REFCOUNTED)) || | 2559 | if ((!(rec->e_flags & OCFS2_EXT_REFCOUNTED)) || |
2556 | (*cow_len && rec_end != le32_to_cpu(rec->e_cpos))) | 2560 | (*cow_len && rec_end != le32_to_cpu(rec->e_cpos)) || |
2561 | (max_cpos <= le32_to_cpu(rec->e_cpos))) | ||
2557 | break; | 2562 | break; |
2558 | 2563 | ||
2559 | leaf_clusters = le16_to_cpu(rec->e_leaf_clusters); | 2564 | leaf_clusters = le16_to_cpu(rec->e_leaf_clusters); |
2560 | rec_end = le32_to_cpu(rec->e_cpos) + leaf_clusters; | 2565 | rec_end = le32_to_cpu(rec->e_cpos) + leaf_clusters; |
2566 | if (rec_end > max_cpos) { | ||
2567 | rec_end = max_cpos; | ||
2568 | leaf_clusters = rec_end - le32_to_cpu(rec->e_cpos); | ||
2569 | } | ||
2561 | 2570 | ||
2562 | /* | 2571 | /* |
2563 | * How many clusters do we actually need from | 2572 | * How many clusters do we actually need from |
@@ -3184,12 +3193,13 @@ static int ocfs2_replace_cow(struct inode *inode, | |||
3184 | } | 3193 | } |
3185 | 3194 | ||
3186 | /* | 3195 | /* |
3187 | * Starting at cpos, try to CoW write_len clusters. | 3196 | * Starting at cpos, try to CoW write_len clusters. Don't CoW |
3188 | * This will stop when it runs into a hole or an unrefcounted extent. | 3197 | * past max_cpos. This will stop when it runs into a hole or an |
3198 | * unrefcounted extent. | ||
3189 | */ | 3199 | */ |
3190 | static int ocfs2_refcount_cow_hunk(struct inode *inode, | 3200 | static int ocfs2_refcount_cow_hunk(struct inode *inode, |
3191 | struct buffer_head *di_bh, | 3201 | struct buffer_head *di_bh, |
3192 | u32 cpos, u32 write_len) | 3202 | u32 cpos, u32 write_len, u32 max_cpos) |
3193 | { | 3203 | { |
3194 | int ret; | 3204 | int ret; |
3195 | u32 cow_start = 0, cow_len = 0; | 3205 | u32 cow_start = 0, cow_len = 0; |
@@ -3201,12 +3211,14 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode, | |||
3201 | 3211 | ||
3202 | BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)); | 3212 | BUG_ON(!(oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL)); |
3203 | 3213 | ||
3204 | ret = ocfs2_refcount_cal_cow_clusters(inode, di_bh, cpos, write_len, | 3214 | ret = ocfs2_refcount_cal_cow_clusters(inode, di_bh, |
3215 | cpos, write_len, max_cpos, | ||
3205 | &cow_start, &cow_len); | 3216 | &cow_start, &cow_len); |
3206 | if (ret) { | 3217 | if (ret) { |
3207 | mlog_errno(ret); | 3218 | mlog_errno(ret); |
3208 | goto out; | 3219 | goto out; |
3209 | } | 3220 | } |
3221 | |||
3210 | mlog(0, "CoW inode %lu, cpos %u, write_len %u, cow_start %u, " | 3222 | mlog(0, "CoW inode %lu, cpos %u, write_len %u, cow_start %u, " |
3211 | "cow_len %u\n", inode->i_ino, | 3223 | "cow_len %u\n", inode->i_ino, |
3212 | cpos, write_len, cow_start, cow_len); | 3224 | cpos, write_len, cow_start, cow_len); |
@@ -3233,12 +3245,12 @@ out: | |||
3233 | 3245 | ||
3234 | /* | 3246 | /* |
3235 | * CoW any and all clusters between cpos and cpos+write_len. | 3247 | * CoW any and all clusters between cpos and cpos+write_len. |
3236 | * If this returns successfully, all clusters between cpos and | 3248 | * Don't CoW past max_cpos. If this returns successfully, all |
3237 | * cpos+write_len are safe to modify. | 3249 | * clusters between cpos and cpos+write_len are safe to modify. |
3238 | */ | 3250 | */ |
3239 | int ocfs2_refcount_cow(struct inode *inode, | 3251 | int ocfs2_refcount_cow(struct inode *inode, |
3240 | struct buffer_head *di_bh, | 3252 | struct buffer_head *di_bh, |
3241 | u32 cpos, u32 write_len) | 3253 | u32 cpos, u32 write_len, u32 max_cpos) |
3242 | { | 3254 | { |
3243 | int ret = 0; | 3255 | int ret = 0; |
3244 | u32 p_cluster, num_clusters; | 3256 | u32 p_cluster, num_clusters; |
@@ -3257,7 +3269,7 @@ int ocfs2_refcount_cow(struct inode *inode, | |||
3257 | 3269 | ||
3258 | if (ext_flags & OCFS2_EXT_REFCOUNTED) { | 3270 | if (ext_flags & OCFS2_EXT_REFCOUNTED) { |
3259 | ret = ocfs2_refcount_cow_hunk(inode, di_bh, cpos, | 3271 | ret = ocfs2_refcount_cow_hunk(inode, di_bh, cpos, |
3260 | num_clusters); | 3272 | num_clusters, max_cpos); |
3261 | if (ret) { | 3273 | if (ret) { |
3262 | mlog_errno(ret); | 3274 | mlog_errno(ret); |
3263 | break; | 3275 | break; |
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h index a8c15b0b2307..356f99c85635 100644 --- a/fs/ocfs2/refcounttree.h +++ b/fs/ocfs2/refcounttree.h | |||
@@ -53,5 +53,5 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode, | |||
53 | int *credits, | 53 | int *credits, |
54 | struct ocfs2_alloc_context **meta_ac); | 54 | struct ocfs2_alloc_context **meta_ac); |
55 | int ocfs2_refcount_cow(struct inode *inode, struct buffer_head *di_bh, | 55 | int ocfs2_refcount_cow(struct inode *inode, struct buffer_head *di_bh, |
56 | u32 cpos, u32 write_len); | 56 | u32 cpos, u32 write_len, u32 max_cpos); |
57 | #endif /* OCFS2_REFCOUNTTREE_H */ | 57 | #endif /* OCFS2_REFCOUNTTREE_H */ |