aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/file.c
diff options
context:
space:
mode:
authorTristan Ye <tristan.ye@oracle.com>2010-05-11 05:54:43 -0400
committerJoel Becker <joel.becker@oracle.com>2010-05-18 15:27:46 -0400
commite8aec068ecb1957630816cfa2c150c6b3ddd1790 (patch)
treeb6140b82846cd2f5ab264d01be2a4473e56faf97 /fs/ocfs2/file.c
parent78f94673d7faf01677f374f4ebbf324ff1a0aa6e (diff)
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/file.c')
-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,
1422 struct buffer_head *di_bh, u64 byte_start, 1422 struct buffer_head *di_bh, u64 byte_start,
1423 u64 byte_len) 1423 u64 byte_len)
1424{ 1424{
1425 int ret = 0; 1425 int ret = 0, flags = 0;
1426 u32 trunc_start, trunc_len, cpos, phys_cpos, alloc_size; 1426 u32 trunc_start, trunc_len, cpos, phys_cpos, alloc_size;
1427 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 1427 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
1428 struct ocfs2_cached_dealloc_ctxt dealloc; 1428 struct ocfs2_cached_dealloc_ctxt dealloc;
1429 struct address_space *mapping = inode->i_mapping; 1429 struct address_space *mapping = inode->i_mapping;
1430 struct ocfs2_extent_tree et; 1430 struct ocfs2_extent_tree et;
1431 struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
1432 u64 refcount_loc = le64_to_cpu(di->i_refcount_loc);
1431 1433
1432 ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh); 1434 ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh);
1433 ocfs2_init_dealloc_ctxt(&dealloc); 1435 ocfs2_init_dealloc_ctxt(&dealloc);
@@ -1453,6 +1455,27 @@ static int ocfs2_remove_inode_range(struct inode *inode,
1453 goto out; 1455 goto out;
1454 } 1456 }
1455 1457
1458 /*
1459 * For reflinks, we may need to CoW 2 clusters which might be
1460 * partially zero'd later, if hole's start and end offset were
1461 * within one cluster(means is not exactly aligned to clustersize).
1462 */
1463
1464 if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) {
1465
1466 ret = ocfs2_cow_file_pos(inode, di_bh, byte_start);
1467 if (ret) {
1468 mlog_errno(ret);
1469 goto out;
1470 }
1471
1472 ret = ocfs2_cow_file_pos(inode, di_bh, byte_start + byte_len);
1473 if (ret) {
1474 mlog_errno(ret);
1475 goto out;
1476 }
1477 }
1478
1456 trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start); 1479 trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start);
1457 trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits; 1480 trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits;
1458 if (trunc_len >= trunc_start) 1481 if (trunc_len >= trunc_start)
@@ -1474,7 +1497,7 @@ static int ocfs2_remove_inode_range(struct inode *inode,
1474 cpos = trunc_start; 1497 cpos = trunc_start;
1475 while (trunc_len) { 1498 while (trunc_len) {
1476 ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, 1499 ret = ocfs2_get_clusters(inode, cpos, &phys_cpos,
1477 &alloc_size, NULL); 1500 &alloc_size, &flags);
1478 if (ret) { 1501 if (ret) {
1479 mlog_errno(ret); 1502 mlog_errno(ret);
1480 goto out; 1503 goto out;
@@ -1487,7 +1510,8 @@ static int ocfs2_remove_inode_range(struct inode *inode,
1487 if (phys_cpos != 0) { 1510 if (phys_cpos != 0) {
1488 ret = ocfs2_remove_btree_range(inode, &et, cpos, 1511 ret = ocfs2_remove_btree_range(inode, &et, cpos,
1489 phys_cpos, alloc_size, 1512 phys_cpos, alloc_size,
1490 0, &dealloc, 0); 1513 flags, &dealloc,
1514 refcount_loc);
1491 if (ret) { 1515 if (ret) {
1492 mlog_errno(ret); 1516 mlog_errno(ret);
1493 goto out; 1517 goto out;