@@ -58,6 +58,7 @@ use crate::os::unix::fs::FileTypeExt;
58
58
use crate :: os:: unix:: io:: { AsRawFd , FromRawFd , RawFd } ;
59
59
use crate :: process:: { ChildStderr , ChildStdin , ChildStdout } ;
60
60
use crate :: ptr;
61
+ use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
61
62
use crate :: sys:: cvt;
62
63
63
64
#[ cfg( test) ]
@@ -440,7 +441,6 @@ pub(super) enum CopyResult {
440
441
/// If the initial file offset was 0 then `Fallback` will only contain `0`.
441
442
pub ( super ) fn copy_regular_files ( reader : RawFd , writer : RawFd , max_len : u64 ) -> CopyResult {
442
443
use crate :: cmp;
443
- use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
444
444
445
445
// Kernel prior to 4.5 don't have copy_file_range
446
446
// We store the availability in a global to avoid unnecessary syscalls
@@ -534,6 +534,30 @@ enum SpliceMode {
534
534
/// performs splice or sendfile between file descriptors
535
535
/// Does _not_ fall back to a generic copy loop.
536
536
fn sendfile_splice ( mode : SpliceMode , reader : RawFd , writer : RawFd , len : u64 ) -> CopyResult {
537
+ static HAS_SENDFILE : AtomicBool = AtomicBool :: new ( true ) ;
538
+ static HAS_SPLICE : AtomicBool = AtomicBool :: new ( true ) ;
539
+
540
+ syscall ! {
541
+ fn splice(
542
+ srcfd: libc:: c_int,
543
+ src_offset: * const i64 ,
544
+ dstfd: libc:: c_int,
545
+ dst_offset: * const i64 ,
546
+ len: libc:: size_t,
547
+ flags: libc:: c_int
548
+ ) -> libc:: ssize_t
549
+ }
550
+
551
+ match mode {
552
+ SpliceMode :: Sendfile if !HAS_SENDFILE . load ( Ordering :: Relaxed ) => {
553
+ return CopyResult :: Fallback ( 0 ) ;
554
+ }
555
+ SpliceMode :: Splice if !HAS_SPLICE . load ( Ordering :: Relaxed ) => {
556
+ return CopyResult :: Fallback ( 0 ) ;
557
+ }
558
+ _ => ( ) ,
559
+ }
560
+
537
561
let mut written = 0u64 ;
538
562
while written < len {
539
563
let chunk_size = crate :: cmp:: min ( len - written, 0x7ffff000_u64 ) as usize ;
@@ -543,7 +567,7 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) ->
543
567
cvt ( unsafe { libc:: sendfile ( writer, reader, ptr:: null_mut ( ) , chunk_size) } )
544
568
}
545
569
SpliceMode :: Splice => cvt ( unsafe {
546
- libc :: splice ( reader, ptr:: null_mut ( ) , writer, ptr:: null_mut ( ) , chunk_size, 0 )
570
+ splice ( reader, ptr:: null_mut ( ) , writer, ptr:: null_mut ( ) , chunk_size, 0 )
547
571
} ) ,
548
572
} ;
549
573
@@ -552,8 +576,18 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) ->
552
576
Ok ( ret) => written += ret as u64 ,
553
577
Err ( err) => {
554
578
return match err. raw_os_error ( ) {
555
- Some ( os_err) if os_err == libc:: EINVAL => {
556
- // splice/sendfile do not support this particular file descritor (EINVAL)
579
+ Some ( libc:: ENOSYS | libc:: EPERM ) => {
580
+ // syscall not supported (ENOSYS)
581
+ // syscall is disallowed, e.g. by seccomp (EPERM)
582
+ match mode {
583
+ SpliceMode :: Sendfile => HAS_SENDFILE . store ( false , Ordering :: Relaxed ) ,
584
+ SpliceMode :: Splice => HAS_SPLICE . store ( false , Ordering :: Relaxed ) ,
585
+ }
586
+ assert_eq ! ( written, 0 ) ;
587
+ CopyResult :: Fallback ( 0 )
588
+ }
589
+ Some ( libc:: EINVAL ) => {
590
+ // splice/sendfile do not support this particular file descriptor (EINVAL)
557
591
assert_eq ! ( written, 0 ) ;
558
592
CopyResult :: Fallback ( 0 )
559
593
}
0 commit comments