Skip to content

Commit 7a6ddb3

Browse files
committed
Lift the probe code of copy_file_range into a function
1 parent 30c876c commit 7a6ddb3

File tree

1 file changed

+31
-29
lines changed

1 file changed

+31
-29
lines changed

std/src/sys/pal/unix/kernel_copy.rs

+31-29
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,23 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
577577
) -> libc::ssize_t
578578
}
579579

580+
fn probe_copy_file_range_support() -> u8 {
581+
// In some cases, we cannot determine availability from the first
582+
// `copy_file_range` call. In this case, we probe with an invalid file
583+
// descriptor so that the results are easily interpretable.
584+
match unsafe {
585+
cvt(copy_file_range(INVALID_FD, ptr::null_mut(), INVALID_FD, ptr::null_mut(), 1, 0))
586+
.map_err(|e| e.raw_os_error())
587+
} {
588+
Err(Some(EPERM | ENOSYS)) => UNAVAILABLE,
589+
Err(Some(EBADF)) => AVAILABLE,
590+
Ok(_) => panic!("unexpected copy_file_range probe success"),
591+
// Treat other errors as the syscall
592+
// being unavailable.
593+
Err(_) => UNAVAILABLE,
594+
}
595+
}
596+
580597
let mut written = 0u64;
581598
while written < max_len {
582599
let bytes_to_copy = cmp::min(max_len - written, usize::MAX as u64);
@@ -614,35 +631,20 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
614631
if written == 0 =>
615632
{
616633
if !have_probed {
617-
let available = match raw_os_error {
618-
EPERM => {
619-
// EPERM can indicate seccomp filters or an
620-
// immutable file. To distinguish these
621-
// cases we probe with invalid file
622-
// descriptors which should result in EBADF
623-
// if the syscall is supported and EPERM or
624-
// ENOSYS if it's not available.
625-
match unsafe {
626-
cvt(copy_file_range(
627-
INVALID_FD,
628-
ptr::null_mut(),
629-
INVALID_FD,
630-
ptr::null_mut(),
631-
1,
632-
0,
633-
))
634-
.map_err(|e| e.raw_os_error())
635-
} {
636-
Err(Some(EPERM | ENOSYS)) => UNAVAILABLE,
637-
Err(Some(EBADF)) => AVAILABLE,
638-
Ok(_) => panic!("unexpected copy_file_range probe success"),
639-
// Treat other errors as the syscall
640-
// being unavailable.
641-
Err(_) => UNAVAILABLE,
642-
}
643-
}
644-
ENOSYS => UNAVAILABLE,
645-
_ => AVAILABLE,
634+
let available = if matches!(raw_os_error, ENOSYS | EOPNOTSUPP | EPERM) {
635+
// EPERM can indicate seccomp filters or an
636+
// immutable file. To distinguish these
637+
// cases we probe with invalid file
638+
// descriptors which should result in EBADF
639+
// if the syscall is supported and EPERM or
640+
// ENOSYS if it's not available.
641+
//
642+
// For EOPNOTSUPP, see below. In the case of
643+
// ENOSYS, we try to cover for faulty FUSE
644+
// drivers.
645+
probe_copy_file_range_support()
646+
} else {
647+
AVAILABLE
646648
};
647649
HAS_COPY_FILE_RANGE.store(available, Ordering::Relaxed);
648650
}

0 commit comments

Comments
 (0)