]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
vfs_default: detect EOPNOTSUPP and ENOSYS errors from copy_file_range()
authorRalph Boehme <slow@samba.org>
Thu, 12 Aug 2021 16:23:21 +0000 (18:23 +0200)
committerRalph Boehme <slow@samba.org>
Fri, 13 Aug 2021 10:57:31 +0000 (10:57 +0000)
When building in a RHEL 7 container on a RHEL 8 host, the current configure
check will detect a working SYS_copy_file_range() syscall.

Later when the resulting smbd binary is run in a RHEL 7 container on a RHEL
7 (vs 8 on the build host) host, SYS_copy_file_range() will fail with
EOPNOTSUPP.

Since the kernel support for copy_file_range() included a fallback in case
filesystems didn't implement it, the caching of copy_file_range() support can be
made a global via the static try_copy_file_range bool, there's no need to deal
with per-fileystem behaviour differences. For the curious: SYS_copy_file_range()
appeared in Linux 4.5, fallback code being vfs_copy_file_range() ->
do_splice_direct().

On current kernels the fallback function is generic_copy_file_range() (which
still calls do_splice_direct()) called from the filesystem backends directly or
from vfs_copy_file_range() -> do_copy_file_range().

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14795

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/modules/vfs_default.c

index aa7dfe3192f8fcca88c198a9d448b8b4550d48ca..5701e37d5ec6e854b4167db15af297aac5cd4473 100644 (file)
@@ -2214,10 +2214,11 @@ static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
        NTSTATUS status;
        bool same_file;
        bool ok;
+       static bool try_copy_file_range = true;
 
-#ifndef USE_COPY_FILE_RANGE
-       return NT_STATUS_MORE_PROCESSING_REQUIRED;
-#endif
+       if (!try_copy_file_range) {
+               return NT_STATUS_MORE_PROCESSING_REQUIRED;
+       }
 
        same_file = file_id_equal(&state->src_fsp->file_id,
                                  &state->dst_fsp->file_id);
@@ -2286,6 +2287,11 @@ static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
                                  (intmax_t)state->remaining,
                                  strerror(errno));
                        switch (errno) {
+                       case EOPNOTSUPP:
+                       case ENOSYS:
+                               try_copy_file_range = false;
+                               status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+                               break;
                        case EXDEV:
                                status = NT_STATUS_MORE_PROCESSING_REQUIRED;
                                break;