Skip to content

Commit 22725ce

Browse files
djwongAl Viro
authored andcommitted
vfs: fix isize/pos/len checks for reflink & dedupe
Strengthen the checking of pos/len vs. i_size, clarify the return values for the clone prep function, and remove pointless code. Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent 33844e6 commit 22725ce

File tree

3 files changed

+13
-9
lines changed

3 files changed

+13
-9
lines changed

fs/ocfs2/refcounttree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4834,7 +4834,7 @@ int ocfs2_reflink_remap_range(struct file *file_in,
48344834

48354835
ret = vfs_clone_file_prep_inodes(inode_in, pos_in, inode_out, pos_out,
48364836
&len, is_dedupe);
4837-
if (ret || len == 0)
4837+
if (ret <= 0)
48384838
goto out_unlock;
48394839

48404840
/* Lock out changes to the allocation maps and remap. */

fs/read_write.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,6 +1669,9 @@ static int clone_verify_area(struct file *file, loff_t pos, u64 len, bool write)
16691669
* Check that the two inodes are eligible for cloning, the ranges make
16701670
* sense, and then flush all dirty data. Caller must ensure that the
16711671
* inodes have been locked against any other modifications.
1672+
*
1673+
* Returns: 0 for "nothing to clone", 1 for "something to clone", or
1674+
* the usual negative error code.
16721675
*/
16731676
int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in,
16741677
struct inode *inode_out, loff_t pos_out,
@@ -1695,17 +1698,15 @@ int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in,
16951698

16961699
/* Are we going all the way to the end? */
16971700
isize = i_size_read(inode_in);
1698-
if (isize == 0) {
1699-
*len = 0;
1701+
if (isize == 0)
17001702
return 0;
1701-
}
17021703

17031704
/* Zero length dedupe exits immediately; reflink goes to EOF. */
17041705
if (*len == 0) {
1705-
if (is_dedupe) {
1706-
*len = 0;
1706+
if (is_dedupe || pos_in == isize)
17071707
return 0;
1708-
}
1708+
if (pos_in > isize)
1709+
return -EINVAL;
17091710
*len = isize - pos_in;
17101711
}
17111712

@@ -1769,7 +1770,7 @@ int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in,
17691770
return -EBADE;
17701771
}
17711772

1772-
return 0;
1773+
return 1;
17731774
}
17741775
EXPORT_SYMBOL(vfs_clone_file_prep_inodes);
17751776

@@ -1955,6 +1956,9 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
19551956
goto out;
19561957
ret = 0;
19571958

1959+
if (off + len > i_size_read(src))
1960+
return -EINVAL;
1961+
19581962
/* pre-format output fields to sane values */
19591963
for (i = 0; i < count; i++) {
19601964
same->info[i].bytes_deduped = 0ULL;

fs/xfs/xfs_reflink.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1161,7 +1161,7 @@ xfs_reflink_remap_range(
11611161

11621162
ret = vfs_clone_file_prep_inodes(inode_in, pos_in, inode_out, pos_out,
11631163
&len, is_dedupe);
1164-
if (ret || len == 0)
1164+
if (ret <= 0)
11651165
goto out_unlock;
11661166

11671167
trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out);

0 commit comments

Comments
 (0)