FAILED: patch "[PATCH] vfs: fix copy_file_range() regression in cross-fs copies" failed to apply to 5.10-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 868f9f2f8e004bfe0d3935b1976f625b2924893b Mon Sep 17 00:00:00 2001
From: Amir Goldstein <[email protected]>
Date: Thu, 30 Jun 2022 22:58:49 +0300
Subject: [PATCH] vfs: fix copy_file_range() regression in cross-fs copies
A regression has been reported by Nicolas Boichat, found while using the copy_file_range syscall to copy a tracefs file.
Before commit 5dae222a5ff0 ("vfs: allow copy_file_range to copy across devices") the kernel would return -EXDEV to userspace when trying to copy a file across different filesystems. After this commit, the syscall doesn't fail anymore and instead returns zero (zero bytes copied), as this file's content is generated on-the-fly and thus reports a size of zero.
Another regression has been reported by He Zhe - the assertion of WARN_ON_ONCE(ret == -EOPNOTSUPP) can be triggered from userspace when copying from a sysfs file whose read operation may return -EOPNOTSUPP.
Since we do not have test coverage for copy_file_range() between any two types of filesystems, the best way to avoid these sort of issues in the future is for the kernel to be more picky about filesystems that are allowed to do copy_file_range().
This patch restores some cross-filesystem copy restrictions that existed prior to commit 5dae222a5ff0 ("vfs: allow copy_file_range to copy across devices"), namely, cross-sb copy is not allowed for filesystems that do not implement ->copy_file_range().
Filesystems that do implement ->copy_file_range() have full control of the result - if this method returns an error, the error is returned to the user. Before this change this was only true for fs that did not implement the ->remap_file_range() operation (i.e. nfsv3).
Filesystems that do not implement ->copy_file_range() still fall-back to the generic_copy_file_range() implementation when the copy is within the same sb. This helps the kernel can maintain a more consistent story about which filesystems support copy_file_range().
nfsd and ksmbd servers are modified to fall-back to the generic_copy_file_range() implementation in case vfs_copy_file_range() fails with -EOPNOTSUPP or -EXDEV, which preserves behavior of server-side-copy.
fall-back to generic_copy_file_range() is not implemented for the smb operation FSCTL_DUPLICATE_EXTENTS_TO_FILE, which is arguably a correct change of behavior.
fs/ksmbd/smb2pdu.c +13 -3
@@ -7810,14 +7810,24 @@ int smb2_ioctl(struct ksmbd_work *work) src_off =le64_to_cpu (dup_ext->SourceFileOffset); dst_off =le64_to_cpu (dup_ext->TargetFileOffset); length =le64_to_cpu (dup_ext->ByteCount); - cloned =vfs_clone_file_range (fp_in->filp, src_off, fp_out->filp, - dst_off, length,0 ); +/* +* XXX: It is not clear if FSCTL_DUPLICATE_EXTENTS_TO_FILE +* should fall back to vfs_copy_file_range(). This could be +* beneficial when re-exporting nfs/smb mount, but note that +* this can result in partial copy that returns an error status. +* If/when FSCTL_DUPLICATE_EXTENTS_TO_FILE_EX is implemented, +* fall back to vfs_copy_file_range(), should be avoided when +* the flag DUPLICATE_EXTENTS_DATA_EX_SOURCE_ATOMIC is set. +*/ + cloned =vfs_clone_file_range (fp_in->filp, src_off, + fp_out->filp, dst_off, length,0 );if (cloned == -EXDEV || cloned == -EOPNOTSUPP ) { ret = -EOPNOTSUPP ; goto dup_ext_out; }else if (cloned != length) { cloned =vfs_copy_file_range (fp_in->filp, src_off, - fp_out->filp, dst_off, length,0 ); + fp_out->filp, dst_off, + length,0 );if (cloned != length) {if (cloned <0 ) ret = cloned;
fs/ksmbd/vfs.c +4 -0
@@ -1779,6 +1779,10 @@ 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 );if (ret <0 )return ret;
fs/nfsd/vfs.c +7 -1
@@ -577,6 +577,7 @@ __be32 nfsd4_clone_file_range(struct svc_rqst *rqstp,ssize_t nfsd_copy_file_range (struct file *src,u64 src_pos,struct file *dst,u64 dst_pos,u64 count) { +ssize_t ret;/* * Limit copy to 4MB to prevent indefinitely blocking an nfsd
@@ -587,7 +588,12 @@ ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,* limit like this and pipeline multiple COPY requests. */ count =min_t (u64, count,1 <<22 ); -return 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 ) + ret =generic_copy_file_range (src, src_pos, dst, dst_pos, + count,0 ); +return ret; } __be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp,
fs/read_write.c +44 -33
104 lines not on this page · raw message