Description
Problem
Rustup fails partway when installing on my university's shared Red Hat 7.8 server, with OS error EOPNOTSUPP (95). I believe this is a bug in std::sys::unix::fs::copy
. This previously wasn't an issue (a few months ago), but I don't know what configuration/software changed on the server. I'm filing a report here to see if anyone else can verify the issue, to see if my analysis is sane, and to make it more visible for those searching for rustup-specific issues.
Steps
Here's the output of curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
with default options:
info: profile set to 'default'
info: default host triple is x86_64-unknown-linux-gnu
info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'
info: latest update on 2020-08-03, rust version 1.45.2 (d3fb005a3 2020-07-31)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: Defaulting to 500.0 MiB unpack ram
info: installing component 'clippy'
info: rolling back changes
error: could not copy file from '/home/TAVIKOHN/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/components' to '/home/TAVIKOHN/.rustup/tmp/nzqk3x5j5klr1bwu_file'
error: caused by: Operation not supported (os error 95)
I haven't been able to reproduce the bug on another system (or VM).
Possible Cause
I suspect the cause is an upstream issue with std::sys::unix::fs::copy
, but I've jumped to a few conclusions and could be completely wrong.
std::sys::unix::fs::copy
uses the copy_file_range
system call to efficiently copy files on Linux kernel v4.5 and later.
RHEL 7 comes with Linux kernel v3.10 and glibc v2.17. The kernel does not support the copy_file_range
system call, and glibc does not provide a wrapper.
This is normally fine, as std::sys::unix::fs::copy
tries the system call and gracefully falls back to use std::io::copy
if the kernel returns one of a few specific errors (ENOSYS, EXDEV, EINVAL, or EPERM). The problem is that from what I can tell, attempting to call copy_file_range
for a file on a NFS filesystem mount reports EOPNOTSUPP instead of ENOSYS, causing std::sys::unix::fs::copy
to break.
Since the university server maps /home
to an NFS volume, rustup fails when it tries to copy a temporary file to the toolchain directory. I think the only reason rustup gets as far as it does is because /tmp
is mapped to an XFS volume, which doesn't seem to have this odd behavior.
Here's the code I'm referring to in rust-lang/rust
Possible Solution(s)
I think the ideal solution is implement a fix in std
, maybe just falling back to std::io::copy
if EOPNOTSUPP is encountered (in addition to the other errors already covered).
While a workaround could be created for rustup specifically, that doesn't really fix the problem of not being able to copy files using the Rust standard library.
Notes
I've taken a trace of each shell command and system call, but I've opted not to include it for now.
Output of rustup --version
:
rustup 1.22.1 (b01adbbc3 2020-07-08)
Output of rustup show
:
Default host: x86_64-unknown-linux-gnu
rustup home: /home/TAVIKOHN/.rustup
no active toolchain
Output of uname -r
3.10.0-1127.8.2.el7.x86_64
Output of ldd --version
ldd (GNU libc) 2.17
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.