about summary refs log tree commit diff
path: root/library/std/src/sys/unix/kernel_copy.rs
diff options
context:
space:
mode:
authorThe8472 <git@infinite-source.de>2020-11-06 23:36:23 +0100
committerThe8472 <git@infinite-source.de>2020-11-13 22:38:27 +0100
commit4854d418a5245b07eca7dbec92a29d18af13a821 (patch)
tree0e33ad776b624690bd080cb1ac04a72717ff7d99 /library/std/src/sys/unix/kernel_copy.rs
parent3dfc377aa12293ace29f9a055f0aeb634d107ed9 (diff)
downloadrust-4854d418a5245b07eca7dbec92a29d18af13a821.tar.gz
rust-4854d418a5245b07eca7dbec92a29d18af13a821.zip
do direct splice syscall and probe availability to get android builds to work
Android builds use feature level 14, the libc wrapper for splice is gated
on feature level 21+ so we have to invoke the syscall directly.
Additionally the emulator doesn't seem to support it so we also have to
add ENOSYS checks.
Diffstat (limited to 'library/std/src/sys/unix/kernel_copy.rs')
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs42
1 files changed, 38 insertions, 4 deletions
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index 6d4dcc30b45..99533dd3c07 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -58,6 +58,7 @@ use crate::os::unix::fs::FileTypeExt;
 use crate::os::unix::io::{AsRawFd, FromRawFd, RawFd};
 use crate::process::{ChildStderr, ChildStdin, ChildStdout};
 use crate::ptr;
+use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sys::cvt;
 
 #[cfg(test)]
@@ -440,7 +441,6 @@ pub(super) enum CopyResult {
 /// If the initial file offset was 0 then `Fallback` will only contain `0`.
 pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> CopyResult {
     use crate::cmp;
-    use crate::sync::atomic::{AtomicBool, Ordering};
 
     // Kernel prior to 4.5 don't have copy_file_range
     // We store the availability in a global to avoid unnecessary syscalls
@@ -534,6 +534,30 @@ enum SpliceMode {
 /// performs splice or sendfile between file descriptors
 /// Does _not_ fall back to a generic copy loop.
 fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) -> CopyResult {
+    static HAS_SENDFILE: AtomicBool = AtomicBool::new(true);
+    static HAS_SPLICE: AtomicBool = AtomicBool::new(true);
+
+    syscall! {
+        fn splice(
+            srcfd: libc::c_int,
+            src_offset: *const i64,
+            dstfd: libc::c_int,
+            dst_offset: *const i64,
+            len: libc::size_t,
+            flags: libc::c_int
+        ) -> libc::ssize_t
+    }
+
+    match mode {
+        SpliceMode::Sendfile if !HAS_SENDFILE.load(Ordering::Relaxed) => {
+            return CopyResult::Fallback(0);
+        }
+        SpliceMode::Splice if !HAS_SPLICE.load(Ordering::Relaxed) => {
+            return CopyResult::Fallback(0);
+        }
+        _ => (),
+    }
+
     let mut written = 0u64;
     while written < len {
         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) ->
                 cvt(unsafe { libc::sendfile(writer, reader, ptr::null_mut(), chunk_size) })
             }
             SpliceMode::Splice => cvt(unsafe {
-                libc::splice(reader, ptr::null_mut(), writer, ptr::null_mut(), chunk_size, 0)
+                splice(reader, ptr::null_mut(), writer, ptr::null_mut(), chunk_size, 0)
             }),
         };
 
@@ -552,8 +576,18 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) ->
             Ok(ret) => written += ret as u64,
             Err(err) => {
                 return match err.raw_os_error() {
-                    Some(os_err) if os_err == libc::EINVAL => {
-                        // splice/sendfile do not support this particular file descritor (EINVAL)
+                    Some(libc::ENOSYS | libc::EPERM) => {
+                        // syscall not supported (ENOSYS)
+                        // syscall is disallowed, e.g. by seccomp (EPERM)
+                        match mode {
+                            SpliceMode::Sendfile => HAS_SENDFILE.store(false, Ordering::Relaxed),
+                            SpliceMode::Splice => HAS_SPLICE.store(false, Ordering::Relaxed),
+                        }
+                        assert_eq!(written, 0);
+                        CopyResult::Fallback(0)
+                    }
+                    Some(libc::EINVAL) => {
+                        // splice/sendfile do not support this particular file descriptor (EINVAL)
                         assert_eq!(written, 0);
                         CopyResult::Fallback(0)
                     }