]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
smb3 client: fix return code mapping of remap_file_range
authorSteve French <stfrench@microsoft.com>
Sun, 24 Aug 2025 02:15:59 +0000 (21:15 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 4 Sep 2025 13:31:54 +0000 (15:31 +0200)
commit 0e08fa789d39aa01923e3ba144bd808291895c3c upstream.

We were returning -EOPNOTSUPP for various remap_file_range cases
but for some of these the copy_file_range_syscall() requires -EINVAL
to be returned (e.g. where source and target file ranges overlap when
source and target are the same file). This fixes xfstest generic/157
which was expecting EINVAL for that (and also e.g. for when the src
offset is beyond end of file).

Cc: stable@vger.kernel.org
Acked-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/smb/client/cifsfs.c

index 9d96b833015c82649df1da0a3815877ea4f3d063..64dc7ec045d87dbbf20eeaeb1e8e9f32a8b4dd9f 100644 (file)
@@ -1348,6 +1348,20 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,
                        truncate_setsize(target_inode, new_size);
                        fscache_resize_cookie(cifs_inode_cookie(target_inode),
                                              new_size);
+               } else if (rc == -EOPNOTSUPP) {
+                       /*
+                        * copy_file_range syscall man page indicates EINVAL
+                        * is returned e.g when "fd_in and fd_out refer to the
+                        * same file and the source and target ranges overlap."
+                        * Test generic/157 was what showed these cases where
+                        * we need to remap EOPNOTSUPP to EINVAL
+                        */
+                       if (off >= src_inode->i_size) {
+                               rc = -EINVAL;
+                       } else if (src_inode == target_inode) {
+                               if (off + len > destoff)
+                                       rc = -EINVAL;
+                       }
                }
                if (rc == 0 && new_size > target_cifsi->netfs.zero_point)
                        target_cifsi->netfs.zero_point = new_size;