diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2016-12-20 02:13:26 +0300 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-12-23 07:00:23 +0300 |
commit | 22725ce4e4a00fbc37694e25dc5c8acef8ad1c28 (patch) | |
tree | c2f79e95c3aba6279faa3967a14ac9cd0d629022 /fs/read_write.c | |
parent | 33844e665104b169a3a7732bdcddb40e4f82b335 (diff) | |
download | linux-22725ce4e4a00fbc37694e25dc5c8acef8ad1c28.tar.xz |
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>
Diffstat (limited to 'fs/read_write.c')
-rw-r--r-- | fs/read_write.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/fs/read_write.c b/fs/read_write.c index da6de12b5c46..7537b6b6b5a2 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -1669,6 +1669,9 @@ static int clone_verify_area(struct file *file, loff_t pos, u64 len, bool write) * Check that the two inodes are eligible for cloning, the ranges make * sense, and then flush all dirty data. Caller must ensure that the * inodes have been locked against any other modifications. + * + * Returns: 0 for "nothing to clone", 1 for "something to clone", or + * the usual negative error code. */ int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in, 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, /* Are we going all the way to the end? */ isize = i_size_read(inode_in); - if (isize == 0) { - *len = 0; + if (isize == 0) return 0; - } /* Zero length dedupe exits immediately; reflink goes to EOF. */ if (*len == 0) { - if (is_dedupe) { - *len = 0; + if (is_dedupe || pos_in == isize) return 0; - } + if (pos_in > isize) + return -EINVAL; *len = isize - pos_in; } @@ -1769,7 +1770,7 @@ int vfs_clone_file_prep_inodes(struct inode *inode_in, loff_t pos_in, return -EBADE; } - return 0; + return 1; } EXPORT_SYMBOL(vfs_clone_file_prep_inodes); @@ -1955,6 +1956,9 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) goto out; ret = 0; + if (off + len > i_size_read(src)) + return -EINVAL; + /* pre-format output fields to sane values */ for (i = 0; i < count; i++) { same->info[i].bytes_deduped = 0ULL; |