Skip to content

Commit

Permalink
Auto merge of rust-lang#134547 - SUPERCILEX:unify-copy, r=<try>
Browse files Browse the repository at this point in the history
Unify fs::copy and io::copy on Linux

Currently, `fs::copy` first tries a regular file copy (via copy_file_range) and then falls back to userspace read/write copying. We should use `io::copy` instead as it tries copy_file_range, sendfile, and splice before falling back to userspace copying. This was discovered here: SUPERCILEX/fuc#40

Perf impact: `fs::copy` will now have two additional statx calls to decide which syscall to use. I wonder if we should get rid of the statx calls and only continue down the next fallback when the relevant syscalls say the FD isn't supported.
  • Loading branch information
bors committed Dec 21, 2024
2 parents 13170cd + 2b4334e commit d179dd5
Showing 1 changed file with 1 addition and 19 deletions.
20 changes: 1 addition & 19 deletions library/std/src/sys/pal/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1980,32 +1980,14 @@ fn open_to_and_set_permissions(
Ok((writer, writer_metadata))
}

#[cfg(not(any(target_os = "linux", target_os = "android", target_vendor = "apple")))]
#[cfg(not(target_vendor = "apple"))]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
let (mut reader, reader_metadata) = open_from(from)?;
let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?;

io::copy(&mut reader, &mut writer)
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
let (mut reader, reader_metadata) = open_from(from)?;
let max_len = u64::MAX;
let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?;

use super::kernel_copy::{CopyResult, copy_regular_files};

match copy_regular_files(reader.as_raw_fd(), writer.as_raw_fd(), max_len) {
CopyResult::Ended(bytes) => Ok(bytes),
CopyResult::Error(e, _) => Err(e),
CopyResult::Fallback(written) => match io::copy::generic_copy(&mut reader, &mut writer) {
Ok(bytes) => Ok(bytes + written),
Err(e) => Err(e),
},
}
}

#[cfg(target_vendor = "apple")]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
const COPYFILE_ALL: libc::copyfile_flags_t = libc::COPYFILE_METADATA | libc::COPYFILE_DATA;
Expand Down

0 comments on commit d179dd5

Please sign in to comment.