mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-23 16:53:58 -05:00
Amir's copy_file_range() fix
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQQqUNBr3gm4hGXdBJlZ7Krx/gZQ6wUCY4OtEwAKCRBZ7Krx/gZQ 66LvAP9tMMKsXoZY5dNjkAeQo/I5PHx81iLYu5GyigqTsf0g8gD+MeM2qxQE9QTt 6gngWpnNif7Pe5Jj5yuwl4IGbjDG9AQ= =Tx7P -----END PGP SIGNATURE----- Merge tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs Pull vfs fix from Al Viro: "Amir's copy_file_range() fix" * tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: vfs: fix copy_file_range() averts filesystem freeze protection
This commit is contained in:
commit
cf562a45a0
4 changed files with 28 additions and 9 deletions
|
@ -1794,9 +1794,9 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
|
|||
ret = vfs_copy_file_range(src_fp->filp, src_off,
|
||||
dst_fp->filp, dst_off, len, 0);
|
||||
if (ret == -EOPNOTSUPP || ret == -EXDEV)
|
||||
ret = generic_copy_file_range(src_fp->filp, src_off,
|
||||
dst_fp->filp, dst_off,
|
||||
len, 0);
|
||||
ret = vfs_copy_file_range(src_fp->filp, src_off,
|
||||
dst_fp->filp, dst_off, len,
|
||||
COPY_FILE_SPLICE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -596,8 +596,8 @@ ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,
|
|||
ret = vfs_copy_file_range(src, src_pos, dst, dst_pos, count, 0);
|
||||
|
||||
if (ret == -EOPNOTSUPP || ret == -EXDEV)
|
||||
ret = generic_copy_file_range(src, src_pos, dst, dst_pos,
|
||||
count, 0);
|
||||
ret = vfs_copy_file_range(src, src_pos, dst, dst_pos, count,
|
||||
COPY_FILE_SPLICE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1388,6 +1388,8 @@ ssize_t generic_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||
struct file *file_out, loff_t pos_out,
|
||||
size_t len, unsigned int flags)
|
||||
{
|
||||
lockdep_assert(sb_write_started(file_inode(file_out)->i_sb));
|
||||
|
||||
return do_splice_direct(file_in, &pos_in, file_out, &pos_out,
|
||||
len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
|
||||
}
|
||||
|
@ -1424,7 +1426,9 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
|
|||
* and several different sets of file_operations, but they all end up
|
||||
* using the same ->copy_file_range() function pointer.
|
||||
*/
|
||||
if (file_out->f_op->copy_file_range) {
|
||||
if (flags & COPY_FILE_SPLICE) {
|
||||
/* cross sb splice is allowed */
|
||||
} else if (file_out->f_op->copy_file_range) {
|
||||
if (file_in->f_op->copy_file_range !=
|
||||
file_out->f_op->copy_file_range)
|
||||
return -EXDEV;
|
||||
|
@ -1474,8 +1478,9 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||
size_t len, unsigned int flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
bool splice = flags & COPY_FILE_SPLICE;
|
||||
|
||||
if (flags != 0)
|
||||
if (flags & ~COPY_FILE_SPLICE)
|
||||
return -EINVAL;
|
||||
|
||||
ret = generic_copy_file_checks(file_in, pos_in, file_out, pos_out, &len,
|
||||
|
@ -1501,14 +1506,14 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||
* same sb using clone, but for filesystems where both clone and copy
|
||||
* are supported (e.g. nfs,cifs), we only call the copy method.
|
||||
*/
|
||||
if (file_out->f_op->copy_file_range) {
|
||||
if (!splice && file_out->f_op->copy_file_range) {
|
||||
ret = file_out->f_op->copy_file_range(file_in, pos_in,
|
||||
file_out, pos_out,
|
||||
len, flags);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (file_in->f_op->remap_file_range &&
|
||||
if (!splice && file_in->f_op->remap_file_range &&
|
||||
file_inode(file_in)->i_sb == file_inode(file_out)->i_sb) {
|
||||
ret = file_in->f_op->remap_file_range(file_in, pos_in,
|
||||
file_out, pos_out,
|
||||
|
@ -1528,6 +1533,8 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||
* consistent story about which filesystems support copy_file_range()
|
||||
* and which filesystems do not, that will allow userspace tools to
|
||||
* make consistent desicions w.r.t using copy_file_range().
|
||||
*
|
||||
* We also get here if caller (e.g. nfsd) requested COPY_FILE_SPLICE.
|
||||
*/
|
||||
ret = generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
|
||||
flags);
|
||||
|
@ -1582,6 +1589,10 @@ SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in,
|
|||
pos_out = f_out.file->f_pos;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
if (flags != 0)
|
||||
goto out;
|
||||
|
||||
ret = vfs_copy_file_range(f_in.file, pos_in, f_out.file, pos_out, len,
|
||||
flags);
|
||||
if (ret > 0) {
|
||||
|
|
|
@ -2089,6 +2089,14 @@ struct dir_context {
|
|||
*/
|
||||
#define REMAP_FILE_ADVISORY (REMAP_FILE_CAN_SHORTEN)
|
||||
|
||||
/*
|
||||
* These flags control the behavior of vfs_copy_file_range().
|
||||
* They are not available to the user via syscall.
|
||||
*
|
||||
* COPY_FILE_SPLICE: call splice direct instead of fs clone/copy ops
|
||||
*/
|
||||
#define COPY_FILE_SPLICE (1 << 0)
|
||||
|
||||
struct iov_iter;
|
||||
struct io_uring_cmd;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue