Skip to content

Commit 268d92c

Browse files
author
CKI KWF Bot
committed
Merge: vfs: fix copy_file_range() averts filesystem freeze protection
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/7429 vfs: fix copy_file_range() averts filesystem freeze protection JIRA: https://issues.redhat.com/browse/RHEL-76048 Conflicts: - Dropping fs/ksmbd hunk as we don't have this in RHEL - RHEL also does not have the work to "Tidy up file permission hooks": https://lore.kernel.org/all/20231122122715.2561213-1-amir73il@gmail.com/ so this patch drops the upstream hunk for lockdep_assert() check for the superblock's s_writers.rw_sem, which would cause a build problem for RHEL debug kernels. commit 10bc8e4 Author: Amir Goldstein <amir73il@gmail.com> Date: Thu Nov 17 22:52:49 2022 +0200 vfs: fix copy_file_range() averts filesystem freeze protection Commit 868f9f2 ("vfs: fix copy_file_range() regression in cross-fs copies") removed fallback to generic_copy_file_range() for cross-fs cases inside vfs_copy_file_range(). To preserve behavior of nfsd and ksmbd server-side-copy, the fallback to generic_copy_file_range() was added in nfsd and ksmbd code, but that call is missing sb_start_write(), fsnotify hooks and more. Ideally, nfsd and ksmbd would pass a flag to vfs_copy_file_range() that will take care of the fallback, but that code would be subtle and we got vfs_copy_file_range() logic wrong too many times already. Instead, add a flag to explicitly request vfs_copy_file_range() to perform only generic_copy_file_range() and let nfsd and ksmbd use this flag only in the fallback path. This choise keeps the logic changes to minimum in the non-nfsd/ksmbd code paths to reduce the risk of further regressions. Fixes: 868f9f2 ("vfs: fix copy_file_range() regression in cross-fs copies") Tested-by: Namjae Jeon <linkinjeon@kernel.org> Tested-by: Luis Henriques <lhenriques@suse.de> Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Benjamin Coddington <bcodding@redhat.com> Approved-by: Jay Shin <jaeshin@redhat.com> Approved-by: Scott Mayhew <smayhew@redhat.com> Approved-by: Olga Kornievskaia <okorniev@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents 2a5f69a + ac5e00d commit 268d92c

File tree

3 files changed

+23
-6
lines changed

3 files changed

+23
-6
lines changed

fs/nfsd/vfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -709,8 +709,8 @@ ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,
709709
ret = vfs_copy_file_range(src, src_pos, dst, dst_pos, count, 0);
710710

711711
if (ret == -EOPNOTSUPP || ret == -EXDEV)
712-
ret = generic_copy_file_range(src, src_pos, dst, dst_pos,
713-
count, 0);
712+
ret = vfs_copy_file_range(src, src_pos, dst, dst_pos, count,
713+
COPY_FILE_SPLICE);
714714
return ret;
715715
}
716716

fs/read_write.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,7 +1420,9 @@ static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
14201420
* and several different sets of file_operations, but they all end up
14211421
* using the same ->copy_file_range() function pointer.
14221422
*/
1423-
if (file_out->f_op->copy_file_range) {
1423+
if (flags & COPY_FILE_SPLICE) {
1424+
/* cross sb splice is allowed */
1425+
} else if (file_out->f_op->copy_file_range) {
14241426
if (file_in->f_op->copy_file_range !=
14251427
file_out->f_op->copy_file_range)
14261428
return -EXDEV;
@@ -1470,8 +1472,9 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
14701472
size_t len, unsigned int flags)
14711473
{
14721474
ssize_t ret;
1475+
bool splice = flags & COPY_FILE_SPLICE;
14731476

1474-
if (flags != 0)
1477+
if (flags & ~COPY_FILE_SPLICE)
14751478
return -EINVAL;
14761479

14771480
ret = generic_copy_file_checks(file_in, pos_in, file_out, pos_out, &len,
@@ -1497,14 +1500,14 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
14971500
* same sb using clone, but for filesystems where both clone and copy
14981501
* are supported (e.g. nfs,cifs), we only call the copy method.
14991502
*/
1500-
if (file_out->f_op->copy_file_range) {
1503+
if (!splice && file_out->f_op->copy_file_range) {
15011504
ret = file_out->f_op->copy_file_range(file_in, pos_in,
15021505
file_out, pos_out,
15031506
len, flags);
15041507
goto done;
15051508
}
15061509

1507-
if (file_in->f_op->remap_file_range &&
1510+
if (!splice && file_in->f_op->remap_file_range &&
15081511
file_inode(file_in)->i_sb == file_inode(file_out)->i_sb) {
15091512
ret = file_in->f_op->remap_file_range(file_in, pos_in,
15101513
file_out, pos_out,
@@ -1524,6 +1527,8 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
15241527
* consistent story about which filesystems support copy_file_range()
15251528
* and which filesystems do not, that will allow userspace tools to
15261529
* make consistent desicions w.r.t using copy_file_range().
1530+
*
1531+
* We also get here if caller (e.g. nfsd) requested COPY_FILE_SPLICE.
15271532
*/
15281533
ret = generic_copy_file_range(file_in, pos_in, file_out, pos_out, len,
15291534
flags);
@@ -1578,6 +1583,10 @@ SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in,
15781583
pos_out = f_out.file->f_pos;
15791584
}
15801585

1586+
ret = -EINVAL;
1587+
if (flags != 0)
1588+
goto out;
1589+
15811590
ret = vfs_copy_file_range(f_in.file, pos_in, f_out.file, pos_out, len,
15821591
flags);
15831592
if (ret > 0) {

include/linux/fs.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1907,6 +1907,14 @@ struct dir_context {
19071907
*/
19081908
#define REMAP_FILE_ADVISORY (REMAP_FILE_CAN_SHORTEN)
19091909

1910+
/*
1911+
* These flags control the behavior of vfs_copy_file_range().
1912+
* They are not available to the user via syscall.
1913+
*
1914+
* COPY_FILE_SPLICE: call splice direct instead of fs clone/copy ops
1915+
*/
1916+
#define COPY_FILE_SPLICE (1 << 0)
1917+
19101918
struct iov_iter;
19111919
struct io_uring_cmd;
19121920

0 commit comments

Comments
 (0)