Skip to content

Commit d21c353

Browse files
Ashish Samanttorvalds
authored andcommitted
ocfs2: fix start offset to ocfs2_zero_range_for_truncate()
If we punch a hole on a reflink such that following conditions are met: 1. start offset is on a cluster boundary 2. end offset is not on a cluster boundary 3. (end offset is somewhere in another extent) or (hole range > MAX_CONTIG_BYTES(1MB)), we dont COW the first cluster starting at the start offset. But in this case, we were wrongly passing this cluster to ocfs2_zero_range_for_truncate() to zero out. This will modify the cluster in place and zero it in the source too. Fix this by skipping this cluster in such a scenario. To reproduce: 1. Create a random file of say 10 MB xfs_io -c 'pwrite -b 4k 0 10M' -f 10MBfile 2. Reflink it reflink -f 10MBfile reflnktest 3. Punch a hole at starting at cluster boundary with range greater that 1MB. You can also use a range that will put the end offset in another extent. fallocate -p -o 0 -l 1048615 reflnktest 4. sync 5. Check the first cluster in the source file. (It will be zeroed out). dd if=10MBfile iflag=direct bs=<cluster size> count=1 | hexdump -C Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ashish Samant <[email protected]> Reported-by: Saar Maoz <[email protected]> Reviewed-by: Srinivas Eeda <[email protected]> Cc: Mark Fasheh <[email protected]> Cc: Joel Becker <[email protected]> Cc: Junxiao Bi <[email protected]> Cc: Joseph Qi <[email protected]> Cc: Eric Ren <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent d979a39 commit d21c353

File tree

1 file changed

+24
-10
lines changed

1 file changed

+24
-10
lines changed

fs/ocfs2/file.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,7 +1506,8 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,
15061506
u64 start, u64 len)
15071507
{
15081508
int ret = 0;
1509-
u64 tmpend, end = start + len;
1509+
u64 tmpend = 0;
1510+
u64 end = start + len;
15101511
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
15111512
unsigned int csize = osb->s_clustersize;
15121513
handle_t *handle;
@@ -1538,18 +1539,31 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,
15381539
}
15391540

15401541
/*
1541-
* We want to get the byte offset of the end of the 1st cluster.
1542+
* If start is on a cluster boundary and end is somewhere in another
1543+
* cluster, we have not COWed the cluster starting at start, unless
1544+
* end is also within the same cluster. So, in this case, we skip this
1545+
* first call to ocfs2_zero_range_for_truncate() truncate and move on
1546+
* to the next one.
15421547
*/
1543-
tmpend = (u64)osb->s_clustersize + (start & ~(osb->s_clustersize - 1));
1544-
if (tmpend > end)
1545-
tmpend = end;
1548+
if ((start & (csize - 1)) != 0) {
1549+
/*
1550+
* We want to get the byte offset of the end of the 1st
1551+
* cluster.
1552+
*/
1553+
tmpend = (u64)osb->s_clustersize +
1554+
(start & ~(osb->s_clustersize - 1));
1555+
if (tmpend > end)
1556+
tmpend = end;
15461557

1547-
trace_ocfs2_zero_partial_clusters_range1((unsigned long long)start,
1548-
(unsigned long long)tmpend);
1558+
trace_ocfs2_zero_partial_clusters_range1(
1559+
(unsigned long long)start,
1560+
(unsigned long long)tmpend);
15491561

1550-
ret = ocfs2_zero_range_for_truncate(inode, handle, start, tmpend);
1551-
if (ret)
1552-
mlog_errno(ret);
1562+
ret = ocfs2_zero_range_for_truncate(inode, handle, start,
1563+
tmpend);
1564+
if (ret)
1565+
mlog_errno(ret);
1566+
}
15531567

15541568
if (tmpend < end) {
15551569
/*

0 commit comments

Comments
 (0)