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
@ -1794,9 +1794,9 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
|
|||||||
ret = vfs_copy_file_range(src_fp->filp, src_off,
|
ret = vfs_copy_file_range(src_fp->filp, src_off,
|
||||||
dst_fp->filp, dst_off, len, 0);
|
dst_fp->filp, dst_off, len, 0);
|
||||||
if (ret == -EOPNOTSUPP || ret == -EXDEV)
|
if (ret == -EOPNOTSUPP || ret == -EXDEV)
|
||||||
ret = generic_copy_file_range(src_fp->filp, src_off,
|
ret = vfs_copy_file_range(src_fp->filp, src_off,
|
||||||
dst_fp->filp, dst_off,
|
dst_fp->filp, dst_off, len,
|
||||||
len, 0);
|
COPY_FILE_SPLICE);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
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);
|
ret = vfs_copy_file_range(src, src_pos, dst, dst_pos, count, 0);
|
||||||
|
|
||||||
if (ret == -EOPNOTSUPP || ret == -EXDEV)
|
if (ret == -EOPNOTSUPP || ret == -EXDEV)
|
||||||
ret = generic_copy_file_range(src, src_pos, dst, dst_pos,
|
ret = vfs_copy_file_range(src, src_pos, dst, dst_pos, count,
|
||||||
count, 0);
|
COPY_FILE_SPLICE);
|
||||||
return ret;
|
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,
|
struct file *file_out, loff_t pos_out,
|
||||||
size_t len, unsigned int flags)
|
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,
|
return do_splice_direct(file_in, &pos_in, file_out, &pos_out,
|
||||||
len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
|
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
|
* and several different sets of file_operations, but they all end up
|
||||||
* using the same ->copy_file_range() function pointer.
|
* 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 !=
|
if (file_in->f_op->copy_file_range !=
|
||||||
file_out->f_op->copy_file_range)
|
file_out->f_op->copy_file_range)
|
||||||
return -EXDEV;
|
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)
|
size_t len, unsigned int flags)
|
||||||
{
|
{
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
bool splice = flags & COPY_FILE_SPLICE;
|
||||||
|
|
||||||
if (flags != 0)
|
if (flags & ~COPY_FILE_SPLICE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ret = generic_copy_file_checks(file_in, pos_in, file_out, pos_out, &len,
|
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
|
* same sb using clone, but for filesystems where both clone and copy
|
||||||
* are supported (e.g. nfs,cifs), we only call the copy method.
|
* 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,
|
ret = file_out->f_op->copy_file_range(file_in, pos_in,
|
||||||
file_out, pos_out,
|
file_out, pos_out,
|
||||||
len, flags);
|
len, flags);
|
||||||
goto done;
|
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) {
|
file_inode(file_in)->i_sb == file_inode(file_out)->i_sb) {
|
||||||
ret = file_in->f_op->remap_file_range(file_in, pos_in,
|
ret = file_in->f_op->remap_file_range(file_in, pos_in,
|
||||||
file_out, pos_out,
|
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()
|
* consistent story about which filesystems support copy_file_range()
|
||||||
* and which filesystems do not, that will allow userspace tools to
|
* and which filesystems do not, that will allow userspace tools to
|
||||||
* make consistent desicions w.r.t using copy_file_range().
|
* 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,
|
ret = generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
|
||||||
flags);
|
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;
|
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,
|
ret = vfs_copy_file_range(f_in.file, pos_in, f_out.file, pos_out, len,
|
||||||
flags);
|
flags);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
|
@ -2089,6 +2089,14 @@ struct dir_context {
|
|||||||
*/
|
*/
|
||||||
#define REMAP_FILE_ADVISORY (REMAP_FILE_CAN_SHORTEN)
|
#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 iov_iter;
|
||||||
struct io_uring_cmd;
|
struct io_uring_cmd;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user