Skip to content

Commit 1316c78

Browse files
committed
Workaround for copy_file_range spuriously returning EOPNOTSUPP when attemted on a NFS mount under RHEL/CentOS 7.
The syscall is supposed to return ENOSYS in most cases but when calling it on NFS it may leak through EOPNOTSUPP even though that's supposed to be handled by the kernel and not returned to userspace. Since it returns ENOSYS in some cases anyway this will trip the HAS_COPY_FILE_RANGE detection anyway, so treat EOPNOTSUPP as if it were a ENOSYS. https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/7.8_release_notes/deprecated_functionality#the_literal_copy_file_range_literal_call_has_been_disabled_on_local_file_systems_and_in_nfs https://bugzilla.redhat.com/show_bug.cgi?id=1783554
1 parent e5e33eb commit 1316c78

File tree

1 file changed

+4
-2
lines changed
  • library/std/src/sys/unix

1 file changed

+4
-2
lines changed

library/std/src/sys/unix/fs.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1162,7 +1162,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
11621162
};
11631163
if let Err(ref copy_err) = copy_result {
11641164
match copy_err.raw_os_error() {
1165-
Some(libc::ENOSYS) | Some(libc::EPERM) => {
1165+
Some(libc::ENOSYS) | Some(libc::EPERM) | Some(libc::EOPNOTSUPP) => {
11661166
HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed);
11671167
}
11681168
_ => {}
@@ -1180,11 +1180,13 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
11801180
if os_err == libc::ENOSYS
11811181
|| os_err == libc::EXDEV
11821182
|| os_err == libc::EINVAL
1183-
|| os_err == libc::EPERM =>
1183+
|| os_err == libc::EPERM
1184+
|| os_err == libc::EOPNOTSUPP =>
11841185
{
11851186
// Try fallback io::copy if either:
11861187
// - Kernel version is < 4.5 (ENOSYS)
11871188
// - Files are mounted on different fs (EXDEV)
1189+
// - copy_file_range is broken in various ways on RHEL/CentOS 7 (EOPNOTSUPP)
11881190
// - copy_file_range is disallowed, for example by seccomp (EPERM)
11891191
// - copy_file_range cannot be used with pipes or device nodes (EINVAL)
11901192
assert_eq!(written, 0);

0 commit comments

Comments
 (0)