about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorNicolas Koch <nioko1337@gmail.com>2018-05-17 14:10:14 +0200
committerNicolas Koch <nioko1337@gmail.com>2018-05-17 14:10:14 +0200
commit09d03bc245b27728c9cdd4976114506ae20208a7 (patch)
treeba1eda7458aaa0f40f36aba1378edd0f57c60350 /src/libstd/sys
parenta5e2942861324493c2cc5a32cb1473e656857b98 (diff)
downloadrust-09d03bc245b27728c9cdd4976114506ae20208a7.tar.gz
rust-09d03bc245b27728c9cdd4976114506ae20208a7.zip
Store ENOSYS in a global to avoid unnecessary system calls
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/unix/fs.rs35
1 files changed, 25 insertions, 10 deletions
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index d8739d65326..8412540934e 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -781,6 +781,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
 #[cfg(any(target_os = "linux", target_os = "android"))]
 pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     use fs::{File, set_permissions};
+    use sync::atomic::{AtomicBool, Ordering};
+
+    // Kernel prior to 4.5 don't have copy_file_range
+    // We store the availability in a global to avoid unneccessary syscalls
+    static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true);
 
     unsafe fn copy_file_range(
         fd_in: libc::c_int,
@@ -820,16 +825,26 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
         } else {
             (len - written) as usize
         };
-        let copy_result = unsafe {
-            // We actually don't have to adjust the offsets,
-            // because copy_file_range adjusts the file offset automatically
-            cvt(copy_file_range(reader.as_raw_fd(),
-                                ptr::null_mut(),
-                                writer.as_raw_fd(),
-                                ptr::null_mut(),
-                                bytes_to_copy,
-                                0)
-                )
+        let copy_result = if HAS_COPY_FILE_RANGE.load(Ordering::Relaxed) {
+            let copy_result = unsafe {
+                // We actually don't have to adjust the offsets,
+                // because copy_file_range adjusts the file offset automatically
+                cvt(copy_file_range(reader.as_raw_fd(),
+                                    ptr::null_mut(),
+                                    writer.as_raw_fd(),
+                                    ptr::null_mut(),
+                                    bytes_to_copy,
+                                    0)
+                    )
+            };
+            if let Err(ref copy_err) = copy_result {
+                if let Some(libc::ENOSYS) = copy_err.raw_os_error() {
+                    HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed);
+                }
+            }
+            copy_result
+        } else {
+            Err(io::Error::from_raw_os_error(libc::ENOSYS))
         };
         match copy_result {
             Ok(ret) => written += ret as u64,