diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-10 23:32:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-10 23:32:37 -0400 |
commit | 40f06c799539739a08a56be8a096f56aeed05731 (patch) | |
tree | b36fd977d7abaa5041222bd07e600938af28a0d1 /fs/nfs | |
parent | a47f5c56b2eb55290e2a8668e9ca9c029990dbf6 (diff) | |
parent | fe0da9c09b2dc448ff781d1426ecb36d145ce51b (diff) |
Merge tag 'copy-file-range-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull copy_file_range updates from Darrick Wong:
"This fixes numerous parameter checking problems and inconsistent
behaviors in the new(ish) copy_file_range system call.
Now the system call will actually check its range parameters
correctly; refuse to copy into files for which the caller does not
have sufficient privileges; update mtime and strip setuid like file
writes are supposed to do; and allows copying up to the EOF of the
source file instead of failing the call like we used to.
Summary:
- Create a generic copy_file_range handler and make individual
filesystems responsible for calling it (i.e. no more assuming that
do_splice_direct will work or is appropriate)
- Refactor copy_file_range and remap_range parameter checking where
they are the same
- Install missing copy_file_range parameter checking(!)
- Remove suid/sgid and update mtime like any other file write
- Change the behavior so that a copy range crossing the source file's
eof will result in a short copy to the source file's eof instead of
EINVAL
- Permit filesystems to decide if they want to handle
cross-superblock copy_file_range in their local handlers"
* tag 'copy-file-range-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
fuse: copy_file_range needs to strip setuid bits and update timestamps
vfs: allow copy_file_range to copy across devices
xfs: use file_modified() helper
vfs: introduce file_modified() helper
vfs: add missing checks to copy_file_range
vfs: remove redundant checks from generic_remap_checks()
vfs: introduce generic_file_rw_checks()
vfs: no fallback for ->copy_file_range
vfs: introduce generic_copy_file_range()
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4file.c | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index cf42a8b939e3..f4157eb1f69d 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c | |||
@@ -129,10 +129,13 @@ nfs4_file_flush(struct file *file, fl_owner_t id) | |||
129 | } | 129 | } |
130 | 130 | ||
131 | #ifdef CONFIG_NFS_V4_2 | 131 | #ifdef CONFIG_NFS_V4_2 |
132 | static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, | 132 | static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in, |
133 | struct file *file_out, loff_t pos_out, | 133 | struct file *file_out, loff_t pos_out, |
134 | size_t count, unsigned int flags) | 134 | size_t count, unsigned int flags) |
135 | { | 135 | { |
136 | /* Only offload copy if superblock is the same */ | ||
137 | if (file_inode(file_in)->i_sb != file_inode(file_out)->i_sb) | ||
138 | return -EXDEV; | ||
136 | if (!nfs_server_capable(file_inode(file_out), NFS_CAP_COPY)) | 139 | if (!nfs_server_capable(file_inode(file_out), NFS_CAP_COPY)) |
137 | return -EOPNOTSUPP; | 140 | return -EOPNOTSUPP; |
138 | if (file_inode(file_in) == file_inode(file_out)) | 141 | if (file_inode(file_in) == file_inode(file_out)) |
@@ -140,6 +143,20 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, | |||
140 | return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); | 143 | return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); |
141 | } | 144 | } |
142 | 145 | ||
146 | static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, | ||
147 | struct file *file_out, loff_t pos_out, | ||
148 | size_t count, unsigned int flags) | ||
149 | { | ||
150 | ssize_t ret; | ||
151 | |||
152 | ret = __nfs4_copy_file_range(file_in, pos_in, file_out, pos_out, count, | ||
153 | flags); | ||
154 | if (ret == -EOPNOTSUPP || ret == -EXDEV) | ||
155 | ret = generic_copy_file_range(file_in, pos_in, file_out, | ||
156 | pos_out, count, flags); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
143 | static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) | 160 | static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) |
144 | { | 161 | { |
145 | loff_t ret; | 162 | loff_t ret; |