From 4a6ea53a24ecfdf061ab404b79bd4e79b5321171 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 14 Dec 2022 18:32:20 +0100 Subject: [PATCH] 5.15-stable patches added patches: vfs-fix-copy_file_range-averts-filesystem-freeze-protection.patch --- queue-5.15/series | 1 + ...-averts-filesystem-freeze-protection.patch | 149 ++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 queue-5.15/vfs-fix-copy_file_range-averts-filesystem-freeze-protection.patch diff --git a/queue-5.15/series b/queue-5.15/series index 2543f952824..232cd09287a 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -1 +1,2 @@ x86-vdso-conditionally-export-__vdso_sgx_enter_enclave.patch +vfs-fix-copy_file_range-averts-filesystem-freeze-protection.patch diff --git a/queue-5.15/vfs-fix-copy_file_range-averts-filesystem-freeze-protection.patch b/queue-5.15/vfs-fix-copy_file_range-averts-filesystem-freeze-protection.patch new file mode 100644 index 00000000000..bbad8cbeaff --- /dev/null +++ b/queue-5.15/vfs-fix-copy_file_range-averts-filesystem-freeze-protection.patch @@ -0,0 +1,149 @@ +From 10bc8e4af65946b727728d7479c028742321b60a Mon Sep 17 00:00:00 2001 +From: Amir Goldstein +Date: Thu, 17 Nov 2022 22:52:49 +0200 +Subject: vfs: fix copy_file_range() averts filesystem freeze protection + +From: Amir Goldstein + +commit 10bc8e4af65946b727728d7479c028742321b60a upstream. + +Commit 868f9f2f8e00 ("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: 868f9f2f8e00 ("vfs: fix copy_file_range() regression in cross-fs copies") +Tested-by: Namjae Jeon +Tested-by: Luis Henriques +Signed-off-by: Amir Goldstein +Signed-off-by: Al Viro +[backport comments for v5.15: - sb_write_started() is missing - assert was dropped ] +Signed-off-by: Amir Goldstein +Signed-off-by: Greg Kroah-Hartman +--- + fs/ksmbd/vfs.c | 6 +++--- + fs/nfsd/vfs.c | 4 ++-- + fs/read_write.c | 17 +++++++++++++---- + include/linux/fs.h | 8 ++++++++ + 4 files changed, 26 insertions(+), 9 deletions(-) + +--- a/fs/ksmbd/vfs.c ++++ b/fs/ksmbd/vfs.c +@@ -1788,9 +1788,9 @@ int ksmbd_vfs_copy_file_ranges(struct ks + 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; + +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -574,8 +574,8 @@ ssize_t nfsd_copy_file_range(struct file + 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; + } + +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -1418,7 +1418,9 @@ static int generic_copy_file_checks(stru + * 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; +@@ -1468,8 +1470,9 @@ ssize_t vfs_copy_file_range(struct file + 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, +@@ -1495,14 +1498,14 @@ ssize_t vfs_copy_file_range(struct file + * 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, +@@ -1522,6 +1525,8 @@ ssize_t vfs_copy_file_range(struct file + * 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); +@@ -1576,6 +1581,10 @@ SYSCALL_DEFINE6(copy_file_range, int, fd + 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) { +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1990,6 +1990,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 file_operations { -- 2.47.3